|
@@ -16,6 +16,92 @@ const router = express.Router();
|
|
|
* tags:
|
|
* tags:
|
|
|
* name: Pages
|
|
* name: Pages
|
|
|
*/
|
|
*/
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @swagger
|
|
|
|
|
+ *
|
|
|
|
|
+ * components:
|
|
|
|
|
+ * schemas:
|
|
|
|
|
+ * Page:
|
|
|
|
|
+ * description: Page
|
|
|
|
|
+ * type: object
|
|
|
|
|
+ * properties:
|
|
|
|
|
+ * _id:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: page ID
|
|
|
|
|
+ * example: 5e07345972560e001761fa63
|
|
|
|
|
+ * __v:
|
|
|
|
|
+ * type: number
|
|
|
|
|
+ * description: DB record version
|
|
|
|
|
+ * example: 0
|
|
|
|
|
+ * commentCount:
|
|
|
|
|
+ * type: number
|
|
|
|
|
+ * description: count of comments
|
|
|
|
|
+ * example: 3
|
|
|
|
|
+ * createdAt:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: date created at
|
|
|
|
|
+ * example: 2010-01-01T00:00:00.000Z
|
|
|
|
|
+ * creator:
|
|
|
|
|
+ * $ref: '#/components/schemas/User'
|
|
|
|
|
+ * extended:
|
|
|
|
|
+ * type: object
|
|
|
|
|
+ * description: extend data
|
|
|
|
|
+ * example: {}
|
|
|
|
|
+ * grant:
|
|
|
|
|
+ * type: number
|
|
|
|
|
+ * description: grant
|
|
|
|
|
+ * example: 1
|
|
|
|
|
+ * grantedUsers:
|
|
|
|
|
+ * type: array
|
|
|
|
|
+ * description: granted users
|
|
|
|
|
+ * items:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: user ID
|
|
|
|
|
+ * example: ["5ae5fccfc5577b0004dbd8ab"]
|
|
|
|
|
+ * lastUpdateUser:
|
|
|
|
|
+ * $ref: '#/components/schemas/User'
|
|
|
|
|
+ * liker:
|
|
|
|
|
+ * type: array
|
|
|
|
|
+ * description: granted users
|
|
|
|
|
+ * items:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: user ID
|
|
|
|
|
+ * example: []
|
|
|
|
|
+ * path:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: page path
|
|
|
|
|
+ * example: /
|
|
|
|
|
+ * redirectTo:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: redirect path
|
|
|
|
|
+ * example: ""
|
|
|
|
|
+ * revision:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: revision ID
|
|
|
|
|
+ * example: ["5ae5fccfc5577b0004dbd8ab"]
|
|
|
|
|
+ * seenUsers:
|
|
|
|
|
+ * type: array
|
|
|
|
|
+ * description: granted users
|
|
|
|
|
+ * items:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: user ID
|
|
|
|
|
+ * example: ["5ae5fccfc5577b0004dbd8ab"]
|
|
|
|
|
+ * status:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: status
|
|
|
|
|
+ * enum:
|
|
|
|
|
+ * - 'wip'
|
|
|
|
|
+ * - 'published'
|
|
|
|
|
+ * - 'deleted'
|
|
|
|
|
+ * - 'deprecated'
|
|
|
|
|
+ * example: published
|
|
|
|
|
+ * updatedAt:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: date updated at
|
|
|
|
|
+ * example: 2010-01-01T00:00:00.000Z
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
module.exports = (crowi) => {
|
|
module.exports = (crowi) => {
|
|
|
const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
|
|
const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
|
|
|
const loginRequired = require('../../middlewares/login-required')(crowi, true);
|
|
const loginRequired = require('../../middlewares/login-required')(crowi, true);
|
|
@@ -48,7 +134,41 @@ module.exports = (crowi) => {
|
|
|
],
|
|
],
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- // TODO write swagger(GW-3384)
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @swagger
|
|
|
|
|
+ *
|
|
|
|
|
+ * /pages/create:
|
|
|
|
|
+ * post:
|
|
|
|
|
+ * tags: [Pages]
|
|
|
|
|
+ * operationId: createPage
|
|
|
|
|
+ * description: Create page
|
|
|
|
|
+ * requestBody:
|
|
|
|
|
+ * content:
|
|
|
|
|
+ * application/json:
|
|
|
|
|
+ * schema:
|
|
|
|
|
+ * properties:
|
|
|
|
|
+ * body:
|
|
|
|
|
+ * type: string
|
|
|
|
|
+ * description: Text of page
|
|
|
|
|
+ * path:
|
|
|
|
|
+ * $ref: '#/components/schemas/Page/properties/path'
|
|
|
|
|
+ * grant:
|
|
|
|
|
+ * $ref: '#/components/schemas/Page/properties/grant'
|
|
|
|
|
+ * required:
|
|
|
|
|
+ * - body
|
|
|
|
|
+ * - path
|
|
|
|
|
+ * responses:
|
|
|
|
|
+ * 200:
|
|
|
|
|
+ * description: Succeeded to create page.
|
|
|
|
|
+ * content:
|
|
|
|
|
+ * application/json:
|
|
|
|
|
+ * schema:
|
|
|
|
|
+ * properties:
|
|
|
|
|
+ * page:
|
|
|
|
|
+ * $ref: '#/components/schemas/Page'
|
|
|
|
|
+ * 409:
|
|
|
|
|
+ * description: page path is already existed
|
|
|
|
|
+ */
|
|
|
router.post('/', accessTokenParser, loginRequiredStrictly, csrf, validator.createPage, apiV3FormValidator, async(req, res) => {
|
|
router.post('/', accessTokenParser, loginRequiredStrictly, csrf, validator.createPage, apiV3FormValidator, async(req, res) => {
|
|
|
const {
|
|
const {
|
|
|
body, grant, grantUserGroupId, pageTags, overwriteScopesOfDescendants, isSlackEnabled, slackChannels, socketClientId,
|
|
body, grant, grantUserGroupId, pageTags, overwriteScopesOfDescendants, isSlackEnabled, slackChannels, socketClientId,
|
|
@@ -62,8 +182,7 @@ module.exports = (crowi) => {
|
|
|
// check page existence
|
|
// check page existence
|
|
|
const isExist = await Page.count({ path }) > 0;
|
|
const isExist = await Page.count({ path }) > 0;
|
|
|
if (isExist) {
|
|
if (isExist) {
|
|
|
- res.code = 'page_exists';
|
|
|
|
|
- return res.apiv3Err('Page exists', 409);
|
|
|
|
|
|
|
+ return res.apiv3Err(new ErrorV3('Failed to post page', 'page_exists'), 500);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const options = { socketClientId };
|
|
const options = { socketClientId };
|
|
@@ -149,12 +268,77 @@ module.exports = (crowi) => {
|
|
|
return res.apiv3(result);
|
|
return res.apiv3(result);
|
|
|
}
|
|
}
|
|
|
catch (err) {
|
|
catch (err) {
|
|
|
- res.code = 'unknown';
|
|
|
|
|
logger.error('Failed to get recent pages', err);
|
|
logger.error('Failed to get recent pages', err);
|
|
|
- return res.apiv3Err(err, 500);
|
|
|
|
|
|
|
+ return res.apiv3Err(new ErrorV3('Failed to get recent pages', 'unknown'), 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // TODO write swagger(GW-3430) and add validation (GW-3429)
|
|
|
|
|
+ router.put('/rename', accessTokenParser, loginRequiredStrictly, csrf, async(req, res) => {
|
|
|
|
|
+ const { pageId, isRecursively, revisionId } = req.body;
|
|
|
|
|
+
|
|
|
|
|
+ let newPagePath = pathUtils.normalizePath(req.body.newPagePath);
|
|
|
|
|
+
|
|
|
|
|
+ const options = {
|
|
|
|
|
+ createRedirectPage: req.body.isRenameRedirect,
|
|
|
|
|
+ updateMetadata: req.body.isRemainMetadata,
|
|
|
|
|
+ socketClientId: +req.body.socketClientId || undefined,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (!Page.isCreatableName(newPagePath)) {
|
|
|
|
|
+ return res.apiv3Err(new ErrorV3(`Could not use the path '${newPagePath})'`, 'invalid_path'), 409);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // check whether path starts slash
|
|
|
|
|
+ newPagePath = pathUtils.addHeadingSlash(newPagePath);
|
|
|
|
|
+
|
|
|
|
|
+ const isExist = await Page.count({ path: newPagePath }) > 0;
|
|
|
|
|
+ if (isExist) {
|
|
|
|
|
+ // if page found, cannot cannot rename to that path
|
|
|
|
|
+ return res.apiv3Err(new ErrorV3(`${newPagePath} already exists`, 'already_exists'), 409);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let page;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ page = await Page.findByIdAndViewer(pageId, req.user);
|
|
|
|
|
+
|
|
|
|
|
+ if (page == null) {
|
|
|
|
|
+ return res.apiv3Err(new ErrorV3(`Page '${pageId}' is not found or forbidden`, 'notfound_or_forbidden'), 401);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!page.isUpdatable(revisionId)) {
|
|
|
|
|
+ return res.apiv3Err(new ErrorV3('Someone could update this page, so couldn\'t delete.', 'notfound_or_forbidden'), 409);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (isRecursively) {
|
|
|
|
|
+ page = await Page.renameRecursively(page, newPagePath, req.user, options);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ page = await Page.rename(page, newPagePath, req.user, options);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (err) {
|
|
|
|
|
+ logger.error(err);
|
|
|
|
|
+ return res.apiv3Err(new ErrorV3('Failed to update page.', 'unknown'), 500);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const result = { page: pageService.serializeToObj(page) };
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // global notification
|
|
|
|
|
+ await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_MOVE, page, req.user, {
|
|
|
|
|
+ oldPath: req.body.path,
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (err) {
|
|
|
|
|
+ logger.error('Move notification failed', err);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ return res.apiv3(result);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* @swagger
|
|
* @swagger
|
|
|
*
|
|
*
|
|
@@ -172,9 +356,7 @@ module.exports = (crowi) => {
|
|
|
return res.apiv3({ pages });
|
|
return res.apiv3({ pages });
|
|
|
}
|
|
}
|
|
|
catch (err) {
|
|
catch (err) {
|
|
|
- res.code = 'unknown';
|
|
|
|
|
- logger.error('Failed to delete trash pages', err);
|
|
|
|
|
- return res.apiv3Err(err, 500);
|
|
|
|
|
|
|
+ return res.apiv3Err(new ErrorV3('Failed to update page.', 'unknown'), 500);
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -238,9 +420,7 @@ module.exports = (crowi) => {
|
|
|
return res.apiv3({ resultPaths });
|
|
return res.apiv3({ resultPaths });
|
|
|
}
|
|
}
|
|
|
catch (err) {
|
|
catch (err) {
|
|
|
- res.code = 'unknown';
|
|
|
|
|
- logger.error('Failed to find the path', err);
|
|
|
|
|
- return res.apiv3Err(err, 500);
|
|
|
|
|
|
|
+ return res.apiv3Err(new ErrorV3('Failed to update page.', 'unknown'), 500);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
});
|
|
});
|