mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-30 02:25:55 +01:00 
			
		
		
		
	feat(writeapi): added POST /api/v1/groups
This commit is contained in:
		| @@ -77,7 +77,7 @@ GroupFullObject: | ||||
|   nullable: true | ||||
| GroupDataObject: | ||||
|   type: object | ||||
|   description: The response from an internal call to `Groups.getGroupData(<groupname>, [])` with **explicitly** no fields passed in | ||||
|   description: The response from an internal call to `Groups.getGroupsFields(<groupname>, [])` with **explicitly** no fields passed in | ||||
|   properties: | ||||
|     name: | ||||
|       type: string | ||||
|   | ||||
| @@ -364,6 +364,61 @@ paths: | ||||
|                     $ref: '#/components/schemas/Status' | ||||
|                   response: | ||||
|                     $ref: '#/components/schemas/CategoryObj' | ||||
|   /groups/: | ||||
|     post: | ||||
|       tags: | ||||
|         - groups | ||||
|       summary: Create a new group | ||||
|       description: This operation creates a new group | ||||
|       requestBody: | ||||
|         required: true | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               type: object | ||||
|               properties: | ||||
|                 name: | ||||
|                   type: string | ||||
|                 timestamp: | ||||
|                   type: number | ||||
|                 disableJoinRequests: | ||||
|                   type: number | ||||
|                   enum: [0, 1] | ||||
|                 disableLeave: | ||||
|                   type: number | ||||
|                   enum: [0, 1] | ||||
|                 hidden: | ||||
|                   type: number | ||||
|                   enum: [0, 1] | ||||
|                 ownerUid: | ||||
|                   type: number | ||||
|                 private: | ||||
|                   type: number | ||||
|                   enum: [0, 1] | ||||
|                 description: | ||||
|                   type: string | ||||
|                 userTitleEnabled: | ||||
|                   type: number | ||||
|                   enum: [0, 1] | ||||
|                 createtime: | ||||
|                   type: number | ||||
|               required: | ||||
|                 - name | ||||
|             example: | ||||
|               name: 'My Test Group' | ||||
|               hidden: 1 | ||||
|       responses: | ||||
|         '200': | ||||
|           description: group successfully created | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: object | ||||
|                 properties: | ||||
|                   status: | ||||
|                     $ref: '#/components/schemas/Status' | ||||
|                   response: | ||||
|                     $ref: components/schemas/GroupObject.yaml#/GroupDataObject | ||||
| components: | ||||
|   schemas: | ||||
|     Status: | ||||
|   | ||||
| @@ -37,20 +37,22 @@ define('admin/manage/groups', [ | ||||
| 				hidden: $('#create-group-hidden').is(':checked') ? 1 : 0, | ||||
| 			}; | ||||
|  | ||||
| 			socket.emit('admin.groups.create', submitObj, function (err, groupData) { | ||||
| 				if (err) { | ||||
| 					if (err.hasOwnProperty('message') && utils.hasLanguageKey(err.message)) { | ||||
| 						err = '[[admin/manage/groups:alerts.create-failure]]'; | ||||
| 					} | ||||
| 					createModalError.translateHtml(err).removeClass('hide'); | ||||
| 				} else { | ||||
| 			$.ajax({ | ||||
| 				url: config.relative_path + '/api/v1/groups', | ||||
| 				method: 'post', | ||||
| 				data: submitObj, | ||||
| 			}).done(function (res) { | ||||
| 				createModalError.addClass('hide'); | ||||
| 				createGroupName.val(''); | ||||
| 				createModal.on('hidden.bs.modal', function () { | ||||
| 						ajaxify.go('admin/manage/groups/' + groupData.name); | ||||
| 					ajaxify.go('admin/manage/groups/' + res.response.name); | ||||
| 				}); | ||||
| 				createModal.modal('hide'); | ||||
| 			}).fail(function (ev) { | ||||
| 				if (utils.hasLanguageKey(ev.responseJSON.status.message)) { | ||||
| 					ev.responseJSON.status.message = '[[admin/manage/groups:alerts.create-failure]]'; | ||||
| 				} | ||||
| 				createModalError.translateHtml(ev.responseJSON.status.message).removeClass('hide'); | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
|   | ||||
| @@ -11,14 +11,16 @@ define('forum/groups/list', ['forum/infinitescroll', 'benchpress'], function (in | ||||
| 		$('button[data-action="new"]').on('click', function () { | ||||
| 			bootbox.prompt('[[groups:new-group.group_name]]', function (name) { | ||||
| 				if (name && name.length) { | ||||
| 					socket.emit('groups.create', { | ||||
| 					$.ajax({ | ||||
| 						url: config.relative_path + '/api/v1/groups', | ||||
| 						method: 'post', | ||||
| 						data: { | ||||
| 							name: name, | ||||
| 					}, function (err) { | ||||
| 						if (!err) { | ||||
| 							ajaxify.go('groups/' + utils.slugify(name)); | ||||
| 						} else { | ||||
| 							app.alertError(err.message); | ||||
| 						} | ||||
| 						}, | ||||
| 					}).done(function (res) { | ||||
| 						ajaxify.go('groups/' + res.response.slug); | ||||
| 					}).fail(function (ev) { | ||||
| 						app.alertError(ev.responseJSON.status.message); | ||||
| 					}); | ||||
| 				} | ||||
| 			}); | ||||
|   | ||||
							
								
								
									
										36
									
								
								src/controllers/write/groups.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/controllers/write/groups.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const groups = require('../../groups'); | ||||
| const events = require('../../events'); | ||||
|  | ||||
| const helpers = require('../helpers'); | ||||
|  | ||||
| const Groups = module.exports; | ||||
|  | ||||
| Groups.create = async (req, res) => { | ||||
| 	if (typeof req.body.name !== 'string' || groups.isPrivilegeGroup(req.body.name)) { | ||||
| 		throw new Error('[[error:invalid-group-name]]'); | ||||
| 	} | ||||
|  | ||||
| 	if (!res.locals.privileges['group:create']) { | ||||
| 		throw new Error('[[error:no-privileges]]'); | ||||
| 	} | ||||
|  | ||||
| 	req.body.ownerUid = req.user.uid; | ||||
| 	req.body.system = false; | ||||
|  | ||||
| 	const groupObj = await groups.create(req.body); | ||||
| 	helpers.formatApiResponse(200, res, groupObj); | ||||
| 	logGroupEvent(req, 'group-create', { | ||||
| 		groupName: req.body.name, | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| function logGroupEvent(req, event, additional) { | ||||
| 	events.log({ | ||||
| 		type: event, | ||||
| 		uid: req.user.uid, | ||||
| 		ip: req.ip, | ||||
| 		...additional, | ||||
| 	}); | ||||
| } | ||||
| @@ -25,7 +25,7 @@ module.exports = function (Groups) { | ||||
|  | ||||
| 		const memberCount = data.hasOwnProperty('ownerUid') ? 1 : 0; | ||||
| 		const isPrivate = data.hasOwnProperty('private') && data.private !== undefined ? parseInt(data.private, 10) === 1 : true; | ||||
| 		const groupData = { | ||||
| 		let groupData = { | ||||
| 			name: data.name, | ||||
| 			slug: utils.slugify(data.name), | ||||
| 			createtime: timestamp, | ||||
| @@ -48,8 +48,6 @@ module.exports = function (Groups) { | ||||
| 		if (data.hasOwnProperty('ownerUid')) { | ||||
| 			await db.setAdd('group:' + groupData.name + ':owners', data.ownerUid); | ||||
| 			await db.sortedSetAdd('group:' + groupData.name + ':members', timestamp, data.ownerUid); | ||||
|  | ||||
| 			groupData.ownerUid = data.ownerUid; | ||||
| 		} | ||||
|  | ||||
| 		if (!isHidden && !isSystem) { | ||||
| @@ -62,6 +60,7 @@ module.exports = function (Groups) { | ||||
|  | ||||
| 		await db.setObjectField('groupslug:groupname', groupData.slug, groupData.name); | ||||
|  | ||||
| 		groupData = await Groups.getGroupData(groupData.name); | ||||
| 		plugins.fireHook('action:group.create', { group: groupData }); | ||||
| 		return groupData; | ||||
| 	}; | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
|  */ | ||||
|  | ||||
| const user = require('../user'); | ||||
| const privileges = require('../privileges'); | ||||
| const utils = require('../utils'); | ||||
|  | ||||
| module.exports = function (middleware) { | ||||
| @@ -37,4 +38,10 @@ module.exports = function (middleware) { | ||||
| 		res.locals.privileges = hash; | ||||
| 		return next(); | ||||
| 	}; | ||||
|  | ||||
| 	middleware.exposePrivilegeSet = async (req, res, next) => { | ||||
| 		// Exposes a user's global privilege set | ||||
| 		res.locals.privileges = await privileges.global.get(req.user.uid); | ||||
| 		return next(); | ||||
| 	}; | ||||
| }; | ||||
|   | ||||
							
								
								
									
										72
									
								
								src/routes/write/groups.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/routes/write/groups.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const router = require('express').Router(); | ||||
| const middleware = require('../../middleware'); | ||||
| const controllers = require('../../controllers'); | ||||
| const routeHelpers = require('../helpers'); | ||||
|  | ||||
| const setupApiRoute = routeHelpers.setupApiRoute; | ||||
|  | ||||
| module.exports = function () { | ||||
| 	const middlewares = [middleware.authenticate]; | ||||
|  | ||||
| 	setupApiRoute(router, '/', middleware, [...middlewares, middleware.checkRequired.bind(null, ['name']), middleware.exposePrivilegeSet], 'post', controllers.write.groups.create); | ||||
|  | ||||
| 	// app.delete('/:slug', apiMiddleware.requireUser, middleware.exposeGroupName, apiMiddleware.validateGroup, apiMiddleware.requireGroupOwner, function(req, res) { | ||||
| 	// 	Groups.destroy(res.locals.groupName, function(err) { | ||||
| 	// 		errorHandler.handle(err, res); | ||||
| 	// 	}); | ||||
| 	// }); | ||||
|  | ||||
| 	// app.put('/:slug/membership', apiMiddleware.requireUser, middleware.exposeGroupName, apiMiddleware.validateGroup, function(req, res) { | ||||
| 	// 	if (Meta.config.allowPrivateGroups !== '0') { | ||||
| 	// 		Groups.isPrivate(res.locals.groupName, function(err, isPrivate) { | ||||
| 	// 			if (isPrivate) { | ||||
| 	// 				Groups.requestMembership(res.locals.groupName, req.user.uid, function(err) { | ||||
| 	// 					errorHandler.handle(err, res); | ||||
| 	// 				}); | ||||
| 	// 			} else { | ||||
| 	// 				Groups.join(res.locals.groupName, req.user.uid, function(err) { | ||||
| 	// 					errorHandler.handle(err, res); | ||||
| 	// 				}); | ||||
| 	// 			} | ||||
| 	// 		}); | ||||
| 	// 	} else { | ||||
| 	// 		Groups.join(res.locals.groupName, req.user.uid, function(err) { | ||||
| 	// 			errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	} | ||||
| 	// }); | ||||
|  | ||||
| 	// app.put('/:slug/membership/:uid', middleware.exposeGroupName, apiMiddleware.validateGroup, apiMiddleware.requireUser, apiMiddleware.requireAdmin, function(req, res) { | ||||
| 	// 	Groups.join(res.locals.groupName, req.params.uid, function(err) { | ||||
| 	// 		errorHandler.handle(err, res); | ||||
| 	// 	}); | ||||
| 	// }); | ||||
|  | ||||
| 	// app.delete('/:slug/membership', apiMiddleware.requireUser, middleware.exposeGroupName, apiMiddleware.validateGroup, function(req, res) { | ||||
| 	// 	Groups.isMember(req.user.uid, res.locals.groupName, function(err, isMember) { | ||||
| 	// 		if (isMember) { | ||||
| 	// 			Groups.leave(res.locals.groupName, req.user.uid, function(err) { | ||||
| 	// 				errorHandler.handle(err, res); | ||||
| 	// 			}); | ||||
| 	// 		} else { | ||||
| 	// 			errorHandler.respond(400, res); | ||||
| 	// 		} | ||||
| 	// 	}); | ||||
| 	// }); | ||||
|  | ||||
| 	// app.delete('/:slug/membership/:uid', middleware.exposeGroupName, apiMiddleware.validateGroup, apiMiddleware.requireUser, apiMiddleware.requireAdmin, function(req, res) { | ||||
| 	//     Groups.isMember(req.params.uid, res.locals.groupName, function(err, isMember) { | ||||
| 	//         if (isMember) { | ||||
| 	//             Groups.leave(res.locals.groupName, req.params.uid, function(err) { | ||||
| 	//                 errorHandler.handle(err, res); | ||||
| 	//             }); | ||||
| 	//         } else { | ||||
| 	//             errorHandler.respond(400, res); | ||||
| 	//         } | ||||
| 	//     }); | ||||
| 	// }); | ||||
|  | ||||
| 	return router; | ||||
| }; | ||||
| @@ -1,10 +1,13 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const groups = require('../../groups'); | ||||
| const sockets = require('..'); | ||||
|  | ||||
| const Groups = module.exports; | ||||
|  | ||||
| Groups.create = async function (socket, data) { | ||||
| 	sockets.warnDeprecated(socket, 'POST /api/v1/groups'); | ||||
|  | ||||
| 	if (!data) { | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} else if (groups.isPrivilegeGroup(data.name)) { | ||||
|   | ||||
| @@ -8,6 +8,7 @@ const utils = require('../utils'); | ||||
| const events = require('../events'); | ||||
| const privileges = require('../privileges'); | ||||
| const notifications = require('../notifications'); | ||||
| const sockets = require('.'); | ||||
|  | ||||
| const SocketGroups = module.exports; | ||||
|  | ||||
| @@ -277,6 +278,8 @@ SocketGroups.kick = async (socket, data) => { | ||||
| }; | ||||
|  | ||||
| SocketGroups.create = async (socket, data) => { | ||||
| 	sockets.warnDeprecated(socket, 'POST /api/v1/groups'); | ||||
|  | ||||
| 	if (!socket.uid) { | ||||
| 		throw new Error('[[error:no-privileges]]'); | ||||
| 	} else if (typeof data.name !== 'string' || groups.isPrivilegeGroup(data.name)) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user