| 
									
										
										
										
											2017-02-18 01:56:23 -07:00
										 |  |  | 'use strict'; | 
					
						
							| 
									
										
										
										
											2015-01-07 16:55:14 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-28 22:44:13 -04:00
										 |  |  | const validator = require('validator'); | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | const groups = require('../groups'); | 
					
						
							|  |  |  | const meta = require('../meta'); | 
					
						
							|  |  |  | const user = require('../user'); | 
					
						
							|  |  |  | const utils = require('../utils'); | 
					
						
							|  |  |  | const events = require('../events'); | 
					
						
							|  |  |  | const privileges = require('../privileges'); | 
					
						
							| 
									
										
										
										
											2019-09-28 22:44:13 -04:00
										 |  |  | const notifications = require('../notifications'); | 
					
						
							| 
									
										
										
										
											2020-04-28 12:07:04 -04:00
										 |  |  | const sockets = require('.'); | 
					
						
							| 
									
										
										
										
											2015-01-07 16:55:14 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | const SocketGroups = module.exports; | 
					
						
							| 
									
										
										
										
											2015-09-17 19:57:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.before = async (socket, method, data) => { | 
					
						
							| 
									
										
										
										
											2015-01-07 16:55:14 -05:00
										 |  |  | 	if (!data) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:invalid-data]]'); | 
					
						
							| 
									
										
										
										
											2015-01-07 16:55:14 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-17 19:57:47 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-01-07 16:55:14 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.join = async (socket, data) => { | 
					
						
							| 
									
										
										
										
											2020-10-07 11:14:37 -04:00
										 |  |  | 	sockets.warnDeprecated(socket, 'PUT /api/v3/groups/:slug/membership/:uid'); | 
					
						
							| 
									
										
										
										
											2020-10-01 14:11:59 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-12 00:20:44 -05:00
										 |  |  | 	if (socket.uid <= 0) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:invalid-uid]]'); | 
					
						
							| 
									
										
										
										
											2015-02-04 00:46:51 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-07 15:40:54 -05:00
										 |  |  | 	if (typeof data.groupName !== 'string') { | 
					
						
							|  |  |  | 		throw new Error('[[error:invalid-group-name]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 19:34:48 +02:00
										 |  |  | 	if (data.groupName === 'administrators' || groups.isPrivilegeGroup(data.groupName)) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:not-allowed]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const exists = await groups.exists(data.groupName); | 
					
						
							|  |  |  | 	if (!exists) { | 
					
						
							|  |  |  | 		throw new Error('[[error:no-group]]'); | 
					
						
							| 
									
										
										
										
											2015-12-15 19:34:48 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	if (!meta.config.allowPrivateGroups) { | 
					
						
							|  |  |  | 		await groups.join(data.groupName, socket.uid); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 		logGroupEvent(socket, 'group-join', { | 
					
						
							|  |  |  | 			groupName: data.groupName, | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const results = await utils.promiseParallel({ | 
					
						
							|  |  |  | 		isAdmin: await user.isAdministrator(socket.uid), | 
					
						
							|  |  |  | 		groupData: await groups.getGroupData(data.groupName), | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (results.groupData.private && results.groupData.disableJoinRequests) { | 
					
						
							| 
									
										
										
										
											2019-09-05 12:01:32 -04:00
										 |  |  | 		throw new Error('[[error:group-join-disabled]]'); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!results.groupData.private || results.isAdmin) { | 
					
						
							|  |  |  | 		await groups.join(data.groupName, socket.uid); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 		logGroupEvent(socket, 'group-join', { | 
					
						
							|  |  |  | 			groupName: data.groupName, | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		await groups.requestMembership(data.groupName, socket.uid); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 		logGroupEvent(socket, 'group-request-membership', { | 
					
						
							|  |  |  | 			groupName: data.groupName, | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-07 16:55:14 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.leave = async (socket, data) => { | 
					
						
							| 
									
										
										
										
											2020-10-07 11:14:37 -04:00
										 |  |  | 	sockets.warnDeprecated(socket, 'DELETE /api/v3/groups/:slug/membership/:uid'); | 
					
						
							| 
									
										
										
										
											2020-04-30 21:36:04 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-12 00:20:44 -05:00
										 |  |  | 	if (socket.uid <= 0) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:invalid-uid]]'); | 
					
						
							| 
									
										
										
										
											2015-02-04 12:09:54 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-07 15:40:54 -05:00
										 |  |  | 	if (typeof data.groupName !== 'string') { | 
					
						
							|  |  |  | 		throw new Error('[[error:invalid-group-name]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-28 13:26:52 -04:00
										 |  |  | 	if (data.groupName === 'administrators') { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:cant-remove-self-as-admin]]'); | 
					
						
							| 
									
										
										
										
											2015-07-28 13:26:52 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-05 12:01:32 -04:00
										 |  |  | 	const groupData = await groups.getGroupData(data.groupName); | 
					
						
							|  |  |  | 	if (groupData.disableLeave) { | 
					
						
							|  |  |  | 		throw new Error('[[error:group-leave-disabled]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	await groups.leave(data.groupName, socket.uid); | 
					
						
							| 
									
										
										
										
											2019-09-28 22:44:13 -04:00
										 |  |  | 	const username = await user.getUserField(socket.uid, 'username'); | 
					
						
							|  |  |  | 	const notification = await notifications.create({ | 
					
						
							|  |  |  | 		type: 'group-leave', | 
					
						
							|  |  |  | 		bodyShort: '[[groups:membership.leave.notification_title, ' + username + ', ' + data.groupName + ']]', | 
					
						
							|  |  |  | 		nid: 'group:' + validator.escape(data.groupName) + ':uid:' + socket.uid + ':group-leave', | 
					
						
							|  |  |  | 		path: '/groups/' + utils.slugify(data.groupName), | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 	const uids = await groups.getOwners(data.groupName); | 
					
						
							|  |  |  | 	await notifications.push(notification, uids); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-leave', { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-01-07 16:55:14 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.addMember = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							| 
									
										
										
										
											2018-06-27 14:36:08 -04:00
										 |  |  | 	if (data.groupName === 'administrators' || groups.isPrivilegeGroup(data.groupName)) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:not-allowed]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-16 13:09:36 -04:00
										 |  |  | 	if (!data.uid) { | 
					
						
							|  |  |  | 		throw new Error('[[error:invalid-data]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data.uid = !Array.isArray(data.uid) ? [data.uid] : data.uid; | 
					
						
							|  |  |  | 	if (data.uid.filter(uid => !(parseInt(uid, 10) > 0)).length) { | 
					
						
							|  |  |  | 		throw new Error('[[error:invalid-uid]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for (const uid of data.uid) { | 
					
						
							|  |  |  | 		// eslint-disable-next-line no-await-in-loop
 | 
					
						
							|  |  |  | 		await groups.join(data.groupName, uid); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-add-member', { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							| 
									
										
										
										
											2020-08-16 13:09:36 -04:00
										 |  |  | 		targetUid: String(data.uid), | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function isOwner(socket, data) { | 
					
						
							| 
									
										
										
										
											2020-01-07 15:40:54 -05:00
										 |  |  | 	if (typeof data.groupName !== 'string') { | 
					
						
							|  |  |  | 		throw new Error('[[error:invalid-group-name]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	const results = await utils.promiseParallel({ | 
					
						
							|  |  |  | 		isAdmin: await user.isAdministrator(socket.uid), | 
					
						
							|  |  |  | 		isGlobalModerator: await user.isGlobalModerator(socket.uid), | 
					
						
							|  |  |  | 		isOwner: await groups.ownership.isOwner(socket.uid, data.groupName), | 
					
						
							|  |  |  | 		group: await groups.getGroupData(data.groupName), | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var isOwner = results.isOwner || results.isAdmin || (results.isGlobalModerator && !results.group.system); | 
					
						
							|  |  |  | 	if (!isOwner) { | 
					
						
							|  |  |  | 		throw new Error('[[error:no-privileges]]'); | 
					
						
							| 
									
										
										
										
											2018-06-27 14:36:08 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-28 13:26:52 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-15 16:58:25 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | async function isInvited(socket, data) { | 
					
						
							| 
									
										
										
										
											2020-01-07 15:40:54 -05:00
										 |  |  | 	if (typeof data.groupName !== 'string') { | 
					
						
							|  |  |  | 		throw new Error('[[error:invalid-group-name]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	const invited = await groups.isInvited(socket.uid, data.groupName); | 
					
						
							|  |  |  | 	if (!invited) { | 
					
						
							|  |  |  | 		throw new Error('[[error:not-invited]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-17 20:55:18 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.grant = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	await groups.ownership.grant(data.toUid, data.groupName); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-owner-grant', { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 		targetUid: data.toUid, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SocketGroups.rescind = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	await groups.ownership.rescind(data.toUid, data.groupName); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-owner-rescind', { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 		targetUid: data.toUid, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SocketGroups.accept = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	await groups.acceptMembership(data.groupName, data.toUid); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-accept-membership', { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 		targetUid: data.toUid, | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SocketGroups.reject = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	await groups.rejectMembership(data.groupName, data.toUid); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-reject-membership', { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 		targetUid: data.toUid, | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SocketGroups.acceptAll = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	await acceptRejectAll(SocketGroups.accept, socket, data); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SocketGroups.rejectAll = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	await acceptRejectAll(SocketGroups.reject, socket, data); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function acceptRejectAll(method, socket, data) { | 
					
						
							| 
									
										
										
										
											2020-01-07 15:40:54 -05:00
										 |  |  | 	if (typeof data.groupName !== 'string') { | 
					
						
							|  |  |  | 		throw new Error('[[error:invalid-group-name]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-14 15:19:00 -04:00
										 |  |  | 	const uids = await groups.getPending(data.groupName); | 
					
						
							|  |  |  | 	await Promise.all(uids.map(async (uid) => { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		await method(socket, { groupName: data.groupName, toUid: uid }); | 
					
						
							|  |  |  | 	})); | 
					
						
							| 
									
										
										
										
											2015-09-17 20:48:40 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-15 16:58:25 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.issueInvite = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	await groups.invite(data.groupName, data.toUid); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-invite', { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 		targetUid: data.toUid, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-07-15 16:58:25 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.issueMassInvite = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							| 
									
										
										
										
											2016-09-26 16:55:38 +03:00
										 |  |  | 	if (!data || !data.usernames || !data.groupName) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:invalid-data]]'); | 
					
						
							| 
									
										
										
										
											2016-09-26 16:55:38 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-18 21:51:32 -04:00
										 |  |  | 	let usernames = String(data.usernames).split(','); | 
					
						
							|  |  |  | 	usernames = usernames.map(username => username && username.trim()); | 
					
						
							| 
									
										
										
										
											2016-09-26 16:55:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	let uids = await user.getUidsByUsernames(usernames); | 
					
						
							| 
									
										
										
										
											2019-08-18 21:51:32 -04:00
										 |  |  | 	uids = uids.filter(uid => !!uid && parseInt(uid, 10)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	await groups.invite(data.groupName, uids); | 
					
						
							| 
									
										
										
										
											2017-02-24 15:05:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-18 21:51:32 -04:00
										 |  |  | 	for (const uid of uids) { | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 		logGroupEvent(socket, 'group-invite', { | 
					
						
							|  |  |  | 			groupName: data.groupName, | 
					
						
							| 
									
										
										
										
											2019-08-18 21:51:32 -04:00
										 |  |  | 			targetUid: uid, | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2016-09-26 16:55:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.rescindInvite = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	await groups.rejectMembership(data.groupName, data.toUid); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-06-09 17:47:02 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.acceptInvite = async (socket, data) => { | 
					
						
							|  |  |  | 	await isInvited(socket, data); | 
					
						
							|  |  |  | 	await groups.acceptMembership(data.groupName, socket.uid); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-invite-accept', { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-02-23 16:46:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.rejectInvite = async (socket, data) => { | 
					
						
							|  |  |  | 	await isInvited(socket, data); | 
					
						
							|  |  |  | 	await groups.rejectMembership(data.groupName, socket.uid); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-invite-reject', { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-02-23 16:46:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.update = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	await groups.update(data.groupName, data.values); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-09-17 20:48:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.kick = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							| 
									
										
										
										
											2015-12-18 13:32:53 +02:00
										 |  |  | 	if (socket.uid === parseInt(data.uid, 10)) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:cant-kick-self]]'); | 
					
						
							| 
									
										
										
										
											2015-12-18 13:32:53 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-21 16:48:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	const isOwnerBit = await groups.ownership.isOwner(data.uid, data.groupName); | 
					
						
							|  |  |  | 	await groups.kick(data.uid, data.groupName, isOwnerBit); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-kick', { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 		targetUid: data.uid, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SocketGroups.create = async (socket, data) => { | 
					
						
							| 
									
										
										
										
											2020-10-07 11:14:37 -04:00
										 |  |  | 	sockets.warnDeprecated(socket, 'POST /api/v3/groups'); | 
					
						
							| 
									
										
										
										
											2020-04-28 12:07:04 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 19:57:47 -04:00
										 |  |  | 	if (!socket.uid) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:no-privileges]]'); | 
					
						
							| 
									
										
										
										
											2020-01-07 15:40:54 -05:00
										 |  |  | 	} else if (typeof data.name !== 'string' || groups.isPrivilegeGroup(data.name)) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:invalid-group-name]]'); | 
					
						
							| 
									
										
										
										
											2015-01-12 13:00:23 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	const canCreate = await privileges.global.can('group:create', socket.uid); | 
					
						
							|  |  |  | 	if (!canCreate) { | 
					
						
							|  |  |  | 		throw new Error('[[error:no-privileges]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data.ownerUid = socket.uid; | 
					
						
							| 
									
										
										
										
											2020-01-07 15:40:54 -05:00
										 |  |  | 	data.system = false; | 
					
						
							| 
									
										
										
										
											2019-08-14 15:19:00 -04:00
										 |  |  | 	const groupData = await groups.create(data); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-create', { | 
					
						
							|  |  |  | 		groupName: data.name, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:19:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return groupData; | 
					
						
							| 
									
										
										
										
											2015-01-12 13:00:23 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.delete = async (socket, data) => { | 
					
						
							|  |  |  | 	await isOwner(socket, data); | 
					
						
							|  |  |  | 	if ( | 
					
						
							|  |  |  | 		data.groupName === 'administrators' || data.groupName === 'registered-users' || | 
					
						
							|  |  |  | 		data.groupName === 'guests' || data.groupName === 'Global Moderators' | 
					
						
							|  |  |  | 	) { | 
					
						
							|  |  |  | 		throw new Error('[[error:not-allowed]]'); | 
					
						
							| 
									
										
										
										
											2015-07-08 12:01:06 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	await groups.destroy(data.groupName); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | 	logGroupEvent(socket, 'group-delete', { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-01-11 18:17:49 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.search = async (socket, data) => { | 
					
						
							| 
									
										
										
										
											2015-07-09 14:01:06 -04:00
										 |  |  | 	data.options = data.options || {}; | 
					
						
							| 
									
										
										
										
											2015-09-17 19:57:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-02 16:20:10 -04:00
										 |  |  | 	if (!data.query) { | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 		const groupsPerPage = 15; | 
					
						
							|  |  |  | 		const groupData = await groups.getGroupsBySort(data.options.sort, 0, groupsPerPage - 1); | 
					
						
							|  |  |  | 		return groupData; | 
					
						
							| 
									
										
										
										
											2015-06-02 16:20:10 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-29 13:35:50 -05:00
										 |  |  | 	data.options.filterHidden = data.options.filterHidden || !await user.isAdministrator(socket.uid); | 
					
						
							| 
									
										
										
										
											2019-08-14 15:19:00 -04:00
										 |  |  | 	return await groups.search(data.query, data.options); | 
					
						
							| 
									
										
										
										
											2015-06-02 16:20:10 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.loadMore = async (socket, data) => { | 
					
						
							| 
									
										
										
										
											2017-02-18 01:52:56 -07:00
										 |  |  | 	if (!data.sort || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:invalid-data]]'); | 
					
						
							| 
									
										
										
										
											2015-06-02 16:20:10 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	const groupsPerPage = 10; | 
					
						
							|  |  |  | 	const start = parseInt(data.after, 10); | 
					
						
							|  |  |  | 	const stop = start + groupsPerPage - 1; | 
					
						
							|  |  |  | 	const groupData = await groups.getGroupsBySort(data.sort, start, stop); | 
					
						
							|  |  |  | 	return { groups: groupData, nextStart: stop + 1 }; | 
					
						
							| 
									
										
										
										
											2015-01-21 15:43:05 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.searchMembers = async (socket, data) => { | 
					
						
							| 
									
										
										
										
											2019-12-03 11:17:11 -05:00
										 |  |  | 	const [isOwner, isMember, isAdmin] = await Promise.all([ | 
					
						
							| 
									
										
										
										
											2019-11-29 13:35:50 -05:00
										 |  |  | 		groups.ownership.isOwner(socket.uid, data.groupName), | 
					
						
							| 
									
										
										
										
											2019-12-03 11:17:11 -05:00
										 |  |  | 		groups.isMember(socket.uid, data.groupName), | 
					
						
							| 
									
										
										
										
											2019-11-29 13:35:50 -05:00
										 |  |  | 		user.isAdministrator(socket.uid), | 
					
						
							|  |  |  | 	]); | 
					
						
							| 
									
										
										
										
											2019-12-03 11:17:11 -05:00
										 |  |  | 	if (!isOwner && !isMember && !isAdmin) { | 
					
						
							| 
									
										
										
										
											2019-11-29 13:35:50 -05:00
										 |  |  | 		throw new Error('[[error:no-privileges]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-29 21:48:31 -04:00
										 |  |  | 	return await groups.searchMembers({ | 
					
						
							|  |  |  | 		uid: socket.uid, | 
					
						
							|  |  |  | 		query: data.query, | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-03-10 14:09:24 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.loadMoreMembers = async (socket, data) => { | 
					
						
							| 
									
										
										
										
											2016-08-11 12:36:27 +00:00
										 |  |  | 	if (!data.groupName || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:invalid-data]]'); | 
					
						
							| 
									
										
										
										
											2015-07-03 16:42:48 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-10 13:20:10 -05:00
										 |  |  | 	const [isHidden, isAdmin, isGlobalMod] = await Promise.all([ | 
					
						
							|  |  |  | 		groups.isHidden(data.groupName), | 
					
						
							|  |  |  | 		user.isAdministrator(socket.uid), | 
					
						
							|  |  |  | 		user.isGlobalModerator(socket.uid), | 
					
						
							|  |  |  | 	]); | 
					
						
							|  |  |  | 	if (isHidden && !isAdmin && !isGlobalMod) { | 
					
						
							|  |  |  | 		const isMember = await groups.isMember(socket.uid, data.groupName); | 
					
						
							|  |  |  | 		if (!isMember) { | 
					
						
							|  |  |  | 			throw new Error('[[error:no-privileges]]'); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-03 16:42:48 -04:00
										 |  |  | 	data.after = parseInt(data.after, 10); | 
					
						
							| 
									
										
										
										
											2020-02-10 13:21:01 -05:00
										 |  |  | 	const users = await groups.getOwnersAndMembers(data.groupName, socket.uid, data.after, data.after + 9); | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	return { | 
					
						
							|  |  |  | 		users: users, | 
					
						
							|  |  |  | 		nextStart: data.after + 10, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2015-07-03 16:42:48 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-12 20:34:15 -05:00
										 |  |  | SocketGroups.cover = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.cover.update = async (socket, data) => { | 
					
						
							| 
									
										
										
										
											2015-09-17 19:57:47 -04:00
										 |  |  | 	if (!socket.uid) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:no-privileges]]'); | 
					
						
							| 
									
										
										
										
											2015-01-12 20:34:15 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-09 18:12:51 -04:00
										 |  |  | 	if (data.file || (!data.imageData && !data.position)) { | 
					
						
							|  |  |  | 		throw new Error('[[error:invalid-data]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	await canModifyGroup(socket.uid, data.groupName); | 
					
						
							| 
									
										
										
										
											2020-07-09 18:12:51 -04:00
										 |  |  | 	return await groups.updateCover(socket.uid, { | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 		imageData: data.imageData, | 
					
						
							|  |  |  | 		position: data.position, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-01-12 20:34:15 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | SocketGroups.cover.remove = async (socket, data) => { | 
					
						
							| 
									
										
										
										
											2015-11-06 10:50:14 -05:00
										 |  |  | 	if (!socket.uid) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:no-privileges]]'); | 
					
						
							| 
									
										
										
										
											2015-11-06 10:50:14 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	await canModifyGroup(socket.uid, data.groupName); | 
					
						
							| 
									
										
										
										
											2020-07-09 18:12:51 -04:00
										 |  |  | 	await groups.removeCover({ | 
					
						
							|  |  |  | 		groupName: data.groupName, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-12-29 10:34:06 +02:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2019-02-05 15:27:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | async function canModifyGroup(uid, groupName) { | 
					
						
							| 
									
										
										
										
											2020-01-07 15:40:54 -05:00
										 |  |  | 	if (typeof groupName !== 'string') { | 
					
						
							|  |  |  | 		throw new Error('[[error:invalid-group-name]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	const results = await utils.promiseParallel({ | 
					
						
							|  |  |  | 		isOwner: groups.ownership.isOwner(uid, groupName), | 
					
						
							| 
									
										
										
										
											2020-01-31 22:56:55 -05:00
										 |  |  | 		system: groups.getGroupField(groupName, 'system'), | 
					
						
							|  |  |  | 		isAdmin: user.isAdministrator(uid), | 
					
						
							|  |  |  | 		isGlobalMod: user.isGlobalModerator(uid), | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 22:56:55 -05:00
										 |  |  | 	if (!(results.isOwner || results.isAdmin || (results.isGlobalMod && !results.system))) { | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 		throw new Error('[[error:no-privileges]]'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-05 15:27:41 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 15:02:30 -04:00
										 |  |  | function logGroupEvent(socket, event, additional) { | 
					
						
							|  |  |  | 	events.log({ | 
					
						
							|  |  |  | 		type: event, | 
					
						
							|  |  |  | 		uid: socket.uid, | 
					
						
							|  |  |  | 		ip: socket.ip, | 
					
						
							|  |  |  | 		...additional, | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 13:54:56 -04:00
										 |  |  | require('../promisify')(SocketGroups); |