Просмотр исходного кода

Merge branch 'master' into support/162426-darkmode-border

satof3 1 год назад
Родитель
Сommit
f97cd06908

+ 290 - 8
apps/app/src/server/routes/apiv3/page/index.ts

@@ -189,7 +189,7 @@ module.exports = (crowi) => {
    *      get:
    *        tags: [Page]
    *        operationId: getPage
-   *        summary: /page
+   *        summary: Get page
    *        description: get page by pagePath or pageId
    *        parameters:
    *          - name: pageId
@@ -266,6 +266,31 @@ module.exports = (crowi) => {
     return res.apiv3({ page, pages });
   });
 
+  /**
+   * @swagger
+   *   /page/exist:
+   *     get:
+   *       tags: [Page]
+   *       summary: Check if page exists
+   *       description: Check if a page exists at the specified path
+   *       parameters:
+   *         - name: path
+   *           in: query
+   *           description: The path to check for existence
+   *           required: true
+   *           schema:
+   *             type: string
+   *       responses:
+   *         200:
+   *           description: Successfully checked page existence.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 type: object
+   *                 properties:
+   *                   isExist:
+   *                     type: boolean
+   */
   router.get('/exist', checkPageExistenceHandlersFactory(crowi));
 
   /**
@@ -274,6 +299,7 @@ module.exports = (crowi) => {
    *    /page:
    *      post:
    *        tags: [Page]
+   *        summary: Create page
    *        operationId: createPage
    *        description: Create page
    *        requestBody:
@@ -397,7 +423,7 @@ module.exports = (crowi) => {
    *    /page/likes:
    *      put:
    *        tags: [Page]
-   *        summary: /page/likes
+   *        summary: Get page likes
    *        description: Update liked status
    *        operationId: updateLikedStatus
    *        requestBody:
@@ -465,7 +491,7 @@ module.exports = (crowi) => {
    *    /page/info:
    *      get:
    *        tags: [Page]
-   *        summary: /page/info
+   *        summary: Get page info
    *        description: Retrieve current page info
    *        operationId: getPageInfo
    *        requestBody:
@@ -509,7 +535,7 @@ module.exports = (crowi) => {
    *    /page/grant-data:
    *      get:
    *        tags: [Page]
-   *        summary: /page/info
+   *        summary: Get page grant data
    *        description: Retrieve current page's grant data
    *        operationId: getPageGrantData
    *        parameters:
@@ -604,6 +630,37 @@ module.exports = (crowi) => {
 
   // Check if non user related groups are granted page access.
   // If specified page does not exist, check the closest ancestor.
+  /**
+   * @swagger
+   *   /page/non-user-related-groups-granted:
+   *     get:
+   *       tags: [Page]
+   *       security:
+   *         - cookieAuth: []
+   *       summary: Check if non-user related groups are granted page access
+   *       description: Check if non-user related groups are granted access to a specific page or its closest ancestor
+   *       parameters:
+   *         - name: path
+   *           in: query
+   *           description: Path of the page
+   *           required: true
+   *           schema:
+   *             type: string
+   *       responses:
+   *         200:
+   *           description: Successfully checked non-user related groups access.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 type: object
+   *                 properties:
+   *                   isNonUserRelatedGroupsGranted:
+   *                     type: boolean
+   *         403:
+   *           description: Forbidden. Cannot access page or ancestor.
+   *         500:
+   *           description: Internal server error.
+   */
   router.get('/non-user-related-groups-granted', loginRequiredStrictly, validator.nonUserRelatedGroupsGranted, apiV3FormValidator,
     async(req, res: ApiV3Response) => {
       const { user } = req;
@@ -635,7 +692,45 @@ module.exports = (crowi) => {
         return res.apiv3Err(err, 500);
       }
     });
-
+  /**
+   * @swagger
+   *   /page/applicable-grant:
+   *     get:
+   *       tags: [Page]
+   *       security:
+   *         - cookieAuth: []
+   *       summary: Get applicable grant data
+   *       description: Retrieve applicable grant data for a specific page
+   *       parameters:
+   *         - name: pageId
+   *           in: query
+   *           description: ID of the page
+   *           required: true
+   *           schema:
+   *             type: string
+   *       responses:
+   *         200:
+   *           description: Successfully retrieved applicable grant data.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 type: object
+   *                 properties:
+   *                   grant:
+   *                     type: number
+   *                   grantedUsers:
+   *                     type: array
+   *                     items:
+   *                       type: string
+   *                   grantedGroups:
+   *                     type: array
+   *                     items:
+   *                       type: string
+   *         400:
+   *           description: Bad request. Page is unreachable or empty.
+   *         500:
+   *           description: Internal server error.
+   */
   router.get('/applicable-grant', loginRequiredStrictly, validator.applicableGrant, apiV3FormValidator, async(req, res) => {
     const { pageId } = req.query;
 
@@ -659,6 +754,43 @@ module.exports = (crowi) => {
     return res.apiv3(data);
   });
 
+  /**
+   * @swagger
+   *   /:pageId/grant:
+   *     put:
+   *       tags: [Page]
+   *       security:
+   *         - cookieAuth: []
+   *       summary: Update page grant
+   *       description: Update the grant of a specific page
+   *       parameters:
+   *         - name: pageId
+   *           in: path
+   *           description: ID of the page
+   *           required: true
+   *           schema:
+   *             type: string
+   *       requestBody:
+   *         content:
+   *           application/json:
+   *             schema:
+   *               properties:
+   *                 grant:
+   *                   type: number
+   *                   description: Grant level
+   *                 userRelatedGrantedGroups:
+   *                   type: array
+   *                   items:
+   *                     type: string
+   *                   description: Array of user-related granted group IDs
+   *       responses:
+   *         200:
+   *           description: Successfully updated page grant.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 $ref: '#/components/schemas/Page'
+   */
   router.put('/:pageId/grant', loginRequiredStrictly, excludeReadOnlyUser, validator.updateGrant, apiV3FormValidator, async(req, res) => {
     const { pageId } = req.params;
     const { grant, userRelatedGrantedGroups } = req.body;
@@ -692,6 +824,8 @@ module.exports = (crowi) => {
   *    /page/export:
   *      get:
   *        tags: [Page]
+  *        security:
+  *          - cookieAuth: []
   *        description: return page's markdown
   *        responses:
   *          200:
@@ -792,7 +926,9 @@ module.exports = (crowi) => {
    *    /page/exist-paths:
    *      get:
    *        tags: [Page]
-   *        summary: /page/exist-paths
+   *        security:
+   *          - cookieAuth: []
+   *        summary: Get already exist paths
    *        description: Get already exist paths
    *        operationId: getAlreadyExistPaths
    *        parameters:
@@ -853,7 +989,7 @@ module.exports = (crowi) => {
    *    /page/subscribe:
    *      put:
    *        tags: [Page]
-   *        summary: /page/subscribe
+   *        summary: Update subscription status
    *        description: Update subscription status
    *        operationId: updateSubscriptionStatus
    *        requestBody:
@@ -900,6 +1036,39 @@ module.exports = (crowi) => {
   });
 
 
+  /**
+   * @swagger
+   *
+   *   /:pageId/content-width:
+   *     put:
+   *       tags: [Page]
+   *       summary: Update content width
+   *       description: Update the content width setting for a specific page
+   *       parameters:
+   *         - name: pageId
+   *           in: path
+   *           description: ID of the page
+   *           required: true
+   *           schema:
+   *             type: string
+   *       requestBody:
+   *         content:
+   *           application/json:
+   *             schema:
+   *               properties:
+   *                 expandContentWidth:
+   *                   type: boolean
+   *                   description: Whether to expand the content width
+   *       responses:
+   *         200:
+   *           description: Successfully updated content width.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 properties:
+   *                   page:
+   *                     $ref: '#/components/schemas/Page'
+   */
   router.put('/:pageId/content-width', accessTokenParser, loginRequiredStrictly, excludeReadOnlyUser,
     validator.contentWidth, apiV3FormValidator, async(req, res) => {
       const { pageId } = req.params;
@@ -921,13 +1090,126 @@ module.exports = (crowi) => {
       }
     });
 
-
+  /**
+   * @swagger
+   *   /:pageId/publish:
+   *     put:
+   *       tags: [Page]
+   *       summary: Publish page
+   *       description: Publish a specific page
+   *       parameters:
+   *         - name: pageId
+   *           in: path
+   *           description: ID of the page
+   *           required: true
+   *           schema:
+   *             type: string
+   *       responses:
+   *         200:
+   *           description: Successfully published the page.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 $ref: '#/components/schemas/Page'
+   */
   router.put('/:pageId/publish', publishPageHandlersFactory(crowi));
 
+  /**
+   * @swagger
+   *   /:pageId/unpublish:
+   *     put:
+   *       tags: [Page]
+   *       summary: Unpublish page
+   *       description: Unpublish a specific page
+   *       parameters:
+   *         - name: pageId
+   *           in: path
+   *           description: ID of the page
+   *           required: true
+   *           schema:
+   *             type: string
+   *       responses:
+   *         200:
+   *           description: Successfully unpublished the page.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 $ref: '#/components/schemas/Page'
+   */
   router.put('/:pageId/unpublish', unpublishPageHandlersFactory(crowi));
 
+  /**
+   * @swagger
+   *   /:pageId/yjs-data:
+   *     get:
+   *       tags: [Page]
+   *       summary: Get Yjs data
+   *       description: Retrieve Yjs data for a specific page
+   *       parameters:
+   *         - name: pageId
+   *           in: path
+   *           description: ID of the page
+   *           required: true
+   *           schema:
+   *             type: string
+   *       responses:
+   *         200:
+   *           description: Successfully retrieved Yjs data.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 type: object
+   *                 properties:
+   *                   yjsData:
+   *                     type: object
+   *                     description: Yjs data
+   *                     properties:
+   *                       hasYdocsNewerThanLatestRevision:
+   *                         type: boolean
+   *                         description: Whether Yjs documents are newer than the latest revision
+   *                       awarenessStateSize:
+   *                         type: number
+   *                         description: Size of the awareness state
+   */
   router.get('/:pageId/yjs-data', getYjsDataHandlerFactory(crowi));
 
+  /**
+   * @swagger
+   *   /:pageId/sync-latest-revision-body-to-yjs-draft:
+   *     put:
+   *       tags: [Page]
+   *       summary: Sync latest revision body to Yjs draft
+   *       description: Sync the latest revision body to the Yjs draft for a specific page
+   *       parameters:
+   *         - name: pageId
+   *           in: path
+   *           description: ID of the page
+   *           required: true
+   *           schema:
+   *             type: string
+   *       requestBody:
+   *         content:
+   *           application/json:
+   *             schema:
+   *               properties:
+   *                 editingMarkdownLength:
+   *                   type: integer
+   *                   description: Length of the editing markdown
+   *       responses:
+   *         200:
+   *           description: Successfully synced the latest revision body to Yjs draft.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 type: object
+   *                 properties:
+   *                   synced:
+   *                     type: boolean
+   *                     description: Whether the latest revision body is synced to the Yjs draft
+   *                   isYjsDataBroken:
+   *                     type: boolean
+   *                     description: Whether Yjs data is broken
+   */
   router.put('/:pageId/sync-latest-revision-body-to-yjs-draft', syncLatestRevisionBodyToYjsDraftHandlerFactory(crowi));
 
   return router;

+ 232 - 7
apps/app/src/server/routes/apiv3/pages/index.js

@@ -129,10 +129,27 @@ module.exports = (crowi) => {
    *      get:
    *        tags: [Pages]
    *        description: Get recently updated pages
+   *        parameters:
+   *          - name: limit
+   *            in: query
+   *            description: Limit of acquisitions
+   *            schema:
+   *              type: number
+   *            example: 10
+   *          - name: offset
+   *            in: query
+   *            description: Offset of acquisitions
+   *            schema:
+   *              type: number
+   *            example: 0
+   *          - name: includeWipPage
+   *            in: query
+   *            description: Whether to include WIP pages
+   *            schema:
+   *              type: string
    *        responses:
    *          200:
    *            description: Return pages recently updated
-   *
    */
   router.get('/recent', accessTokenParser, loginRequired, validator.recent, apiV3FormValidator, async(req, res) => {
     const limit = parseInt(req.query.limit) || 20;
@@ -233,6 +250,9 @@ module.exports = (crowi) => {
    *                  isRecursively:
    *                    type: boolean
    *                    description: whether rename page with descendants
+   *                  isMoveMode:
+   *                    type: boolean
+   *                    description: whether rename page with moving
    *                required:
    *                  - pageId
    *                  - revisionId
@@ -328,6 +348,28 @@ module.exports = (crowi) => {
     }
   });
 
+  /**
+    * @swagger
+    *    /pages/resume-rename:
+    *      post:
+    *        tags: [Pages]
+    *        operationId: resumeRenamePage
+    *        description: Resume rename page operation
+    *        requestBody:
+    *          content:
+    *            application/json:
+    *              schema:
+    *                properties:
+    *                  pageId:
+    *                    $ref: '#/components/schemas/Page/properties/_id'
+    *                required:
+    *                  - pageId
+    *        responses:
+    *          200:
+    *            description: Succeeded to resume rename page operation.
+    *            content:
+    *              description: Empty response
+    */
   router.post('/resume-rename', accessTokenParser, loginRequiredStrictly, validator.resumeRenamePage, apiV3FormValidator,
     async(req, res) => {
 
@@ -369,6 +411,14 @@ module.exports = (crowi) => {
    *        responses:
    *          200:
    *            description: Succeeded to remove all trash pages
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    deletablePages:
+   *                      type: array
+   *                      items:
+   *                        $ref: '#/components/schemas/Page'
    */
   router.delete('/empty-trash', accessTokenParser, loginRequired, excludeReadOnlyUser, addActivity, apiV3FormValidator, async(req, res) => {
     const options = {};
@@ -423,6 +473,59 @@ module.exports = (crowi) => {
     query('limit').if(value => value != null).isInt({ max: 100 }).withMessage('You should set less than 100 or not to set limit.'),
   ];
 
+  /**
+    * @swagger
+    *
+    *    /pages/list:
+    *      get:
+    *        tags: [Pages]
+    *        operationId: getList
+    *        description: Get list of pages
+    *        parameters:
+    *          - name: path
+    *            in: query
+    *            description: Path to search
+    *            schema:
+    *              type: string
+    *          - name: limit
+    *            in: query
+    *            description: Limit of acquisitions
+    *            schema:
+    *              type: number
+    *          - name: page
+    *            in: query
+    *            description: Page number
+    *            schema:
+    *              type: number
+    *        responses:
+    *          200:
+    *            description: Succeeded to retrieve pages.
+    *            content:
+    *              application/json:
+    *                schema:
+    *                  properties:
+    *                    totalCount:
+    *                      type: number
+    *                      description: Total count of pages
+    *                      example: 3
+    *                    offset:
+    *                      type: number
+    *                      description: Offset of pages
+    *                      example: 0
+    *                    limit:
+    *                      type: number
+    *                      description: Limit of pages
+    *                      example: 10
+    *                    pages:
+    *                      type: array
+    *                      items:
+    *                        allOf:
+    *                          - $ref: '#/components/schemas/Page'
+    *                          - type: object
+    *                            properties:
+    *                              lastUpdateUser:
+    *                                $ref: '#/components/schemas/User'
+    */
   router.get('/list', accessTokenParser, loginRequired, validator.displayList, apiV3FormValidator, async(req, res) => {
 
     const { path } = req.query;
@@ -480,6 +583,9 @@ module.exports = (crowi) => {
    *                  isRecursively:
    *                    type: boolean
    *                    description: whether duplicate page with descendants
+   *                  onlyDuplicateUserRelatedResources:
+   *                    type: boolean
+   *                    description: whether duplicate only user related resources
    *                required:
    *                  - pageId
    *        responses:
@@ -589,11 +695,10 @@ module.exports = (crowi) => {
    *              application/json:
    *                schema:
    *                  properties:
-   *                    subordinatedPaths:
-   *                      type: object
-   *                      description: descendants page
-   *          500:
-   *            description: Internal server error.
+   *                    subordinatedPages:
+   *                      type: array
+   *                      items:
+   *                        $ref: '#/components/schemas/Page'
    */
   router.get('/subordinated-list', accessTokenParser, loginRequired, async(req, res) => {
     const { path } = req.query;
@@ -611,6 +716,50 @@ module.exports = (crowi) => {
 
   });
 
+  /**
+    * @swagger
+    *    /pages/delete:
+    *      post:
+    *        tags: [Pages]
+    *        operationId: deletePages
+    *        description: Delete pages
+    *        requestBody:
+    *          content:
+    *            application/json:
+    *              schema:
+    *                properties:
+    *                  pageIdToRevisionIdMap:
+    *                    type: object
+    *                    description: Map of page IDs to revision IDs
+    *                    example: { "5e2d6aede35da4004ef7e0b7": "5e07345972560e001761fa63" }
+    *                  isCompletely:
+    *                    type: boolean
+    *                    description: Whether to delete pages completely
+    *                  isRecursively:
+    *                    type: boolean
+    *                    description: Whether to delete pages recursively
+    *                  isAnyoneWithTheLink:
+    *                    type: boolean
+    *                    description: Whether the page is restricted to anyone with the link
+    *        responses:
+    *          200:
+    *            description: Succeeded to delete pages.
+    *            content:
+    *              application/json:
+    *                schema:
+    *                  properties:
+    *                    paths:
+    *                      type: array
+    *                      items:
+    *                        type: string
+    *                      description: List of deleted page paths
+    *                    isRecursively:
+    *                      type: boolean
+    *                      description: Whether pages were deleted recursively
+    *                    isCompletely:
+    *                      type: boolean
+    *                      description: Whether pages were deleted completely
+    */
   router.post('/delete', accessTokenParser, loginRequiredStrictly, excludeReadOnlyUser, validator.deletePages, apiV3FormValidator, async(req, res) => {
     const {
       pageIdToRevisionIdMap, isCompletely, isRecursively, isAnyoneWithTheLink,
@@ -665,7 +814,32 @@ module.exports = (crowi) => {
     return res.apiv3({ paths: pagesCanBeDeleted.map(p => p.path), isRecursively, isCompletely });
   });
 
-
+  /**
+   * @swagger
+   *
+   *    /pages/convert-pages-by-path:
+   *      post:
+   *        tags: [Pages]
+   *        operationId: convertPagesByPath
+   *        description: Convert pages by path
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  convertPath:
+   *                    type: string
+   *                    description: Path to convert
+   *                    example: /user/alice
+   *        responses:
+   *          200:
+   *            description: Succeeded to convert pages.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  type: object
+   *                  description: Empty object
+   */
   // eslint-disable-next-line max-len
   router.post('/convert-pages-by-path', accessTokenParser, loginRequiredStrictly, excludeReadOnlyUser, adminRequired, validator.convertPagesByPath, apiV3FormValidator, async(req, res) => {
     const { convertPath } = req.body;
@@ -688,6 +862,36 @@ module.exports = (crowi) => {
     return res.apiv3({});
   });
 
+  /**
+   * @swagger
+   *
+   *    /pages/legacy-pages-migration:
+   *      post:
+   *        tags: [Pages]
+   *        operationId: legacyPagesMigration
+   *        description: Migrate legacy pages
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  pageIds:
+   *                    type: array
+   *                    items:
+   *                      type: string
+   *                    description: List of page IDs to migrate
+   *                  isRecursively:
+   *                    type: boolean
+   *                    description: Whether to migrate pages recursively
+   *        responses:
+   *          200:
+   *            description: Succeeded to migrate legacy pages.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  type: object
+   *                  description: Empty object
+  */
   // eslint-disable-next-line max-len
   router.post('/legacy-pages-migration', accessTokenParser, loginRequired, excludeReadOnlyUser, validator.legacyPagesMigration, apiV3FormValidator, async(req, res) => {
     const { pageIds: _pageIds, isRecursively } = req.body;
@@ -717,6 +921,27 @@ module.exports = (crowi) => {
     return res.apiv3({});
   });
 
+  /**
+   * @swagger
+   *
+   *    /pages/v5-migration-status:
+   *      get:
+   *        tags: [Pages]
+   *        description: Get V5 migration status
+   *        responses:
+   *          200:
+   *            description: Return V5 migration status
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    isV5Compatible:
+   *                      type: boolean
+   *                      description: Whether the app is V5 compatible
+   *                    migratablePagesCount:
+   *                      type: number
+   *                      description: Number of pages that can be migrated
+   */
   router.get('/v5-migration-status', accessTokenParser, loginRequired, async(req, res) => {
     try {
       const isV5Compatible = crowi.configManager.getConfig('app:isV5Compatible');

+ 26 - 4
apps/app/src/server/routes/apiv3/slack-integration-legacy-settings.js

@@ -55,6 +55,8 @@ module.exports = (crowi) => {
    *    /slack-integration-legacy-setting/:
    *      get:
    *        tags: [SlackIntegrationLegacySetting]
+   *        security:
+   *          - cookieAuth: []
    *        description: Get slack configuration setting
    *        responses:
    *          200:
@@ -63,9 +65,15 @@ module.exports = (crowi) => {
    *              application/json:
    *                schema:
    *                  properties:
-   *                    notificationParams:
+   *                    slackIntegrationParams:
    *                      type: object
-   *                      description: slack configuration setting params
+   *                      allOf:
+   *                        - $ref: '#/components/schemas/SlackConfigurationParams'
+   *                        - type: object
+   *                          properties:
+   *                            isSlackbotConfigured:
+   *                              type: boolean
+   *                              description: whether slackbot is configured
    */
   router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
 
@@ -84,20 +92,34 @@ module.exports = (crowi) => {
    *    /slack-integration-legacy-setting/:
    *      put:
    *        tags: [SlackIntegrationLegacySetting]
+   *        security:
+   *          - cookieAuth: []
    *        description: Update slack configuration setting
    *        requestBody:
    *          required: true
    *          content:
    *            application/json:
    *              schema:
-   *                $ref: '#/components/schemas/SlackConfigurationParams'
+   *                properties:
+   *                  webhookUrl:
+   *                    type: string
+   *                    description: incoming webhooks url
+   *                  isIncomingWebhookPrioritized:
+   *                    type: boolean
+   *                    description: use incoming webhooks even if Slack App settings are enabled
+   *                  slackToken:
+   *                    type: string
+   *                    description: OAuth access token
    *        responses:
    *          200:
    *            description: Succeeded to update slack configuration setting
    *            content:
    *              application/json:
    *                schema:
-   *                  $ref: '#/components/schemas/SlackConfigurationParams'
+   *                  properties:
+   *                    responseParams:
+   *                      type: object
+   *                      $ref: '#/components/schemas/SlackConfigurationParams'
    */
   router.put('/', loginRequiredStrictly, adminRequired, addActivity, validator.slackConfiguration, apiV3FormValidator, async(req, res) => {