Skip to content

Commit f8b7b56

Browse files
fix(organizations,users): address CodeRabbit review — returnDocument, membership permissions
- Replace deprecated {new: true} with {returnDocument: 'after'} in repositories - Return empty array for non-admin users listing pending requests instead of 403 - Remove policy middleware from GET requests route (controller handles auth) - Add integration tests for pending requests permissions - Update e2e tests to match new behavior
1 parent 8a709b2 commit f8b7b56

6 files changed

Lines changed: 56 additions & 17 deletions

File tree

modules/organizations/controllers/organizations.membershipRequest.controller.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ const create = async (req, res) => {
3333
*/
3434
const listPending = async (req, res) => {
3535
try {
36-
if (req.membership && req.membership.role === 'member') {
37-
return responses.error(res, 403, 'Forbidden', 'Only admin or owner can list pending requests')();
36+
if (!req.membership || req.membership.role === 'member') {
37+
return responses.success(res, 'membership request list')([]);
3838
}
3939
const requests = await MembershipService.listPending(req.organization._id || req.organization.id);
4040
responses.success(res, 'membership request list')(requests);

modules/organizations/routes/organizations.membershipRequest.routes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default (app) => {
2424
.route('/api/organizations/:organizationId/requests')
2525
.all(passport.authenticate('jwt', { session: false }))
2626
.post(limiters.api, organizations.loadMembership, policy.isAllowed, membershipRequests.create)
27-
.get(organizations.loadMembership, policy.isAllowed, membershipRequests.listPending);
27+
.get(organizations.loadMembership, membershipRequests.listPending);
2828

2929
// Approve a membership request
3030
app

modules/organizations/tests/organizations.domainJoin.e2e.tests.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -161,17 +161,6 @@ describe('Organizations domain join E2E tests:', () => {
161161
}
162162
});
163163

164-
test('pending user cannot list pending requests — 403', async () => {
165-
try {
166-
await agentMember
167-
.get(`/api/organizations/${org._id}/requests`)
168-
.expect(403);
169-
} catch (err) {
170-
console.log(err);
171-
expect(err).toBeFalsy();
172-
}
173-
});
174-
175164
test('owner can list pending requests and sees the new joiner — 200', async () => {
176165
try {
177166
const result = await agentOwner

modules/organizations/tests/organizations.integration.tests.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,56 @@ describe('Organizations integration tests:', () => {
9595
});
9696
});
9797

98+
describe('GET /api/organizations/:id/requests (pending requests permissions)', () => {
99+
let owner;
100+
let member;
101+
let ownerAgent;
102+
let memberAgent;
103+
let org;
104+
105+
beforeAll(async () => {
106+
config.organizations = { enabled: true, autoCreate: true, domainMatching: false };
107+
ownerAgent = request.agent((await bootstrap()).app);
108+
memberAgent = request.agent((await bootstrap()).app);
109+
110+
// Create owner with auto-created org
111+
const ownerRes = await ownerAgent
112+
.post('/api/auth/signup')
113+
.send({ firstName: 'Owner', lastName: 'Test', email: 'owner-req@test.com', password: 'W@os.jsI$Aw3$0m3', provider: 'local' })
114+
.expect(200);
115+
owner = ownerRes.body.user;
116+
117+
const orgsRes = await ownerAgent.get('/api/organizations').expect(200);
118+
org = orgsRes.body.data[0];
119+
120+
// Create member and add to same org
121+
const memberRes = await memberAgent
122+
.post('/api/auth/signup')
123+
.send({ firstName: 'Member', lastName: 'Test', email: 'member-req@test.com', password: 'W@os.jsI$Aw3$0m3', provider: 'local' })
124+
.expect(200);
125+
member = memberRes.body.user;
126+
127+
// Add member to owner's org as 'member'
128+
const MembershipService = (await import(path.resolve('./modules/organizations/services/organizations.membership.service.js'))).default;
129+
await MembershipService.create({ userId: member._id || member.id, organizationId: org._id || org.id, role: 'member' });
130+
});
131+
132+
test('owner should see pending requests — 200 with array', async () => {
133+
const result = await ownerAgent.get(`/api/organizations/${org._id || org.id}/requests`).expect(200);
134+
expect(result.body.data).toBeInstanceOf(Array);
135+
});
136+
137+
test('member should get empty array for pending requests — 200', async () => {
138+
const result = await memberAgent.get(`/api/organizations/${org._id || org.id}/requests`).expect(200);
139+
expect(result.body.data).toEqual([]);
140+
});
141+
142+
afterAll(async () => {
143+
await cleanupUser(owner);
144+
await cleanupUser(member);
145+
});
146+
});
147+
98148
// Mongoose disconnect
99149
afterAll(async () => {
100150
config.organizations = { ...originalOrganizations };

modules/uploads/repositories/uploads.repository.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const getStream = (upload) => {
4444
* @param {Object} update
4545
* @return {Object} upload updated
4646
*/
47-
const update = (id, update) => Uploads.findOneAndUpdate({ _id: id }, update, { new: true }).exec();
47+
const update = (id, update) => Uploads.findOneAndUpdate({ _id: id }, update, { returnDocument: 'after' }).exec();
4848

4949
/**
5050
* @desc Function to remove an upload from db

modules/users/repositories/users.repository.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ const search = (input) => User.find(input).exec();
8585
*/
8686
const update = (user) => {
8787
if (user._id) {
88-
return User.findByIdAndUpdate(user._id, user, { new: true, runValidators: true }).exec();
88+
return User.findByIdAndUpdate(user._id, user, { returnDocument: 'after', runValidators: true }).exec();
8989
}
9090
return new User(user).save();
9191
};
@@ -173,7 +173,7 @@ const updateById = (id, data) => User.updateOne({ _id: id }, data, { runValidato
173173
* @returns {Object} updated user
174174
*/
175175
const findByIdAndUpdatePopulated = (id, data, populateFields) =>
176-
User.findByIdAndUpdate(id, data, { new: true, runValidators: true }).populate(populateFields).exec();
176+
User.findByIdAndUpdate(id, data, { returnDocument: 'after', runValidators: true }).populate(populateFields).exec();
177177

178178
/**
179179
* @desc Function to find users matching a filter with optional field selection

0 commit comments

Comments
 (0)