mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +01:00 
			
		
		
		
	feat(writeapi): post editing
This commit is contained in:
		| @@ -790,6 +790,42 @@ paths: | ||||
|                   response: | ||||
|                     type: object | ||||
|                     properties: {} | ||||
|   /posts/{pid}: | ||||
|     put: | ||||
|       tags: | ||||
|         - posts | ||||
|       summary: Edit a post | ||||
|       description: This operation edits a post | ||||
|       requestBody: | ||||
|         required: true | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               type: object | ||||
|               properties: | ||||
|                 content: | ||||
|                   type: string | ||||
|                   description: New post content | ||||
|                 title: | ||||
|                   type: string | ||||
|                   description: Topic title, only accepted for main posts | ||||
|               required: | ||||
|                 - content | ||||
|             example: | ||||
|               content: 'New post content' | ||||
|               title: 'New title' | ||||
|       responses: | ||||
|         '200': | ||||
|           description: Post successfully edited | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: object | ||||
|                 properties: | ||||
|                   status: | ||||
|                     $ref: '#/components/schemas/Status' | ||||
|                   response: | ||||
|                     $ref: components/schemas/PostsObject.yaml#/PostsObject | ||||
| components: | ||||
|   schemas: | ||||
|     Status: | ||||
|   | ||||
| @@ -6,3 +6,4 @@ Write.users = require('./users'); | ||||
| Write.groups = require('./groups'); | ||||
| Write.categories = require('./categories'); | ||||
| Write.topics = require('./topics'); | ||||
| Write.posts = require('./posts'); | ||||
|   | ||||
							
								
								
									
										81
									
								
								src/controllers/write/posts.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/controllers/write/posts.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const validator = require('validator'); | ||||
| const _ = require('lodash'); | ||||
|  | ||||
| const meta = require('../../meta'); | ||||
| const groups = require('../../groups'); | ||||
| const posts = require('../../posts'); | ||||
| const events = require('../../events'); | ||||
| const utils = require('../../utils'); | ||||
|  | ||||
| const helpers = require('../helpers'); | ||||
| const sockets = require('../../socket.io'); | ||||
|  | ||||
| const Posts = module.exports; | ||||
|  | ||||
| Posts.edit = async (req, res) => { | ||||
| 	if (meta.config.minimumPostLength !== 0 && !req.body.content) { | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	// Trim and remove HTML (latter for composers that send in HTML, like redactor) | ||||
| 	var contentLen = utils.stripHTMLTags(req.body.content).trim().length; | ||||
|  | ||||
| 	if (req.body.title && req.body.title.length < meta.config.minimumTitleLength) { | ||||
| 		throw new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]'); | ||||
| 	} else if (req.body.title && req.body.title.length > meta.config.maximumTitleLength) { | ||||
| 		throw new Error('[[error:title-too-long, ' + meta.config.maximumTitleLength + ']]'); | ||||
| 	} else if (meta.config.minimumPostLength !== 0 && contentLen < meta.config.minimumPostLength) { | ||||
| 		throw new Error('[[error:content-too-short, ' + meta.config.minimumPostLength + ']]'); | ||||
| 	} else if (contentLen > meta.config.maximumPostLength) { | ||||
| 		throw new Error('[[error:content-too-long, ' + meta.config.maximumPostLength + ']]'); | ||||
| 	} | ||||
|  | ||||
| 	// Payload construction | ||||
| 	var payload = { | ||||
| 		req, | ||||
| 		uid: req.user.uid, | ||||
| 		pid: req.params.pid, | ||||
| 		content: req.body.content, | ||||
| 		options: {}, | ||||
| 	}; | ||||
| 	['handle', 'title'].forEach((prop) => { | ||||
| 		if (req.body.hasOwnProperty(prop)) { | ||||
| 			payload[prop] = req.body[prop]; | ||||
| 		} | ||||
| 	}); | ||||
| 	['topic_thumb', 'tags'].forEach((prop) => { | ||||
| 		if (req.body.hasOwnProperty(prop)) { | ||||
| 			payload.options[prop] = req.body[prop]; | ||||
| 		} | ||||
| 	}); | ||||
|  | ||||
| 	const editResult = await posts.edit(payload); | ||||
| 	helpers.formatApiResponse(200, res, await posts.getPostSummaryByPids([editResult.pid], req.user.uid, {})); | ||||
|  | ||||
| 	if (editResult.topic.renamed) { | ||||
| 		await events.log({ | ||||
| 			type: 'topic-rename', | ||||
| 			uid: req.user.uid, | ||||
| 			ip: req.ip, | ||||
| 			tid: editResult.topic.tid, | ||||
| 			oldTitle: validator.escape(String(editResult.topic.oldTitle)), | ||||
| 			newTitle: validator.escape(String(editResult.topic.title)), | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	if (!editResult.post.deleted) { | ||||
| 		sockets.in('topic_' + editResult.topic.tid).emit('event:post_edited', editResult); | ||||
| 	} | ||||
|  | ||||
| 	const memberData = await groups.getMembersOfGroups([ | ||||
| 		'administrators', | ||||
| 		'Global Moderators', | ||||
| 		'cid:' + editResult.topic.cid + ':privileges:moderate', | ||||
| 		'cid:' + editResult.topic.cid + ':privileges:groups:moderate', | ||||
| 	]); | ||||
|  | ||||
| 	const uids = _.uniq(_.flatten(memberData).concat(req.user.uid.toString())); | ||||
| 	uids.forEach(uid =>	sockets.in('uid_' + uid).emit('event:post_edited', editResult)); | ||||
| }; | ||||
| @@ -24,7 +24,7 @@ Write.reload = (params) => { | ||||
| 	router.use('/api/v1/groups', require('./groups')()); | ||||
| 	router.use('/api/v1/categories', require('./categories')()); | ||||
| 	router.use('/api/v1/topics', require('./topics')()); | ||||
| 	// router.use('/api/v1/posts', require('./posts')()); | ||||
| 	router.use('/api/v1/posts', require('./posts')()); | ||||
| 	// router.use('/api/v1/util', require('./util')()); | ||||
|  | ||||
| 	router.get('/api/v1/ping', function (req, res) { | ||||
|   | ||||
							
								
								
									
										94
									
								
								src/routes/write/posts.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/routes/write/posts.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| '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, '/:pid', middleware, [...middlewares, middleware.checkRequired.bind(null, ['content'])], 'put', controllers.write.posts.edit); | ||||
|  | ||||
| 	// app.route('/:pid') | ||||
| 	// 	.put(apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 		if (!utils.checkRequired(['content'], req, res)) { | ||||
| 	// 			return false; | ||||
| 	// 		} | ||||
|  | ||||
| 	// 		var payload = { | ||||
| 	// 			uid: req.user.uid, | ||||
| 	// 			pid: req.params.pid, | ||||
| 	// 			content: req.body.content, | ||||
| 	// 			options: {} | ||||
| 	// 		}; | ||||
|  | ||||
| 	// 		if (req.body.handle) { payload.handle = req.body.handle; } | ||||
| 	// 		if (req.body.title) { payload.title = req.body.title; } | ||||
| 	// 		if (req.body.topic_thumb) { payload.options.topic_thumb = req.body.topic_thumb; } | ||||
| 	// 		if (req.body.tags) { payload.options.tags = req.body.tags; } | ||||
|  | ||||
| 	// 		posts.edit(payload, function(err) { | ||||
| 	// 			errorHandler.handle(err, res); | ||||
| 	// 		}) | ||||
| 	// 	}) | ||||
| 	// 	.delete(apiMiddleware.requireUser, apiMiddleware.validatePid, function(req, res) { | ||||
| 	// 		posts.purge(req.params.pid, req.user.uid, function(err) { | ||||
| 	// 			errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	}); | ||||
|  | ||||
| 	// app.route('/:pid/state') | ||||
| 	// 	.put(apiMiddleware.requireUser, apiMiddleware.validatePid, function (req, res) { | ||||
| 	// 		posts.restore(req.params.pid, req.user.uid, function (err) { | ||||
| 	// 			errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	}) | ||||
| 	// 	.delete(apiMiddleware.requireUser, apiMiddleware.validatePid, function (req, res) { | ||||
| 	// 		posts.delete(req.params.pid, req.user.uid, function (err) { | ||||
| 	// 			errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	}); | ||||
|  | ||||
| 	// app.route('/:pid/vote') | ||||
| 	// 	.post(apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 		if (!utils.checkRequired(['delta'], req, res)) { | ||||
| 	// 			return false; | ||||
| 	// 		} | ||||
|  | ||||
| 	// 		if (req.body.delta > 0) { | ||||
| 	// 			posts.upvote(req.params.pid, req.user.uid, function(err, data) { | ||||
| 	// 				errorHandler.handle(err, res, data); | ||||
| 	// 			}) | ||||
| 	// 		} else if (req.body.delta < 0) { | ||||
| 	// 			posts.downvote(req.params.pid, req.user.uid, function(err, data) { | ||||
| 	// 				errorHandler.handle(err, res, data); | ||||
| 	// 			}) | ||||
| 	// 		} else { | ||||
| 	// 			posts.unvote(req.params.pid, req.user.uid, function(err, data) { | ||||
| 	// 				errorHandler.handle(err, res, data); | ||||
| 	// 			}) | ||||
| 	// 		} | ||||
| 	// 	}) | ||||
| 	// 	.delete(apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 		posts.unvote(req.params.pid, req.user.uid, function(err, data) { | ||||
| 	// 			errorHandler.handle(err, res, data); | ||||
| 	// 		}) | ||||
| 	// 	}); | ||||
|  | ||||
| 	// app.route('/:pid/bookmark') | ||||
| 	// 	.post(apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 		posts.bookmark(req.params.pid, req.user.uid, function (err) { | ||||
| 	// 			errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	}) | ||||
| 	// 	.delete(apiMiddleware.requireUser, apiMiddleware.validatePid, function (req, res) { | ||||
| 	// 		posts.unbookmark(req.params.pid, req.user.uid, function (err) { | ||||
| 	// 			errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	}); | ||||
|  | ||||
| 	return router; | ||||
| }; | ||||
| @@ -12,6 +12,8 @@ const websockets = require('../index'); | ||||
|  | ||||
| module.exports = function (SocketPosts) { | ||||
| 	SocketPosts.edit = async function (socket, data) { | ||||
| 		websockets.warnDeprecated(socket, 'PUT /api/v1/posts/:pid'); | ||||
|  | ||||
| 		if (!socket.uid) { | ||||
| 			throw new Error('[[error:not-logged-in]]'); | ||||
| 		} else if (!data || !data.pid || (meta.config.minimumPostLength !== 0 && !data.content)) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user