Преглед изворни кода

Merge pull request #9567 from weseek/master

Release v7.1.9
mergify[bot] пре 1 година
родитељ
комит
c94229a906
34 измењених фајлова са 685 додато и 354 уклоњено
  1. 2 0
      .github/workflows/ci-app.yml
  2. 3 13
      .github/workflows/reusable-app-prod.yml
  3. 0 10
      apps/app/.eslintrc.js
  4. 3 5
      apps/app/package.json
  5. 6 7
      apps/app/src/client/components/Navbar/GrowiContextualSubNavigation.tsx
  6. 8 0
      apps/app/src/client/components/PagePathNavSticky/PagePathNavSticky.module.scss
  7. 1 1
      apps/app/src/components/Layout/BasicLayout.tsx
  8. 1 1
      apps/app/src/components/PageView/PageContentFooter.module.scss
  9. 4 6
      apps/app/src/components/PageView/PageContentFooter.tsx
  10. 1 1
      apps/app/src/components/PageView/PageViewLayout.tsx
  11. 1 4
      apps/app/src/pages/share/[[...path]].page.tsx
  12. 15 0
      apps/app/src/server/routes/apiv3/logout.js
  13. 88 12
      apps/app/src/server/routes/apiv3/markdown-setting.js
  14. 3 0
      apps/app/src/server/routes/apiv3/mongo.js
  15. 149 19
      apps/app/src/server/routes/apiv3/notification-setting.js
  16. 22 2
      apps/app/src/server/routes/apiv3/page/index.ts
  17. 1 1
      apps/app/src/server/service/passport.ts
  18. 1 2
      apps/slackbot-proxy/package.json
  19. 75 30
      bin/data-migrations/src/index.js
  20. 1 1
      bin/data-migrations/src/migrations/custom.js
  21. 16 0
      bin/data-migrations/src/types.d.ts
  22. 8 0
      bin/data-migrations/tsconfig.json
  23. 3 2
      package.json
  24. 1 2
      packages/core/package.json
  25. 0 2
      packages/presentation/package.json
  26. 1 2
      packages/remark-attachment-refs/package.json
  27. 28 0
      packages/remark-attachment-refs/turbo.json
  28. 0 1
      packages/remark-drawio/package.json
  29. 4 0
      packages/remark-drawio/src/components/DrawioViewer.module.scss
  30. 1 2
      packages/remark-lsx/package.json
  31. 28 0
      packages/remark-lsx/turbo.json
  32. 1 2
      packages/slack/package.json
  33. 209 196
      pnpm-lock.yaml
  34. 0 30
      turbo.json

+ 2 - 0
.github/workflows/ci-app.yml

@@ -6,6 +6,8 @@ on:
       - release/**
       - rc/**
       - changeset-release/**
+      - mergify/merge-queue/**
+      - tmp-mergify/merge-queue/**
     paths:
       - .github/mergify.yml
       - .github/workflows/ci-app.yml

+ 3 - 13
.github/workflows/reusable-app-prod.yml

@@ -50,18 +50,6 @@ jobs:
       run: |
         pnpm install --frozen-lockfile
 
-    - name: Cache/Restore dist
-      uses: actions/cache@v4
-      with:
-        path: |
-          **/.turbo
-          **/dist
-          **/node_modules/.cache/turbo
-          ${{ github.workspace }}/apps/app/.next
-        key: dist-app-prod-${{ runner.OS }}-node${{ inputs.node-version }}-${{ github.sha }}
-        restore-keys: |
-          dist-app-prod-${{ runner.OS }}-node${{ inputs.node-version }}-
-
     - name: Build
       working-directory: ./apps/app
       run: |
@@ -315,7 +303,9 @@ jobs:
         pnpm install --frozen-lockfile
 
     - name: Merge into HTML Report
-      run: pnpm playwright merge-reports --reporter html ./all-blob-reports
+      run: |
+        mkdir -p all-blob-reports
+        pnpm playwright merge-reports --reporter html ./all-blob-reports
 
     - name: Upload HTML report
       uses: actions/upload-artifact@v4

+ 0 - 10
apps/app/.eslintrc.js

@@ -4,7 +4,6 @@ module.exports = {
     'weseek/react',
   ],
   plugins: [
-    'regex',
   ],
   settings: {
     // resolve path aliases by eslint-import-resolver-typescript
@@ -17,15 +16,6 @@ module.exports = {
       name: 'axios',
       message: 'Please use src/utils/axios instead.',
     }],
-    'regex/invalid': ['error', [
-      {
-        regex: '\\?\\<\\!',
-        message: 'Do not use any negative lookbehind',
-      }, {
-        regex: '\\?\\<\\=',
-        message: 'Do not use any Positive lookbehind',
-      },
-    ]],
     '@typescript-eslint/no-var-requires': 'off',
 
     // set 'warn' temporarily -- 2021.08.02 Yuki Takei

+ 3 - 5
apps/app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/app",
-  "version": "7.1.8",
+  "version": "7.1.9-RC.0",
   "license": "MIT",
   "private": "true",
   "scripts": {
@@ -114,7 +114,6 @@
     "ejs": "^3.1.10",
     "esa-node": "^0.2.2",
     "escape-string-regexp": "^4.0.0",
-    "eslint-plugin-regex": "^1.8.0",
     "expose-gc": "^1.0.0",
     "express": "^4.20.0",
     "express-bunyan-logger": "^1.3.3",
@@ -135,7 +134,7 @@
     "is-iso-date": "^0.0.1",
     "js-tiktoken": "^1.0.15",
     "js-yaml": "^4.1.0",
-    "katex": "^0.16.11",
+    "katex": "^0.16.21",
     "ldapjs": "^3.0.2",
     "lucene-query-parser": "^1.2.0",
     "markdown-table": "^3.0.3",
@@ -150,7 +149,7 @@
     "migrate-mongo": "^11.0.0",
     "mkdirp": "^1.0.3",
     "mongodb": "^4.17.2",
-    "mongoose": "^6.11.3",
+    "mongoose": "^6.13.6",
     "mongoose-gridfs": "^1.2.42",
     "mongoose-paginate-v2": "^1.3.9",
     "mongoose-unique-validator": "^2.0.3",
@@ -283,7 +282,6 @@
     "downshift": "^8.2.3",
     "eazy-logger": "^3.1.0",
     "eslint-plugin-jest": "^26.5.3",
-    "eslint-plugin-regex": "^1.8.0",
     "fslightbox-react": "^1.7.6",
     "handsontable": "=6.2.2",
     "happy-dom": "^15.7.4",

+ 6 - 7
apps/app/src/client/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -9,11 +9,10 @@ import type {
 import { pagePathUtils } from '@growi/core/dist/utils';
 import { GlobalCodeMirrorEditorKey } from '@growi/editor';
 import { useCodeMirrorEditorIsolated } from '@growi/editor/dist/client/stores/codemirror-editor';
-import { auto } from '@popperjs/core';
-import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import Link from 'next/link';
 import { useRouter } from 'next/router';
+import { useTranslation } from 'next-i18next';
 import Sticky from 'react-stickynode';
 import { DropdownItem, UncontrolledTooltip } from 'reactstrap';
 
@@ -22,11 +21,6 @@ import { toastSuccess, toastError, toastWarning } from '~/client/util/toastr';
 import { GroundGlassBar } from '~/components/Navbar/GroundGlassBar';
 import type { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import { useShouldExpandContent } from '~/services/layout/use-should-expand-content';
-import {
-  useCurrentPathname,
-  useCurrentUser, useIsGuestUser, useIsReadOnlyUser, useIsLocalAccountRegistrationEnabled, useIsSharedUser, useShareLinkId,
-} from '~/stores-universal/context';
-import { useEditorMode } from '~/stores-universal/ui';
 import {
   usePageAccessoriesModal, PageAccessoriesModalContents, type IPageForPageDuplicateModal,
   usePageDuplicateModal, usePageRenameModal, usePageDeleteModal, usePagePresentationModal,
@@ -40,6 +34,11 @@ import {
   useIsAbleToChangeEditorMode,
   useIsDeviceLargerThanMd,
 } from '~/stores/ui';
+import {
+  useCurrentPathname,
+  useCurrentUser, useIsGuestUser, useIsReadOnlyUser, useIsLocalAccountRegistrationEnabled, useIsSharedUser, useShareLinkId,
+} from '~/stores-universal/context';
+import { useEditorMode } from '~/stores-universal/ui';
 
 import { NotAvailable } from '../NotAvailable';
 import { Skeleton } from '../Skeleton';

+ 8 - 0
apps/app/src/client/components/PagePathNavSticky/PagePathNavSticky.module.scss

@@ -13,3 +13,11 @@
     }
   }
 }
+
+@media print {
+  .grw-page-path-nav-sticky :global {
+    .sticky-inner-wrapper {
+      position: static !important;
+    }
+  }
+}

+ 1 - 1
apps/app/src/components/Layout/BasicLayout.tsx

@@ -46,7 +46,7 @@ export const BasicLayout = ({ children, className }: Props): JSX.Element => {
   return (
     <RawLayout className={`${moduleClass} ${className ?? ''}`}>
       <div className="page-wrapper flex-row">
-        <div className="z-2">
+        <div className="z-2 d-print-none">
           <Sidebar />
         </div>
 

+ 1 - 1
apps/app/src/components/PageView/PageContentFooter.module.scss

@@ -1,7 +1,7 @@
 @use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .page-content-footer :global {
-  border-top: solid 1px transparent;
+  border-top: solid 1px var(--bs-border-color);
   .page-meta {
     font-size: 0.95em;
   }

+ 4 - 6
apps/app/src/components/PageView/PageContentFooter.tsx

@@ -22,12 +22,10 @@ export const PageContentFooter = (props: PageContentFooterProps): JSX.Element =>
   }
 
   return (
-    <div className={`${styles['page-content-footer']} page-content-footer py-4 d-edit-none d-print-none}`}>
-      <div className="container-lg grw-container-convertible">
-        <div className="page-meta">
-          <AuthorInfo user={creator} date={createdAt} mode="create" locate="footer" />
-          <AuthorInfo user={lastUpdateUser} date={updatedAt} mode="update" locate="footer" />
-        </div>
+    <div className={`${styles['page-content-footer']} my-4 pt-4 d-edit-none d-print-none}`}>
+      <div className="page-meta">
+        <AuthorInfo user={creator} date={createdAt} mode="create" locate="footer" />
+        <AuthorInfo user={lastUpdateUser} date={updatedAt} mode="update" locate="footer" />
       </div>
     </div>
   );

+ 1 - 1
apps/app/src/components/PageView/PageViewLayout.tsx

@@ -51,7 +51,7 @@ export const PageViewLayout = (props: Props): JSX.Element => {
       </div>
 
       { footerContents != null && (
-        <footer className={`footer d-edit-none wide-gutter-x-lg ${fluidLayoutClass}`}>
+        <footer className={`footer d-edit-none container-lg wide-gutter-x-lg ${fluidLayoutClass}`}>
           {footerContents}
         </footer>
       ) }

+ 1 - 4
apps/app/src/pages/share/[[...path]].page.tsx

@@ -63,10 +63,7 @@ superjson.registerCustom<IShareLinkRelatedPage, string>(
   {
     isApplicable: (v): v is IShareLinkRelatedPage => {
       return v != null
-        && v.toObject != null
-        && v.lastUpdateUser != null
-        && v.creator != null
-        && v.revision != null;
+        && v.toObject != null;
     },
     serialize: (v) => { return superjson.stringify(v.toObject()) },
     deserialize: (v) => { return superjson.parse(v) },

+ 15 - 0
apps/app/src/server/routes/apiv3/logout.js

@@ -13,6 +13,21 @@ module.exports = (crowi) => {
   const activityEvent = crowi.event('activity');
   const addActivity = generateAddActivityMiddleware(crowi);
 
+  /**
+   * @swagger
+   *  /logout:
+   *    post:
+   *      tags: [Users]
+   *      security:
+   *        - cookieAuth: []
+   *      summary: Logout user
+   *      description: Logout the currently authenticated user
+   *      responses:
+   *        200:
+   *          description: Successfully logged out
+   *        500:
+   *          description: Internal server error
+   */
   router.post('/', addActivity, async(req, res) => {
     req.session.destroy();
 

+ 88 - 12
apps/app/src/server/routes/apiv3/markdown-setting.js

@@ -37,6 +37,37 @@ const validator = {
  *
  *  components:
  *    schemas:
+ *      MarkdownParams:
+ *        description: MarkdownParams
+ *        type: object
+ *        properties:
+ *          isEnabledLinebreaks:
+ *            type: boolean
+ *            description: enable lineBreak
+ *          isEnabledLinebreaksInComments:
+ *            type: boolean
+ *            description: enable lineBreak in comment
+ *          adminPreferredIndentSize:
+ *            type: number
+ *            description: preferred indent size
+ *          isIndentSizeForced:
+ *            type: boolean
+ *            description: force indent size
+ *          isEnabledXss:
+ *            type: boolean
+ *            description: enable xss
+ *          xssOption:
+ *            type: number
+ *            description: number of xss option
+ *          tagWhitelist:
+ *            type: array
+ *            description: array of tag whitelist
+ *            items:
+ *              type: string
+ *              description: tag whitelist
+ *          attrWhitelist:
+ *            type: string
+ *            description: attr whitelist
  *      LineBreakParams:
  *        description: LineBreakParams
  *        type: object
@@ -61,7 +92,7 @@ const validator = {
  *        description: XssParams
  *        type: object
  *        properties:
- *          isEnabledPrevention:
+ *          isEnabledXss:
  *            type: boolean
  *            description: enable xss
  *          xssOption:
@@ -74,11 +105,18 @@ const validator = {
  *              type: string
  *              description: tag whitelist
  *          attrWhitelist:
- *            type: array
- *            description: array of attr whitelist
- *            items:
- *              type: string
- *              description: attr whitelist
+ *            type: string
+ *            description: attr whitelist
+ *      IndentParams:
+ *        description: IndentParams
+ *        type: object
+ *        properties:
+ *          adminPreferredIndentSize:
+ *            type: number
+ *            description: preferred indent size
+ *          isIndentSizeForced:
+ *            type: boolean
+ *            description: force indent size
  */
 
 module.exports = (crowi) => {
@@ -94,9 +132,10 @@ module.exports = (crowi) => {
    *    /markdown-setting:
    *      get:
    *        tags: [MarkDownSetting]
+   *        security:
+   *          - cookieAuth: []
    *        operationId: getMarkdownSetting
-   *        summary: /markdown-setting
-   *        description: Get markdown parameters
+   *        summary: Get markdown parameters
    *        responses:
    *          200:
    *            description: params of markdown
@@ -107,6 +146,7 @@ module.exports = (crowi) => {
    *                    markdownParams:
    *                      type: object
    *                      description: markdown params
+   *                      $ref: '#/components/schemas/MarkdownParams'
    */
   router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
     const markdownParams = {
@@ -129,9 +169,10 @@ module.exports = (crowi) => {
    *    /markdown-setting/lineBreak:
    *      put:
    *        tags: [MarkDownSetting]
+   *        security:
+   *          - cookieAuth: []
    *        operationId: updateLineBreakMarkdownSetting
-   *        summary: /markdown-setting/lineBreak
-   *        description: Update lineBreak setting
+   *        summary: Update lineBreak setting
    *        requestBody:
    *          required: true
    *          content:
@@ -144,7 +185,11 @@ module.exports = (crowi) => {
    *            content:
    *              application/json:
    *                schema:
-  *                   $ref: '#/components/schemas/LineBreakParams'
+   *                  type: object
+   *                  properties:
+   *                    lineBreaksParams:
+   *                      type: object
+   *                      $ref: '#/components/schemas/LineBreakParams'
    */
   router.put('/lineBreak', loginRequiredStrictly, adminRequired, addActivity, validator.lineBreak, apiV3FormValidator, async(req, res) => {
 
@@ -173,6 +218,35 @@ module.exports = (crowi) => {
 
   });
 
+  /**
+   * @swagger
+   *
+   *    /markdown-setting/indent:
+   *      put:
+   *        tags: [MarkDownSetting]
+   *        security:
+   *          - cookieAuth: []
+   *        operationId: updateIndentMarkdownSetting
+   *        summary: Update indent setting
+   *        requestBody:
+   *          required: true
+   *          content:
+   *            application/json:
+   *              schema:
+   *                $ref: '#/components/schemas/IndentParams'
+   *        responses:
+   *          200:
+   *            description: Succeeded to update indent setting
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  type: object
+   *                  properties:
+   *                    indentParams:
+   *                      type: object
+   *                      description: indent params
+   *                      $ref: '#/components/schemas/IndentParams'
+   */
   router.put('/indent', loginRequiredStrictly, adminRequired, addActivity, validator.indent, apiV3FormValidator, async(req, res) => {
 
     const requestIndentParams = {
@@ -206,8 +280,10 @@ module.exports = (crowi) => {
    *    /markdown-setting/xss:
    *      put:
    *        tags: [MarkDownSetting]
+   *        security:
+   *          - cookieAuth: []
    *        operationId: updateXssMarkdownSetting
-   *        summary: /markdown-setting/xss
+   *        summary: Update XSS setting
    *        description: Update xss
    *        requestBody:
    *          required: true

+ 3 - 0
apps/app/src/server/routes/apiv3/mongo.js

@@ -27,6 +27,9 @@ module.exports = (crowi) => {
    *            application/json:
    *              schema:
    *                properties:
+   *                  ok:
+   *                    type: boolean
+   *                    description: whether the request is succeeded
    *                  collections:
    *                    type: array
    *                    items:

+ 149 - 19
apps/app/src/server/routes/apiv3/notification-setting.js

@@ -46,6 +46,66 @@ const validator = {
  *
  *  components:
  *    schemas:
+ *      NotificationParams:
+ *        type: object
+ *        properties:
+ *          isSlackbotConfigured:
+ *            type: boolean
+ *            description: status of slack integration
+ *          isSlackLegacyConfigured:
+ *            type: boolean
+ *            description: status of slack legacy integration
+ *          currentBotType:
+ *            type: string
+ *            description: current bot type
+ *          userNotifications:
+ *            type: array
+ *            items:
+ *              $ref: '#/components/schemas/UserNotification'
+ *          isNotificationForOwnerPageEnabled:
+ *            type: boolean
+ *            description: Whether to notify on owner page
+ *          isNotificationForGroupPageEnabled:
+ *            type: boolean
+ *            description: Whether to notify on group page
+ *          globalNotifications:
+ *            type: array
+ *            items:
+ *              $ref: '#/components/schemas/GlobalNotificationParams'
+ *            description: global notifications
+ *      UserNotification:
+ *        type: object
+ *        properties:
+ *          channel:
+ *            type: string
+ *            description: slack channel name without '#'
+ *          pathPattern:
+ *            type: string
+ *            description: path name of wiki
+ *          createdAt:
+ *            type: string
+ *            description: created date
+ *          creator:
+ *            $ref: '#/components/schemas/User'
+ *            description: user who set notification
+ *          patternPrefix:
+ *            type: string
+ *            description: path pattern prefix
+ *          patternPrefix2:
+ *            type: string
+ *            description: path pattern prefix2
+ *          provider:
+ *            type: string
+ *            description: provider
+ *          updatedAt:
+ *            type: string
+ *            description: updated date
+ *          __v:
+ *            type: number
+ *            description: version
+ *          _id:
+ *            type: string
+ *            description: id
  *      UserNotificationParams:
  *        type: object
  *        properties:
@@ -59,11 +119,37 @@ const validator = {
  *        type: object
  *        properties:
  *          isNotificationForOwnerPageEnabled:
- *            type: string
+ *            type: boolean
  *            description: Whether to notify on owner page
  *          isNotificationForGroupPageEnabled:
- *            type: string
+ *            type: boolean
  *            description: Whether to notify on group page
+ *      GlobalNotification:
+ *        type: object
+ *        properties:
+ *          _id:
+ *            type: string
+ *            description: id
+ *          isEnabled:
+ *            type: boolean
+ *            description: is notification enabled
+ *          triggerEvents:
+ *            type: array
+ *            items:
+ *              type: string
+ *            description: trigger events for notify
+ *          __t:
+ *            type: string
+ *            description: type of notification
+ *          slackChannels:
+ *            type: string
+ *            description: channels for notify
+ *          triggerPath:
+ *            type: string
+ *            description: trigger path for notify
+ *          __v:
+ *            type: number
+ *            description: version
  *      GlobalNotificationParams:
  *        type: object
  *        properties:
@@ -83,7 +169,7 @@ const validator = {
  *            type: array
  *            items:
  *              type: string
- *              description: trigger events for notify
+ *            description: trigger events for notify
  */
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
@@ -103,6 +189,8 @@ module.exports = (crowi) => {
    *    /notification-setting/:
    *      get:
    *        tags: [NotificationSetting]
+   *        security:
+   *          - cookieAuth: []
    *        description: Get notification paramators
    *        responses:
    *          200:
@@ -114,6 +202,7 @@ module.exports = (crowi) => {
    *                    notificationParams:
    *                      type: object
    *                      description: notification params
+   *                      $ref: '#/components/schemas/NotificationParams'
    */
   router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
 
@@ -137,6 +226,8 @@ module.exports = (crowi) => {
   *    /notification-setting/user-notification:
   *      post:
   *        tags: [NotificationSetting]
+  *        security:
+  *         - cookieAuth: []
   *        description: add user notification setting
   *        requestBody:
   *          required: true
@@ -151,12 +242,18 @@ module.exports = (crowi) => {
   *              application/json:
   *                schema:
   *                  properties:
-  *                    createdUser:
-  *                      type: object
-  *                      description: user who set notification
-  *                    userNotifications:
+  *                    responseParams:
   *                      type: object
-  *                      description: user trigger notifications for updated
+  *                      description: response params
+  *                      properties:
+  *                        createdUser:
+  *                          $ref: '#/components/schemas/User'
+  *                          description: user who set notification
+  *                        userNotifications:
+  *                          type: array
+  *                          items:
+  *                            $ref: '#/components/schemas/UserNotification'
+  *                            description: user notification settings
   */
   // eslint-disable-next-line max-len
   router.post('/user-notification', loginRequiredStrictly, adminRequired, addActivity, validator.userNotification, apiV3FormValidator, async(req, res) => {
@@ -188,6 +285,8 @@ module.exports = (crowi) => {
    *    /notification-setting/user-notification/{id}:
    *      delete:
    *        tags: [NotificationSetting]
+   *        security:
+   *          - cookieAuth: []
    *        description: delete user trigger notification pattern
    *        parameters:
    *          - name: id
@@ -202,10 +301,7 @@ module.exports = (crowi) => {
    *            content:
    *              application/json:
    *                schema:
-   *                  properties:
-   *                    deletedNotificaton:
-   *                      type: object
-   *                      description: deleted notification
+   *                  $ref: '#/components/schemas/UserNotification'
    */
   router.delete('/user-notification/:id', loginRequiredStrictly, adminRequired, addActivity, async(req, res) => {
     const { id } = req.params;
@@ -228,6 +324,32 @@ module.exports = (crowi) => {
   });
 
 
+  /**
+   * @swagger
+   *
+   *    /notification-setting/global-notification/{id}:
+   *      get:
+   *        tags: [NotificationSetting]
+   *        security:
+   *          - cookieAuth: []
+   *        description: get global notification setting
+   *        parameters:
+   *          - name: id
+   *            in: path
+   *            required: true
+   *            description: id of global notification
+   *            schema:
+   *              type: string
+   *        responses:
+   *          200:
+   *            description: Succeeded to get global notification setting
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    globalNotification:
+   *                      $ref: '#/components/schemas/GlobalNotification'
+   */
   router.get('/global-notification/:id', loginRequiredStrictly, adminRequired, validator.globalNotification, async(req, res) => {
 
     const notificationSettingId = req.params.id;
@@ -251,6 +373,8 @@ module.exports = (crowi) => {
    *    /notification-setting/global-notification:
    *      post:
    *        tags: [NotificationSetting]
+   *        security:
+   *          - cookieAuth: []
    *        description: add global notification
    *        requestBody:
    *          required: true
@@ -268,6 +392,7 @@ module.exports = (crowi) => {
    *                    createdNotification:
    *                      type: object
    *                      description: notification param created
+   *                      $ref: '#/components/schemas/GlobalNotification'
    */
   // eslint-disable-next-line max-len
   router.post('/global-notification', loginRequiredStrictly, adminRequired, addActivity, validator.globalNotification, apiV3FormValidator, async(req, res) => {
@@ -336,6 +461,7 @@ module.exports = (crowi) => {
    *                    createdNotification:
    *                      type: object
    *                      description: notification param updated
+   *                      $ref: '#/components/schemas/GlobalNotification'
    */
   // eslint-disable-next-line max-len
   router.put('/global-notification/:id', loginRequiredStrictly, adminRequired, addActivity, validator.globalNotification, apiV3FormValidator, async(req, res) => {
@@ -398,6 +524,8 @@ module.exports = (crowi) => {
    *    /notification-setting/notify-for-page-grant:
    *      put:
    *        tags: [NotificationSetting]
+   *        security:
+   *          - cookieAuth: []
    *        description: Update settings for notify for page grant
    *        requestBody:
    *          required: true
@@ -449,6 +577,8 @@ module.exports = (crowi) => {
    *    /notification-setting/global-notification/{id}/enabled:
    *      put:
    *        tags: [NotificationSetting]
+   *        security:
+   *          - cookieAuth: []
    *        description: toggle enabled global notification
    *        parameters:
    *          - name: id
@@ -473,9 +603,9 @@ module.exports = (crowi) => {
    *              application/json:
    *                schema:
    *                  properties:
-   *                    deletedNotificaton:
-   *                      type: object
-   *                      description: notification id for updated
+   *                    id:
+   *                      type: string
+   *                      description: notification id
    */
   router.put('/global-notification/:id/enabled', loginRequiredStrictly, adminRequired, addActivity, async(req, res) => {
     const { id } = req.params;
@@ -513,6 +643,8 @@ module.exports = (crowi) => {
   *    /notification-setting/global-notification/{id}:
   *      delete:
   *        tags: [NotificationSetting]
+  *        security:
+  *          - cookieAuth: []
   *        description: delete global notification pattern
   *        parameters:
   *          - name: id
@@ -527,10 +659,8 @@ module.exports = (crowi) => {
   *            content:
   *              application/json:
   *                schema:
-  *                  properties:
-  *                    deletedNotificaton:
-  *                      type: object
-  *                      description: deleted notification
+  *                  description: deleted notification
+  *                  $ref: '#/components/schemas/GlobalNotification'
   */
   router.delete('/global-notification/:id', loginRequiredStrictly, adminRequired, addActivity, async(req, res) => {
     const { id } = req.params;

+ 22 - 2
apps/app/src/server/routes/apiv3/page/index.ts

@@ -339,15 +339,35 @@ module.exports = (crowi) => {
    *                properties:
    *                  body:
    *                    $ref: '#/components/schemas/Revision/properties/body'
-   *                  page_id:
+   *                  pageId:
    *                    $ref: '#/components/schemas/Page/properties/_id'
    *                  revisionId:
    *                    $ref: '#/components/schemas/Revision/properties/_id'
    *                  grant:
    *                    $ref: '#/components/schemas/Page/properties/grant'
+   *                  userRelatedGrantUserGroupIds:
+   *                    type: array
+   *                    items:
+   *                      type: string
+   *                      description: UserGroup ID
+   *                  overwriteScopesOfDescendants:
+   *                    type: boolean
+   *                    description: Determine whether the scopes of descendants should be overwritten
+   *                  isSlackEnabled:
+   *                    type: boolean
+   *                    description: Determine whether the page is enabled to be posted to Slack
+   *                  slackChannels:
+   *                    type: string
+   *                    description: Slack channel IDs
+   *                  origin:
+   *                    type: string
+   *                    description: Origin is "view" or "editor"
+   *                  wip:
+   *                    type: boolean
+   *                    description: Determine whether the page is WIP
    *                required:
    *                  - body
-   *                  - page_id
+   *                  - pageId
    *                  - revisionId
    *        responses:
    *          200:

+ 1 - 1
apps/app/src/server/service/passport.ts

@@ -197,7 +197,7 @@ class PassportService implements S2sMessageHandlable {
     const func = this.getSetupFunction(authId);
 
     try {
-      this[func.setup]();
+      await this[func.setup]();
     }
     catch (err) {
       logger.debug(err);

+ 1 - 2
apps/slackbot-proxy/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slackbot-proxy",
-  "version": "7.1.8-slackbot-proxy.0",
+  "version": "7.1.9-slackbot-proxy.0",
   "license": "MIT",
   "private": "true",
   "scripts": {
@@ -76,7 +76,6 @@
     "@types/bunyan": "^1.8.11",
     "bootstrap": "=5.3.2",
     "browser-bunyan": "^1.6.3",
-    "eslint-plugin-regex": "^1.8.0",
     "morgan": "^1.10.0"
   }
 }

+ 75 - 30
bin/data-migrations/src/index.js

@@ -5,13 +5,14 @@
 /**
  * @typedef {import('./types').MigrationModule} MigrationModule
  * @typedef {import('./types').ReplaceLatestRevisions} ReplaceLatestRevisions
+ * @typedef {import('./types').Operatioins } Operations
  */
 
 var pagesCollection = db.getCollection('pages');
 var revisionsCollection = db.getCollection('revisions');
 
-var batchSize = process.env.BATCH_SIZE ?? 100; // default 100 revisions in 1 bulkwrite
-var batchSizeInterval = process.env.BATCH_INTERVAL ?? 3000; // default 3 sec
+var batchSize = Number(process.env.BATCH_SIZE ?? 100); // default 100 revisions in 1 bulkwrite
+var batchSizeInterval = Number(process.env.BATCH_INTERVAL ?? 3000); // default 3 sec
 
 var migrationModule = process.env.MIGRATION_MODULE;
 
@@ -24,37 +25,81 @@ if (migrationModules.length === 0) {
 
 /** @type {ReplaceLatestRevisions} */
 function replaceLatestRevisions(body, migrationModules) {
-  var replacedBody = body;
-  migrationModules.forEach((migrationModule) => {
-    replacedBody = migrationModule(replacedBody);
-  });
-  return replacedBody;
+  return migrationModules.reduce((replacedBody, module) => module(replacedBody), body);
 }
 
-var operations = [];
-pagesCollection.find({}).forEach((doc) => {
-  if (doc.revision) {
-    var revision = revisionsCollection.findOne({ _id: doc.revision });
-    var replacedBody = replaceLatestRevisions(revision.body, [...migrationModules]);
-    var operation = {
-      updateOne: {
-        filter: { _id: revision._id },
-        update: {
-          $set: { body: replacedBody },
+var pipeline = [
+  // Join pages with revisions
+  {
+    $lookup: {
+      from: 'revisions',
+      localField: 'revision',
+      foreignField: '_id',
+      as: 'revisionDoc',
+    },
+  },
+  // Unwind the revision array
+  {
+    $unwind: '$revisionDoc',
+  },
+  // Project only needed fields
+  {
+    $project: {
+      _id: '$revisionDoc._id',
+      body: '$revisionDoc.body',
+    },
+  },
+];
+
+
+try {
+  /** @type {Operations} */
+  var operations = [];
+  var processedCount = 0;
+
+  var cursor = pagesCollection.aggregate(pipeline, {
+    allowDiskUse: true,
+    cursor: { batchSize },
+  });
+
+  while (cursor.hasNext()) {
+    var doc = cursor.next();
+
+    if (doc == null || doc.body == null) {
+      continue;
+    }
+
+    try {
+      var replacedBody = replaceLatestRevisions(doc.body, [...migrationModules]);
+
+      operations.push({
+        updateOne: {
+          filter: { _id: doc._id },
+          update: {
+            $set: { body: replacedBody },
+          },
         },
-      },
-    };
-    operations.push(operation);
-
-    // bulkWrite per 100 revisions
-    if (operations.length > (batchSize - 1)) {
-      revisionsCollection.bulkWrite(operations);
-      // sleep time can be set from env var
-      sleep(batchSizeInterval);
-      operations = [];
+      });
+
+      processedCount++;
+
+      if (operations.length >= batchSize || !cursor.hasNext()) {
+        revisionsCollection.bulkWrite(operations);
+        if (batchSizeInterval > 0) {
+          sleep(batchSizeInterval);
+        }
+
+        operations = [];
+      }
+    }
+    catch (err) {
+      print(`Error processing document ${doc?._id}: ${err}`);
     }
   }
-});
-revisionsCollection.bulkWrite(operations);
 
-print('migration complete!');
+  print('Migration complete!');
+}
+catch (err) {
+  print(`Fatal error during migration: ${err}`);
+  throw err;
+}

+ 1 - 1
bin/data-migrations/src/migrations/custom.js

@@ -1,5 +1,5 @@
 /**
- * @typedef {import('../../types').MigrationModule} MigrationModule
+ * @typedef {import('../types').MigrationModule} MigrationModule
  */
 
 module.exports = [

+ 16 - 0
bin/data-migrations/src/types.d.ts

@@ -1,2 +1,18 @@
 export type MigrationModule = (body: string) => string;
 export type ReplaceLatestRevisions = (body: string, migrationModules: MigrationModule[]) => string;
+
+export type Operatioins = Array<
+  {
+    updateOne: {
+      filter: { _id: string }
+      update: { $set: { body: string }}
+    }
+  }
+>
+
+export declare global {
+  const db;
+  const sleep;
+
+  function print(arg: string): void;
+}

+ 8 - 0
bin/data-migrations/tsconfig.json

@@ -0,0 +1,8 @@
+{
+  "$schema": "http://json.schemastore.org/tsconfig",
+  "extends": "../../tsconfig.base.json",
+  "compilerOptions": {
+    "checkJs": true,
+    "strict": true,
+  }
+}

+ 3 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "7.1.8",
+  "version": "7.1.9-RC.0",
   "description": "Team collaboration software using markdown",
   "license": "MIT",
   "private": "true",
@@ -70,6 +70,7 @@
     "eslint-plugin-playwright": "^1.6.2",
     "eslint-plugin-react": "^7.30.1",
     "eslint-plugin-react-hooks": "^4.6.0",
+    "eslint-plugin-regex": "^1.8.0",
     "eslint-plugin-rulesdir": "^0.2.2",
     "eslint-plugin-vitest": "^0.2.3",
     "glob": "^8.1.0",
@@ -95,7 +96,7 @@
     "turbo": "^2.1.3",
     "typescript": "~5.0.0",
     "typescript-transform-paths": "^3.4.7",
-    "vite": "^5.4.6",
+    "vite": "^5.4.12",
     "vite-plugin-dts": "^3.9.1",
     "vite-tsconfig-paths": "^5.0.1",
     "vitest": "^2.1.1",

+ 1 - 2
packages/core/package.json

@@ -73,8 +73,7 @@
     "escape-string-regexp": "^4.0.0"
   },
   "devDependencies": {
-    "eslint-plugin-regex": "^1.8.0",
-    "mongoose": "^6.11.3",
+    "mongoose": "^6.13.6",
     "socket.io-client": "^4.7.5",
     "swr": "^2.2.2"
   }

+ 0 - 2
packages/presentation/package.json

@@ -39,7 +39,6 @@
     "lint": "run-p lint:*"
   },
   "dependencies": {
-    "@growi/core": "workspace:^"
   },
   "devDependencies": {
     "@marp-team/marp-core": "^3.9.1",
@@ -47,7 +46,6 @@
     "@types/mdast": "^4.0.4",
     "@types/reveal.js": "^4.4.1",
     "@types/unist": "^3.0.3",
-    "eslint-plugin-regex": "^1.8.0",
     "hast-util-sanitize": "^5.0.1",
     "hast-util-select": "^6.0.2",
     "mdast-util-frontmatter": "^2.0.1",

+ 1 - 2
packages/remark-attachment-refs/package.json

@@ -51,7 +51,7 @@
     "bunyan": "^1.8.15",
     "hast-util-select": "^6.0.2",
     "express": "^4.20.0",
-    "mongoose": "^6.11.3",
+    "mongoose": "^6.13.6",
     "swr": "^2.2.2",
     "universal-bunyan": "^0.9.2",
     "xss": "^1.0.15"
@@ -60,7 +60,6 @@
     "@types/bunyan": "^1.8.11",
     "@types/hast": "^3.0.4",
     "csstype": "^3.0.2",
-    "eslint-plugin-regex": "^1.8.0",
     "hast-util-sanitize": "^5.0.1",
     "hast-util-select": "^6.0.2",
     "npm-run-all": "^4.1.5",

+ 28 - 0
packages/remark-attachment-refs/turbo.json

@@ -0,0 +1,28 @@
+{
+  "$schema": "https://turbo.build/schema.json",
+  "extends": ["//"],
+  "tasks": {
+    "build": {
+      "dependsOn": ["@growi/core#build", "@growi/remark-growi-directive#build", "@growi/ui#build"],
+      "outputs": ["dist/**"],
+      "outputLogs": "new-only"
+    },
+    "dev": {
+      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"],
+      "outputs": ["dist/**"],
+      "outputLogs": "new-only"
+    },
+    "watch": {
+      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"],
+      "outputs": ["dist/**"],
+      "outputLogs": "new-only"
+    },
+    "lint": {
+      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"]
+    },
+    "test": {
+      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"],
+      "outputLogs": "new-only"
+    }
+  }
+}

+ 0 - 1
packages/remark-drawio/package.json

@@ -35,7 +35,6 @@
     "@types/mdast": "^4.0.4",
     "@types/react": "^18.2.14",
     "@types/react-dom": "^18.2.6",
-    "eslint-plugin-regex": "^1.8.0",
     "hast-util-sanitize": "^5.0.1",
     "pako": "^2.1.0",
     "throttle-debounce": "^5.0.0",

+ 4 - 0
packages/remark-drawio/src/components/DrawioViewer.module.scss

@@ -3,3 +3,7 @@
   border: 1px solid transparent;
   border-radius: 4px;
 }
+
+.drawio-viewer * {
+  box-sizing: content-box;
+}

+ 1 - 2
packages/remark-lsx/package.json

@@ -40,7 +40,7 @@
     "express": "^4.20.0",
     "express-validator": "^6.14.0",
     "http-errors": "^2.0.0",
-    "mongoose": "^6.11.3",
+    "mongoose": "^6.13.6",
     "swr": "^2.2.2",
     "xss": "^1.0.15"
   },
@@ -49,7 +49,6 @@
     "@types/hast": "^3.0.4",
     "axios": "^0.24.0",
     "is-absolute-url": "^4.0.1",
-    "eslint-plugin-regex": "^1.8.0",
     "hast-util-sanitize": "^5.0.1",
     "hast-util-select": "^6.0.2",
     "unified": "^11.0.0",

+ 28 - 0
packages/remark-lsx/turbo.json

@@ -0,0 +1,28 @@
+{
+  "$schema": "https://turbo.build/schema.json",
+  "extends": ["//"],
+  "tasks": {
+    "build": {
+      "dependsOn": ["@growi/core#build", "@growi/remark-growi-directive#build", "@growi/ui#build"],
+      "outputs": ["dist/**"],
+      "outputLogs": "new-only"
+    },
+    "dev": {
+      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"],
+      "outputs": ["dist/**"],
+      "outputLogs": "new-only"
+    },
+    "watch": {
+      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"],
+      "outputs": ["dist/**"],
+      "outputLogs": "new-only"
+    },
+    "lint": {
+      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"]
+    },
+    "test": {
+      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"],
+      "outputLogs": "new-only"
+    }
+  }
+}

+ 1 - 2
packages/slack/package.json

@@ -68,7 +68,6 @@
   "devDependencies": {
     "@slack/types": "^2.14.0",
     "@types/express": "^4",
-    "@types/qs": "^6.9.16",
-    "eslint-plugin-regex": "^1.8.0"
+    "@types/qs": "^6.9.16"
   }
 }

Разлика између датотеке није приказан због своје велике величине
+ 209 - 196
pnpm-lock.yaml


+ 0 - 30
turbo.json

@@ -19,16 +19,6 @@
       "cache": false
     },
 
-    "@growi/remark-attachment-refs#build": {
-      "dependsOn": ["@growi/core#build", "@growi/remark-growi-directive#build", "@growi/ui#build"],
-      "outputs": ["dist/**"],
-      "outputLogs": "new-only"
-    },
-    "@growi/remark-lsx#build": {
-      "dependsOn": ["@growi/core#build", "@growi/remark-growi-directive#build", "@growi/ui#build"],
-      "outputs": ["dist/**"],
-      "outputLogs": "new-only"
-    },
     "@growi/ui#build": {
       "dependsOn": ["@growi/core#build"],
       "outputs": ["dist/**"],
@@ -47,16 +37,6 @@
       "outputLogs": "new-only"
     },
 
-    "@growi/remark-attachment-refs#dev": {
-      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"],
-      "outputs": ["dist/**"],
-      "outputLogs": "new-only"
-    },
-    "@growi/remark-lsx#dev": {
-      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"],
-      "outputs": ["dist/**"],
-      "outputLogs": "new-only"
-    },
     "@growi/ui#dev": {
       "dependsOn": ["@growi/core#dev"],
       "outputs": ["dist/**"],
@@ -87,12 +67,6 @@
       "persistent": true
     },
 
-    "@growi/remark-attachment-refs#lint": {
-      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"]
-    },
-    "@growi/remark-lsx#lint": {
-      "dependsOn": ["@growi/core#dev", "@growi/remark-growi-directive#dev", "@growi/ui#dev"]
-    },
     "@growi/ui#lint": {
       "dependsOn": ["@growi/core#dev"]
     },
@@ -103,10 +77,6 @@
       "dependsOn": ["@growi/pluginkit#dev"],
       "outputLogs": "new-only"
     },
-    "@growi/remark-lsx#test": {
-      "dependsOn": ["@growi/core#dev"],
-      "outputLogs": "new-only"
-    },
     "test": {
       "outputLogs": "new-only"
     },

Неке датотеке нису приказане због велике количине промена