Skip to content

Commit

Permalink
Children Members Followup (#8456)
Browse files Browse the repository at this point in the history
* refact: remove children memberships when added to parent collective

* refact: add includeInheritedMembers flag to members resolver

* fix: consider inherited admins in isLastAdmin()

* fix: reviewed suggestions

Co-authored-by: François Hodierne <francois@hodierne.net>

---------

Co-authored-by: François Hodierne <francois@hodierne.net>
  • Loading branch information
kewitz and znarf committed Jan 30, 2023
1 parent b8248de commit a5fe646
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 4 deletions.
4 changes: 4 additions & 0 deletions server/graphql/v2/interface/Account.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ const accountFieldsDefinition = () => ({
type: new GraphQLList(AccountType),
description: 'Type of accounts (BOT/COLLECTIVE/EVENT/ORGANIZATION/INDIVIDUAL)',
},
includeInherited: {
type: GraphQLBoolean,
defaultValue: true,
},
},
},
memberInvitations: {
Expand Down
8 changes: 6 additions & 2 deletions server/graphql/v2/interface/HasMembers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GraphQLInt, GraphQLList, GraphQLNonNull } from 'graphql';
import { GraphQLBoolean, GraphQLInt, GraphQLList, GraphQLNonNull } from 'graphql';
import { intersection } from 'lodash';

import { types as CollectiveTypes } from '../../../constants/collectives';
Expand Down Expand Up @@ -31,6 +31,10 @@ export const HasMembersFields = {
defaultValue: { field: 'createdAt', direction: 'ASC' },
description: 'Order of the results',
},
includeInherited: {
type: GraphQLBoolean,
defaultValue: true,
},
},
async resolve(collective, args, req) {
// TODO: isn't it a better practice to return null?
Expand All @@ -52,7 +56,7 @@ export const HasMembersFields = {
}

// Inherit Accountants and Admin from parent collective for Events and Projects
if ([CollectiveTypes.EVENT, CollectiveTypes.PROJECT].includes(collective.type)) {
if (args.includeInherited && [CollectiveTypes.EVENT, CollectiveTypes.PROJECT].includes(collective.type)) {
const inheritedRoles = [MemberRoles.ACCOUNTANT, MemberRoles.ADMIN, MemberRoles.MEMBER];
where = {
[Op.or]: [
Expand Down
5 changes: 4 additions & 1 deletion server/graphql/v2/mutation/MemberMutations.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ import { AccountReferenceInput, fetchAccountWithReference } from '../input/Accou
import { Member } from '../object/Member';

const isLastAdmin = async (account, memberAccount) => {
// When checking if the member is the last admin for Minimum Amount of Admins policy,
// make sure we consider inherited admins, otherwise we won't be able to remove the event/project admin.
const CollectiveId = account.ParentCollectiveId ? [account.ParentCollectiveId, account.id] : account.id;
const admins = await models.Member.findAll({
where: {
CollectiveId: account.id,
CollectiveId,
role: MemberRoles.ADMIN,
},
});
Expand Down
16 changes: 15 additions & 1 deletion server/models/Collective.js
Original file line number Diff line number Diff line change
Expand Up @@ -1963,11 +1963,25 @@ Collective.prototype.addUserWithRole = async function (user, role, defaultAttrib

case roles.MEMBER:
case roles.ACCOUNTANT:
case roles.ADMIN:
case roles.ADMIN: {
if (![types.FUND, types.PROJECT, types.EVENT].includes(this.type)) {
await this.sendNewMemberEmail(user, role, member, sequelizeParams);
}

// Sanitization: Clean memberships of children collectives
const children = await this.getChildren();
if (children.length > 0) {
await models.Member.destroy({
where: {
MemberCollectiveId: user.CollectiveId,
CollectiveId: children.map(c => c.id),
role,
},
});
}

break;
}
}

return member;
Expand Down

0 comments on commit a5fe646

Please sign in to comment.