Skip to content

Commit 3313db4

Browse files
WikiRikRik Smale
andauthored
feat(body-memberships): add email for when member leaves their last body (#1162)
Co-authored-by: Rik Smale <[email protected]>
1 parent f1605e5 commit 3313db4

File tree

4 files changed

+174
-84
lines changed

4 files changed

+174
-84
lines changed

lib/constants.js

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module.exports = {
1313
'privacy_consent',
1414
'address',
1515
'about_me',
16-
'primary_email'
16+
'primary_email',
1717
],
1818
UPDATE: [
1919
'username',
@@ -26,45 +26,41 @@ module.exports = {
2626
'privacy_consent',
2727
'address',
2828
'about_me',
29-
'primary_email'
30-
]
29+
'primary_email',
30+
],
3131
},
3232
CIRCLE: {
33-
CREATE: ['name', 'description']
33+
CREATE: ['name', 'description'],
3434
},
3535
PAYMENT: {
36-
UPDATE: ['starts', 'expires', 'amount', 'currency', 'comment', 'invoice_name', 'invoice_address']
37-
}
36+
UPDATE: [
37+
'starts',
38+
'expires',
39+
'amount',
40+
'currency',
41+
'comment',
42+
'invoice_name',
43+
'invoice_address',
44+
],
45+
},
3846
},
3947
FIELDS_TO_QUERY: {
4048
BODY: ['code', 'name', 'abbreviation'],
4149
CAMPAIGN: ['name', 'url', 'description_short', 'description_long'],
4250
CIRCLE: ['name', 'description'],
43-
JOIN_REQUEST: [
44-
'user.first_name',
45-
'user.last_name',
46-
'user.email',
47-
],
48-
BODY_MEMBERSHIP: [
49-
'user.first_name',
50-
'user.last_name',
51-
'user.email',
52-
],
53-
CIRCLE_MEMBERSHIP: [
54-
'user.first_name',
55-
'user.last_name',
56-
'user.email',
57-
],
51+
JOIN_REQUEST: ['user.first_name', 'user.last_name', 'user.email'],
52+
BODY_MEMBERSHIP: ['user.first_name', 'user.last_name', 'user.email'],
53+
CIRCLE_MEMBERSHIP: ['user.first_name', 'user.last_name', 'user.email'],
5854
MEMBER: ['first_name', 'last_name', 'email', 'gsuite_id'],
59-
PERMISSION: ['combined', 'description']
55+
PERMISSION: ['combined', 'description'],
6056
},
6157
FIELDS_TO_FIND: {
6258
JOIN_REQUEST: {
63-
status: 'string'
59+
status: 'string',
6460
},
6561
BODY: {
66-
type: 'array'
67-
}
62+
type: 'array',
63+
},
6864
},
6965
PUBLIC_FIELDS: {
7066
CAMPAIGN: [
@@ -74,25 +70,26 @@ module.exports = {
7470
'active',
7571
'description_short',
7672
'description_long',
77-
'autojoin_body'
78-
]
73+
'autojoin_body',
74+
],
7975
},
8076
TOKEN_LENGTH: {
8177
MAIL_CONFIRMATION: 128,
8278
ACCESS_TOKEN: 32,
8379
REFRESH_TOKEN: 128,
8480
PASSWORD: 10,
8581
PASSWORD_RESET: 128,
86-
MAIL_CHANGE: 128
82+
MAIL_CHANGE: 128,
8783
},
8884
MAIL_SUBJECTS: {
8985
MAIL_CONFIRMATION: 'MyAEGEE: Please confirm your account',
9086
MAIL_CHANGE: 'MyAEGEE: Email change',
9187
PASSWORD_RESET: 'MyAEGEE: Password reset request',
9288
NEW_JOIN_REQUEST: 'MyAEGEE: New join request for your body',
9389
NEW_MEMBER: 'MyAEGEE: Welcome to AEGEE',
94-
WORKSPACE_NEW_MEMBER: 'MyAEGEE: A new member has joined their first local'
90+
WORKSPACE_NEW_MEMBER: 'MyAEGEE: A new member has joined their first local',
91+
WORKSPACE_DELETED_MEMBER: 'MyAEGEE: A member has been removed from their last body',
9592
},
9693
RESTRICTED_EMAILS: ['aegee.org', 'aegee.eu'],
97-
LISTSERV_LISTS: ['AEGEE-L', 'AEGEENEWS-L', 'ANNOUNCE-L', 'AEGEE-EVENT-L']
94+
LISTSERV_LISTS: ['AEGEE-L', 'AEGEENEWS-L', 'ANNOUNCE-L', 'AEGEE-EVENT-L'],
9895
};

middlewares/body-memberships.js

Lines changed: 98 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const {
33
BodyMembership,
44
CircleMembership,
55
Circle,
6-
User
6+
User,
77
} = require('../models');
88
const helpers = require('../lib/helpers');
99
const { sequelize, Sequelize } = require('../lib/sequelize');
@@ -18,41 +18,56 @@ exports.listAllMemberships = async (req, res) => {
1818
}
1919

2020
if (!req.permissions.hasPermission('view_members:body')) {
21-
return errors.makeForbiddenError(res, 'Permission view_members:body is required, but not present.');
21+
return errors.makeForbiddenError(
22+
res,
23+
'Permission view_members:body is required, but not present.'
24+
);
2225
}
2326

2427
const result = await BodyMembership.findAndCountAll({
2528
where: {
2629
body_id: req.currentBody.id,
27-
...helpers.filterBy(req.query.query, constants.FIELDS_TO_QUERY.BODY_MEMBERSHIP)
30+
...helpers.filterBy(
31+
req.query.query,
32+
constants.FIELDS_TO_QUERY.BODY_MEMBERSHIP
33+
),
2834
},
2935
...helpers.getPagination(req.query),
3036
order: helpers.getSorting(req.query),
31-
include: [User]
37+
include: [User],
3238
});
3339

3440
return res.json({
3541
success: true,
3642
data: result.rows,
37-
meta: { count: result.count }
43+
meta: { count: result.count },
3844
});
3945
};
4046

4147
exports.listAllMembershipsWithPermission = async (req, res) => {
4248
if (!req.permissions.hasPermission('view_members:body')) {
43-
return errors.makeForbiddenError(res, 'Permission view_members:body is required, but not present.');
49+
return errors.makeForbiddenError(
50+
res,
51+
'Permission view_members:body is required, but not present.'
52+
);
4453
}
4554

46-
if (!req.query.holds_permission.action || !req.query.holds_permission.object) {
47-
return errors.makeBadRequestError(res, 'Action or object is not specified.');
55+
if (
56+
!req.query.holds_permission.action
57+
|| !req.query.holds_permission.object
58+
) {
59+
return errors.makeBadRequestError(
60+
res,
61+
'Action or object is not specified.'
62+
);
4863
}
4964

5065
const permission = await Permission.findOne({
5166
where: {
5267
scope: 'local',
5368
action: req.query.holds_permission.action,
54-
object: req.query.holds_permission.object
55-
}
69+
object: req.query.holds_permission.object,
70+
},
5671
});
5772

5873
if (!permission) {
@@ -67,40 +82,53 @@ exports.listAllMembershipsWithPermission = async (req, res) => {
6782
body_id: req.currentBody.id,
6883
'$user.circle_memberships.circle_id$': { [Sequelize.Op.in]: circleIds },
6984
'$user.circle_memberships.circle.body_id$': req.currentBody.id,
70-
...helpers.filterBy(req.query.query, constants.FIELDS_TO_QUERY.BODY_MEMBERSHIP)
85+
...helpers.filterBy(
86+
req.query.query,
87+
constants.FIELDS_TO_QUERY.BODY_MEMBERSHIP
88+
),
7189
},
7290
...helpers.getPagination(req.query),
7391
order: helpers.getSorting(req.query),
74-
include: [{
75-
model: User,
76-
include: [{
77-
model: CircleMembership,
78-
include: [Circle]
79-
}]
80-
}]
92+
include: [
93+
{
94+
model: User,
95+
include: [
96+
{
97+
model: CircleMembership,
98+
include: [Circle],
99+
},
100+
],
101+
},
102+
],
81103
});
82104

83105
return res.json({
84106
success: true,
85107
data: result.rows,
86-
meta: { count: result.count }
108+
meta: { count: result.count },
87109
});
88110
};
89111

90112
exports.getMembership = async (req, res) => {
91113
if (!req.permissions.hasPermission('view_members:body')) {
92-
return errors.makeForbiddenError(res, 'Permission view_members:body is required, but not present.');
114+
return errors.makeForbiddenError(
115+
res,
116+
'Permission view_members:body is required, but not present.'
117+
);
93118
}
94119

95120
return res.json({
96121
success: true,
97-
data: req.currentBodyMembership
122+
data: req.currentBodyMembership,
98123
});
99124
};
100125

101126
exports.createMembership = async (req, res) => {
102127
if (!req.permissions.hasPermission('add_member:body')) {
103-
return errors.makeForbiddenError(res, 'Permission add_member:body is required, but not present.');
128+
return errors.makeForbiddenError(
129+
res,
130+
'Permission add_member:body is required, but not present.'
131+
);
104132
}
105133

106134
const user = await User.findByPk(req.body.user_id);
@@ -111,12 +139,17 @@ exports.createMembership = async (req, res) => {
111139
let membership;
112140

113141
await sequelize.transaction(async (t) => {
114-
const bodyCount = await BodyMembership.count({ where: { user_id: user.id } });
115-
116-
membership = await BodyMembership.create({
117-
user_id: user.id,
118-
body_id: req.currentBody.id
119-
}, { transaction: t });
142+
const bodyCount = await BodyMembership.count({
143+
where: { user_id: user.id },
144+
});
145+
146+
membership = await BodyMembership.create(
147+
{
148+
user_id: user.id,
149+
body_id: req.currentBody.id,
150+
},
151+
{ transaction: t }
152+
);
120153

121154
if (bodyCount === 0) {
122155
await mailer.sendMail({
@@ -127,8 +160,8 @@ exports.createMembership = async (req, res) => {
127160
member_firstname: user.first_name,
128161
member_lastname: user.last_name,
129162
body_name: req.currentBody.name,
130-
body_id: req.currentBody.id
131-
}
163+
body_id: req.currentBody.id,
164+
},
132165
});
133166

134167
await mailer.sendMail({
@@ -139,46 +172,72 @@ exports.createMembership = async (req, res) => {
139172
member_firstname: user.first_name,
140173
member_lastname: user.last_name,
141174
user_id: user.id,
142-
member_email: user.email
143-
}
175+
member_email: user.email,
176+
},
144177
});
145178
}
146179
});
147180

148181
return res.json({
149182
success: true,
150-
data: membership
183+
data: membership,
151184
});
152185
};
153186

154187
exports.updateMembership = async (req, res) => {
155188
if (!req.permissions.hasPermission('update_member:body')) {
156-
return errors.makeForbiddenError(res, 'Permission update_member:body is required, but not present.');
189+
return errors.makeForbiddenError(
190+
res,
191+
'Permission update_member:body is required, but not present.'
192+
);
157193
}
158194

159195
await req.currentBodyMembership.update({ comment: req.body.comment });
160196
return res.json({
161197
success: true,
162-
data: req.currentBodyMembership
198+
data: req.currentBodyMembership,
163199
});
164200
};
165201

166202
exports.deleteMembership = async (req, res) => {
167203
if (!req.permissions.hasPermission('delete_member:body')) {
168-
return errors.makeForbiddenError(res, 'Permission delete_member:body is required, but not present.');
204+
return errors.makeForbiddenError(
205+
res,
206+
'Permission delete_member:body is required, but not present.'
207+
);
169208
}
170209

171210
await req.currentBodyMembership.destroy();
172211

212+
const bodyCount = await BodyMembership.count({
213+
where: { user_id: req.currentBodyMembership.user_id },
214+
});
215+
216+
if (bodyCount === 0) {
217+
const user = await User.findByPk(req.currentBodyMembership.user_id);
218+
219+
await mailer.sendMail({
220+
to: config.google_workspace_notifications,
221+
subject: constants.MAIL_SUBJECTS.WORKSPACE_DELETED_MEMBER,
222+
template: 'workspace_deleted_member.html',
223+
parameters: {
224+
member_firstname: user.first_name,
225+
member_lastname: user.last_name,
226+
user_id: user.id,
227+
member_workspace_email: user.gsuite_id,
228+
},
229+
});
230+
}
231+
173232
return res.json({
174233
success: true,
175-
message: 'Membership is deleted.'
234+
message: 'Membership is deleted',
176235
});
177236
};
178237

179238
exports.deleteOwnMembership = async (req, res) => {
180239
const bodyMembership = await BodyMembership.findOne({
181-
where: { user_id: req.user.id, body_id: req.currentBody.id }
240+
where: { user_id: req.user.id, body_id: req.currentBody.id },
182241
});
183242

184243
if (!bodyMembership) {
@@ -189,6 +248,6 @@ exports.deleteOwnMembership = async (req, res) => {
189248

190249
return res.json({
191250
success: true,
192-
message: 'Membership is deleted.'
251+
message: 'Membership is deleted.',
193252
});
194253
};

middlewares/join-requests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ exports.changeRequestStatus = async (req, res) => {
138138
member_firstname: user.first_name,
139139
member_lastname: user.last_name,
140140
user_id: user.id,
141-
email: user.email
141+
member_email: user.email
142142
}
143143
});
144144
}

0 commit comments

Comments
 (0)