Sfoglia il codice sorgente

Merge branch 'master' into feat/page-bulk-export-pnpm

Futa Arai 1 anno fa
parent
commit
2ed6cc39e7
100 ha cambiato i file con 869 aggiunte e 1225 eliminazioni
  1. 5 2
      .changeset/config.json
  2. 0 59
      .devcontainer/Dockerfile
  3. 3 22
      .devcontainer/compose.yml
  4. 34 33
      .devcontainer/devcontainer.json
  5. 19 0
      .devcontainer/postCreateCommand.sh
  6. 2 3
      .github/workflows/ci-app-prod.yml
  7. 16 47
      .github/workflows/ci-app.yml
  8. 22 50
      .github/workflows/ci-slackbot-proxy.yml
  9. 6 6
      .github/workflows/release-slackbot-proxy.yml
  10. 14 34
      .github/workflows/release-subpackages.yml
  11. 15 15
      .github/workflows/release.yml
  12. 23 50
      .github/workflows/reusable-app-prod.yml
  13. 5 15
      .github/workflows/reusable-app-reg-suit.yml
  14. 1 0
      .gitignore
  15. 0 0
      .npmrc
  16. 2 1
      .vscode/launch.json
  17. 8 1
      CHANGELOG.md
  18. 7 7
      README.md
  19. 7 7
      README_JP.md
  20. 28 0
      apps/app/bin/swagger-jsdoc/definition-apiv1.js
  21. 93 0
      apps/app/bin/swagger-jsdoc/definition-apiv3.js
  22. 15 0
      apps/app/bin/swagger-jsdoc/generate-spec-apiv1.sh
  23. 14 0
      apps/app/bin/swagger-jsdoc/generate-spec-apiv3.sh
  24. 0 37
      apps/app/config/swagger-definition.js
  25. 27 70
      apps/app/docker/Dockerfile
  26. 1 0
      apps/app/docker/Dockerfile.dockerignore
  27. 1 1
      apps/app/docker/README.md
  28. 1 3
      apps/app/docker/codebuild/buildspec.yml
  29. 4 0
      apps/app/nodemon.json
  30. 70 51
      apps/app/package.json
  31. 1 1
      apps/app/playwright.config.ts
  32. 4 2
      apps/app/public/static/locales/en_US/translation.json
  33. 4 2
      apps/app/public/static/locales/fr_FR/translation.json
  34. 4 2
      apps/app/public/static/locales/ja_JP/translation.json
  35. 4 2
      apps/app/public/static/locales/zh_CN/translation.json
  36. 4 4
      apps/app/src/client/components/Admin/AdminHome/SystemInfomationTable.tsx
  37. 0 1
      apps/app/src/client/components/Admin/UserGroup/UserGroupDeleteModal.tsx
  38. 12 11
      apps/app/src/client/components/Bookmarks/DragAndDropWrapper.tsx
  39. 1 1
      apps/app/src/client/components/InfiniteScroll.tsx
  40. 3 2
      apps/app/src/client/components/Me/InAppNotificationSettings.tsx
  41. 1 2
      apps/app/src/client/components/PageComment/CommentEditor.tsx
  42. 0 1
      apps/app/src/client/components/PageEditor/MarkdownTableDataImportForm.tsx
  43. 3 3
      apps/app/src/client/components/PageEditor/PageEditor.tsx
  44. 1 1
      apps/app/src/client/components/PageEditor/markdown-drawio-util-for-editor.ts
  45. 1 1
      apps/app/src/client/components/PageEditor/markdown-table-util-for-editor.ts
  46. 2 3
      apps/app/src/client/components/SearchPage/SearchResultList.tsx
  47. 3 3
      apps/app/src/client/services/AdminHomeContainer.js
  48. 1 1
      apps/app/src/features/callout/services/callout.ts
  49. 34 6
      apps/app/src/features/openai/chat/components/AiChatModal/AiChatModal.tsx
  50. 1 1
      apps/app/src/features/openai/interfaces/message-error.ts
  51. 8 5
      apps/app/src/features/openai/server/routes/message.ts
  52. 13 0
      apps/app/src/features/openai/server/services/getStreamErrorCode.ts
  53. 4 4
      apps/app/src/features/templates/server/routes/apiv3/index.ts
  54. 1 13
      apps/app/src/pages/admin/index.page.tsx
  55. 2 3
      apps/app/src/server/crowi/express-init.js
  56. 1 2
      apps/app/src/server/events/bookmark.js
  57. 10 7
      apps/app/src/server/events/page.js
  58. 3 2
      apps/app/src/server/middlewares/access-token-parser.js
  59. 10 7
      apps/app/src/server/models/bookmark.js
  60. 13 12
      apps/app/src/server/models/external-account.ts
  61. 5 6
      apps/app/src/server/models/obsolete-page.js
  62. 0 0
      apps/app/src/server/models/openapi/error-v3.ts
  63. 79 0
      apps/app/src/server/models/openapi/page.ts
  64. 39 0
      apps/app/src/server/models/openapi/revision.ts
  65. 2 2
      apps/app/src/server/models/revision.ts
  66. 10 7
      apps/app/src/server/models/user-group-relation.ts
  67. 4 10
      apps/app/src/server/routes/apiv3/admin-home.js
  68. 2 9
      apps/app/src/server/routes/apiv3/app-settings.js
  69. 1 8
      apps/app/src/server/routes/apiv3/attachment.js
  70. 0 6
      apps/app/src/server/routes/apiv3/bookmarks.js
  71. 0 6
      apps/app/src/server/routes/apiv3/customize-setting.js
  72. 0 43
      apps/app/src/server/routes/apiv3/docs.js
  73. 0 6
      apps/app/src/server/routes/apiv3/export.js
  74. 0 6
      apps/app/src/server/routes/apiv3/healthcheck.ts
  75. 0 6
      apps/app/src/server/routes/apiv3/import.js
  76. 6 3
      apps/app/src/server/routes/apiv3/invited.ts
  77. 0 6
      apps/app/src/server/routes/apiv3/markdown-setting.js
  78. 1 7
      apps/app/src/server/routes/apiv3/mongo.js
  79. 0 6
      apps/app/src/server/routes/apiv3/notification-setting.js
  80. 4 83
      apps/app/src/server/routes/apiv3/page/index.ts
  81. 0 87
      apps/app/src/server/routes/apiv3/pages/index.js
  82. 11 17
      apps/app/src/server/routes/apiv3/personal-setting.js
  83. 0 45
      apps/app/src/server/routes/apiv3/revisions.js
  84. 3 8
      apps/app/src/server/routes/apiv3/search.js
  85. 26 32
      apps/app/src/server/routes/apiv3/security-settings/index.js
  86. 1 7
      apps/app/src/server/routes/apiv3/share-links.js
  87. 0 6
      apps/app/src/server/routes/apiv3/slack-integration-legacy-settings.js
  88. 13 19
      apps/app/src/server/routes/apiv3/slack-integration-settings.js
  89. 0 5
      apps/app/src/server/routes/apiv3/statistics.js
  90. 1 7
      apps/app/src/server/routes/apiv3/user-group-relation.js
  91. 14 20
      apps/app/src/server/routes/apiv3/user-group.js
  92. 14 20
      apps/app/src/server/routes/apiv3/users.js
  93. 4 3
      apps/app/src/server/routes/attachment/api.js
  94. 4 4
      apps/app/src/server/routes/comment.js
  95. 0 2
      apps/app/src/server/routes/index.js
  96. 19 21
      apps/app/src/server/routes/login-passport.js
  97. 1 2
      apps/app/src/server/routes/login.js
  98. 5 71
      apps/app/src/server/routes/page.js
  99. 1 2
      apps/app/src/server/routes/search.ts
  100. 7 8
      apps/app/src/server/service/page/index.ts

+ 5 - 2
.changeset/config.json

@@ -18,8 +18,11 @@
     "@growi/markdown-splitter",
     "@growi/markdown-splitter",
     "@growi/editor",
     "@growi/editor",
     "@growi/presentation",
     "@growi/presentation",
-    "@growi/preset-*",
-    "@growi/remark-*",
+    "@growi/preset-templates",
+    "@growi/preset-themes",
+    "@growi/remark-attachment-refs",
+    "@growi/remark-drawio",
+    "@growi/remark-lsx",
     "@growi/slack",
     "@growi/slack",
     "@growi/ui"
     "@growi/ui"
   ]
   ]

+ 0 - 59
.devcontainer/Dockerfile

@@ -1,59 +0,0 @@
-#-------------------------------------------------------------------------------------------------------------
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
-#-------------------------------------------------------------------------------------------------------------
-
-FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-20
-
-# The node image includes a non-root user with sudo access. Use the
-# "remoteUser" property in devcontainer.json to use it. On Linux, update
-# these values to ensure the container user's UID/GID matches your local values.
-# See https://aka.ms/vscode-remote/containers/non-root-user for details.
-ARG USERNAME=node
-ARG USER_UID=1000
-ARG USER_GID=$USER_UID
-
-RUN mkdir -p /workspace/growi/node_modules
-RUN mkdir -p /workspace/growi/apps/app/node_modules
-RUN mkdir -p /workspace/growi/apps/slackbot-proxy/node_modules
-RUN mkdir -p /workspace/growi/apps/app/.next
-
-# [Optional] Update UID/GID if needed
-RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
-        groupmod --gid $USER_GID $USERNAME \
-        && usermod --uid $USER_UID --gid $USER_GID $USERNAME; \
-    fi
-RUN chown -R $USER_UID:$USER_GID /home/$USERNAME /workspace;
-
-# *************************************************************
-# * Uncomment this section to use RUN instructions to install *
-# * any needed dependencies after executing "apt-get update". *
-# * See https://docs.docker.com/engine/reference/builder/#run *
-# *************************************************************
-ENV DEBIAN_FRONTEND=noninteractive
-
-# Prepare to install Chrome for VRT
-RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
-RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
-
-RUN apt-get update \
-    && apt-get -y install --no-install-recommends \
-      git-lfs \
-      iputils-ping net-tools dnsutils \
-
-    # Uncomment below lines to install Chromium
-    # --- works only on AMD64 ---
-    # && apt-get -y install --no-install-recommends chromium \
-    #    libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb fonts-noto-cjk \
-
-    # Clean up
-    && apt-get autoremove -y \
-    && apt-get clean -y \
-    && rm -rf /var/lib/apt/lists/*
-ENV DEBIAN_FRONTEND=dialog
-
-RUN yarn global add turbo
-RUN yarn global add node-gyp
-
-# Uncomment to default to non-root user
-# USER $USER_UID

+ 3 - 22
.devcontainer/docker-compose.yml → .devcontainer/compose.yml

@@ -1,30 +1,12 @@
-#-------------------------------------------------------------------------------------------------------------
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
-#-------------------------------------------------------------------------------------------------------------
-
-version: '3'
 services:
 services:
   node:
   node:
-    # Uncomment the next line to use a non-root user for all processes. You can also
-    # simply use the "remoteUser" property in devcontainer.json if you just want VS Code
-    # and its sub-processes (terminals, tasks, debugging) to execute as the user. On Linux,
-    # you may need to update USER_UID and USER_GID in .devcontainer/Dockerfile to match your
-    # user if not 1000. See https://aka.ms/vscode-remote/containers/non-root for details.
-    user: node
-
-    build:
-      context: .
-      dockerfile: Dockerfile
-
+    image: mcr.microsoft.com/devcontainers/base:ubuntu
     volumes:
     volumes:
       - ..:/workspace/growi:delegated
       - ..:/workspace/growi:delegated
+      - pnpm-store:/workspace/growi/.pnpm-store
       - node_modules:/workspace/growi/node_modules
       - node_modules:/workspace/growi/node_modules
-      - node_modules_app:/workspace/growi/apps/app/node_modules
-      - node_modules_slackbot-proxy:/workspace/growi/apps/slackbot-proxy/node_modules
       - buildcache_app:/workspace/growi/apps/app/.next
       - buildcache_app:/workspace/growi/apps/app/.next
       - ../../growi-docker-compose:/workspace/growi-docker-compose:delegated
       - ../../growi-docker-compose:/workspace/growi-docker-compose:delegated
-
     tty: true
     tty: true
 
 
   mongo:
   mongo:
@@ -59,7 +41,6 @@ services:
       - ../../growi-docker-compose/elasticsearch/v8/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
       - ../../growi-docker-compose/elasticsearch/v8/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
 
 
 volumes:
 volumes:
+  pnpm-store:
   node_modules:
   node_modules:
-  node_modules_app:
-  node_modules_slackbot-proxy:
   buildcache_app:
   buildcache_app:

+ 34 - 33
.devcontainer/devcontainer.json

@@ -1,44 +1,45 @@
-// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
-// https://github.com/microsoft/vscode-dev-containers/tree/v0.117.1/containers/javascript-node-12-mongo
-// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the
+// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
 {
 {
   "name": "GROWI-Dev",
   "name": "GROWI-Dev",
-  "dockerComposeFile": "docker-compose.yml",
+  "dockerComposeFile": "compose.yml",
   "service": "node",
   "service": "node",
   "workspaceFolder": "/workspace/growi",
   "workspaceFolder": "/workspace/growi",
 
 
-  // Set *default* container specific settings.json values on container create.
-  "settings": {
-    "terminal.integrated.defaultProfile.linux": "bash"
+  "features": {
+    "ghcr.io/devcontainers/features/node:1": {
+      "version": "20.18.0"
+    }
   },
   },
 
 
-  // Add the IDs of extensions you want installed when the container is created.
-  "extensions": [
-    "dbaeumer.vscode-eslint",
-    "mhutchie.git-graph",
-    "eamodio.gitlens",
-    "github.vscode-pull-request-github",
-    "cschleiden.vscode-github-actions",
-    "cweijan.vscode-database-client2",
-    "mongodb.mongodb-vscode",
-    "msjsdiag.debugger-for-chrome",
-    "firefox-devtools.vscode-firefox-debug",
-    "editorconfig.editorconfig",
-    "shinnn.stylelint",
-    "stylelint.vscode-stylelint",
-    "vitest.explorer",
-    "ms-playwright.playwright"
-  ],
-
-  // Uncomment the next line if you want start specific services in your Docker Compose config.
-  // "runServices": [],
-
-  // Uncomment the line below if you want to keep your containers running after VS Code shuts down.
-  // "shutdownAction": "none",
+  // Use 'forwardPorts' to make a list of ports inside the container available locally.
+  // "forwardPorts": [],
 
 
   // Use 'postCreateCommand' to run commands after the container is created.
   // Use 'postCreateCommand' to run commands after the container is created.
-  "postCreateCommand": "git-lfs pull & turbo run bootstrap",
+  "postCreateCommand": "/bin/bash ./.devcontainer/postCreateCommand.sh",
+
+  // Configure tool-specific properties.
+  "customizations": {
+    "vscode": {
+      "extensions": [
+        "dbaeumer.vscode-eslint",
+        "mhutchie.git-graph",
+        "eamodio.gitlens",
+        "github.vscode-pull-request-github",
+        "cschleiden.vscode-github-actions",
+        "cweijan.vscode-database-client2",
+        "mongodb.mongodb-vscode",
+        "msjsdiag.debugger-for-chrome",
+        "firefox-devtools.vscode-firefox-debug",
+        "editorconfig.editorconfig",
+        "shinnn.stylelint",
+        "stylelint.vscode-stylelint",
+        "vitest.explorer",
+        "ms-playwright.playwright"
+      ],
+    }
+  },
 
 
-  // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
-  "remoteUser": "node"
+  // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+  // "remoteUser": "root"
 }
 }

+ 19 - 0
.devcontainer/postCreateCommand.sh

@@ -0,0 +1,19 @@
+sudo chown -R vscode:vscode /workspace;
+
+# Instal additional packages
+sudo apt update
+sudo apt-get install -y --no-install-recommends \
+  git-lfs \
+  iputils-ping net-tools dnsutils
+sudo apt-get clean -y
+
+# Setup pnpm
+SHELL=bash pnpm setup
+eval "$(cat /home/vscode/.bashrc)"
+
+# Install turbo
+pnpm install turbo --global
+
+# Install dependencies
+git-lfs pull
+turbo run bootstrap

+ 2 - 3
.github/workflows/ci-app-prod.yml

@@ -5,7 +5,6 @@ on:
     branches:
     branches:
       - master
       - master
       - dev/7.*.x
       - dev/7.*.x
-      - dev/6.*.x
     paths:
     paths:
       - .github/mergify.yml
       - .github/mergify.yml
       - .github/workflows/ci-app-prod.yml
       - .github/workflows/ci-app-prod.yml
@@ -13,7 +12,7 @@ on:
       - .github/workflows/reusable-app-reg-suit.yml
       - .github/workflows/reusable-app-reg-suit.yml
       - tsconfig.base.json
       - tsconfig.base.json
       - turbo.json
       - turbo.json
-      - yarn.lock
+      - pnpm-lock.yaml
       - package.json
       - package.json
       - apps/app/**
       - apps/app/**
       - '!apps/app/docker/**'
       - '!apps/app/docker/**'
@@ -26,7 +25,7 @@ on:
       - .github/workflows/reusable-app-prod.yml
       - .github/workflows/reusable-app-prod.yml
       - .github/workflows/reusable-app-reg-suit.yml
       - .github/workflows/reusable-app-reg-suit.yml
       - tsconfig.base.json
       - tsconfig.base.json
-      - yarn.lock
+      - pnpm-lock.yaml
       - turbo.json
       - turbo.json
       - package.json
       - package.json
       - apps/app/**
       - apps/app/**

+ 16 - 47
.github/workflows/ci-app.yml

@@ -12,7 +12,7 @@ on:
       - .eslint*
       - .eslint*
       - tsconfig.base.json
       - tsconfig.base.json
       - turbo.json
       - turbo.json
-      - yarn.lock
+      - pnpm-lock.yaml
       - package.json
       - package.json
       - apps/app/**
       - apps/app/**
       - '!apps/app/docker/**'
       - '!apps/app/docker/**'
@@ -34,21 +34,12 @@ jobs:
     steps:
     steps:
       - uses: actions/checkout@v4
       - uses: actions/checkout@v4
 
 
+      - uses: pnpm/action-setup@v4
+
       - uses: actions/setup-node@v4
       - uses: actions/setup-node@v4
         with:
         with:
           node-version: ${{ matrix.node-version }}
           node-version: ${{ matrix.node-version }}
-          cache: 'yarn'
-          cache-dependency-path: '**/yarn.lock'
-
-      - name: Cache/Restore node_modules
-        uses: actions/cache@v4
-        with:
-          path: |
-            **/node_modules
-            !**/node_modules/.cache/turbo
-          key: node_modules-app-devdependencies-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            node_modules-app-devdependencies-${{ runner.OS }}-node${{ matrix.node-version }}-
+          cache: 'pnpm'
 
 
       - name: Cache/Restore dist
       - name: Cache/Restore dist
         uses: actions/cache@v4
         uses: actions/cache@v4
@@ -63,9 +54,8 @@ jobs:
 
 
       - name: Install dependencies
       - name: Install dependencies
         run: |
         run: |
-          yarn global add turbo
-          yarn global add node-gyp
-          yarn --frozen-lockfile
+          pnpm add turbo --global
+          pnpm install
 
 
       - name: Lint
       - name: Lint
         run: |
         run: |
@@ -98,21 +88,12 @@ jobs:
     steps:
     steps:
       - uses: actions/checkout@v4
       - uses: actions/checkout@v4
 
 
+      - uses: pnpm/action-setup@v4
+
       - uses: actions/setup-node@v4
       - uses: actions/setup-node@v4
         with:
         with:
           node-version: ${{ matrix.node-version }}
           node-version: ${{ matrix.node-version }}
-          cache: 'yarn'
-          cache-dependency-path: '**/yarn.lock'
-
-      - name: Cache/Restore node_modules
-        uses: actions/cache@v4
-        with:
-          path: |
-            **/node_modules
-            !**/node_modules/.cache/turbo
-          key: node_modules-app-devdependencies-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            node_modules-app-devdependencies-${{ runner.OS }}-node${{ matrix.node-version }}-
+          cache: 'pnpm'
 
 
       - name: Cache/Restore dist
       - name: Cache/Restore dist
         uses: actions/cache@v4
         uses: actions/cache@v4
@@ -127,9 +108,8 @@ jobs:
 
 
       - name: Install dependencies
       - name: Install dependencies
         run: |
         run: |
-          yarn global add turbo
-          yarn global add node-gyp
-          yarn --frozen-lockfile
+          pnpm add turbo --global
+          pnpm install
 
 
       - name: Test
       - name: Test
         run: |
         run: |
@@ -172,22 +152,12 @@ jobs:
     steps:
     steps:
       - uses: actions/checkout@v4
       - uses: actions/checkout@v4
 
 
+      - uses: pnpm/action-setup@v4
+
       - uses: actions/setup-node@v4
       - uses: actions/setup-node@v4
         with:
         with:
           node-version: ${{ matrix.node-version }}
           node-version: ${{ matrix.node-version }}
-          cache: 'yarn'
-          cache-dependency-path: '**/yarn.lock'
-
-      - name: Cache/Restore node_modules
-        uses: actions/cache@v4
-        with:
-          path: |
-            **/node_modules
-            !**/node_modules/.cache/turbo
-          key: node_modules-app-devdependencies-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            node_modules-app-devdependencies-${{ runner.OS }}-node${{ matrix.node-version }}-
-            node_modules-app-devdependencies-${{ runner.OS }}-node${{ matrix.node-version }}-
+          cache: 'pnpm'
 
 
       - name: Cache/Restore dist
       - name: Cache/Restore dist
         uses: actions/cache@v4
         uses: actions/cache@v4
@@ -202,9 +172,8 @@ jobs:
 
 
       - name: Install dependencies
       - name: Install dependencies
         run: |
         run: |
-          yarn global add turbo
-          yarn global add node-gyp
-          yarn --frozen-lockfile
+          pnpm add turbo --global
+          pnpm install
 
 
       - name: turbo run launch-dev:ci
       - name: turbo run launch-dev:ci
         working-directory: ./apps/app
         working-directory: ./apps/app

+ 22 - 50
.github/workflows/ci-slackbot-proxy.yml

@@ -12,7 +12,7 @@ on:
       - .eslint*
       - .eslint*
       - tsconfig.base.json
       - tsconfig.base.json
       - turbo.json
       - turbo.json
-      - yarn.lock
+      - pnpm-lock.yaml
       - package.json
       - package.json
       - apps/slackbot-proxy/**
       - apps/slackbot-proxy/**
       - '!apps/slackbot-proxy/docker/**'
       - '!apps/slackbot-proxy/docker/**'
@@ -35,21 +35,12 @@ jobs:
     steps:
     steps:
     - uses: actions/checkout@v4
     - uses: actions/checkout@v4
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
-
-    - name: Cache/Restore node_modules
-      uses: actions/cache@v4
-      with:
-        path: |
-          **/node_modules
-        key: node_modules-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('apps/slackbot-proxy/package.json') }}
-        restore-keys: |
-          node_modules-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}-
-          node_modules-${{ runner.OS }}-node${{ matrix.node-version }}-
+        cache: 'pnpm'
 
 
     - name: Restore dist
     - name: Restore dist
       uses: actions/cache/restore@v4
       uses: actions/cache/restore@v4
@@ -63,9 +54,8 @@ jobs:
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
-        yarn global add turbo
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm add turbo --global
+        pnpm install
 
 
     - name: Lint
     - name: Lint
       run: |
       run: |
@@ -110,21 +100,12 @@ jobs:
     steps:
     steps:
     - uses: actions/checkout@v4
     - uses: actions/checkout@v4
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
-
-    - name: Cache/Restore node_modules
-      uses: actions/cache@v4
-      with:
-        path: |
-          **/node_modules
-        key: node_modules-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('apps/slackbot-proxy/package.json') }}
-        restore-keys: |
-          node_modules-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}-
-          node_modules-${{ runner.OS }}-node${{ matrix.node-version }}-
+        cache: 'pnpm'
 
 
     - name: Restore dist
     - name: Restore dist
       uses: actions/cache/restore@v4
       uses: actions/cache/restore@v4
@@ -138,11 +119,10 @@ jobs:
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
-        yarn global add turbo
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm add turbo --global
+        pnpm install
 
 
-    - name: yarn dev:ci
+    - name: turbo run dev:ci
       working-directory: ./apps/slackbot-proxy
       working-directory: ./apps/slackbot-proxy
       run: |
       run: |
         cp config/ci/.env.local.for-ci .env.development.local
         cp config/ci/.env.local.for-ci .env.development.local
@@ -198,15 +178,16 @@ jobs:
     steps:
     steps:
     - uses: actions/checkout@v4
     - uses: actions/checkout@v4
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
+        cache: 'pnpm'
 
 
     - name: Install turbo
     - name: Install turbo
       run: |
       run: |
-        yarn global add turbo
+        pnpm add turbo --global
 
 
     - name: Prune repositories
     - name: Prune repositories
       run: |
       run: |
@@ -214,20 +195,10 @@ jobs:
         rm -rf apps packages
         rm -rf apps packages
         mv out/* .
         mv out/* .
 
 
-    - name: Cache/Restore node_modules
-      id: cache-dependencies
-      uses: actions/cache@v4
-      with:
-        path: |
-          **/node_modules
-        key: node_modules-slackbot-prxy-build-prod-${{ runner.OS }}-node${{ inputs.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          node_modules-slackbot-proxy-build-prod-${{ runner.OS }}-node${{ inputs.node-version }}-
-
     - name: Install dependencies
     - name: Install dependencies
+      # Run pnpm install with `--no-frozen-lockfile` option after `turbo prune` to avoid ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY
       run: |
       run: |
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm install --no-frozen-lockfile
 
 
     - name: Restore dist
     - name: Restore dist
       uses: actions/cache/restore@v4
       uses: actions/cache/restore@v4
@@ -245,14 +216,15 @@ jobs:
         turbo run build
         turbo run build
 
 
     - name: Install dependencies for production
     - name: Install dependencies for production
+      # Run pnpm install with `--no-frozen-lockfile` option after `turbo prune` to avoid ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY
       run: |
       run: |
-        yarn --production
+        pnpm install --no-frozen-lockfile --prod
 
 
-    - name: yarn start:prod:ci
+    - name: pnpm run start:prod:ci
       working-directory: ./apps/slackbot-proxy
       working-directory: ./apps/slackbot-proxy
       run: |
       run: |
         cp config/ci/.env.local.for-ci .env.production.local
         cp config/ci/.env.local.for-ci .env.production.local
-        yarn start:prod:ci
+        pnpm run start:prod:ci
       env:
       env:
         SERVER_URI: http://localhost:8080
         SERVER_URI: http://localhost:8080
         TYPEORM_CONNECTION: mysql
         TYPEORM_CONNECTION: mysql

+ 6 - 6
.github/workflows/release-slackbot-proxy.yml

@@ -93,21 +93,21 @@ jobs:
       with:
       with:
         ref: ${{ github.event.pull_request.base.ref }}
         ref: ${{ github.event.pull_request.base.ref }}
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: '18'
         node-version: '18'
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
+        cache: 'pnpm'
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
-        yarn global add turbo
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm add turbo --global
+        pnpm install
 
 
     - name: Bump versions for next RC
     - name: Bump versions for next RC
       run: |
       run: |
-        turbo run version --filter=@growi/slackbot-proxy -- --prerelease
+        turbo run version:prerelease --filter=@growi/slackbot-proxy
 
 
     - name: Retrieve information from package.json
     - name: Retrieve information from package.json
       uses: myrotvorets/info-from-package-json-action@2.0.1
       uses: myrotvorets/info-from-package-json-action@2.0.1

+ 14 - 34
.github/workflows/release-subpackages.yml

@@ -28,27 +28,17 @@ jobs:
     steps:
     steps:
     - uses: actions/checkout@v4
     - uses: actions/checkout@v4
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: '20'
         node-version: '20'
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
-
-    - name: Cache/Restore node_modules
-      id: cache-dependencies
-      uses: actions/cache@v4
-      with:
-        path: |
-          **/node_modules
-        key: node_modules-release-subpackages-${{ runner.OS }}-node${{ inputs.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          node_modules-release-subpackages-${{ runner.OS }}-node${{ inputs.node-version }}-
+        cache: 'pnpm'
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
-        yarn global add turbo
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm add turbo --global
+        pnpm install
 
 
     - name: Setup .npmrc
     - name: Setup .npmrc
       run: |
       run: |
@@ -61,14 +51,14 @@ jobs:
     - name: Retrieve changesets information
     - name: Retrieve changesets information
       id: changesets-status
       id: changesets-status
       run: |
       run: |
-        yarn changeset status --output status.json
+        pnpm changeset status --output status.json
         echo "CHANGESETS_LENGTH=$(jq -r '.changesets | length' status.json)" >> $GITHUB_OUTPUT
         echo "CHANGESETS_LENGTH=$(jq -r '.changesets | length' status.json)" >> $GITHUB_OUTPUT
         rm status.json
         rm status.json
 
 
     - name: Snapshot release to npm
     - name: Snapshot release to npm
       if: steps.changesets-status.outputs.CHANGESETS_LENGTH > 0
       if: steps.changesets-status.outputs.CHANGESETS_LENGTH > 0
       run: |
       run: |
-        yarn release-subpackages:snapshot
+        pnpm run release-subpackages:snapshot
       env:
       env:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
         NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -81,35 +71,25 @@ jobs:
     steps:
     steps:
     - uses: actions/checkout@v4
     - uses: actions/checkout@v4
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: '20'
         node-version: '20'
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
-
-    - name: Cache/Restore node_modules
-      id: cache-dependencies
-      uses: actions/cache@v4
-      with:
-        path: |
-          **/node_modules
-        key: node_modules-release-subpackages-${{ runner.OS }}-node${{ inputs.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          node_modules-release-subpackages-${{ runner.OS }}-node${{ inputs.node-version }}-
+        cache: 'pnpm'
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
-        yarn global add turbo
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm add turbo --global
+        pnpm install
 
 
     - name: Create Release Pull Request or Publish to npm
     - name: Create Release Pull Request or Publish to npm
       id: changesets
       id: changesets
       uses: changesets/action@v1
       uses: changesets/action@v1
       with:
       with:
         title: Release Subpackages
         title: Release Subpackages
-        version: yarn version-subpackages
-        publish: yarn release-subpackages
+        version: pnpm run version-subpackages
+        publish: pnpm run release-subpackages
       env:
       env:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
         NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

+ 15 - 15
.github/workflows/release.yml

@@ -22,22 +22,22 @@ jobs:
       with:
       with:
         ref: ${{ github.event.pull_request.base.ref }}
         ref: ${{ github.event.pull_request.base.ref }}
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: '20'
         node-version: '20'
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
+        cache: 'pnpm'
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
-        yarn global add turbo
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm add turbo --global
+        pnpm install
 
 
     - name: Bump versions
     - name: Bump versions
       run: |
       run: |
-        turbo run version --filter=@growi/app -- --patch
-        yarn upgrade --scope=@growi
+        turbo run version:patch --filter=@growi/app
+        pnpm upgrade --scope=@growi
         sh ./apps/app/bin/github-actions/update-readme.sh
         sh ./apps/app/bin/github-actions/update-readme.sh
 
 
     - name: Retrieve information from package.json
     - name: Retrieve information from package.json
@@ -162,23 +162,23 @@ jobs:
       with:
       with:
         ref: v${{ needs.create-github-release.outputs.RELEASED_VERSION }}
         ref: v${{ needs.create-github-release.outputs.RELEASED_VERSION }}
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: '20'
         node-version: '20'
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
+        cache: 'pnpm'
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
-        yarn global add turbo
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm add turbo --global
+        pnpm install
 
 
     - name: Bump versions for next RC
     - name: Bump versions for next RC
       run: |
       run: |
-        turbo run version --filter=@growi/app -- --prepatch
-        turbo run version --filter=@growi/slackbot-proxy -- --prepatch
-        yarn upgrade --scope=@growi
+        turbo run version:prepatch --filter=@growi/app
+        turbo run version:prepatch --filter=@growi/slackbot-proxy
+        pnpm upgrade --scope=@growi
 
 
     - name: Retrieve information from package.json
     - name: Retrieve information from package.json
       uses: myrotvorets/info-from-package-json-action@2.0.1
       uses: myrotvorets/info-from-package-json-action@2.0.1

+ 23 - 50
.github/workflows/reusable-app-prod.yml

@@ -26,15 +26,16 @@ jobs:
         # retrieve local font files
         # retrieve local font files
         lfs: true
         lfs: true
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: ${{ inputs.node-version }}
         node-version: ${{ inputs.node-version }}
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
+        cache: 'pnpm'
 
 
     - name: Install turbo
     - name: Install turbo
       run: |
       run: |
-        yarn global add turbo
+        pnpm add turbo --global
 
 
     - name: Prune repositories
     - name: Prune repositories
       run: |
       run: |
@@ -42,20 +43,10 @@ jobs:
         rm -rf apps packages
         rm -rf apps packages
         mv out/* .
         mv out/* .
 
 
-    - name: Cache/Restore node_modules
-      uses: actions/cache@v4
-      with:
-        path: |
-          **/node_modules
-          !**/node_modules/.cache/turbo
-        key: node_modules-app-build-prod-${{ runner.OS }}-node${{ inputs.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          node_modules-app-build-prod-${{ runner.OS }}-node${{ inputs.node-version }}-
-
     - name: Install dependencies
     - name: Install dependencies
+      # Run pnpm install with `--no-frozen-lockfile` option after `turbo prune` to avoid ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY
       run: |
       run: |
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm install --no-frozen-lockfile
 
 
     - name: Cache/Restore dist
     - name: Cache/Restore dist
       uses: actions/cache@v4
       uses: actions/cache@v4
@@ -79,7 +70,7 @@ jobs:
     - name: Archive production files
     - name: Archive production files
       id: archive-prod-files
       id: archive-prod-files
       run: |
       run: |
-        tar -zcf production.tar.gz \
+        tar -zcf production.tar.gz --exclude ./apps/app/.next/cache \
           package.json \
           package.json \
           apps/app/.next \
           apps/app/.next \
           apps/app/config \
           apps/app/config \
@@ -137,15 +128,16 @@ jobs:
     steps:
     steps:
     - uses: actions/checkout@v4
     - uses: actions/checkout@v4
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: ${{ inputs.node-version }}
         node-version: ${{ inputs.node-version }}
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
+        cache: 'pnpm'
 
 
     - name: Install turbo
     - name: Install turbo
       run: |
       run: |
-        yarn global add turbo
+        pnpm add turbo --global
 
 
     - name: Prune repositories
     - name: Prune repositories
       run: |
       run: |
@@ -153,19 +145,10 @@ jobs:
         rm -rf apps packages
         rm -rf apps packages
         mv out/* .
         mv out/* .
 
 
-    - name: Restore node_modules
-      uses: actions/cache/restore@v4
-      with:
-        path: |
-          **/node_modules
-        # shared key with build-prod
-        key: node_modules-app-build-prod-${{ runner.OS }}-node${{ inputs.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          node_modules-app-build-prod-${{ runner.OS }}-node${{ inputs.node-version }}-
-
     - name: Install dependencies
     - name: Install dependencies
+      # Run pnpm install with `--no-frozen-lockfile` option after `turbo prune` to avoid ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY
       run: |
       run: |
-        yarn --production
+        pnpm install --no-frozen-lockfile --prod
 
 
     - name: Download production files artifact
     - name: Download production files artifact
       uses: actions/download-artifact@v4
       uses: actions/download-artifact@v4
@@ -176,11 +159,11 @@ jobs:
       run: |
       run: |
         tar -xf ${{ needs.build-prod.outputs.PROD_FILES }}
         tar -xf ${{ needs.build-prod.outputs.PROD_FILES }}
 
 
-    - name: yarn server:ci
+    - name: pnpm run server:ci
       working-directory: ./apps/app
       working-directory: ./apps/app
       run: |
       run: |
         cp config/ci/.env.local.for-ci .env.production.local
         cp config/ci/.env.local.for-ci .env.production.local
-        yarn server:ci
+        pnpm run server:ci
       env:
       env:
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi
         ELASTICSEARCH_URI: http://localhost:${{ job.services.elasticsearch.ports['9200'] }}/growi
         ELASTICSEARCH_URI: http://localhost:${{ job.services.elasticsearch.ports['9200'] }}/growi
@@ -228,30 +211,20 @@ jobs:
     steps:
     steps:
     - uses: actions/checkout@v4
     - uses: actions/checkout@v4
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: ${{ inputs.node-version }}
         node-version: ${{ inputs.node-version }}
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
-
-    - name: Restore node_modules
-      uses: actions/cache/restore@v4
-      with:
-        path: |
-          **/node_modules
-        # saved key by build-prod
-        key: node_modules-app-build-prod-${{ runner.OS }}-node${{ inputs.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          node_modules-app-build-prod-${{ runner.OS }}-node${{ inputs.node-version }}-
+        cache: 'pnpm'
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm install
 
 
     - name: Install Playwright browsers
     - name: Install Playwright browsers
       run: |
       run: |
-        yarn playwright install --with-deps ${{ matrix.browser }}
+        pnpm playwright install --with-deps ${{ matrix.browser }}
 
 
     - name: Download production files artifact
     - name: Download production files artifact
       uses: actions/download-artifact@v4
       uses: actions/download-artifact@v4
@@ -271,7 +244,7 @@ jobs:
       if: ${{ matrix.browser == 'chromium' }}
       if: ${{ matrix.browser == 'chromium' }}
       working-directory: ./apps/app
       working-directory: ./apps/app
       run: |
       run: |
-        yarn playwright test --project=chromium/installer
+        pnpm playwright test --project=chromium/installer
       env:
       env:
         HOME: /root # ref: https://github.com/microsoft/playwright/issues/6500
         HOME: /root # ref: https://github.com/microsoft/playwright/issues/6500
         MONGO_URI: mongodb://mongodb:27017/growi-playwright-installer
         MONGO_URI: mongodb://mongodb:27017/growi-playwright-installer
@@ -285,7 +258,7 @@ jobs:
     - name: Playwright Run
     - name: Playwright Run
       working-directory: ./apps/app
       working-directory: ./apps/app
       run: |
       run: |
-        yarn playwright test --project=${{ matrix.browser }} --shard=${{ matrix.shard }}
+        pnpm playwright test --project=${{ matrix.browser }} --shard=${{ matrix.shard }}
       env:
       env:
         HOME: /root # ref: https://github.com/microsoft/playwright/issues/6500
         HOME: /root # ref: https://github.com/microsoft/playwright/issues/6500
         MONGO_URI: mongodb://mongodb:27017/growi-playwright
         MONGO_URI: mongodb://mongodb:27017/growi-playwright
@@ -299,7 +272,7 @@ jobs:
     - name: Playwright Run (--project=${browser}/guest-mode)
     - name: Playwright Run (--project=${browser}/guest-mode)
       working-directory: ./apps/app
       working-directory: ./apps/app
       run: |
       run: |
-        yarn playwright test --project=${{ matrix.browser }}/guest-mode --shard=${{ matrix.shard }}
+        pnpm playwright test --project=${{ matrix.browser }}/guest-mode --shard=${{ matrix.shard }}
       env:
       env:
         HOME: /root # ref: https://github.com/microsoft/playwright/issues/6500
         HOME: /root # ref: https://github.com/microsoft/playwright/issues/6500
         MONGO_URI: mongodb://mongodb:27017/growi-playwright-guest-mode
         MONGO_URI: mongodb://mongodb:27017/growi-playwright-guest-mode

+ 5 - 15
.github/workflows/reusable-app-reg-suit.yml

@@ -54,26 +54,16 @@ jobs:
         ref: ${{ inputs.checkout-ref }}
         ref: ${{ inputs.checkout-ref }}
         fetch-depth: 0
         fetch-depth: 0
 
 
+    - uses: pnpm/action-setup@v4
+
     - uses: actions/setup-node@v4
     - uses: actions/setup-node@v4
       with:
       with:
         node-version: ${{ inputs.node-version }}
         node-version: ${{ inputs.node-version }}
-        cache: 'yarn'
-        cache-dependency-path: '**/yarn.lock'
-
-    - name: Restore node_modules
-      uses: actions/cache/restore@v4
-      with:
-        path: |
-          **/node_modules
-        # saved key by launch-prod
-        key: node_modules-app-launch-prod-${{ runner.OS }}-node${{ inputs.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          node_modules-app-launch-prod-${{ runner.OS }}-node${{ inputs.node-version }}-
+        cache: 'pnpm'
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
-        yarn global add node-gyp
-        yarn --frozen-lockfile
+        pnpm install
 
 
     - name: Download screenshots taken by cypress
     - name: Download screenshots taken by cypress
       uses: actions/download-artifact@v4
       uses: actions/download-artifact@v4
@@ -85,7 +75,7 @@ jobs:
     - name: Run reg-suit
     - name: Run reg-suit
       working-directory: ./apps/app
       working-directory: ./apps/app
       run: |
       run: |
-        yarn reg:run
+        pnpm run reg:run
 
 
     - name: Slack Notification
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
       uses: weseek/ghaction-slack-notification@master

+ 1 - 0
.gitignore

@@ -4,6 +4,7 @@
 node_modules
 node_modules
 /.pnp
 /.pnp
 .pnp.js
 .pnp.js
+.pnpm-store
 
 
 # testing
 # testing
 coverage
 coverage

+ 0 - 0
.npmrc


+ 2 - 1
.vscode/launch.json

@@ -31,8 +31,9 @@
         "request": "launch",
         "request": "launch",
         "name": "Debug: Server",
         "name": "Debug: Server",
         "cwd": "${workspaceFolder}/apps/app",
         "cwd": "${workspaceFolder}/apps/app",
-        "runtimeExecutable": "yarn",
+        "runtimeExecutable": "pnpm",
         "runtimeArgs": [
         "runtimeArgs": [
+          "run",
           "dev"
           "dev"
         ],
         ],
         "skipFiles": [
         "skipFiles": [

+ 8 - 1
CHANGELOG.md

@@ -1,9 +1,16 @@
 # Changelog
 # Changelog
 
 
-## [Unreleased](https://github.com/weseek/growi/compare/v7.0.21...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v7.0.22...HEAD)
 
 
 *Please do not manually update this file. We've automated the process.*
 *Please do not manually update this file. We've automated the process.*
 
 
+## [v7.0.22](https://github.com/weseek/growi/compare/v7.0.21...v7.0.22) - 2024-10-21
+
+### 🐛 Bug Fixes
+
+* fix: Edit button appear for the side of header (#9270) @yuki-takei
+* fix: Collaborative editing occurs unstable behavior (#9267) @yuki-takei
+
 ## [v7.0.21](https://github.com/weseek/growi/compare/v7.0.20...v7.0.21) - 2024-10-15
 ## [v7.0.21](https://github.com/weseek/growi/compare/v7.0.20...v7.0.21) - 2024-10-15
 
 
 ### 🚀 Improvement
 ### 🚀 Improvement

+ 7 - 7
README.md

@@ -81,9 +81,9 @@ See [GROWI Docs: Environment Variables](https://docs.growi.org/en/admin-guide/ad
 
 
 - Node.js v18.x or v20.x
 - Node.js v18.x or v20.x
 - npm 6.x
 - npm 6.x
-- yarn
+- pnpm 9.x
 - [Turborepo](https://turbo.build/repo)
 - [Turborepo](https://turbo.build/repo)
-- MongoDB 4.4 or above
+- MongoDB 6.0 or above
 
 
 ### Optional Dependencies
 ### Optional Dependencies
 
 
@@ -95,11 +95,11 @@ See [GROWI Docs: Environment Variables](https://docs.growi.org/en/admin-guide/ad
 
 
 ## Command details
 ## Command details
 
 
-| command           | desc                                                    |
-| ------------------| ------------------------------------------------------- |
-| `yarn app:build`  | Build GROWI app client                                  |
-| `yarn app:server` | Launch GROWI app server                                 |
-| `yarn start`      | Invoke `yarn app:build` and `yarn app:server`           |
+| command               | desc                                                    |
+| --------------------- | ------------------------------------------------------- |
+| `pnpm run app:build`  | Build GROWI app client                                  |
+| `pnpm run app:server` | Launch GROWI app server                                 |
+| `pnpm run start`      | Invoke `pnpm run app:build` and `pnpm run app:server`   |
 
 
 For more info, see [GROWI Docs: List of npm Scripts](https://docs.growi.org/en/dev/startup-v5/start-development.html#list-of-npm-scripts).
 For more info, see [GROWI Docs: List of npm Scripts](https://docs.growi.org/en/dev/startup-v5/start-development.html#list-of-npm-scripts).
 
 

+ 7 - 7
README_JP.md

@@ -80,9 +80,9 @@ Crowi からの移行は **[こちら](https://docs.growi.org/en/admin-guide/mig
 
 
 - Node.js v18.x or v20.x
 - Node.js v18.x or v20.x
 - npm 6.x
 - npm 6.x
-- yarn
+- pnpm 9.x
 - [Turborepo](https://turbo.build/repo)
 - [Turborepo](https://turbo.build/repo)
-- MongoDB 4.4 以上
+- MongoDB 6.0 以上
 
 
 ### オプションの依存関係
 ### オプションの依存関係
 
 
@@ -94,11 +94,11 @@ Crowi からの移行は **[こちら](https://docs.growi.org/en/admin-guide/mig
 
 
 ## コマンド詳細
 ## コマンド詳細
 
 
-| コマンド          | 説明                                                    |
-| ------------------| ------------------------------------------------------- |
-| `yarn app:build`  | GROWI app クライアントをビルドします。                  |
-| `yarn app:server` | GROWI app サーバーを起動します。                        |
-| `yarn start`      | `yarn app:build` と `yarn app:server` を呼び出します。  |
+| コマンド              | 説明                                                            |
+| --------------------- | --------------------------------------------------------------- |
+| `pnpm run app:build`  | GROWI app クライアントをビルドします。                          |
+| `pnpm run app:server` | GROWI app サーバーを起動します。                                |
+| `pnpm run start`      | `pnpm run app:build` と `pnpm run app:server` を呼び出します。  |
 
 
 詳しくは [GROWI Docs: npm スクリプトリスト](https://docs.growi.org/ja/dev/startup-v5/start-development.html#npm-%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%95%E3%82%9A%E3%83%88%E3%83%AA%E3%82%B9%E3%83%88)をご覧ください。
 詳しくは [GROWI Docs: npm スクリプトリスト](https://docs.growi.org/ja/dev/startup-v5/start-development.html#npm-%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%95%E3%82%9A%E3%83%88%E3%83%AA%E3%82%B9%E3%83%88)をご覧ください。
 
 

+ 28 - 0
apps/app/bin/swagger-jsdoc/definition-apiv1.js

@@ -0,0 +1,28 @@
+const pkg = require('../../package.json');
+
+module.exports = {
+  openapi: '3.0.1',
+  info: {
+    title: 'GROWI REST API v1',
+    version: pkg.version,
+  },
+  servers: [
+    {
+      url: 'https://demo.growi.org/_api',
+    },
+  ],
+  security: [
+    {
+      api_key: [],
+    },
+  ],
+  components: {
+    securitySchemes: {
+      api_key: {
+        type: 'apiKey',
+        name: 'access_token',
+        in: 'query',
+      },
+    },
+  },
+};

+ 93 - 0
apps/app/bin/swagger-jsdoc/definition-apiv3.js

@@ -0,0 +1,93 @@
+const pkg = require('../../package.json');
+
+module.exports = {
+  openapi: '3.0.1',
+  info: {
+    title: 'GROWI REST API v3',
+    version: pkg.version,
+  },
+  servers: [
+    {
+      url: 'https://demo.growi.org/_api/v3',
+    },
+  ],
+  security: [
+    {
+      api_key: [],
+    },
+  ],
+  components: {
+    securitySchemes: {
+      api_key: {
+        type: 'apiKey',
+        name: 'access_token',
+        in: 'query',
+      },
+    },
+  },
+  'x-tagGroups': [
+    {
+      name: 'User API',
+      tags: [
+        'Attachment',
+        'Bookmarks',
+        'Page',
+        'Pages',
+        'Revisions',
+        'ShareLinks',
+        'Users',
+        '',
+        '',
+      ],
+    },
+    {
+      name: 'User Personal Settings API',
+      tags: [
+        'GeneralSetting',
+        'EditorSetting',
+        'InAppNotificationSettings',
+        '',
+        '',
+        '',
+        '',
+        '',
+      ],
+    },
+    {
+      name: 'System Management API',
+      tags: [
+        'Home',
+        'AppSettings',
+        'SecuritySetting',
+        'MarkDownSetting',
+        'CustomizeSetting',
+        'Import',
+        'Export',
+        'MongoDB',
+        'NotificationSetting',
+        'SlackIntegrationSettings',
+        'SlackIntegrationSettings (with proxy)',
+        'SlackIntegrationSettings (without proxy)',
+        'SlackIntegrationLegacySetting',
+        'ShareLink Management',
+        'UserGroupRelations',
+        'UserGroups',
+        'Users Management',
+        'FullTextSearch Management',
+      ],
+    },
+    {
+      name: 'Public API',
+      tags: [
+        'Healthcheck',
+        'Statistics',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+      ],
+    },
+  ],
+};

+ 15 - 0
apps/app/bin/swagger-jsdoc/generate-spec-apiv1.sh

@@ -0,0 +1,15 @@
+# USAGE:
+#   cd apps/app && sh bin/swagger-jsdoc/generate-spec-apiv1.sh
+#   APP_PATH=/path/to/apps/app sh bin/swagger-jsdoc/generate-spec-apiv1.sh
+#   APP_PATH=/path/to/apps/app OUT=/path/to/output sh bin/swagger-jsdoc/generate-spec-apiv1.sh
+
+APP_PATH=${APP_PATH:-"."}
+
+OUT=${OUT:-"${APP_PATH}/tmp/openapi-spec-apiv1.json"}
+
+swagger-jsdoc \
+  -o "${OUT}" \
+  -d "${APP_PATH}/bin/swagger-jsdoc/definition-apiv1.js" \
+  "${APP_PATH}/src/server/routes/*.{js,ts}" \
+  "${APP_PATH}/src/server/routes/attachment/**/*.{js,ts}" \
+  "${APP_PATH}/src/server/models/openapi/**/*.{js,ts}"

+ 14 - 0
apps/app/bin/swagger-jsdoc/generate-spec-apiv3.sh

@@ -0,0 +1,14 @@
+# USAGE:
+#   cd apps/app && sh bin/swagger-jsdoc/generate-spec-apiv3.sh
+#   APP_PATH=/path/to/apps/app sh bin/swagger-jsdoc/generate-spec-apiv3.sh
+#   APP_PATH=/path/to/apps/app OUT=/path/to/output sh bin/swagger-jsdoc/generate-spec-apiv3.sh
+
+APP_PATH=${APP_PATH:-"."}
+
+OUT=${OUT:-"${APP_PATH}/tmp/openapi-spec-apiv3.json"}
+
+swagger-jsdoc \
+  -o "${OUT}" \
+  -d "${APP_PATH}/bin/swagger-jsdoc/definition-apiv3.js" \
+  "${APP_PATH}/src/server/routes/apiv3/**/*.{js,ts}" \
+  "${APP_PATH}/src/server/models/openapi/**/*.{js,ts}"

+ 0 - 37
apps/app/config/swagger-definition.js

@@ -1,37 +0,0 @@
-const pkg = require('../package.json');
-
-const apiVersion = process.env.API_VERSION || '3';
-const basePath = (apiVersion === '1' ? '/_api' : `/_api/v${apiVersion}`);
-
-module.exports = {
-  openapi: '3.0.1',
-  info: {
-    title: `GROWI REST API v${apiVersion}`,
-    version: pkg.version,
-  },
-  servers: [
-    {
-      url: 'https://demo.growi.org{basePath}',
-      variables: {
-        basePath: {
-          default: basePath,
-          description: 'base path',
-        },
-      },
-    },
-  ],
-  security: [
-    {
-      api_key: [],
-    },
-  ],
-  components: {
-    securitySchemes: {
-      api_key: {
-        type: 'apiKey',
-        name: 'access_token',
-        in: 'query',
-      },
-    },
-  },
-};

+ 27 - 70
apps/app/docker/Dockerfile

@@ -10,85 +10,40 @@ ENV optDir /opt
 
 
 WORKDIR ${optDir}
 WORKDIR ${optDir}
 
 
-RUN yarn global add turbo
-COPY . .
-RUN turbo prune @growi/app --docker
-
-
-##
-## deps-resolver
-##
-FROM node:20-slim AS deps-resolver
-
-ENV optDir /opt
-
-WORKDIR ${optDir}
-
-RUN set -eux; \
-	apt-get update; \
-	apt-get install -y python3 build-essential;
-
-# copy files
-COPY --from=base ${optDir}/out/json/ .
-COPY --from=base ${optDir}/out/yarn.lock ./yarn.lock
+# install pnpm
+RUN apt-get update && apt-get install -y ca-certificates wget --no-install-recommends \
+  && wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
+ENV PNPM_HOME "/root/.local/share/pnpm"
+ENV PATH "$PNPM_HOME:$PATH"
 
 
-# setup (with network-timeout = 1 hour)
-RUN yarn config set network-timeout 3600000
-RUN yarn global add node-gyp
-RUN yarn --frozen-lockfile
-
-# make artifacts
-RUN tar -cf node_modules.tar \
-  node_modules \
-  apps/*/node_modules \
-  packages/*/node_modules
-
-
-
-##
-## deps-resolver-prod
-##
-FROM deps-resolver AS deps-resolver-prod
-
-RUN yarn --production
-# make artifacts
-RUN tar -cf node_modules.tar \
-  node_modules \
-  apps/*/node_modules \
-  packages/*/node_modules
+# install turbo
+RUN pnpm add turbo --global
 
 
 
 
 
 
 ##
 ##
 ## builder
 ## builder
 ##
 ##
-FROM node:20-slim AS builder
+FROM base AS builder
 
 
 ENV optDir /opt
 ENV optDir /opt
 
 
 WORKDIR ${optDir}
 WORKDIR ${optDir}
 
 
-RUN yarn global add turbo
-
-# copy files
-COPY --from=base ${optDir}/out/full/ .
-COPY --from=base ${optDir}/out/yarn.lock ./yarn.lock
-COPY ["tsconfig.base.json", "./"]
-
-# copy dependent packages
-COPY --from=deps-resolver \
-  ${optDir}/node_modules.tar ${optDir}/
+COPY . .
 
 
-# extract node_modules.tar
-RUN tar -xf node_modules.tar
-RUN rm node_modules.tar
+RUN pnpm add node-gyp --global
+RUN pnpm install ---frozen-lockfile
 
 
 # build
 # build
 RUN turbo run clean
 RUN turbo run clean
-RUN turbo run build
+RUN turbo run build --filter @growi/app
 
 
 # make artifacts
 # make artifacts
-RUN tar -cf packages.tar \
+RUN pnpm --filter @growi/app --prod deploy pruned
+RUN rm -rf apps/app/node_modules && mv pruned/node_modules apps/app/node_modules
+RUN rm -rf apps/app/.next/cache
+RUN tar -zcf packages.tar.gz \
   package.json \
   package.json \
   apps/app/.next \
   apps/app/.next \
   apps/app/config \
   apps/app/config \
@@ -99,8 +54,7 @@ RUN tar -cf packages.tar \
   apps/app/.env.production* \
   apps/app/.env.production* \
   apps/app/next.config.js \
   apps/app/next.config.js \
   apps/app/package.json \
   apps/app/package.json \
-  packages/*/package.json \
-  packages/*/dist
+  apps/app/node_modules
 
 
 
 
 
 
@@ -124,17 +78,20 @@ RUN set -eux; \
 # verify that the binary works
 # verify that the binary works
 	gosu nobody true
 	gosu nobody true
 
 
-COPY --from=deps-resolver-prod --chown=node:node \
-  ${optDir}/node_modules.tar ${appDir}/
+# Add pnpm for 'node' user
+RUN apt-get update && apt-get install -y sudo ca-certificates wget --no-install-recommends \
+  && wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sudo -u node sh - \
+  && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false
+ENV PNPM_HOME="/home/node/.local/share/pnpm"
+ENV PATH "$PNPM_HOME:$PATH"
+
 COPY --from=builder --chown=node:node \
 COPY --from=builder --chown=node:node \
-  ${optDir}/packages.tar ${appDir}/
+  ${optDir}/packages.tar.gz ${appDir}/
 
 
 # extract artifacts as 'node' user
 # extract artifacts as 'node' user
 USER node
 USER node
 WORKDIR ${appDir}
 WORKDIR ${appDir}
-RUN tar -xf node_modules.tar
-RUN tar -xf packages.tar
-RUN rm node_modules.tar packages.tar
+RUN tar -zxf packages.tar.gz && rm packages.tar.gz
 
 
 COPY --chown=node:node --chmod=700 apps/app/docker/docker-entrypoint.sh /
 COPY --chown=node:node --chmod=700 apps/app/docker/docker-entrypoint.sh /
 
 
@@ -145,4 +102,4 @@ VOLUME /data
 EXPOSE 3000
 EXPOSE 3000
 
 
 ENTRYPOINT ["/docker-entrypoint.sh"]
 ENTRYPOINT ["/docker-entrypoint.sh"]
-CMD ["yarn migrate && node -r dotenv-flow/config --expose_gc dist/server/app.js"]
+CMD ["pnpm run migrate && node -r dotenv-flow/config --expose_gc dist/server/app.js"]

+ 1 - 0
apps/app/docker/Dockerfile.dockerignore

@@ -2,6 +2,7 @@
 **/coverage
 **/coverage
 **/Dockerfile
 **/Dockerfile
 **/*.dockerignore
 **/*.dockerignore
+**/.pnpm-store
 **/.next
 **/.next
 **/.turbo
 **/.turbo
 out
 out

+ 1 - 1
apps/app/docker/README.md

@@ -10,7 +10,7 @@ GROWI Official docker image
 Supported tags and respective Dockerfile links
 Supported tags and respective Dockerfile links
 ------------------------------------------------
 ------------------------------------------------
 
 
-* [`7.0.21`, `7.0`, `7`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v7.0.21/apps/app/docker/Dockerfile)
+* [`7.0.22`, `7.0`, `7`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v7.0.22/apps/app/docker/Dockerfile)
 * [`6.3.2`, `6.3`, `6` (Dockerfile)](https://github.com/weseek/growi/blob/v6.3.2/apps/app/docker/Dockerfile)
 * [`6.3.2`, `6.3`, `6` (Dockerfile)](https://github.com/weseek/growi/blob/v6.3.2/apps/app/docker/Dockerfile)
 * [`6.2.4`, `6.2` (Dockerfile)](https://github.com/weseek/growi/blob/v6.2.4/apps/app/docker/Dockerfile)
 * [`6.2.4`, `6.2` (Dockerfile)](https://github.com/weseek/growi/blob/v6.2.4/apps/app/docker/Dockerfile)
 * [`6.1.15`, `6.1` (Dockerfile)](https://github.com/weseek/growi/blob/v6.1.15/apps/app/docker/Dockerfile)
 * [`6.1.15`, `6.1` (Dockerfile)](https://github.com/weseek/growi/blob/v6.1.15/apps/app/docker/Dockerfile)

+ 1 - 3
apps/app/docker/codebuild/buildspec.yml

@@ -27,6 +27,4 @@ phases:
 
 
 cache:
 cache:
   paths:
   paths:
-    - node_modules/**/*
-    - apps/*/node_modules/**/*
-    - packages/*/node_modules/**/*
+    - .pnpm-store/**/*

+ 4 - 0
apps/app/nodemon.json

@@ -1,5 +1,9 @@
 {
 {
   "ext": "js,ts,json",
   "ext": "js,ts,json",
+  "watch": [
+    ".",
+    "../../packages/**/dist"
+  ],
   "ignore": [
   "ignore": [
     ".next",
     ".next",
     "public/static",
     "public/static",

+ 70 - 51
apps/app/package.json

@@ -6,33 +6,35 @@
   "scripts": {
   "scripts": {
     "//// for production": "",
     "//// for production": "",
     "build": "run-p build:*",
     "build": "run-p build:*",
-    "start": "yarn next start",
-    "build:client": "yarn next build",
-    "build:server": "yarn cross-env NODE_ENV=production tspc -p tsconfig.build.server.json",
+    "start": "next start",
+    "build:client": "next build",
+    "build:server": "cross-env NODE_ENV=production tspc -p tsconfig.build.server.json",
     "postbuild:server": "shx echo \"Listing files under transpiled\" && shx ls transpiled && shx rm -rf dist && shx mv transpiled/src dist && shx rm -rf transpiled",
     "postbuild:server": "shx echo \"Listing files under transpiled\" && shx ls transpiled && shx rm -rf dist && shx mv transpiled/src dist && shx rm -rf transpiled",
     "clean": "shx rm -rf dist transpiled",
     "clean": "shx rm -rf dist transpiled",
-    "server": "yarn cross-env NODE_ENV=production node -r dotenv-flow/config dist/server/app.js",
-    "server:ci": "yarn server --ci",
-    "preserver": "yarn cross-env NODE_ENV=production yarn migrate",
+    "server": "cross-env NODE_ENV=production node -r dotenv-flow/config dist/server/app.js",
+    "server:ci": "pnpm run server --ci",
+    "preserver": "cross-env NODE_ENV=production pnpm run migrate",
     "styles-prebuilt": "vite build -c vite.styles-prebuilt.config.ts",
     "styles-prebuilt": "vite build -c vite.styles-prebuilt.config.ts",
-    "migrate": "node -r dotenv-flow/config node_modules/.bin/migrate-mongo up -f config/migrate-mongo-config.js",
+    "migrate": "node -r dotenv-flow/config node_modules/migrate-mongo/bin/migrate-mongo up -f config/migrate-mongo-config.js",
     "//// for development": "",
     "//// for development": "",
-    "dev": "yarn cross-env NODE_ENV=development nodemon --exec yarn ts-node --inspect src/server/app.ts",
-    "dev:styles-prebuilt": "yarn styles-prebuilt --mode dev",
-    "dev:migrate-mongo": "yarn cross-env NODE_ENV=development yarn ts-node node_modules/.bin/migrate-mongo",
-    "dev:migrate": "yarn dev:migrate:status > tmp/cache/migration-status.out && yarn dev:migrate:up",
-    "dev:migrate:create": "yarn dev:migrate-mongo create -f config/migrate-mongo-config.js",
-    "dev:migrate:status": "yarn dev:migrate-mongo status -f config/migrate-mongo-config.js",
-    "dev:migrate:up": "yarn dev:migrate-mongo up -f config/migrate-mongo-config.js",
-    "dev:migrate:down": "yarn dev:migrate-mongo down -f config/migrate-mongo-config.js",
+    "dev": "cross-env NODE_ENV=development nodemon --exec pnpm run ts-node --inspect src/server/app.ts",
+    "dev:styles-prebuilt": "pnpm run styles-prebuilt --mode dev",
+    "dev:migrate-mongo": "cross-env NODE_ENV=development pnpm run ts-node node_modules/migrate-mongo/bin/migrate-mongo",
+    "dev:migrate": "pnpm run dev:migrate:status > tmp/cache/migration-status.out && pnpm run dev:migrate:up",
+    "dev:migrate:create": "pnpm run dev:migrate-mongo create -f config/migrate-mongo-config.js",
+    "dev:migrate:status": "pnpm run dev:migrate-mongo status -f config/migrate-mongo-config.js",
+    "dev:migrate:up": "pnpm run dev:migrate-mongo up -f config/migrate-mongo-config.js",
+    "dev:migrate:down": "pnpm run dev:migrate-mongo down -f config/migrate-mongo-config.js",
     "//// for CI": "",
     "//// for CI": "",
-    "launch-dev:ci": "yarn cross-env NODE_ENV=development yarn dev:migrate && yarn ts-node src/server/app.ts --ci",
+    "launch-dev:ci": "cross-env NODE_ENV=development pnpm run dev:migrate && pnpm run ts-node src/server/app.ts --ci",
     "lint:typecheck": "npx -y tspc",
     "lint:typecheck": "npx -y tspc",
-    "lint:eslint": "yarn eslint --quiet \"**/*.{js,jsx,ts,tsx}\"",
+    "lint:eslint": "eslint --quiet \"**/*.{js,jsx,ts,tsx}\"",
     "lint:styles": "stylelint \"src/**/*.scss\"",
     "lint:styles": "stylelint \"src/**/*.scss\"",
-    "lint:swagger2openapi": "node node_modules/.bin/oas-validate tmp/swagger.json",
+    "lint:swagger2openapi:apiv3": "node node_modules/swagger2openapi/oas-validate tmp/openapi-spec-apiv3.json",
+    "lint:swagger2openapi:apiv1": "node node_modules/swagger2openapi/oas-validate tmp/openapi-spec-apiv1.json",
     "lint": "run-p lint:*",
     "lint": "run-p lint:*",
-    "prelint:swagger2openapi": "yarn openapi:v3",
+    "prelint:swagger2openapi:apiv3": "pnpm run swagger2openapi:apiv3",
+    "prelint:swagger2openapi:apiv1": "pnpm run swagger2openapi:apiv1",
     "test": "run-p test:*",
     "test": "run-p test:*",
     "test:jest": "cross-env NODE_ENV=test TS_NODE_PROJECT=test/integration/tsconfig.json jest",
     "test:jest": "cross-env NODE_ENV=test TS_NODE_PROJECT=test/integration/tsconfig.json jest",
     "test:vitest": "vitest run --coverage",
     "test:vitest": "vitest run --coverage",
@@ -40,20 +42,21 @@
     "reg:run": "reg-suit run",
     "reg:run": "reg-suit run",
     "previtest:run:integ": "vitest run -c test-with-vite/download-mongo-binary/vitest.config.ts test-with-vite/download-mongo-binary",
     "previtest:run:integ": "vitest run -c test-with-vite/download-mongo-binary/vitest.config.ts test-with-vite/download-mongo-binary",
     "//// misc": "",
     "//// misc": "",
-    "console": "yarn repl",
-    "repl": "yarn cross-env NODE_ENV=development yarn ts-node src/server/repl.ts",
-    "swagger-jsdoc": "swagger-jsdoc -o tmp/swagger.json -d config/swagger-definition.js",
-    "openapi:v3": "yarn cross-env API_VERSION=3 yarn swagger-jsdoc -- \"src/server/routes/apiv3/**/*.js\" \"src/server/models/**/*.js\"",
-    "openapi:v1": "yarn cross-env API_VERSION=1 yarn swagger-jsdoc -- \"src/server/*/*.js\" \"src/server/models/**/*.js\"",
+    "console": "cross-env NODE_ENV=development pnpm run ts-node --experimental-repl-await src/server/console.js",
+    "swagger2openapi:apiv3": "sh bin/swagger-jsdoc/generate-spec-apiv3.sh",
+    "swagger2openapi:apiv1": "sh bin/swagger-jsdoc/generate-spec-apiv1.sh",
     "ts-node": "node -r ts-node/register/transpile-only -r tsconfig-paths/register -r dotenv-flow/config",
     "ts-node": "node -r ts-node/register/transpile-only -r tsconfig-paths/register -r dotenv-flow/config",
-    "version": "yarn version --no-git-tag-version --non-interactive --preid=RC"
+    "version:patch": "pnpm version patch",
+    "version:prerelease": "pnpm version prerelease --preid=RC",
+    "version:prepatch": "pnpm version prepatch --preid=RC",
+    "version:preminor": "pnpm version preminor --preid=RC",
+    "version:premajor": "pnpm version premajor --preid=RC"
   },
   },
   "// comments for dependencies": {
   "// comments for dependencies": {
     "@aws-skd/*": "fix version above 3.186.0 that is required by mongodb@4.16.0",
     "@aws-skd/*": "fix version above 3.186.0 that is required by mongodb@4.16.0",
     "@keycloak/keycloak-admin-client": "19.0.0 or above exports only ESM.",
     "@keycloak/keycloak-admin-client": "19.0.0 or above exports only ESM.",
     "escape-string-regexp": "5.0.0 or above exports only ESM",
     "escape-string-regexp": "5.0.0 or above exports only ESM",
     "next-themes": "0.3.0 causes a type error: https://github.com/pacocoursey/next-themes/issues/122",
     "next-themes": "0.3.0 causes a type error: https://github.com/pacocoursey/next-themes/issues/122",
-    "remark-wiki-link": "!!DO NOT REMOVE!! including 'mdast-util-wiki-link' and 'micromark-extension-wiki-link' required by pukiwiki-like-linker",
     "string-width": "5.0.0 or above exports only ESM."
     "string-width": "5.0.0 or above exports only ESM."
   },
   },
   "dependencies": {
   "dependencies": {
@@ -68,22 +71,20 @@
     "@elastic/elasticsearch8": "npm:@elastic/elasticsearch@^8.7.0",
     "@elastic/elasticsearch8": "npm:@elastic/elasticsearch@^8.7.0",
     "@godaddy/terminus": "^4.9.0",
     "@godaddy/terminus": "^4.9.0",
     "@google-cloud/storage": "^5.8.5",
     "@google-cloud/storage": "^5.8.5",
-    "@growi/core": "link:../../packages/core",
-    "@growi/pluginkit": "link:../../packages/pluginkit",
-    "@growi/presentation": "link:../../packages/presentation",
-    "@growi/preset-templates": "link:../../packages/preset-templates",
-    "@growi/preset-themes": "link:../../packages/preset-themes",
-    "@growi/remark-attachment-refs": "link:../../packages/remark-attachment-refs",
-    "@growi/remark-drawio": "link:../../packages/remark-drawio",
-    "@growi/remark-growi-directive": "link:../../packages/remark-growi-directive",
-    "@growi/remark-lsx": "link:../../packages/remark-lsx",
-    "@growi/slack": "link:../../packages/slack",
+    "@growi/core": "workspace:^",
+    "@growi/pluginkit": "workspace:^",
+    "@growi/presentation": "workspace:^",
+    "@growi/preset-templates": "workspace:^",
+    "@growi/preset-themes": "workspace:^",
+    "@growi/remark-attachment-refs": "workspace:^",
+    "@growi/remark-drawio": "workspace:^",
+    "@growi/remark-growi-directive": "workspace:^",
+    "@growi/remark-lsx": "workspace:^",
+    "@growi/slack": "workspace:^",
     "@keycloak/keycloak-admin-client": "^18.0.0",
     "@keycloak/keycloak-admin-client": "^18.0.0",
     "@slack/web-api": "^6.2.4",
     "@slack/web-api": "^6.2.4",
     "@slack/webhook": "^6.0.0",
     "@slack/webhook": "^6.0.0",
     "@types/async": "^3.2.24",
     "@types/async": "^3.2.24",
-    "@types/jest": "^29.5.2",
-    "@types/ldapjs": "^2.2.5",
     "JSONStream": "^1.3.5",
     "JSONStream": "^1.3.5",
     "archiver": "^5.3.0",
     "archiver": "^5.3.0",
     "array.prototype.flatmap": "^1.2.2",
     "array.prototype.flatmap": "^1.2.2",
@@ -94,7 +95,7 @@
     "browser-bunyan": "^1.8.0",
     "browser-bunyan": "^1.8.0",
     "bson-objectid": "^2.0.4",
     "bson-objectid": "^2.0.4",
     "bunyan": "^1.8.15",
     "bunyan": "^1.8.15",
-    "check-node-version": "^4.1.0",
+    "check-node-version": "^4.2.1",
     "compression": "^1.7.4",
     "compression": "^1.7.4",
     "connect-flash": "~0.1.1",
     "connect-flash": "~0.1.1",
     "connect-mongo": "^4.6.0",
     "connect-mongo": "^4.6.0",
@@ -120,6 +121,7 @@
     "extensible-custom-error": "^0.0.7",
     "extensible-custom-error": "^0.0.7",
     "form-data": "^4.0.0",
     "form-data": "^4.0.0",
     "graceful-fs": "^4.1.11",
     "graceful-fs": "^4.1.11",
+    "hast-util-sanitize": "^5.0.1",
     "hast-util-select": "^6.0.2",
     "hast-util-select": "^6.0.2",
     "helmet": "^4.6.0",
     "helmet": "^4.6.0",
     "http-errors": "^2.0.0",
     "http-errors": "^2.0.0",
@@ -127,14 +129,21 @@
     "i18next-resources-to-backend": "^1.2.1",
     "i18next-resources-to-backend": "^1.2.1",
     "is-absolute-url": "^4.0.1",
     "is-absolute-url": "^4.0.1",
     "is-iso-date": "^0.0.1",
     "is-iso-date": "^0.0.1",
+    "katex": "^0.16.11",
     "ldapjs": "^3.0.2",
     "ldapjs": "^3.0.2",
     "lucene-query-parser": "^1.2.0",
     "lucene-query-parser": "^1.2.0",
     "markdown-table": "^3.0.3",
     "markdown-table": "^3.0.3",
+    "mdast-util-from-markdown": "^2.0.1",
+    "mdast-util-gfm-table": "^2.0.0",
+    "mdast-util-wiki-link": "^0.1.2",
     "md5": "^2.2.1",
     "md5": "^2.2.1",
     "mermaid": "^11.2.0",
     "mermaid": "^11.2.0",
     "method-override": "^3.0.0",
     "method-override": "^3.0.0",
+    "micromark-extension-gfm-table": "^2.1.0",
+    "micromark-extension-wiki-link": "^0.0.4",
     "migrate-mongo": "^11.0.0",
     "migrate-mongo": "^11.0.0",
     "mkdirp": "^1.0.3",
     "mkdirp": "^1.0.3",
+    "mongodb": "^4.17.2",
     "mongoose": "^6.11.3",
     "mongoose": "^6.11.3",
     "mongoose-gridfs": "^1.2.42",
     "mongoose-gridfs": "^1.2.42",
     "mongoose-paginate-v2": "^1.3.9",
     "mongoose-paginate-v2": "^1.3.9",
@@ -160,6 +169,7 @@
     "passport-ldapauth": "^3.0.1",
     "passport-ldapauth": "^3.0.1",
     "passport-local": "^1.0.0",
     "passport-local": "^1.0.0",
     "passport-saml": "^3.2.0",
     "passport-saml": "^3.2.0",
+    "prop-types": "^15.8.1",
     "qs": "^6.11.1",
     "qs": "^6.11.1",
     "rate-limiter-flexible": "^2.3.7",
     "rate-limiter-flexible": "^2.3.7",
     "react": "^18.2.0",
     "react": "^18.2.0",
@@ -180,27 +190,32 @@
     "reactstrap": "^9.2.2",
     "reactstrap": "^9.2.2",
     "reconnecting-websocket": "^4.4.0",
     "reconnecting-websocket": "^4.4.0",
     "redis": "^3.0.2",
     "redis": "^3.0.2",
-    "rehype-katex": "^7.0.0",
+    "rehype-katex": "^7.0.1",
     "rehype-raw": "^7.0.0",
     "rehype-raw": "^7.0.0",
     "rehype-sanitize": "^6.0.0",
     "rehype-sanitize": "^6.0.0",
     "rehype-slug": "^6.0.0",
     "rehype-slug": "^6.0.0",
     "rehype-toc": "^3.0.2",
     "rehype-toc": "^3.0.2",
     "remark-breaks": "^4.0.0",
     "remark-breaks": "^4.0.0",
+    "remark-directive": "^3.0.0",
     "remark-emoji": "^5.0.0",
     "remark-emoji": "^5.0.0",
     "remark-frontmatter": "^5.0.0",
     "remark-frontmatter": "^5.0.0",
     "remark-gfm": "^4.0.0",
     "remark-gfm": "^4.0.0",
     "remark-math": "^6.0.0",
     "remark-math": "^6.0.0",
+    "remark-parse": "^11.0.0",
+    "remark-rehype": "^11.1.1",
     "remark-toc": "^9.0.0",
     "remark-toc": "^9.0.0",
-    "remark-wiki-link": "^2.0.1",
     "sanitize-filename": "^1.6.3",
     "sanitize-filename": "^1.6.3",
     "socket.io": "^4.7.5",
     "socket.io": "^4.7.5",
     "stream-to-promise": "^3.0.0",
     "stream-to-promise": "^3.0.0",
     "string-width": "=4.2.2",
     "string-width": "=4.2.2",
     "superjson": "^1.9.1",
     "superjson": "^1.9.1",
-    "swagger-jsdoc": "^6.1.0",
+    "swagger-jsdoc": "^6.2.8",
     "swr": "^2.2.2",
     "swr": "^2.2.2",
     "throttle-debounce": "^5.0.0",
     "throttle-debounce": "^5.0.0",
+    "uid-safe": "^2.1.5",
     "uglifycss": "^0.0.29",
     "uglifycss": "^0.0.29",
+    "unified": "^11.0.0",
+    "unist-util-visit": "^5.0.0",
     "universal-bunyan": "^0.9.2",
     "universal-bunyan": "^0.9.2",
     "unstated": "^2.1.1",
     "unstated": "^2.1.1",
     "unzip-stream": "^0.3.2",
     "unzip-stream": "^0.3.2",
@@ -220,11 +235,11 @@
     "mongodb": "mongoose which is used requires mongo@4.16.0."
     "mongodb": "mongoose which is used requires mongo@4.16.0."
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@growi/core-styles": "link:../../packages/core-styles",
-    "@growi/custom-icons": "link:../../packages/custom-icons",
-    "@growi/editor": "link:../../packages/editor",
-    "@growi/markdown-splitter": "link:../../packages/markdown-splitter",
-    "@growi/ui": "link:../../packages/ui",
+    "@growi/core-styles": "workspace:^",
+    "@growi/custom-icons": "workspace:^",
+    "@growi/editor": "workspace:^",
+    "@growi/markdown-splitter": "workspace:^",
+    "@growi/ui": "workspace:^",
     "@handsontable/react": "=2.1.0",
     "@handsontable/react": "=2.1.0",
     "@next/bundle-analyzer": "^14.1.3",
     "@next/bundle-analyzer": "^14.1.3",
     "@popperjs/core": "^2.11.8",
     "@popperjs/core": "^2.11.8",
@@ -236,13 +251,19 @@
     "@testing-library/user-event": "^14.5.2",
     "@testing-library/user-event": "^14.5.2",
     "@types/archiver": "^6.0.2",
     "@types/archiver": "^6.0.2",
     "@types/express": "^4.17.21",
     "@types/express": "^4.17.21",
+    "@types/hast": "^3.0.4",
     "@types/jest": "^29.5.2",
     "@types/jest": "^29.5.2",
+    "@types/ldapjs": "^2.2.5",
+    "@types/mdast": "^4.0.4",
     "@types/node-cron": "^3.0.11",
     "@types/node-cron": "^3.0.11",
+    "@types/react": "^18.2.14",
+    "@types/react-dom": "^18.2.6",
     "@types/react-input-autosize": "^2.2.4",
     "@types/react-input-autosize": "^2.2.4",
     "@types/react-scroll": "^1.8.4",
     "@types/react-scroll": "^1.8.4",
     "@types/react-stickynode": "^4.0.3",
     "@types/react-stickynode": "^4.0.3",
     "@types/testing-library__dom": "^7.5.0",
     "@types/testing-library__dom": "^7.5.0",
     "@types/throttle-debounce": "^5.0.1",
     "@types/throttle-debounce": "^5.0.1",
+    "@types/unist": "^3.0.3",
     "@types/unzip-stream": "^0.3.4",
     "@types/unzip-stream": "^0.3.4",
     "@types/url-join": "^4.0.2",
     "@types/url-join": "^4.0.2",
     "babel-loader": "^8.2.5",
     "babel-loader": "^8.2.5",
@@ -265,24 +286,22 @@
     "jest-localstorage-mock": "^2.4.14",
     "jest-localstorage-mock": "^2.4.14",
     "load-css-file": "^1.0.0",
     "load-css-file": "^1.0.0",
     "material-icons": "^1.11.3",
     "material-icons": "^1.11.3",
-    "mongodb": "4.16.0",
+    "mdast-util-directive": "^3.0.0",
     "mongodb-memory-server-core": "^9.1.1",
     "mongodb-memory-server-core": "^9.1.1",
     "morgan": "^1.10.0",
     "morgan": "^1.10.0",
     "null-loader": "^4.0.1",
     "null-loader": "^4.0.1",
-    "plantuml-encoder": "^1.2.5",
     "pretty-bytes": "^6.1.1",
     "pretty-bytes": "^6.1.1",
     "react-copy-to-clipboard": "^5.0.1",
     "react-copy-to-clipboard": "^5.0.1",
     "react-dnd": "^14.0.5",
     "react-dnd": "^14.0.5",
     "react-dnd-html5-backend": "^14.1.0",
     "react-dnd-html5-backend": "^14.1.0",
     "react-dropzone": "^14.2.3",
     "react-dropzone": "^14.2.3",
+    "react-hook-form": "^7.45.4",
     "react-hotkeys": "^2.0.0",
     "react-hotkeys": "^2.0.0",
     "react-input-autosize": "^3.0.0",
     "react-input-autosize": "^3.0.0",
     "react-toastify": "^9.1.3",
     "react-toastify": "^9.1.3",
     "rehype-rewrite": "^4.0.2",
     "rehype-rewrite": "^4.0.2",
     "remark-github-admonitions-to-directives": "^2.0.0",
     "remark-github-admonitions-to-directives": "^2.0.0",
-    "replacestream": "^4.0.3",
     "sass": "^1.53.0",
     "sass": "^1.53.0",
-    "simple-load-script": "^1.0.2",
     "simplebar-react": "^2.3.6",
     "simplebar-react": "^2.3.6",
     "socket.io-client": "^4.7.5",
     "socket.io-client": "^4.7.5",
     "source-map-loader": "^4.0.1",
     "source-map-loader": "^4.0.1",

+ 1 - 1
apps/app/playwright.config.ts

@@ -51,7 +51,7 @@ export default defineConfig({
   reporter: process.env.CI ? 'github' : 'list',
   reporter: process.env.CI ? 'github' : 'list',
 
 
   webServer: {
   webServer: {
-    command: 'yarn server',
+    command: 'pnpm run server',
     url: 'http://localhost:3000',
     url: 'http://localhost:3000',
     reuseExistingServer: !process.env.CI,
     reuseExistingServer: !process.env.CI,
     stdout: 'ignore',
     stdout: 'ignore',

+ 4 - 2
apps/app/public/static/locales/en_US/translation.json

@@ -492,8 +492,10 @@
     "caution_against_hallucination": "Please verify the information and check the sources.",
     "caution_against_hallucination": "Please verify the information and check the sources.",
     "progress_label": "Generating answers",
     "progress_label": "Generating answers",
     "failed_to_create_or_retrieve_thread": "Failed to create or retrieve thread",
     "failed_to_create_or_retrieve_thread": "Failed to create or retrieve thread",
-    "rate_limit_exceeded": "You have reached your usage limit for OpenAI's API. To use the Knowledge Assistant again, please add credits from the OpenAI billing page.",
-    "rate_limit_exceeded_for_growi_cloud": "You have reached your OpenAI API usage limit. To use the Knowledge Assistant again, please add credits from the GROWI.cloud admin page for Hosted users or from the OpenAI billing page for Owned users."
+    "budget_exceeded": "You have reached your usage limit for OpenAI's API. To use the Knowledge Assistant again, please add credits from the OpenAI billing page.",
+    "budget_exceeded_for_growi_cloud": "You have reached your OpenAI API usage limit. To use the Knowledge Assistant again, please add credits from the GROWI.cloud admin page for Hosted users or from the OpenAI billing page for Owned users.",
+    "error_message": "An error has occurred",
+    "show_error_detail": "Show error details"
 
 
   },
   },
   "link_edit": {
   "link_edit": {

+ 4 - 2
apps/app/public/static/locales/fr_FR/translation.json

@@ -486,8 +486,10 @@
     "caution_against_hallucination": "Veuillez vérifier les informations et consulter les sources.",
     "caution_against_hallucination": "Veuillez vérifier les informations et consulter les sources.",
     "progress_label": "Génération des réponses",
     "progress_label": "Génération des réponses",
     "failed_to_create_or_retrieve_thread": "Échec de la création ou de la récupération du fil de discussion",
     "failed_to_create_or_retrieve_thread": "Échec de la création ou de la récupération du fil de discussion",
-    "rate_limit_exceeded": "Vous avez atteint votre limite d'utilisation de l'API de l'OpenAI. Pour utiliser à nouveau l'assistant de connaissance, veuillez ajouter des crédits à partir de la page de facturation d'OpenAI.",
-    "rate_limit_exceeded_for_growi_cloud": "Vous avez atteint votre limite d'utilisation de l'API de l'OpenAI. Pour utiliser à nouveau l'assistant de connaissance, veuillez ajouter des crédits à partir de la page d'administration de GROWI.cloud pour les utilisateurs hébergés ou à partir de la page de facturation de l'OpenAI pour les utilisateurs propriétaires."
+    "budget_exceeded": "Vous avez atteint votre limite d'utilisation de l'API de l'OpenAI. Pour utiliser à nouveau l'assistant de connaissance, veuillez ajouter des crédits à partir de la page de facturation d'OpenAI.",
+    "budget_exceeded_for_growi_cloud": "Vous avez atteint votre limite d'utilisation de l'API de l'OpenAI. Pour utiliser à nouveau l'assistant de connaissance, veuillez ajouter des crédits à partir de la page d'administration de GROWI.cloud pour les utilisateurs hébergés ou à partir de la page de facturation de l'OpenAI pour les utilisateurs propriétaires.",
+    "error_message": "Erreur",
+    "show_error_detail": "Détails de l'exposition"
   },
   },
   "link_edit": {
   "link_edit": {
     "edit_link": "Modifier lien",
     "edit_link": "Modifier lien",

+ 4 - 2
apps/app/public/static/locales/ja_JP/translation.json

@@ -525,8 +525,10 @@
     "caution_against_hallucination": "情報が正しいか出典を確認しましょう",
     "caution_against_hallucination": "情報が正しいか出典を確認しましょう",
     "progress_label": "回答を生成しています",
     "progress_label": "回答を生成しています",
     "failed_to_create_or_retrieve_thread": "スレッドの作成または取得に失敗しました",
     "failed_to_create_or_retrieve_thread": "スレッドの作成または取得に失敗しました",
-    "rate_limit_exceeded": "OpenAI の API の利用上限に達しました。ナレッジアシスタントを再度利用するには OpenAI の請求ページからクレジットを追加してください。",
-    "rate_limit_exceeded_for_growi_cloud": "OpenAI の API の利用上限に達しました。ナレッジアシスタントを再度利用するには Hosted の場合は GROWI.cloud の管理画面から Owned の場合は OpenAI の請求ページからクレジットを追加してください。"
+    "budget_exceeded": "OpenAI の API の利用上限に達しました。ナレッジアシスタントを再度利用するには OpenAI の請求ページからクレジットを追加してください。",
+    "budget_exceeded_for_growi_cloud": "OpenAI の API の利用上限に達しました。ナレッジアシスタントを再度利用するには Hosted の場合は GROWI.cloud の管理画面から Owned の場合は OpenAI の請求ページからクレジットを追加してください。",
+    "error_message": "エラーが発生しました",
+    "show_error_detail": "詳細を表示"
   },
   },
   "link_edit": {
   "link_edit": {
     "edit_link": "リンク編集",
     "edit_link": "リンク編集",

+ 4 - 2
apps/app/public/static/locales/zh_CN/translation.json

@@ -481,8 +481,10 @@
     "caution_against_hallucination": "请核实信息并检查来源。",
     "caution_against_hallucination": "请核实信息并检查来源。",
     "progress_label": "生成答案中",
     "progress_label": "生成答案中",
     "failed_to_create_or_retrieve_thread": "创建或获取线程失败",
     "failed_to_create_or_retrieve_thread": "创建或获取线程失败",
-    "rate_limit_exceeded": "您已达到 OpenAI API 的使用上限。要再次使用知识助手,请从 OpenAI 账单页面添加点数。",
-    "rate_limit_exceeded_for_growi_cloud": "您已达到 OpenAI API 使用上限。如需再次使用知识助手,请从GROWI.cloud管理页面为托管用户添加点数,或从OpenAI计费页面为自有用户添加点数。"
+    "budget_exceeded": "您已达到 OpenAI API 的使用上限。要再次使用知识助手,请从 OpenAI 账单页面添加点数。",
+    "budget_exceeded_for_growi_cloud": "您已达到 OpenAI API 使用上限。如需再次使用知识助手,请从GROWI.cloud管理页面为托管用户添加点数,或从OpenAI计费页面为自有用户添加点数。",
+    "error_message": "错误",
+    "show_error_detail": "显示详情"
   },
   },
   "link_edit": {
   "link_edit": {
     "edit_link": "Edit Link",
     "edit_link": "Edit Link",

+ 4 - 4
apps/app/src/client/components/Admin/AdminHome/SystemInfomationTable.tsx

@@ -13,10 +13,10 @@ const SystemInformationTable = (props: Props) => {
   const { adminHomeContainer } = props;
   const { adminHomeContainer } = props;
 
 
   const {
   const {
-    growiVersion, nodeVersion, npmVersion, yarnVersion,
+    growiVersion, nodeVersion, npmVersion, pnpmVersion,
   } = adminHomeContainer.state;
   } = adminHomeContainer.state;
 
 
-  if (growiVersion == null || nodeVersion == null || npmVersion == null || yarnVersion == null) {
+  if (growiVersion == null || nodeVersion == null || npmVersion == null || pnpmVersion == null) {
     return <></>;
     return <></>;
   }
   }
 
 
@@ -36,8 +36,8 @@ const SystemInformationTable = (props: Props) => {
           <td>{ npmVersion }</td>
           <td>{ npmVersion }</td>
         </tr>
         </tr>
         <tr>
         <tr>
-          <th>yarn</th>
-          <td>{ yarnVersion }</td>
+          <th>pnpm</th>
+          <td>{ pnpmVersion }</td>
         </tr>
         </tr>
       </tbody>
       </tbody>
     </table>
     </table>

+ 0 - 1
apps/app/src/client/components/Admin/UserGroup/UserGroupDeleteModal.tsx

@@ -120,7 +120,6 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
       <select
       <select
         name="actionName"
         name="actionName"
         className="form-control"
         className="form-control"
-        placeholder="select"
         value={actionName ?? ''}
         value={actionName ?? ''}
         onChange={handleActionChange}
         onChange={handleActionChange}
       >
       >

+ 12 - 11
apps/app/src/client/components/Bookmarks/DragAndDropWrapper.tsx

@@ -1,8 +1,8 @@
-import React, { ReactNode } from 'react';
+import type { ReactNode } from 'react';
 
 
 import { useDrag, useDrop } from 'react-dnd';
 import { useDrag, useDrop } from 'react-dnd';
 
 
-import { DragItemDataType } from '~/interfaces/bookmark-info';
+import type { DragItemDataType } from '~/interfaces/bookmark-info';
 
 
 type DragAndDropWrapperProps = {
 type DragAndDropWrapperProps = {
   item?: Partial<DragItemDataType>
   item?: Partial<DragItemDataType>
@@ -53,20 +53,21 @@ export const DragAndDropWrapper = (props: DragAndDropWrapperProps): JSX.Element
     }),
     }),
   }));
   }));
 
 
-
-  const getRef = (c: HTMLDivElement | null) => {
+  const getCallback = (c: HTMLDivElement | null) => {
     if (useDragMode && useDropMode) {
     if (useDragMode && useDropMode) {
-      return [dragRef(c), dropRef(c)];
-    } if (useDragMode) {
-      return dragRef(c);
-    } if (useDropMode) {
-      return dropRef(c);
+      dragRef(c);
+      dropRef(c);
+    }
+    else if (useDragMode) {
+      dragRef(c);
+    }
+    else if (useDropMode) {
+      dropRef(c);
     }
     }
-    return null;
   };
   };
 
 
   return (
   return (
-    <div ref={c => getRef(c)} className={`grw-drag-drop-container ${isOver ? 'grw-accept-drop-item' : ''}`}>
+    <div ref={getCallback} className={`grw-drag-drop-container ${isOver ? 'grw-accept-drop-item' : ''}`}>
       {children}
       {children}
     </div>
     </div>
   );
   );

+ 1 - 1
apps/app/src/client/components/InfiniteScroll.tsx

@@ -27,7 +27,7 @@ const useIntersection = <E extends HTMLElement>(): [boolean, Ref<E>] => {
     }
     }
     return;
     return;
   }, [element]);
   }, [element]);
-  return [intersecting, el => el && setElement(el)];
+  return [intersecting, (el) => { if (el != null) setElement(el); }];
 };
 };
 
 
 const LoadingIndicator = (): React.ReactElement => {
 const LoadingIndicator = (): React.ReactElement => {

+ 3 - 2
apps/app/src/client/components/Me/InAppNotificationSettings.tsx

@@ -1,7 +1,6 @@
 import type { FC } from 'react';
 import type { FC } from 'react';
 import React, { useState, useEffect, useCallback } from 'react';
 import React, { useState, useEffect, useCallback } from 'react';
 
 
-import pullAllBy from 'lodash/pullAllBy';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 
 
 import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
 import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
@@ -28,7 +27,9 @@ const isCheckedRule = (ruleName: string, subscribeRules: SubscribeRule[]) => (
 
 
 const updateIsEnabled = (subscribeRules: SubscribeRule[], ruleName: string, isChecked: boolean) => {
 const updateIsEnabled = (subscribeRules: SubscribeRule[], ruleName: string, isChecked: boolean) => {
   const target = [{ name: ruleName, isEnabled: isChecked }];
   const target = [{ name: ruleName, isEnabled: isChecked }];
-  return pullAllBy(subscribeRules, target, 'name').concat(target);
+  return subscribeRules
+    .filter(rule => rule.name !== ruleName)
+    .concat(target);
 };
 };
 
 
 
 

+ 1 - 2
apps/app/src/client/components/PageComment/CommentEditor.tsx

@@ -9,7 +9,6 @@ import { CodeMirrorEditorComment } from '@growi/editor/dist/client/components/Co
 import { useCodeMirrorEditorIsolated } from '@growi/editor/dist/client/stores/codemirror-editor';
 import { useCodeMirrorEditorIsolated } from '@growi/editor/dist/client/stores/codemirror-editor';
 import { useResolvedThemeForEditor } from '@growi/editor/dist/client/stores/use-resolved-theme';
 import { useResolvedThemeForEditor } from '@growi/editor/dist/client/stores/use-resolved-theme';
 import { UserPicture } from '@growi/ui/dist/components';
 import { UserPicture } from '@growi/ui/dist/components';
-import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
 import {
 import {
@@ -209,7 +208,7 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
     });
     });
   }, [codeMirrorEditor, pageId]);
   }, [codeMirrorEditor, pageId]);
 
 
-  const cmProps = useMemo<ReactCodeMirrorProps>(() => ({
+  const cmProps = useMemo(() => ({
     onChange: async(value: string) => {
     onChange: async(value: string) => {
       const dirtyNum = await evaluateEditorDirtyMap(editorKey, value);
       const dirtyNum = await evaluateEditorDirtyMap(editorKey, value);
       mutateIsEnabledUnsavedWarning(dirtyNum > 0);
       mutateIsEnabledUnsavedWarning(dirtyNum > 0);

+ 0 - 1
apps/app/src/client/components/PageEditor/MarkdownTableDataImportForm.tsx

@@ -57,7 +57,6 @@ export const MarkdownTableDataImportForm = (props: MarkdownTableDataImportFormPr
         <select
         <select
           id="data-import-form-type-select"
           id="data-import-form-type-select"
           className="form-select"
           className="form-select"
-          placeholder="select"
           value={dataFormat}
           value={dataFormat}
           onChange={(e) => { return setDataFormat(e.target.value) }}
           onChange={(e) => { return setDataFormat(e.target.value) }}
         >
         >

+ 3 - 3
apps/app/src/client/components/PageEditor/PageEditor.tsx

@@ -6,14 +6,14 @@ import React, {
 import type EventEmitter from 'events';
 import type EventEmitter from 'events';
 import nodePath from 'path';
 import nodePath from 'path';
 
 
-import { type IPageHasId, Origin } from '@growi/core';
+import { Origin } from '@growi/core';
+import type { IPageHasId } from '@growi/core/dist/interfaces';
 import { pathUtils } from '@growi/core/dist/utils';
 import { pathUtils } from '@growi/core/dist/utils';
 import { GlobalCodeMirrorEditorKey } from '@growi/editor';
 import { GlobalCodeMirrorEditorKey } from '@growi/editor';
 import { CodeMirrorEditorMain } from '@growi/editor/dist/client/components/CodeMirrorEditorMain';
 import { CodeMirrorEditorMain } from '@growi/editor/dist/client/components/CodeMirrorEditorMain';
 import { useCodeMirrorEditorIsolated } from '@growi/editor/dist/client/stores/codemirror-editor';
 import { useCodeMirrorEditorIsolated } from '@growi/editor/dist/client/stores/codemirror-editor';
 import { useResolvedThemeForEditor } from '@growi/editor/dist/client/stores/use-resolved-theme';
 import { useResolvedThemeForEditor } from '@growi/editor/dist/client/stores/use-resolved-theme';
 import { useRect } from '@growi/ui/dist/utils';
 import { useRect } from '@growi/ui/dist/utils';
-import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
 import detectIndent from 'detect-indent';
 import detectIndent from 'detect-indent';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import { throttle, debounce } from 'throttle-debounce';
 import { throttle, debounce } from 'throttle-debounce';
@@ -267,7 +267,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   }, [codeMirrorEditor, pageId]);
   }, [codeMirrorEditor, pageId]);
 
 
 
 
-  const cmProps = useMemo<ReactCodeMirrorProps>(() => ({
+  const cmProps = useMemo(() => ({
     onChange: (value: string) => {
     onChange: (value: string) => {
       setMarkdownPreviewWithDebounce(value);
       setMarkdownPreviewWithDebounce(value);
     },
     },

+ 1 - 1
apps/app/src/client/components/PageEditor/markdown-drawio-util-for-editor.ts

@@ -1,4 +1,4 @@
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@growi/editor';
 
 
 const lineBeginPartOfDrawioRE = /^```(\s.*)drawio$/;
 const lineBeginPartOfDrawioRE = /^```(\s.*)drawio$/;
 const lineEndPartOfDrawioRE = /^```$/;
 const lineEndPartOfDrawioRE = /^```$/;

+ 1 - 1
apps/app/src/client/components/PageEditor/markdown-table-util-for-editor.ts

@@ -1,4 +1,4 @@
-import type { EditorView } from '@codemirror/view';
+import type { EditorView } from '@growi/editor';
 import { MarkdownTable } from '@growi/editor';
 import { MarkdownTable } from '@growi/editor';
 
 
 // https://regex101.com/r/7BN2fR/10
 // https://regex101.com/r/7BN2fR/10

+ 2 - 3
apps/app/src/client/components/SearchPage/SearchResultList.tsx

@@ -5,7 +5,7 @@ import React, {
 
 
 import {
 import {
   type IPageInfoForListing, type IPageWithMeta, isIPageInfoForListing,
   type IPageInfoForListing, type IPageWithMeta, isIPageInfoForListing,
-} from '@growi/core';
+} from '@growi/core/dist/interfaces';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 
 
 import type { ISelectable, ISelectableAll } from '~/client/interfaces/selectable-all';
 import type { ISelectable, ISelectableAll } from '~/client/interfaces/selectable-all';
@@ -130,8 +130,7 @@ const SearchResultListSubstance: ForwardRefRenderFunction<ISelectableAll, Props>
         return (
         return (
           <PageListItemL
           <PageListItemL
             key={page.data._id}
             key={page.data._id}
-            // eslint-disable-next-line no-return-assign
-            ref={c => itemsRef.current[i] = c}
+            ref={(c) => { itemsRef.current[i] = c }}
             page={page}
             page={page}
             isEnableActions={!isGuestUser}
             isEnableActions={!isGuestUser}
             isReadOnlyUser={!!isReadOnlyUser}
             isReadOnlyUser={!!isReadOnlyUser}

+ 3 - 3
apps/app/src/client/services/AdminHomeContainer.js

@@ -31,7 +31,7 @@ export default class AdminHomeContainer extends Container {
       growiVersion: null,
       growiVersion: null,
       nodeVersion: null,
       nodeVersion: null,
       npmVersion: null,
       npmVersion: null,
-      yarnVersion: null,
+      pnpmVersion: null,
       copyState: this.copyStateValues.DEFAULT,
       copyState: this.copyStateValues.DEFAULT,
       installedPlugins: null,
       installedPlugins: null,
       isV5Compatible: null,
       isV5Compatible: null,
@@ -64,7 +64,7 @@ export default class AdminHomeContainer extends Container {
         growiVersion: adminHomeParams.growiVersion,
         growiVersion: adminHomeParams.growiVersion,
         nodeVersion: adminHomeParams.nodeVersion,
         nodeVersion: adminHomeParams.nodeVersion,
         npmVersion: adminHomeParams.npmVersion,
         npmVersion: adminHomeParams.npmVersion,
-        yarnVersion: adminHomeParams.yarnVersion,
+        pnpmVersion: adminHomeParams.pnpmVersion,
         envVars: adminHomeParams.envVars,
         envVars: adminHomeParams.envVars,
         isV5Compatible: adminHomeParams.isV5Compatible,
         isV5Compatible: adminHomeParams.isV5Compatible,
         isMaintenanceMode: adminHomeParams.isMaintenanceMode,
         isMaintenanceMode: adminHomeParams.isMaintenanceMode,
@@ -103,7 +103,7 @@ export default class AdminHomeContainer extends Container {
 |GROWI     |${this.state.growiVersion}|
 |GROWI     |${this.state.growiVersion}|
 |node.js   |${this.state.nodeVersion}|
 |node.js   |${this.state.nodeVersion}|
 |npm       |${this.state.npmVersion}|
 |npm       |${this.state.npmVersion}|
-|yarn      |${this.state.yarnVersion}|
+|pnpm      |${this.state.pnpmVersion}|
 |Using Docker|yes/no|
 |Using Docker|yes/no|
 |Using [growi-docker-compose][growi-docker-compose]|yes/no|
 |Using [growi-docker-compose][growi-docker-compose]|yes/no|
 
 

+ 1 - 1
apps/app/src/features/callout/services/callout.ts

@@ -11,7 +11,7 @@ export const remarkPlugin: Plugin = () => {
         const data = node.data ?? (node.data = {});
         const data = node.data ?? (node.data = {});
         data.hName = 'callout';
         data.hName = 'callout';
         data.hProperties = {
         data.hProperties = {
-          name: node.name,
+          name: node.name.toLocaleLowerCase(),
         };
         };
       }
       }
     });
     });

+ 34 - 6
apps/app/src/features/openai/chat/components/AiChatModal/AiChatModal.tsx

@@ -4,6 +4,7 @@ import React, { useCallback, useEffect, useState } from 'react';
 import { useForm, Controller } from 'react-hook-form';
 import { useForm, Controller } from 'react-hook-form';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import {
 import {
+  Collapse,
   Modal, ModalBody, ModalFooter, ModalHeader,
   Modal, ModalBody, ModalFooter, ModalHeader,
 } from 'reactstrap';
 } from 'reactstrap';
 
 
@@ -48,6 +49,8 @@ const AiChatModalSubstance = (): JSX.Element => {
   const [threadId, setThreadId] = useState<string | undefined>();
   const [threadId, setThreadId] = useState<string | undefined>();
   const [messageLogs, setMessageLogs] = useState<Message[]>([]);
   const [messageLogs, setMessageLogs] = useState<Message[]>([]);
   const [generatingAnswerMessage, setGeneratingAnswerMessage] = useState<Message>();
   const [generatingAnswerMessage, setGeneratingAnswerMessage] = useState<Message>();
+  const [errorMessage, setErrorMessage] = useState<string | undefined>();
+  const [isErrorDetailCollapsed, setIsErrorDetailCollapsed] = useState<boolean>(false);
 
 
   const { data: growiCloudUri } = useGrowiCloudUri();
   const { data: growiCloudUri } = useGrowiCloudUri();
 
 
@@ -95,6 +98,7 @@ const AiChatModalSubstance = (): JSX.Element => {
 
 
     // reset form
     // reset form
     form.reset();
     form.reset();
+    setErrorMessage(undefined);
 
 
     // add an empty assistant message
     // add an empty assistant message
     const newAnswerMessage = { id: (logLength + 1).toString(), content: '' };
     const newAnswerMessage = { id: (logLength + 1).toString(), content: '' };
@@ -157,11 +161,8 @@ const AiChatModalSubstance = (): JSX.Element => {
             logger.error(error.errorMessage);
             logger.error(error.errorMessage);
             form.setError('input', { type: 'manual', message: error.message });
             form.setError('input', { type: 'manual', message: error.message });
 
 
-            if (error.code === StreamErrorCode.RATE_LIMIT_EXCEEDED) {
-              const toastErrorMessage = growiCloudUri != null
-                ? 'modal_aichat.rate_limit_exceeded_for_growi_cloud'
-                : 'modal_aichat.rate_limit_exceeded';
-              toastError(t(toastErrorMessage));
+            if (error.code === StreamErrorCode.BUDGET_EXCEEDED) {
+              setErrorMessage(growiCloudUri != null ? 'modal_aichat.budget_exceeded_for_growi_cloud' : 'modal_aichat.budget_exceeded');
             }
             }
           }
           }
         });
         });
@@ -241,7 +242,34 @@ const AiChatModalSubstance = (): JSX.Element => {
         </form>
         </form>
 
 
         {form.formState.errors.input != null && (
         {form.formState.errors.input != null && (
-          <span className="text-danger small">{form.formState.errors.input?.message}</span>
+          <div className="mt-4 bg-danger bg-opacity-10 rounded-3 p-2 w-100">
+            <div>
+              <span className="material-symbols-outlined text-danger me-2">error</span>
+              <span className="text-danger">{ errorMessage != null ? t(errorMessage) : t('modal_aichat.error_message') }</span>
+            </div>
+
+            <button
+              type="button"
+              className="btn btn-link text-secondary p-0"
+              aria-expanded={isErrorDetailCollapsed}
+              onClick={() => setIsErrorDetailCollapsed(!isErrorDetailCollapsed)}
+            >
+              <span className={`material-symbols-outlined mt-2 me-1 ${isErrorDetailCollapsed ? 'rotate-90' : ''}`}>
+                chevron_right
+              </span>
+              <span className="small">{t('modal_aichat.show_error_detail')}</span>
+            </button>
+
+            <Collapse isOpen={isErrorDetailCollapsed}>
+              <div className="ms-2">
+                <div className="">
+                  <div className="text-secondary small">
+                    {form.formState.errors.input?.message}
+                  </div>
+                </div>
+              </div>
+            </Collapse>
+          </div>
         )}
         )}
       </ModalFooter>
       </ModalFooter>
     </>
     </>

+ 1 - 1
apps/app/src/features/openai/interfaces/message-error.ts

@@ -3,7 +3,7 @@ export const MessageErrorCode = {
 } as const;
 } as const;
 
 
 export const StreamErrorCode = {
 export const StreamErrorCode = {
-  RATE_LIMIT_EXCEEDED: 'rate_limit_exceeded',
+  BUDGET_EXCEEDED: 'budget-exceeded',
 } as const;
 } as const;
 
 
 export type StreamErrorCode = typeof StreamErrorCode[keyof typeof StreamErrorCode];
 export type StreamErrorCode = typeof StreamErrorCode[keyof typeof StreamErrorCode];

+ 8 - 5
apps/app/src/features/openai/server/routes/message.ts

@@ -11,8 +11,9 @@ import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
 import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
 import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
-import { MessageErrorCode, StreamErrorCode } from '../../interfaces/message-error';
+import { MessageErrorCode, type StreamErrorCode } from '../../interfaces/message-error';
 import { openaiClient } from '../services';
 import { openaiClient } from '../services';
+import { getStreamErrorCode } from '../services/getStreamErrorCode';
 
 
 import { certifyAiService } from './middlewares/certify-ai-service';
 import { certifyAiService } from './middlewares/certify-ai-service';
 
 
@@ -80,16 +81,18 @@ export const postMessageHandlersFactory: PostMessageHandlersFactory = (crowi) =>
         res.write(`data: ${JSON.stringify(delta)}\n\n`);
         res.write(`data: ${JSON.stringify(delta)}\n\n`);
       };
       };
 
 
-      const sendError = (code: StreamErrorCode, message: string) => {
+      const sendError = (message: string, code?: StreamErrorCode) => {
         res.write(`error: ${JSON.stringify({ code, message })}\n\n`);
         res.write(`error: ${JSON.stringify({ code, message })}\n\n`);
       };
       };
 
 
       stream.on('event', (delta) => {
       stream.on('event', (delta) => {
         if (delta.event === 'thread.run.failed') {
         if (delta.event === 'thread.run.failed') {
-          if (delta.data.last_error?.code === StreamErrorCode.RATE_LIMIT_EXCEEDED) {
-            logger.error(delta.data.last_error.message);
-            sendError(StreamErrorCode.RATE_LIMIT_EXCEEDED, delta.data.last_error.message);
+          const errorMessage = delta.data.last_error?.message;
+          if (errorMessage == null) {
+            return;
           }
           }
+          logger.error(errorMessage);
+          sendError(errorMessage, getStreamErrorCode(errorMessage));
         }
         }
       });
       });
       stream.on('messageDelta', messageDeltaHandler);
       stream.on('messageDelta', messageDeltaHandler);

+ 13 - 0
apps/app/src/features/openai/server/services/getStreamErrorCode.ts

@@ -0,0 +1,13 @@
+import { StreamErrorCode } from '../../interfaces/message-error';
+
+const OpenaiStreamErrorMessageRegExp = {
+  BUDGET_EXCEEDED: /exceeded your current quota/i, // stream-error-message: "You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: https://platform.openai.com/docs/guides/error-codes/api-errors."
+} as const;
+
+export const getStreamErrorCode = (errorMessage: string): StreamErrorCode | undefined => {
+  for (const [code, regExp] of Object.entries(OpenaiStreamErrorMessageRegExp)) {
+    if (regExp.test(errorMessage)) {
+      return StreamErrorCode[code];
+    }
+  }
+};

+ 4 - 4
apps/app/src/features/templates/server/routes/apiv3/index.ts

@@ -1,7 +1,7 @@
 import path from 'path';
 import path from 'path';
 
 
 import { GrowiPluginType } from '@growi/core';
 import { GrowiPluginType } from '@growi/core';
-import { TemplateSummary } from '@growi/pluginkit/dist/v4';
+import type { TemplateSummary } from '@growi/pluginkit/dist/v4';
 import { scanAllTemplates, getMarkdown } from '@growi/pluginkit/dist/v4/server/index.cjs';
 import { scanAllTemplates, getMarkdown } from '@growi/pluginkit/dist/v4/server/index.cjs';
 import express from 'express';
 import express from 'express';
 import { param, query } from 'express-validator';
 import { param, query } from 'express-validator';
@@ -9,7 +9,7 @@ import { param, query } from 'express-validator';
 import { PLUGIN_STORING_PATH } from '~/features/growi-plugin/server/consts';
 import { PLUGIN_STORING_PATH } from '~/features/growi-plugin/server/consts';
 import { GrowiPlugin } from '~/features/growi-plugin/server/models';
 import { GrowiPlugin } from '~/features/growi-plugin/server/models';
 import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
 import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
-import { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
+import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 import { resolveFromRoot } from '~/utils/project-dir-utils';
 import { resolveFromRoot } from '~/utils/project-dir-utils';
 
 
@@ -40,7 +40,7 @@ module.exports = (crowi) => {
 
 
     // scan preset templates
     // scan preset templates
     if (presetTemplateSummaries == null) {
     if (presetTemplateSummaries == null) {
-      const presetTemplatesRoot = resolveFromRoot('../../node_modules/@growi/preset-templates');
+      const presetTemplatesRoot = resolveFromRoot('node_modules/@growi/preset-templates');
 
 
       try {
       try {
         presetTemplateSummaries = await scanAllTemplates(presetTemplatesRoot, {
         presetTemplateSummaries = await scanAllTemplates(presetTemplatesRoot, {
@@ -76,7 +76,7 @@ module.exports = (crowi) => {
       templateId, locale,
       templateId, locale,
     } = req.params;
     } = req.params;
 
 
-    const presetTemplatesRoot = resolveFromRoot('../../node_modules/@growi/preset-templates');
+    const presetTemplatesRoot = resolveFromRoot('node_modules/@growi/preset-templates');
 
 
     try {
     try {
       const markdown = await getMarkdown(presetTemplatesRoot, templateId, locale);
       const markdown = await getMarkdown(presetTemplatesRoot, templateId, locale);

+ 1 - 13
apps/app/src/pages/admin/index.page.tsx

@@ -25,10 +25,6 @@ const ForbiddenPage = dynamic(() => import('~/client/components/Admin/ForbiddenP
 
 
 
 
 type Props = CommonProps & {
 type Props = CommonProps & {
-  nodeVersion: string,
-  npmVersion: string,
-  yarnVersion: string,
-  installedPlugins: any,
   growiCloudUri: string,
   growiCloudUri: string,
   growiAppIdForGrowiCloud: number,
   growiAppIdForGrowiCloud: number,
 };
 };
@@ -64,12 +60,7 @@ const AdminHomepage: NextPage<Props> = (props) => {
         <Head>
         <Head>
           <title>{title}</title>
           <title>{title}</title>
         </Head>
         </Head>
-        <AdminHome
-          nodeVersion={props.nodeVersion}
-          npmVersion={props.npmVersion}
-          yarnVersion={props.yarnVersion}
-          installedPlugins={props.installedPlugins}
-        />
+        <AdminHome />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>
   );
   );
@@ -80,9 +71,6 @@ const injectServerConfigurations = async(context: GetServerSidePropsContext, pro
   const req: CrowiRequest = context.req as CrowiRequest;
   const req: CrowiRequest = context.req as CrowiRequest;
   const { crowi } = req;
   const { crowi } = req;
 
 
-  props.nodeVersion = crowi.runtimeVersions.versions.node ? crowi.runtimeVersions.versions.node.version.version : null;
-  props.npmVersion = crowi.runtimeVersions.versions.npm ? crowi.runtimeVersions.versions.npm.version.version : null;
-  props.yarnVersion = crowi.runtimeVersions.versions.yarn ? crowi.runtimeVersions.versions.yarn.version.version : null;
   props.growiCloudUri = await crowi.configManager.getConfig('crowi', 'app:growiCloudUri');
   props.growiCloudUri = await crowi.configManager.getConfig('crowi', 'app:growiCloudUri');
   props.growiAppIdForGrowiCloud = await crowi.configManager.getConfig('crowi', 'app:growiAppIdForCloud');
   props.growiAppIdForGrowiCloud = await crowi.configManager.getConfig('crowi', 'app:growiAppIdForCloud');
 };
 };

+ 2 - 3
apps/app/src/server/crowi/express-init.js

@@ -11,7 +11,6 @@ import registerSafeRedirectFactory from '../middlewares/safe-redirect';
 const logger = loggerFactory('growi:crowi:express-init');
 const logger = loggerFactory('growi:crowi:express-init');
 
 
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
-  const debug = require('debug')('growi:crowi:express-init');
   const express = require('express');
   const express = require('express');
   const compression = require('compression');
   const compression = require('compression');
   const helmet = require('helmet');
   const helmet = require('helmet');
@@ -85,7 +84,7 @@ module.exports = function(crowi, app) {
   const staticOption = (crowi.node_env === 'production') ? { maxAge: '30d' } : {};
   const staticOption = (crowi.node_env === 'production') ? { maxAge: '30d' } : {};
   app.use(express.static(crowi.publicDir, staticOption));
   app.use(express.static(crowi.publicDir, staticOption));
   app.use('/static/preset-themes', express.static(
   app.use('/static/preset-themes', express.static(
-    resolveFromRoot(`../../node_modules/@growi/preset-themes/${presetThemesRootPath}`),
+    resolveFromRoot(`node_modules/@growi/preset-themes/${presetThemesRootPath}`),
   ));
   ));
   app.use(PLUGIN_EXPRESS_STATIC_DIR, express.static(PLUGIN_STORING_PATH));
   app.use(PLUGIN_EXPRESS_STATIC_DIR, express.static(PLUGIN_STORING_PATH));
 
 
@@ -124,7 +123,7 @@ module.exports = function(crowi, app) {
   app.use(csrf({ ignoreMethods: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'POST', 'DELETE'], cookie: false }));
   app.use(csrf({ ignoreMethods: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'POST', 'DELETE'], cookie: false }));
 
 
   // passport
   // passport
-  debug('initialize Passport');
+  logger.debug('initialize Passport');
   app.use(passport.initialize());
   app.use(passport.initialize());
   app.use(passport.session());
   app.use(passport.session());
 
 

+ 1 - 2
apps/app/src/server/events/bookmark.js

@@ -1,6 +1,5 @@
-// var debug = require('debug')('crowi:events:page')
-const util = require('util');
 const events = require('events');
 const events = require('events');
+const util = require('util');
 
 
 function BookmarkEvent(crowi) {
 function BookmarkEvent(crowi) {
   this.crowi = crowi;
   this.crowi = crowi;

+ 10 - 7
apps/app/src/server/events/page.js

@@ -1,6 +1,9 @@
-const debug = require('debug')('growi:events:page');
-const util = require('util');
-const events = require('events');
+import events from 'events';
+import util from 'util';
+
+import loggerFactory from '~/utils/logger';
+
+const logger = loggerFactory('growi:events:page');
 
 
 function PageEvent(crowi) {
 function PageEvent(crowi) {
   this.crowi = crowi;
   this.crowi = crowi;
@@ -10,15 +13,15 @@ function PageEvent(crowi) {
 util.inherits(PageEvent, events.EventEmitter);
 util.inherits(PageEvent, events.EventEmitter);
 
 
 PageEvent.prototype.onCreate = function(page, user) {
 PageEvent.prototype.onCreate = function(page, user) {
-  debug('onCreate event fired');
+  logger.debug('onCreate event fired');
 };
 };
 PageEvent.prototype.onUpdate = function(page, user) {
 PageEvent.prototype.onUpdate = function(page, user) {
-  debug('onUpdate event fired');
+  logger.debug('onUpdate event fired');
 };
 };
 PageEvent.prototype.onCreateMany = function(pages, user) {
 PageEvent.prototype.onCreateMany = function(pages, user) {
-  debug('onCreateMany event fired');
+  logger.debug('onCreateMany event fired');
 };
 };
 PageEvent.prototype.onAddSeenUsers = function(pages, user) {
 PageEvent.prototype.onAddSeenUsers = function(pages, user) {
-  debug('onAddSeenUsers event fired');
+  logger.debug('onAddSeenUsers event fired');
 };
 };
 module.exports = PageEvent;
 module.exports = PageEvent;

+ 3 - 2
apps/app/src/server/middlewares/access-token-parser.js

@@ -1,4 +1,5 @@
 import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
+import mongoose from 'mongoose';
 
 
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
@@ -14,11 +15,11 @@ module.exports = (crowi) => {
       return next();
       return next();
     }
     }
 
 
-    const User = crowi.model('User');
+    const User = mongoose.model('User');
 
 
     logger.debug('accessToken is', accessToken);
     logger.debug('accessToken is', accessToken);
 
 
-    const user = await User.findUserByApiToken(accessToken);
+    const user = await User.findUserByApiToken(accessToken).lean();
 
 
     if (user == null) {
     if (user == null) {
       logger.debug('The access token is invalid');
       logger.debug('The access token is invalid');

+ 10 - 7
apps/app/src/server/models/bookmark.js

@@ -1,9 +1,12 @@
 /* eslint-disable no-return-await */
 /* eslint-disable no-return-await */
 
 
-const debug = require('debug')('growi:models:bookmark');
-const mongoose = require('mongoose');
-const mongoosePaginate = require('mongoose-paginate-v2');
-const uniqueValidator = require('mongoose-unique-validator');
+import mongoose from 'mongoose';
+import mongoosePaginate from 'mongoose-paginate-v2';
+import uniqueValidator from 'mongoose-unique-validator';
+
+import loggerFactory from '~/utils/logger';
+
+const logger = loggerFactory('growi:models:bookmark');
 
 
 const ObjectId = mongoose.Schema.Types.ObjectId;
 const ObjectId = mongoose.Schema.Types.ObjectId;
 
 
@@ -74,7 +77,7 @@ const factory = (crowi) => {
         // duplicate key (dummy response of new object)
         // duplicate key (dummy response of new object)
         return newBookmark;
         return newBookmark;
       }
       }
-      debug('Bookmark.save failed', err);
+      logger.debug('Bookmark.save failed', err);
       throw err;
       throw err;
     }
     }
   };
   };
@@ -93,7 +96,7 @@ const factory = (crowi) => {
       return data;
       return data;
     }
     }
     catch (err) {
     catch (err) {
-      debug('Bookmark.remove failed (removeBookmarkByPage)', err);
+      logger.debug('Bookmark.remove failed (removeBookmarkByPage)', err);
       throw err;
       throw err;
     }
     }
   };
   };
@@ -107,7 +110,7 @@ const factory = (crowi) => {
       return data;
       return data;
     }
     }
     catch (err) {
     catch (err) {
-      debug('Bookmark.findOneAndRemove failed', err);
+      logger.debug('Bookmark.findOneAndRemove failed', err);
       throw err;
       throw err;
     }
     }
   };
   };

+ 13 - 12
apps/app/src/server/models/external-account.ts

@@ -1,17 +1,18 @@
 // disable no-return-await for model functions
 // disable no-return-await for model functions
 /* eslint-disable no-return-await */
 /* eslint-disable no-return-await */
-import type { IExternalAccount, IExternalAccountHasId, IUserHasId } from '@growi/core';
-import type { Model, Document } from 'mongoose';
-import { Schema } from 'mongoose';
+import type { IUser } from '@growi/core/dist/interfaces';
+import { type IExternalAccount, type IExternalAccountHasId, type IUserHasId } from '@growi/core/dist/interfaces';
+import type { Model, Document, HydratedDocument } from 'mongoose';
+import mongoose, { Schema } from 'mongoose';
+import mongoosePaginate from 'mongoose-paginate-v2';
+import uniqueValidator from 'mongoose-unique-validator';
 
 
 import { NullUsernameToBeRegisteredError } from '~/server/models/errors';
 import { NullUsernameToBeRegisteredError } from '~/server/models/errors';
+import loggerFactory from '~/utils/logger';
 
 
 import { getOrCreateModel } from '../util/mongoose-utils';
 import { getOrCreateModel } from '../util/mongoose-utils';
 
 
-const debug = require('debug')('growi:models:external-account');
-const mongoose = require('mongoose');
-const mongoosePaginate = require('mongoose-paginate-v2');
-const uniqueValidator = require('mongoose-unique-validator');
+const logger = loggerFactory('growi:models:external-account');
 
 
 
 
 export interface ExternalAccountDocument extends IExternalAccount, Document {}
 export interface ExternalAccountDocument extends IExternalAccount, Document {}
@@ -75,7 +76,7 @@ schema.statics.findOrRegister = function(
     .then((account) => {
     .then((account) => {
     // ExternalAccount is found
     // ExternalAccount is found
       if (account != null) {
       if (account != null) {
-        debug(`ExternalAccount '${accountId}' is found `, account);
+        logger.debug(`ExternalAccount '${accountId}' is found `, account);
         return account;
         return account;
       }
       }
 
 
@@ -83,9 +84,9 @@ schema.statics.findOrRegister = function(
         throw new NullUsernameToBeRegisteredError('username_should_not_be_null');
         throw new NullUsernameToBeRegisteredError('username_should_not_be_null');
       }
       }
 
 
-      const User = mongoose.model('User');
+      const User = mongoose.model<HydratedDocument<IUser>, Model<IUser> & { createUser, STATUS_ACTIVE }>('User');
 
 
-      let promise = User.findOne({ username: usernameToBeRegistered });
+      let promise = User.findOne({ username: usernameToBeRegistered }).exec();
       if (isSameUsernameTreatedAsIdenticalUser && isSameEmailTreatedAsIdenticalUser) {
       if (isSameUsernameTreatedAsIdenticalUser && isSameEmailTreatedAsIdenticalUser) {
         promise = promise
         promise = promise
           .then((user) => {
           .then((user) => {
@@ -94,7 +95,7 @@ schema.statics.findOrRegister = function(
           });
           });
       }
       }
       else if (isSameEmailTreatedAsIdenticalUser) {
       else if (isSameEmailTreatedAsIdenticalUser) {
-        promise = User.findOne({ email: mailToBeRegistered });
+        promise = User.findOne({ email: mailToBeRegistered }).exec();
       }
       }
 
 
       return promise
       return promise
@@ -109,7 +110,7 @@ schema.statics.findOrRegister = function(
           }
           }
 
 
           // create a new User with STATUS_ACTIVE
           // create a new User with STATUS_ACTIVE
-          debug(`ExternalAccount '${accountId}' is not found, it is going to be registered.`);
+          logger.debug(`ExternalAccount '${accountId}' is not found, it is going to be registered.`);
           return User.createUser(nameToBeRegistered, usernameToBeRegistered, mailToBeRegistered, undefined, undefined, User.STATUS_ACTIVE);
           return User.createUser(nameToBeRegistered, usernameToBeRegistered, mailToBeRegistered, undefined, undefined, User.STATUS_ACTIVE);
         })
         })
         .then((newUser) => {
         .then((newUser) => {

+ 5 - 6
apps/app/src/server/models/obsolete-page.js

@@ -11,6 +11,8 @@ import loggerFactory from '~/utils/logger';
 import UserGroup from './user-group';
 import UserGroup from './user-group';
 import UserGroupRelation from './user-group-relation';
 import UserGroupRelation from './user-group-relation';
 
 
+const logger = loggerFactory('growi:models:page');
+
 
 
 // disable no-return-await for model functions
 // disable no-return-await for model functions
 /* eslint-disable no-return-await */
 /* eslint-disable no-return-await */
@@ -19,15 +21,12 @@ import UserGroupRelation from './user-group-relation';
 
 
 const nodePath = require('path');
 const nodePath = require('path');
 
 
-const debug = require('debug')('growi:models:page');
 const mongoose = require('mongoose');
 const mongoose = require('mongoose');
 const urljoin = require('url-join');
 const urljoin = require('url-join');
 
 
 const { isTopPage, isTrashPage } = pagePathUtils;
 const { isTopPage, isTrashPage } = pagePathUtils;
 const { checkTemplatePath } = templateChecker;
 const { checkTemplatePath } = templateChecker;
 
 
-const logger = loggerFactory('growi:models:page');
-
 const GRANT_PUBLIC = 1;
 const GRANT_PUBLIC = 1;
 const GRANT_RESTRICTED = 2;
 const GRANT_RESTRICTED = 2;
 const GRANT_SPECIFIED = 3;
 const GRANT_SPECIFIED = 3;
@@ -216,7 +215,7 @@ export const getPageSchema = (crowi) => {
 
 
   pageSchema.methods.seen = async function(userData) {
   pageSchema.methods.seen = async function(userData) {
     if (this.isSeenUser(userData)) {
     if (this.isSeenUser(userData)) {
-      debug('seenUsers not updated');
+      logger.debug('seenUsers not updated');
       return this;
       return this;
     }
     }
 
 
@@ -227,7 +226,7 @@ export const getPageSchema = (crowi) => {
     const added = this.seenUsers.addToSet(userData._id);
     const added = this.seenUsers.addToSet(userData._id);
     const saved = await this.save();
     const saved = await this.save();
 
 
-    debug('seenUsers updated!', added);
+    logger.debug('seenUsers updated!', added);
     pageEvent.emit('addSeenUsers', saved);
     pageEvent.emit('addSeenUsers', saved);
 
 
     return saved;
     return saved;
@@ -290,7 +289,7 @@ export const getPageSchema = (crowi) => {
       .then((count) => {
       .then((count) => {
         self.update({ _id: pageId }, { commentCount: count }, {}, (err, data) => {
         self.update({ _id: pageId }, { commentCount: count }, {}, (err, data) => {
           if (err) {
           if (err) {
-            debug('Update commentCount Error', err);
+            logger.debug('Update commentCount Error', err);
             throw err;
             throw err;
           }
           }
 
 

+ 0 - 0
apps/app/src/server/models/vo/error-v3.js → apps/app/src/server/models/openapi/error-v3.ts


+ 79 - 0
apps/app/src/server/models/openapi/page.ts

@@ -0,0 +1,79 @@
+/**
+ * @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: /
+ *          revision:
+ *            type: string
+ *            description: page revision
+ *          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
+ */

+ 39 - 0
apps/app/src/server/models/openapi/revision.ts

@@ -0,0 +1,39 @@
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      Revision:
+ *        description: Revision
+ *        type: object
+ *        properties:
+ *          _id:
+ *            type: string
+ *            description: revision ID
+ *            example: 5e0734e472560e001761fa68
+ *          __v:
+ *            type: number
+ *            description: DB record version
+ *            example: 0
+ *          author:
+ *            $ref: '#/components/schemas/User/properties/_id'
+ *          body:
+ *            type: string
+ *            description: content body
+ *            example: |
+ *              # test
+ *
+ *              test
+ *          format:
+ *            type: string
+ *            description: format
+ *            example: markdown
+ *          path:
+ *            type: string
+ *            description: path
+ *            example: /user/alice/test
+ *          createdAt:
+ *            type: string
+ *            description: date created at
+ *            example: 2010-01-01T00:00:00.000Z
+ */

+ 2 - 2
apps/app/src/server/models/revision.ts

@@ -1,9 +1,9 @@
+import { allOrigin } from '@growi/core';
 import type {
 import type {
   HasObjectId,
   HasObjectId,
   IRevision,
   IRevision,
   Origin,
   Origin,
-} from '@growi/core';
-import { allOrigin } from '@growi/core';
+} from '@growi/core/dist/interfaces';
 import type { Types } from 'mongoose';
 import type { Types } from 'mongoose';
 import {
 import {
   Schema, type Document, type Model,
   Schema, type Document, type Model,

+ 10 - 7
apps/app/src/server/models/user-group-relation.ts

@@ -1,17 +1,20 @@
 import {
 import {
-  getIdForRef, isPopulated, type IUserGroupRelation,
+  getIdForRef, isPopulated,
 } from '@growi/core';
 } from '@growi/core';
+import type { IUserGroupRelation } from '@growi/core/dist/interfaces';
 import type { Model, Document } from 'mongoose';
 import type { Model, Document } from 'mongoose';
 import mongoose, { Schema } from 'mongoose';
 import mongoose, { Schema } from 'mongoose';
+import mongoosePaginate from 'mongoose-paginate-v2';
+import uniqueValidator from 'mongoose-unique-validator';
+
+import loggerFactory from '~/utils/logger';
 
 
 import type { ObjectIdLike } from '../interfaces/mongoose-utils';
 import type { ObjectIdLike } from '../interfaces/mongoose-utils';
 import { getOrCreateModel } from '../util/mongoose-utils';
 import { getOrCreateModel } from '../util/mongoose-utils';
 
 
 import type { UserGroupDocument } from './user-group';
 import type { UserGroupDocument } from './user-group';
 
 
-const debug = require('debug')('growi:models:userGroupRelation');
-const mongoosePaginate = require('mongoose-paginate-v2');
-const uniqueValidator = require('mongoose-unique-validator');
+const logger = loggerFactory('growi:models:userGroupRelation');
 
 
 
 
 export interface UserGroupRelationDocument extends IUserGroupRelation, Document {}
 export interface UserGroupRelationDocument extends IUserGroupRelation, Document {}
@@ -87,7 +90,7 @@ schema.statics.findAllRelation = function() {
  * @memberof UserGroupRelation
  * @memberof UserGroupRelation
  */
  */
 schema.statics.findAllRelationForUserGroup = function(userGroup) {
 schema.statics.findAllRelationForUserGroup = function(userGroup) {
-  debug('findAllRelationForUserGroup is called', userGroup);
+  logger.debug('findAllRelationForUserGroup is called', userGroup);
   return this
   return this
     .find({ relatedGroup: userGroup })
     .find({ relatedGroup: userGroup })
     .populate('relatedUser')
     .populate('relatedUser')
@@ -130,7 +133,7 @@ schema.statics.findAllRelationForUserGroups = function(userGroups) {
 schema.statics.findAllGroupsForUser = async function(user): Promise<UserGroupDocument[]> {
 schema.statics.findAllGroupsForUser = async function(user): Promise<UserGroupDocument[]> {
   const userGroupRelations = await this.find({ relatedUser: user._id }).populate('relatedGroup');
   const userGroupRelations = await this.find({ relatedUser: user._id }).populate('relatedGroup');
   const userGroups = userGroupRelations.map((relation) => {
   const userGroups = userGroupRelations.map((relation) => {
-    return isPopulated(relation.relatedGroup) ? relation.relatedGroup as UserGroupDocument : null;
+    return isPopulated(relation.relatedGroup) ? relation.relatedGroup as unknown as UserGroupDocument : null;
   });
   });
   return userGroups.filter((group): group is NonNullable<UserGroupDocument> => group != null);
   return userGroups.filter((group): group is NonNullable<UserGroupDocument> => group != null);
 };
 };
@@ -203,7 +206,7 @@ schema.statics.findUserByNotRelatedGroup = function(userGroup, queryOptions) {
         $or: searthField,
         $or: searthField,
       };
       };
 
 
-      debug('findUserByNotRelatedGroup ', query);
+      logger.debug('findUserByNotRelatedGroup ', query);
       return User.find(query).exec();
       return User.find(query).exec();
     });
     });
 };
 };

+ 4 - 10
apps/app/src/server/routes/apiv3/admin-home.js

@@ -4,12 +4,6 @@ const express = require('express');
 
 
 const router = express.Router();
 const router = express.Router();
 
 
-/**
- * @swagger
- *  tags:
- *    name: adminHome
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *
@@ -27,9 +21,9 @@ const router = express.Router();
  *          npmVersion:
  *          npmVersion:
  *            type: string
  *            type: string
  *            description: version of npm
  *            description: version of npm
- *          yarnVersion:
+ *          pnpmVersion:
  *            type: string
  *            type: string
- *            description: version of yarn
+ *            description: version of pnpm
  *      InstalledPluginsParams:
  *      InstalledPluginsParams:
  *        type: object
  *        type: object
  *        properties:
  *        properties:
@@ -47,7 +41,7 @@ module.exports = (crowi) => {
    *
    *
    *    /admin-home/:
    *    /admin-home/:
    *      get:
    *      get:
-   *        tags: [AdminHome]
+   *        tags: [Admin]
    *        operationId: getAdminHome
    *        operationId: getAdminHome
    *        summary: /admin-home
    *        summary: /admin-home
    *        description: Get adminHome parameters
    *        description: Get adminHome parameters
@@ -67,7 +61,7 @@ module.exports = (crowi) => {
       growiVersion: crowi.version,
       growiVersion: crowi.version,
       nodeVersion: crowi.runtimeVersions.versions.node ? crowi.runtimeVersions.versions.node.version.version : '-',
       nodeVersion: crowi.runtimeVersions.versions.node ? crowi.runtimeVersions.versions.node.version.version : '-',
       npmVersion: crowi.runtimeVersions.versions.npm ? crowi.runtimeVersions.versions.npm.version.version : '-',
       npmVersion: crowi.runtimeVersions.versions.npm ? crowi.runtimeVersions.versions.npm.version.version : '-',
-      yarnVersion: crowi.runtimeVersions.versions.yarn ? crowi.runtimeVersions.versions.yarn.version.version : '-',
+      pnpmVersion: crowi.runtimeVersions.versions.pnpm ? crowi.runtimeVersions.versions.pnpm.version.version : '-',
       envVars: await ConfigLoader.getEnvVarsForDisplay(true),
       envVars: await ConfigLoader.getEnvVarsForDisplay(true),
       isV5Compatible: crowi.configManager.getConfig('crowi', 'app:isV5Compatible'),
       isV5Compatible: crowi.configManager.getConfig('crowi', 'app:isV5Compatible'),
       isMaintenanceMode: crowi.configManager.getConfig('crowi', 'app:isMaintenanceMode'),
       isMaintenanceMode: crowi.configManager.getConfig('crowi', 'app:isMaintenanceMode'),

+ 2 - 9
apps/app/src/server/routes/apiv3/app-settings.js

@@ -13,17 +13,10 @@ import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
 const logger = loggerFactory('growi:routes:apiv3:app-settings');
 const logger = loggerFactory('growi:routes:apiv3:app-settings');
 
 
 const { pathUtils } = require('@growi/core/dist/utils');
 const { pathUtils } = require('@growi/core/dist/utils');
-const debug = require('debug')('growi:routes:admin');
 const express = require('express');
 const express = require('express');
 
 
 const router = express.Router();
 const router = express.Router();
 
 
-/**
- * @swagger
- *  tags:
- *    name: AppSettings
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *
@@ -462,7 +455,7 @@ module.exports = (crowi) => {
     }
     }
 
 
     const smtpClient = mailService.createSMTPClient(option);
     const smtpClient = mailService.createSMTPClient(option);
-    debug('mailer setup for validate SMTP setting', smtpClient);
+    logger.debug('mailer setup for validate SMTP setting', smtpClient);
 
 
     const mailOptions = {
     const mailOptions = {
       from: fromAddress,
       from: fromAddress,
@@ -567,7 +560,7 @@ module.exports = (crowi) => {
     catch (err) {
     catch (err) {
       const msg = req.t('validation.failed_to_send_a_test_email');
       const msg = req.t('validation.failed_to_send_a_test_email');
       logger.error('Error', err);
       logger.error('Error', err);
-      debug('Error validate mail setting: ', err);
+      logger.debug('Error validate mail setting: ', err);
       return res.apiv3Err(new ErrorV3(msg, 'send-email-with-smtp-failed'));
       return res.apiv3Err(new ErrorV3(msg, 'send-email-with-smtp-failed'));
     }
     }
   });
   });

+ 1 - 8
apps/app/src/server/routes/apiv3/attachment.js

@@ -24,13 +24,6 @@ const {
 } = require('express-validator');
 } = require('express-validator');
 
 
 
 
-/**
- * @swagger
- *  tags:
- *    name: Attachment
- */
-
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *
@@ -231,7 +224,7 @@ module.exports = (crowi) => {
    *
    *
    *    /attachment:
    *    /attachment:
    *      post:
    *      post:
-   *        tags: [Attachment, CrowiCompatibles]
+   *        tags: [Attachment]
    *        operationId: addAttachment
    *        operationId: addAttachment
    *        summary: /attachment
    *        summary: /attachment
    *        description: Add attachment to the page
    *        description: Add attachment to the page

+ 0 - 6
apps/app/src/server/routes/apiv3/bookmarks.js

@@ -17,12 +17,6 @@ const { body, query, param } = require('express-validator');
 
 
 const router = express.Router();
 const router = express.Router();
 
 
-/**
- * @swagger
- *  tags:
- *    name: Bookmarks
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *

+ 0 - 6
apps/app/src/server/routes/apiv3/customize-setting.js

@@ -21,12 +21,6 @@ const logger = loggerFactory('growi:routes:apiv3:customize-setting');
 const router = express.Router();
 const router = express.Router();
 
 
 
 
-/**
- * @swagger
- *  tags:
- *    name: CustomizeSetting
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *

+ 0 - 43
apps/app/src/server/routes/apiv3/docs.js

@@ -1,43 +0,0 @@
-import loggerFactory from '~/utils/logger';
-import swaggerDefinition from '^/config/swagger-definition';
-
-const express = require('express');
-const swaggerJSDoc = require('swagger-jsdoc');
-
-const logger = loggerFactory('growi:routes:apiv3:docs'); // eslint-disable-line no-unused-vars
-
-const router = express.Router();
-
-// paths to scan
-const APIS = [
-  'src/server/routes/apiv3/**/*.js',
-  'src/server/models/**/*.js',
-];
-
-module.exports = (crowi) => {
-
-  // skip if disabled
-  if (!crowi.configManager.getConfig('crowi', 'app:publishOpenAPI')) {
-    return router;
-  }
-
-  // generate swagger spec
-  const options = {
-    swaggerDefinition,
-    apis: APIS,
-  };
-  const swaggerSpec = swaggerJSDoc(options);
-
-  // publish swagger spec
-  router.get('/swagger-spec.json', (req, res) => {
-    res.setHeader('Content-Type', 'application/json');
-    res.send(swaggerSpec);
-  });
-
-  // publish redoc
-  router.get('/', (req, res) => {
-    res.render('redoc');
-  });
-
-  return router;
-};

+ 0 - 6
apps/app/src/server/routes/apiv3/export.js

@@ -14,12 +14,6 @@ const { param } = require('express-validator');
 
 
 const router = express.Router();
 const router = express.Router();
 
 
-/**
- * @swagger
- *  tags:
- *    name: Export
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *

+ 0 - 6
apps/app/src/server/routes/apiv3/healthcheck.ts

@@ -13,12 +13,6 @@ const logger = loggerFactory('growi:routes:apiv3:healthcheck');
 
 
 const router = express.Router();
 const router = express.Router();
 
 
-/**
- * @swagger
- *  tags:
- *    name: Healthcheck
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *

+ 0 - 6
apps/app/src/server/routes/apiv3/import.js

@@ -17,12 +17,6 @@ const multer = require('multer');
 
 
 const router = express.Router();
 const router = express.Router();
 
 
-/**
- * @swagger
- *  tags:
- *    name: Import
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *

+ 6 - 3
apps/app/src/server/routes/apiv3/invited.ts

@@ -1,18 +1,21 @@
-import type { IUser } from '@growi/core';
+import type { IUser } from '@growi/core/dist/interfaces';
 import type { Request, Router } from 'express';
 import type { Request, Router } from 'express';
 import express from 'express';
 import express from 'express';
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
+import loggerFactory from '~/utils/logger';
+
 import type Crowi from '../../crowi';
 import type Crowi from '../../crowi';
 import { invitedRules, invitedValidation } from '../../middlewares/invited-form-validator';
 import { invitedRules, invitedValidation } from '../../middlewares/invited-form-validator';
 
 
 import type { ApiV3Response } from './interfaces/apiv3-response';
 import type { ApiV3Response } from './interfaces/apiv3-response';
 
 
+const logger = loggerFactory('growi:routes:login');
+
 type InvitedFormRequest = Request & { form: any, user: any };
 type InvitedFormRequest = Request & { form: any, user: any };
 
 
 module.exports = (crowi: Crowi): Router => {
 module.exports = (crowi: Crowi): Router => {
   const applicationInstalled = require('../../middlewares/application-installed')(crowi);
   const applicationInstalled = require('../../middlewares/application-installed')(crowi);
-  const debug = require('debug')('growi:routes:login');
   const router = express.Router();
   const router = express.Router();
 
 
   router.post('/', applicationInstalled, invitedRules(), invitedValidation, async(req: InvitedFormRequest, res: ApiV3Response) => {
   router.post('/', applicationInstalled, invitedRules(), invitedValidation, async(req: InvitedFormRequest, res: ApiV3Response) => {
@@ -41,7 +44,7 @@ module.exports = (crowi: Crowi): Router => {
 
 
     const creatable = await User.isRegisterableUsername(username);
     const creatable = await User.isRegisterableUsername(username);
     if (!creatable) {
     if (!creatable) {
-      debug('username', username);
+      logger.debug('username', username);
       return res.apiv3Err('message.unable_to_use_this_user', 403);
       return res.apiv3Err('message.unable_to_use_this_user', 403);
     }
     }
 
 

+ 0 - 6
apps/app/src/server/routes/apiv3/markdown-setting.js

@@ -32,12 +32,6 @@ const validator = {
 };
 };
 
 
 
 
-/**
- * @swagger
- *  tags:
- *    name: MarkDownSetting
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *

+ 1 - 7
apps/app/src/server/routes/apiv3/mongo.js

@@ -7,12 +7,6 @@ const mongoose = require('mongoose');
 
 
 const router = express.Router();
 const router = express.Router();
 
 
-/**
- * @swagger
- *  tags:
- *    name: Mongo
- */
-
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
@@ -22,7 +16,7 @@ module.exports = (crowi) => {
    *
    *
    *  /mongo/collections:
    *  /mongo/collections:
    *    get:
    *    get:
-   *      tags: [Mongo]
+   *      tags: [MongoDB]
    *      operationId: getMongoCollections
    *      operationId: getMongoCollections
    *      summary: /mongo/collections
    *      summary: /mongo/collections
    *      description: get mongodb collections names
    *      description: get mongodb collections names

+ 0 - 6
apps/app/src/server/routes/apiv3/notification-setting.js

@@ -41,12 +41,6 @@ const validator = {
   ],
   ],
 };
 };
 
 
-/**
- * @swagger
- *  tags:
- *    name: NotificationSetting
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *

+ 4 - 83
apps/app/src/server/routes/apiv3/page/index.ts

@@ -47,91 +47,12 @@ const { body, query, param } = require('express-validator');
 
 
 const router = express.Router();
 const router = express.Router();
 
 
-/**
- * @swagger
- *  tags:
- *    name: Page
- */
 
 
 /**
 /**
  * @swagger
  * @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: /
- *          revision:
- *            type: string
- *            description: page revision
- *          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
- *
+ * components:
+ *   schemas:
  *      LikeParams:
  *      LikeParams:
  *        description: LikeParams
  *        description: LikeParams
  *        type: object
  *        type: object
@@ -745,9 +666,9 @@ module.exports = (crowi) => {
   /**
   /**
   * @swagger
   * @swagger
   *
   *
-  *    /pages/export:
+  *    /page/export:
   *      get:
   *      get:
-  *        tags: [Export]
+  *        tags: [Page]
   *        description: return page's markdown
   *        description: return page's markdown
   *        responses:
   *        responses:
   *          200:
   *          200:

+ 0 - 87
apps/app/src/server/routes/apiv3/pages/index.js

@@ -27,12 +27,6 @@ const router = express.Router();
 const LIMIT_FOR_LIST = 10;
 const LIMIT_FOR_LIST = 10;
 const LIMIT_FOR_MULTIPLE_PAGE_OP = 20;
 const LIMIT_FOR_MULTIPLE_PAGE_OP = 20;
 
 
-/**
- * @swagger
- *  tags:
- *    name: Pages
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *
@@ -63,87 +57,6 @@ const LIMIT_FOR_MULTIPLE_PAGE_OP = 20;
  *            example: 3
  *            example: 3
  */
  */
 
 
-/**
- * @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: /Sandbox/Math
- *          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);

+ 11 - 17
apps/app/src/server/routes/apiv3/personal-setting.js

@@ -21,12 +21,6 @@ const passport = require('passport');
 
 
 const router = express.Router();
 const router = express.Router();
 
 
-/**
- * @swagger
- *  tags:
- *    name: PersonalSetting
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *
@@ -136,7 +130,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting:
    *    /personal-setting:
    *      get:
    *      get:
-   *        tags: [PersonalSetting]
+   *        tags: [GeneralSetting]
    *        operationId: getPersonalSetting
    *        operationId: getPersonalSetting
    *        summary: /personal-setting
    *        summary: /personal-setting
    *        description: Get personal parameters
    *        description: Get personal parameters
@@ -175,7 +169,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting/is-password-set:
    *    /personal-setting/is-password-set:
    *      get:
    *      get:
-   *        tags: [PersonalSetting]
+   *        tags: [GeneralSetting]
    *        operationId: getIsPasswordSet
    *        operationId: getIsPasswordSet
    *        summary: /personal-setting
    *        summary: /personal-setting
    *        description: Get whether a password has been set
    *        description: Get whether a password has been set
@@ -210,7 +204,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting:
    *    /personal-setting:
    *      put:
    *      put:
-   *        tags: [PersonalSetting]
+   *        tags: [GeneralSetting]
    *        operationId: updatePersonalSetting
    *        operationId: updatePersonalSetting
    *        summary: /personal-setting
    *        summary: /personal-setting
    *        description: Update personal setting
    *        description: Update personal setting
@@ -267,7 +261,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting/image-type:
    *    /personal-setting/image-type:
    *      put:
    *      put:
-   *        tags: [PersonalSetting]
+   *        tags: [GeneralSetting]
    *        operationId: putUserImageType
    *        operationId: putUserImageType
    *        summary: /personal-setting/image-type
    *        summary: /personal-setting/image-type
    *        description: Update user image type
    *        description: Update user image type
@@ -304,7 +298,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting/external-accounts:
    *    /personal-setting/external-accounts:
    *      get:
    *      get:
-   *        tags: [PersonalSetting]
+   *        tags: [GeneralSetting]
    *        operationId: getExternalAccounts
    *        operationId: getExternalAccounts
    *        summary: /personal-setting/external-accounts
    *        summary: /personal-setting/external-accounts
    *        description: Get external accounts that linked current user
    *        description: Get external accounts that linked current user
@@ -338,7 +332,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting/password:
    *    /personal-setting/password:
    *      put:
    *      put:
-   *        tags: [PersonalSetting]
+   *        tags: [GeneralSetting]
    *        operationId: putUserPassword
    *        operationId: putUserPassword
    *        summary: /personal-setting/password
    *        summary: /personal-setting/password
    *        description: Update user password
    *        description: Update user password
@@ -386,7 +380,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting/api-token:
    *    /personal-setting/api-token:
    *      put:
    *      put:
-   *        tags: [PersonalSetting]
+   *        tags: [GeneralSetting]
    *        operationId: putUserApiToken
    *        operationId: putUserApiToken
    *        summary: /personal-setting/api-token
    *        summary: /personal-setting/api-token
    *        description: Update user api token
    *        description: Update user api token
@@ -424,7 +418,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting/associate-ldap:
    *    /personal-setting/associate-ldap:
    *      put:
    *      put:
-   *        tags: [PersonalSetting]
+   *        tags: [GeneralSetting]
    *        operationId: associateLdapAccount
    *        operationId: associateLdapAccount
    *        summary: /personal-setting/associate-ldap
    *        summary: /personal-setting/associate-ldap
    *        description: associate Ldap account
    *        description: associate Ldap account
@@ -476,7 +470,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting/disassociate-ldap:
    *    /personal-setting/disassociate-ldap:
    *      put:
    *      put:
-   *        tags: [PersonalSetting]
+   *        tags: [GeneralSetting]
    *        operationId: disassociateLdapAccount
    *        operationId: disassociateLdapAccount
    *        summary: /personal-setting/disassociate-ldap
    *        summary: /personal-setting/disassociate-ldap
    *        description: disassociate Ldap account
    *        description: disassociate Ldap account
@@ -609,7 +603,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting/in-app-notification-settings:
    *    /personal-setting/in-app-notification-settings:
    *      put:
    *      put:
-   *        tags: [in-app-notification-settings]
+   *        tags: [InAppNotificationSettings]
    *        operationId: putInAppNotificationSettings
    *        operationId: putInAppNotificationSettings
    *        summary: personal-setting/in-app-notification-settings
    *        summary: personal-setting/in-app-notification-settings
    *        description: Put InAppNotificationSettings
    *        description: Put InAppNotificationSettings
@@ -653,7 +647,7 @@ module.exports = (crowi) => {
    *
    *
    *    /personal-setting/in-app-notification-settings:
    *    /personal-setting/in-app-notification-settings:
    *      get:
    *      get:
-   *        tags: [in-app-notification-settings]
+   *        tags: [InAppNotificationSettings]
    *        operationId: getInAppNotificationSettings
    *        operationId: getInAppNotificationSettings
    *        summary: personal-setting/in-app-notification-settings
    *        summary: personal-setting/in-app-notification-settings
    *        description: Get InAppNotificationSettings
    *        description: Get InAppNotificationSettings

+ 0 - 45
apps/app/src/server/routes/apiv3/revisions.js

@@ -17,51 +17,6 @@ const router = express.Router();
 
 
 const MIGRATION_FILE_NAME = '20211227060705-revision-path-to-page-id-schema-migration--fixed-7549';
 const MIGRATION_FILE_NAME = '20211227060705-revision-path-to-page-id-schema-migration--fixed-7549';
 
 
-/**
- * @swagger
- *  tags:
- *    name: Revisions
- */
-
-/**
- * @swagger
- *
- *  components:
- *    schemas:
- *      Revision:
- *        description: Revision
- *        type: object
- *        properties:
- *          _id:
- *            type: string
- *            description: revision ID
- *            example: 5e0734e472560e001761fa68
- *          __v:
- *            type: number
- *            description: DB record version
- *            example: 0
- *          author:
- *            $ref: '#/components/schemas/User/properties/_id'
- *          body:
- *            type: string
- *            description: content body
- *            example: |
- *              # test
- *
- *              test
- *          format:
- *            type: string
- *            description: format
- *            example: markdown
- *          path:
- *            type: string
- *            description: path
- *            example: /user/alice/test
- *          createdAt:
- *            type: string
- *            description: date created at
- *            example: 2010-01-01T00:00:00.000Z
- */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const certifySharedPage = require('../../middlewares/certify-shared-page')(crowi);
   const certifySharedPage = require('../../middlewares/certify-shared-page')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);

+ 3 - 8
apps/app/src/server/routes/apiv3/search.js

@@ -16,11 +16,6 @@ const router = express.Router();
 
 
 const noCache = require('nocache');
 const noCache = require('nocache');
 
 
-/**
- * @swagger
- *  tags:
- *    name: Search
- */
 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);
   const loginRequired = require('../../middlewares/login-required')(crowi);
@@ -34,7 +29,7 @@ module.exports = (crowi) => {
    *
    *
    *  /search/indices:
    *  /search/indices:
    *    get:
    *    get:
-   *      tags: [Search]
+   *      tags: [FullTextSearch Management]
    *      summary: /search/indices
    *      summary: /search/indices
    *      description: Get current status of indices
    *      description: Get current status of indices
    *      responses:
    *      responses:
@@ -68,7 +63,7 @@ module.exports = (crowi) => {
    *
    *
    *  /search/connection:
    *  /search/connection:
    *    get:
    *    get:
-   *      tags: [Search]
+   *      tags: [FullTextSearch Management]
    *      summary: /search/connection
    *      summary: /search/connection
    *      description: Reconnect to Elasticsearch
    *      description: Reconnect to Elasticsearch
    *      responses:
    *      responses:
@@ -103,7 +98,7 @@ module.exports = (crowi) => {
    *
    *
    *  /search/indices:
    *  /search/indices:
    *    put:
    *    put:
-   *      tags: [Search]
+   *      tags: [FullTextSearch Management]
    *      summary: /search/indices
    *      summary: /search/indices
    *      description: Operate indices
    *      description: Operate indices
    *      requestBody:
    *      requestBody:

+ 26 - 32
apps/app/src/server/routes/apiv3/security-settings/index.js

@@ -108,12 +108,6 @@ const validator = {
   ],
   ],
 };
 };
 
 
-/**
- * @swagger
- *  tags:
- *    name: SecuritySetting
- */
-
 
 
 /**
 /**
  * @swagger
  * @swagger
@@ -333,9 +327,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/:
+   *    /security-setting/:
    *      get:
    *      get:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Get security paramators
    *        description: Get security paramators
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -461,9 +455,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/authentication/enabled:
+   *    /security-setting/authentication/enabled:
    *      put:
    *      put:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Update authentication isEnabled
    *        description: Update authentication isEnabled
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -576,9 +570,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/authentication:
+   *    /security-setting/authentication:
    *      get:
    *      get:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Get setup strategies for passport
    *        description: Get setup strategies for passport
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -604,9 +598,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/general-setting:
+   *    /security-setting/general-setting:
    *      put:
    *      put:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Update GeneralSetting
    *        description: Update GeneralSetting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -690,9 +684,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/share-link-setting:
+   *    /security-setting/share-link-setting:
    *      put:
    *      put:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Update ShareLink Setting
    *        description: Update ShareLink Setting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -733,9 +727,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/all-share-links:
+   *    /security-setting/all-share-links:
    *      get:
    *      get:
-   *        tags: [ShareLinkSettings, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Get All ShareLinks at Share Link Setting
    *        description: Get All ShareLinks at Share Link Setting
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -776,9 +770,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/all-share-links:
+   *    /security-setting/all-share-links:
    *      delete:
    *      delete:
-   *        tags: [ShareLinkSettings, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Delete All ShareLinks at Share Link Setting
    *        description: Delete All ShareLinks at Share Link Setting
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -801,9 +795,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/local-setting:
+   *    /security-setting/local-setting:
    *      put:
    *      put:
-   *        tags: [LocalSetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Update LocalSetting
    *        description: Update LocalSetting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -853,9 +847,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/ldap:
+   *    /security-setting/ldap:
    *      put:
    *      put:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Update LDAP setting
    *        description: Update LDAP setting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -918,9 +912,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/saml:
+   *    /security-setting/saml:
    *      put:
    *      put:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Update SAML setting
    *        description: Update SAML setting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -1011,9 +1005,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/oidc:
+   *    /security-setting/oidc:
    *      put:
    *      put:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Update OpenID Connect setting
    *        description: Update OpenID Connect setting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -1088,9 +1082,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/google-oauth:
+   *    /security-setting/google-oauth:
    *      put:
    *      put:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Update google OAuth
    *        description: Update google OAuth
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -1136,9 +1130,9 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/security-setting/github-oauth:
+   *    /security-setting/github-oauth:
    *      put:
    *      put:
-   *        tags: [SecuritySetting, apiv3]
+   *        tags: [SecuritySetting]
    *        description: Update github OAuth
    *        description: Update github OAuth
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true

+ 1 - 7
apps/app/src/server/routes/apiv3/share-links.js

@@ -20,12 +20,6 @@ const validator = {};
 
 
 const today = new Date();
 const today = new Date();
 
 
-/**
- * @swagger
- *  tags:
- *    name: ShareLink
- */
-
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
@@ -212,7 +206,7 @@ module.exports = (crowi) => {
   *
   *
   *    /share-links/all:
   *    /share-links/all:
   *      delete:
   *      delete:
-  *        tags: [ShareLinks]
+  *        tags: [ShareLink Management]
   *        description: delete all share links
   *        description: delete all share links
   *        responses:
   *        responses:
   *          200:
   *          200:

+ 0 - 6
apps/app/src/server/routes/apiv3/slack-integration-legacy-settings.js

@@ -22,12 +22,6 @@ const validator = {
   ],
   ],
 };
 };
 
 
-/**
- * @swagger
- *  tags:
- *    name: SlackIntegrationLegacySetting
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *

+ 13 - 19
apps/app/src/server/routes/apiv3/slack-integration-settings.js

@@ -25,12 +25,6 @@ const logger = loggerFactory('growi:routes:apiv3:slack-integration-settings');
 const router = express.Router();
 const router = express.Router();
 
 
 
 
-/**
- * @swagger
- *  tags:
- *    name: SlackIntegrationSettings
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *
@@ -166,9 +160,9 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/:
    *    /slack-integration-settings/:
    *      get:
    *      get:
-   *        tags: [SlackBotSettingParams]
+   *        tags: [SlackIntegrationSettings]
    *        operationId: getSlackBotSettingParams
    *        operationId: getSlackBotSettingParams
-   *        summary: get /slack-integration
+   *        summary: /slack-integration
    *        description: Get current settings and connection statuses.
    *        description: Get current settings and connection statuses.
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -295,7 +289,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/bot-type/:
    *    /slack-integration-settings/bot-type/:
    *      put:
    *      put:
-   *        tags: [botType]
+   *        tags: [SlackIntegrationSettings]
    *        operationId: putBotType
    *        operationId: putBotType
    *        summary: /slack-integration/bot-type
    *        summary: /slack-integration/bot-type
    *        description: Put botType setting.
    *        description: Put botType setting.
@@ -334,7 +328,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration/bot-type/:
    *    /slack-integration/bot-type/:
    *      delete:
    *      delete:
-   *        tags: [botType]
+   *        tags: [SlackIntegrationSettings]
    *        operationId: deleteBotType
    *        operationId: deleteBotType
    *        summary: /slack-integration/bot-type
    *        summary: /slack-integration/bot-type
    *        description: Delete botType setting.
    *        description: Delete botType setting.
@@ -365,7 +359,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/without-proxy/update-settings/:
    *    /slack-integration-settings/without-proxy/update-settings/:
    *      put:
    *      put:
-   *        tags: [UpdateWithoutProxySettings]
+   *        tags: [SlackIntegrationSettings (without proxy)]
    *        operationId: putWithoutProxySettings
    *        operationId: putWithoutProxySettings
    *        summary: update customBotWithoutProxy settings
    *        summary: update customBotWithoutProxy settings
    *        description: Update customBotWithoutProxy setting.
    *        description: Update customBotWithoutProxy setting.
@@ -405,7 +399,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/without-proxy/update-permissions/:
    *    /slack-integration-settings/without-proxy/update-permissions/:
    *      put:
    *      put:
-   *        tags: [UpdateWithoutProxyPermissions]
+   *        tags: [SlackIntegrationSettings (without proxy)]
    *        operationId: putWithoutProxyPermissions
    *        operationId: putWithoutProxyPermissions
    *        summary: update customBotWithoutProxy permissions
    *        summary: update customBotWithoutProxy permissions
    *        description: Update customBotWithoutProxy permissions.
    *        description: Update customBotWithoutProxy permissions.
@@ -448,7 +442,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/slack-app-integrations:
    *    /slack-integration-settings/slack-app-integrations:
    *      post:
    *      post:
-   *        tags: [SlackIntegration]
+   *        tags: [SlackIntegrationSettings (with proxy)]
    *        operationId: putSlackAppIntegrations
    *        operationId: putSlackAppIntegrations
    *        summary: /slack-integration
    *        summary: /slack-integration
    *        description: Generate SlackAppIntegrations
    *        description: Generate SlackAppIntegrations
@@ -498,7 +492,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/slack-app-integrations/:id:
    *    /slack-integration-settings/slack-app-integrations/:id:
    *      delete:
    *      delete:
-   *        tags: [SlackIntegration]
+   *        tags: [SlackIntegrationSettings (with proxy)]
    *        operationId: deleteAccessTokens
    *        operationId: deleteAccessTokens
    *        summary: delete accessTokens
    *        summary: delete accessTokens
    *        description: Delete accessTokens
    *        description: Delete accessTokens
@@ -556,7 +550,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/slack-app-integrations/:id/makeprimary:
    *    /slack-integration-settings/slack-app-integrations/:id/makeprimary:
    *      put:
    *      put:
-   *        tags: [SlackIntegration]
+   *        tags: [SlackIntegrationSettings (with proxy)]
    *        operationId: makePrimary
    *        operationId: makePrimary
    *        summary: /slack-integration
    *        summary: /slack-integration
    *        description: Make SlackAppTokens primary
    *        description: Make SlackAppTokens primary
@@ -603,7 +597,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/slack-app-integrations/:id/regenerate-tokens:
    *    /slack-integration-settings/slack-app-integrations/:id/regenerate-tokens:
    *      put:
    *      put:
-   *        tags: [SlackIntegration]
+   *        tags: [SlackIntegrationSettings (with proxy)]
    *        operationId: putRegenerateTokens
    *        operationId: putRegenerateTokens
    *        summary: /slack-integration
    *        summary: /slack-integration
    *        description: Regenerate SlackAppTokens
    *        description: Regenerate SlackAppTokens
@@ -636,7 +630,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/slack-app-integrations/:id/permissions:
    *    /slack-integration-settings/slack-app-integrations/:id/permissions:
    *      put:
    *      put:
-   *        tags: [SlackIntegration]
+   *        tags: [SlackIntegrationSettings (with proxy)]
    *        operationId: putSupportedCommands
    *        operationId: putSupportedCommands
    *        summary: /slack-integration-settings/:id/permissions
    *        summary: /slack-integration-settings/:id/permissions
    *        description: update supported commands
    *        description: update supported commands
@@ -695,7 +689,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/slack-app-integrations/:id/relation-test:
    *    /slack-integration-settings/slack-app-integrations/:id/relation-test:
    *      post:
    *      post:
-   *        tags: [botType]
+   *        tags: [SlackIntegrationSettings (with proxy)]
    *        operationId: postRelationTest
    *        operationId: postRelationTest
    *        summary: Test relation
    *        summary: Test relation
    *        description: Delete botType setting.
    *        description: Delete botType setting.
@@ -766,7 +760,7 @@ module.exports = (crowi) => {
    *
    *
    *    /slack-integration-settings/without-proxy/test:
    *    /slack-integration-settings/without-proxy/test:
    *      post:
    *      post:
-   *        tags: [botType]
+   *        tags: [SlackIntegrationSettings (without proxy)]
    *        operationId: postTest
    *        operationId: postTest
    *        summary: test the connection
    *        summary: test the connection
    *        description: Test the connection with slack work space.
    *        description: Test the connection with slack work space.

+ 0 - 5
apps/app/src/server/routes/apiv3/statistics.js

@@ -17,11 +17,6 @@ const USER_STATUS_MASTER = {
 };
 };
 
 
 
 
-/**
- * @swagger
- *  tags:
- *    name: Statistics
- */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
 
 
   const models = crowi.models;
   const models = crowi.models;

+ 1 - 7
apps/app/src/server/routes/apiv3/user-group-relation.js

@@ -13,12 +13,6 @@ const router = express.Router();
 
 
 const validator = {};
 const validator = {};
 
 
-/**
- * @swagger
- *  tags:
- *    name: UserGroupRelation
- */
-
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
@@ -33,7 +27,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-group-relations:
    *    /user-group-relations:
    *      get:
    *      get:
-   *        tags: [UserGroupRelation]
+   *        tags: [UserGroupRelations]
    *        operationId: listUserGroupRelations
    *        operationId: listUserGroupRelations
    *        summary: /user-group-relations
    *        summary: /user-group-relations
    *        description: Gets the user group relations
    *        description: Gets the user group relations

+ 14 - 20
apps/app/src/server/routes/apiv3/user-group.js

@@ -24,12 +24,6 @@ const logger = loggerFactory('growi:routes:apiv3:user-group'); // eslint-disable
 const router = express.Router();
 const router = express.Router();
 
 
 
 
-/**
- * @swagger
- *  tags:
- *    name: UserGroup
- */
-
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
@@ -94,7 +88,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups:
    *    /user-groups:
    *      get:
    *      get:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: getUserGroup
    *        operationId: getUserGroup
    *        summary: /user-groups
    *        summary: /user-groups
    *        description: Get usergroups
    *        description: Get usergroups
@@ -137,7 +131,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /ancestors:
    *    /ancestors:
    *      get:
    *      get:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: getAncestorUserGroups
    *        operationId: getAncestorUserGroups
    *        summary: /ancestors
    *        summary: /ancestors
    *        description: Get ancestor user groups.
    *        description: Get ancestor user groups.
@@ -200,7 +194,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups:
    *    /user-groups:
    *      post:
    *      post:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: createUserGroup
    *        operationId: createUserGroup
    *        summary: /user-groups
    *        summary: /user-groups
    *        description: Adds userGroup
    *        description: Adds userGroup
@@ -250,7 +244,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /selectable-parent-groups:
    *    /selectable-parent-groups:
    *      get:
    *      get:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: getSelectableParentGroups
    *        operationId: getSelectableParentGroups
    *        summary: /selectable-parent-groups
    *        summary: /selectable-parent-groups
    *        description: Get selectable parent UserGroups
    *        description: Get selectable parent UserGroups
@@ -299,7 +293,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /selectable-child-groups:
    *    /selectable-child-groups:
    *      get:
    *      get:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: getSelectableChildGroups
    *        operationId: getSelectableChildGroups
    *        summary: /selectable-child-groups
    *        summary: /selectable-child-groups
    *        description: Get selectable child UserGroups
    *        description: Get selectable child UserGroups
@@ -351,7 +345,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups/{id}:
    *    /user-groups/{id}:
    *      get:
    *      get:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: getUserGroupFromGroupId
    *        operationId: getUserGroupFromGroupId
    *        summary: /user-groups/{id}
    *        summary: /user-groups/{id}
    *        description: Get UserGroup from Group ID
    *        description: Get UserGroup from Group ID
@@ -393,7 +387,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups/{id}:
    *    /user-groups/{id}:
    *      delete:
    *      delete:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: deleteUserGroup
    *        operationId: deleteUserGroup
    *        summary: /user-groups/{id}
    *        summary: /user-groups/{id}
    *        description: Deletes userGroup
    *        description: Deletes userGroup
@@ -457,7 +451,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups/{id}:
    *    /user-groups/{id}:
    *      put:
    *      put:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: updateUserGroups
    *        operationId: updateUserGroups
    *        summary: /user-groups/{id}
    *        summary: /user-groups/{id}
    *        description: Update userGroup
    *        description: Update userGroup
@@ -507,7 +501,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups/{id}/users:
    *    /user-groups/{id}/users:
    *      get:
    *      get:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: getUsersUserGroups
    *        operationId: getUsersUserGroups
    *        summary: /user-groups/{id}/users
    *        summary: /user-groups/{id}/users
    *        description: Get users related to the userGroup
    *        description: Get users related to the userGroup
@@ -558,7 +552,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups/{id}/unrelated-users:
    *    /user-groups/{id}/unrelated-users:
    *      get:
    *      get:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: getUnrelatedUsersUserGroups
    *        operationId: getUnrelatedUsersUserGroups
    *        summary: /user-groups/{id}/unrelated-users
    *        summary: /user-groups/{id}/unrelated-users
    *        description: Get users unrelated to the userGroup
    *        description: Get users unrelated to the userGroup
@@ -619,7 +613,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups/{id}/users:
    *    /user-groups/{id}/users:
    *      post:
    *      post:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: addUserUserGroups
    *        operationId: addUserUserGroups
    *        summary: /user-groups/{id}/users
    *        summary: /user-groups/{id}/users
    *        description: Add a user to the userGroup
    *        description: Add a user to the userGroup
@@ -686,7 +680,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups/{id}/users:
    *    /user-groups/{id}/users:
    *      delete:
    *      delete:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: deleteUsersUserGroups
    *        operationId: deleteUsersUserGroups
    *        summary: /user-groups/{id}/users
    *        summary: /user-groups/{id}/users
    *        description: remove a user from the userGroup
    *        description: remove a user from the userGroup
@@ -738,7 +732,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups/{id}/user-group-relations:
    *    /user-groups/{id}/user-group-relations:
    *      get:
    *      get:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: getUserGroupRelationsUserGroups
    *        operationId: getUserGroupRelationsUserGroups
    *        summary: /user-groups/{id}/user-group-relations
    *        summary: /user-groups/{id}/user-group-relations
    *        description: Get the user group relations for the userGroup
    *        description: Get the user group relations for the userGroup
@@ -785,7 +779,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /user-groups/{id}/pages:
    *    /user-groups/{id}/pages:
    *      get:
    *      get:
-   *        tags: [UserGroup]
+   *        tags: [UserGroups]
    *        operationId: getPagesUserGroups
    *        operationId: getPagesUserGroups
    *        summary: /user-groups/{id}/pages
    *        summary: /user-groups/{id}/pages
    *        description: Get closed pages for the userGroup
    *        description: Get closed pages for the userGroup

+ 14 - 20
apps/app/src/server/routes/apiv3/users.js

@@ -30,12 +30,6 @@ const PAGE_ITEMS = 50;
 
 
 const validator = {};
 const validator = {};
 
 
-/**
- * @swagger
- *  tags:
- *    name: Users
- */
-
 /**
 /**
  * @swagger
  * @swagger
  *
  *
@@ -408,7 +402,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/invite:
    *    /users/invite:
    *      post:
    *      post:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: inviteUser
    *        operationId: inviteUser
    *        summary: /users/invite
    *        summary: /users/invite
    *        description: Create new users and send Emails
    *        description: Create new users and send Emails
@@ -476,7 +470,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/{id}/grant-admin:
    *    /users/{id}/grant-admin:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: grantAdminUser
    *        operationId: grantAdminUser
    *        summary: /users/{id}/grant-admin
    *        summary: /users/{id}/grant-admin
    *        description: Grant user admin
    *        description: Grant user admin
@@ -523,7 +517,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/{id}/revoke-admin:
    *    /users/{id}/revoke-admin:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: revokeAdminUser
    *        operationId: revokeAdminUser
    *        summary: /users/{id}/revoke-admin
    *        summary: /users/{id}/revoke-admin
    *        description: Revoke user admin
    *        description: Revoke user admin
@@ -570,7 +564,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/{id}/grant-read-only:
    *    /users/{id}/grant-read-only:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: ReadOnly
    *        operationId: ReadOnly
    *        summary: /users/{id}/grant-read-only
    *        summary: /users/{id}/grant-read-only
    *        description: Grant user read only access
    *        description: Grant user read only access
@@ -622,7 +616,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/{id}/revoke-read-only:
    *    /users/{id}/revoke-read-only:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: revokeReadOnly
    *        operationId: revokeReadOnly
    *        summary: /users/{id}/revoke-read-only
    *        summary: /users/{id}/revoke-read-only
    *        description: Revoke user read only access
    *        description: Revoke user read only access
@@ -674,7 +668,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/{id}/activate:
    *    /users/{id}/activate:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: activateUser
    *        operationId: activateUser
    *        summary: /users/{id}/activate
    *        summary: /users/{id}/activate
    *        description: Activate user
    *        description: Activate user
@@ -728,7 +722,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/{id}/deactivate:
    *    /users/{id}/deactivate:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: deactivateUser
    *        operationId: deactivateUser
    *        summary: /users/{id}/deactivate
    *        summary: /users/{id}/deactivate
    *        description: Deactivate user
    *        description: Deactivate user
@@ -775,7 +769,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/{id}/remove:
    *    /users/{id}/remove:
    *      delete:
    *      delete:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: removeUser
    *        operationId: removeUser
    *        summary: /users/{id}/remove
    *        summary: /users/{id}/remove
    *        description: Delete user
    *        description: Delete user
@@ -835,7 +829,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/external-accounts:
    *    /users/external-accounts:
    *      get:
    *      get:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: listExternalAccountsUsers
    *        operationId: listExternalAccountsUsers
    *        summary: /users/external-accounts
    *        summary: /users/external-accounts
    *        description: Get external-account
    *        description: Get external-account
@@ -868,7 +862,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/external-accounts/{id}/remove:
    *    /users/external-accounts/{id}/remove:
    *      delete:
    *      delete:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: removeExternalAccountUser
    *        operationId: removeExternalAccountUser
    *        summary: /users/external-accounts/{id}/remove
    *        summary: /users/external-accounts/{id}/remove
    *        description: Delete ExternalAccount
    *        description: Delete ExternalAccount
@@ -911,7 +905,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/update.imageUrlCache:
    *    /users/update.imageUrlCache:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: update.imageUrlCache
    *        operationId: update.imageUrlCache
    *        summary: /users/update.imageUrlCache
    *        summary: /users/update.imageUrlCache
    *        description: update imageUrlCache
    *        description: update imageUrlCache
@@ -963,7 +957,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/reset-password:
    *    /users/reset-password:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: resetPassword
    *        operationId: resetPassword
    *        summary: /users/reset-password
    *        summary: /users/reset-password
    *        description: update imageUrlCache
    *        description: update imageUrlCache
@@ -1004,7 +998,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/reset-password-email:
    *    /users/reset-password-email:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: resetPasswordEmail
    *        operationId: resetPasswordEmail
    *        summary: /users/reset-password-email
    *        summary: /users/reset-password-email
    *        description: send new password email
    *        description: send new password email
@@ -1051,7 +1045,7 @@ module.exports = (crowi) => {
    *  paths:
    *  paths:
    *    /users/send-invitation-email:
    *    /users/send-invitation-email:
    *      put:
    *      put:
-   *        tags: [Users]
+   *        tags: [Users Management]
    *        operationId: sendInvitationEmail
    *        operationId: sendInvitationEmail
    *        summary: /users/send-invitation-email
    *        summary: /users/send-invitation-email
    *        description: send invitation email
    *        description: send invitation email

+ 4 - 3
apps/app/src/server/routes/attachment/api.js

@@ -253,9 +253,10 @@ export const routesFactory = (crowi) => {
 
 
     let attachment;
     let attachment;
     try {
     try {
-      req.user.deleteImage();
+      const user = await User.findById(req.user._id);
+      await user.deleteImage();
       attachment = await attachmentService.createAttachment(file, req.user, null, AttachmentType.PROFILE_IMAGE);
       attachment = await attachmentService.createAttachment(file, req.user, null, AttachmentType.PROFILE_IMAGE);
-      await req.user.updateImage(attachment);
+      await user.updateImage(attachment);
     }
     }
     catch (err) {
     catch (err) {
       logger.error(err);
       logger.error(err);
@@ -274,7 +275,7 @@ export const routesFactory = (crowi) => {
    *
    *
    *    /attachments.remove:
    *    /attachments.remove:
    *      post:
    *      post:
-   *        tags: [Attachments, CrowiCompatibles]
+   *        tags: [Attachments]
    *        operationId: removeAttachment
    *        operationId: removeAttachment
    *        summary: /attachments.remove
    *        summary: /attachments.remove
    *        description: Remove attachment
    *        description: Remove attachment

+ 4 - 4
apps/app/src/server/routes/comment.js

@@ -79,7 +79,7 @@ module.exports = function(crowi, app) {
    *
    *
    *    /comments.get:
    *    /comments.get:
    *      get:
    *      get:
-   *        tags: [Comments, CrowiCompatibles]
+   *        tags: [Comments]
    *        operationId: getComments
    *        operationId: getComments
    *        summary: /comments.get
    *        summary: /comments.get
    *        description: Get comments of the page of the revision
    *        description: Get comments of the page of the revision
@@ -176,7 +176,7 @@ module.exports = function(crowi, app) {
    *
    *
    *    /comments.add:
    *    /comments.add:
    *      post:
    *      post:
-   *        tags: [Comments, CrowiCompatibles]
+   *        tags: [Comments]
    *        operationId: addComment
    *        operationId: addComment
    *        summary: /comments.add
    *        summary: /comments.add
    *        description: Post comment for the page
    *        description: Post comment for the page
@@ -319,7 +319,7 @@ module.exports = function(crowi, app) {
    *
    *
    *    /comments.update:
    *    /comments.update:
    *      post:
    *      post:
-   *        tags: [Comments, CrowiCompatibles]
+   *        tags: [Comments]
    *        operationId: updateComment
    *        operationId: updateComment
    *        summary: /comments.update
    *        summary: /comments.update
    *        description: Update comment dody
    *        description: Update comment dody
@@ -422,7 +422,7 @@ module.exports = function(crowi, app) {
    *
    *
    *    /comments.remove:
    *    /comments.remove:
    *      post:
    *      post:
-   *        tags: [Comments, CrowiCompatibles]
+   *        tags: [Comments]
    *        operationId: removeComment
    *        operationId: removeComment
    *        summary: /comments.remove
    *        summary: /comments.remove
    *        description: Remove specified comment
    *        description: Remove specified comment

+ 0 - 2
apps/app/src/server/routes/index.js

@@ -57,8 +57,6 @@ module.exports = function(crowi, app) {
 
 
   const [apiV3Router, apiV3AdminRouter, apiV3AuthRouter] = require('./apiv3')(crowi, app);
   const [apiV3Router, apiV3AdminRouter, apiV3AuthRouter] = require('./apiv3')(crowi, app);
 
 
-  app.use('/api-docs', require('./apiv3/docs')(crowi, app));
-
   // Rate limiter
   // Rate limiter
   app.use(rateLimiterFactory());
   app.use(rateLimiterFactory());
 
 

+ 19 - 21
apps/app/src/server/routes/login-passport.js

@@ -1,5 +1,4 @@
 import { ErrorV3 } from '@growi/core/dist/models';
 import { ErrorV3 } from '@growi/core/dist/models';
-import next from 'next';
 
 
 import { SupportedAction } from '~/interfaces/activity';
 import { SupportedAction } from '~/interfaces/activity';
 import { ExternalAccountLoginError } from '~/models/vo/external-account-login-error';
 import { ExternalAccountLoginError } from '~/models/vo/external-account-login-error';
@@ -11,7 +10,6 @@ import { externalAccountService } from '../service/external-account';
 /* eslint-disable no-use-before-define */
 /* eslint-disable no-use-before-define */
 
 
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
-  const debug = require('debug')('growi:routes:login-passport');
   const logger = loggerFactory('growi:routes:login-passport');
   const logger = loggerFactory('growi:routes:login-passport');
   const passport = require('passport');
   const passport = require('passport');
   const passportService = crowi.passportService;
   const passportService = crowi.passportService;
@@ -58,7 +56,7 @@ module.exports = function(crowi, app) {
     user.updateLastLoginAt(new Date(), (err, userData) => {
     user.updateLastLoginAt(new Date(), (err, userData) => {
       if (err) {
       if (err) {
         logger.error(`updateLastLoginAt dumps error: ${err}`);
         logger.error(`updateLastLoginAt dumps error: ${err}`);
-        debug(`updateLastLoginAt dumps error: ${err}`);
+        logger.debug(`updateLastLoginAt dumps error: ${err}`);
       }
       }
     });
     });
 
 
@@ -164,7 +162,7 @@ module.exports = function(crowi, app) {
    */
    */
   const loginWithLdap = async(req, res, next) => {
   const loginWithLdap = async(req, res, next) => {
     if (!passportService.isLdapStrategySetup) {
     if (!passportService.isLdapStrategySetup) {
-      debug('LdapStrategy has not been set up');
+      logger.debug('LdapStrategy has not been set up');
       return next();
       return next();
     }
     }
 
 
@@ -180,7 +178,7 @@ module.exports = function(crowi, app) {
       ldapAccountInfo = await promisifiedPassportAuthentication(strategyName, req, res);
       ldapAccountInfo = await promisifiedPassportAuthentication(strategyName, req, res);
     }
     }
     catch (err) {
     catch (err) {
-      debug(err.message);
+      logger.debug(err.message);
       return next(err);
       return next(err);
     }
     }
 
 
@@ -227,7 +225,7 @@ module.exports = function(crowi, app) {
     // login
     // login
     await req.logIn(user, (err) => {
     await req.logIn(user, (err) => {
       if (err) {
       if (err) {
-        debug(err.message);
+        logger.debug(err.message);
         return next(err);
         return next(err);
       }
       }
 
 
@@ -243,7 +241,7 @@ module.exports = function(crowi, app) {
    */
    */
   const testLdapCredentials = (req, res) => {
   const testLdapCredentials = (req, res) => {
     if (!passportService.isLdapStrategySetup) {
     if (!passportService.isLdapStrategySetup) {
-      debug('LdapStrategy has not been set up');
+      logger.debug('LdapStrategy has not been set up');
       return res.json(ApiResponse.success({
       return res.json(ApiResponse.success({
         status: 'warning',
         status: 'warning',
         message: req.t('message.strategy_has_not_been_set_up', { strategy: 'LdapStrategy' }),
         message: req.t('message.strategy_has_not_been_set_up', { strategy: 'LdapStrategy' }),
@@ -299,7 +297,7 @@ module.exports = function(crowi, app) {
    */
    */
   const loginWithLocal = (req, res, next) => {
   const loginWithLocal = (req, res, next) => {
     if (!passportService.isLocalStrategySetup) {
     if (!passportService.isLocalStrategySetup) {
-      debug('LocalStrategy has not been set up');
+      logger.debug('LocalStrategy has not been set up');
       return next();
       return next();
     }
     }
 
 
@@ -308,9 +306,9 @@ module.exports = function(crowi, app) {
     }
     }
 
 
     passport.authenticate('local', (err, user, info) => {
     passport.authenticate('local', (err, user, info) => {
-      debug('--- authenticate with LocalStrategy ---');
-      debug('user', user);
-      debug('info', info);
+      logger.debug('--- authenticate with LocalStrategy ---');
+      logger.debug('user', user);
+      logger.debug('info', info);
 
 
       if (err) { // DB Error
       if (err) { // DB Error
         logger.error('Database Server Error: ', err);
         logger.error('Database Server Error: ', err);
@@ -321,7 +319,7 @@ module.exports = function(crowi, app) {
       }
       }
       req.logIn(user, (err) => {
       req.logIn(user, (err) => {
         if (err) {
         if (err) {
-          debug(err.message);
+          logger.debug(err.message);
           return next(err);
           return next(err);
         }
         }
 
 
@@ -332,7 +330,7 @@ module.exports = function(crowi, app) {
 
 
   const loginWithGoogle = function(req, res, next) {
   const loginWithGoogle = function(req, res, next) {
     if (!passportService.isGoogleStrategySetup) {
     if (!passportService.isGoogleStrategySetup) {
-      debug('GoogleStrategy has not been set up');
+      logger.debug('GoogleStrategy has not been set up');
       const error = new ExternalAccountLoginError('message.strategy_has_not_been_set_up', { strategy: 'GoogleStrategy' });
       const error = new ExternalAccountLoginError('message.strategy_has_not_been_set_up', { strategy: 'GoogleStrategy' });
       return next(error);
       return next(error);
     }
     }
@@ -394,7 +392,7 @@ module.exports = function(crowi, app) {
 
 
     // login
     // login
     req.logIn(user, async(err) => {
     req.logIn(user, async(err) => {
-      if (err) { debug(err.message); return next(new ExternalAccountLoginError(err.message)) }
+      if (err) { logger.debug(err.message); return next(new ExternalAccountLoginError(err.message)) }
 
 
       return loginSuccessHandler(req, res, user, SupportedAction.ACTION_USER_LOGIN_WITH_GOOGLE, true);
       return loginSuccessHandler(req, res, user, SupportedAction.ACTION_USER_LOGIN_WITH_GOOGLE, true);
     });
     });
@@ -402,7 +400,7 @@ module.exports = function(crowi, app) {
 
 
   const loginWithGitHub = function(req, res, next) {
   const loginWithGitHub = function(req, res, next) {
     if (!passportService.isGitHubStrategySetup) {
     if (!passportService.isGitHubStrategySetup) {
-      debug('GitHubStrategy has not been set up');
+      logger.debug('GitHubStrategy has not been set up');
       const error = new ExternalAccountLoginError('message.strategy_has_not_been_set_up', { strategy: 'GitHubStrategy' });
       const error = new ExternalAccountLoginError('message.strategy_has_not_been_set_up', { strategy: 'GitHubStrategy' });
       return next(error);
       return next(error);
     }
     }
@@ -437,7 +435,7 @@ module.exports = function(crowi, app) {
 
 
     // login
     // login
     req.logIn(user, async(err) => {
     req.logIn(user, async(err) => {
-      if (err) { debug(err.message); return next(new ExternalAccountLoginError(err.message)) }
+      if (err) { logger.debug(err.message); return next(new ExternalAccountLoginError(err.message)) }
 
 
       return loginSuccessHandler(req, res, user, SupportedAction.ACTION_USER_LOGIN_WITH_GITHUB, true);
       return loginSuccessHandler(req, res, user, SupportedAction.ACTION_USER_LOGIN_WITH_GITHUB, true);
     });
     });
@@ -445,7 +443,7 @@ module.exports = function(crowi, app) {
 
 
   const loginWithOidc = function(req, res, next) {
   const loginWithOidc = function(req, res, next) {
     if (!passportService.isOidcStrategySetup) {
     if (!passportService.isOidcStrategySetup) {
-      debug('OidcStrategy has not been set up');
+      logger.debug('OidcStrategy has not been set up');
       const error = new ExternalAccountLoginError('message.strategy_has_not_been_set_up', { strategy: 'OidcStrategy' });
       const error = new ExternalAccountLoginError('message.strategy_has_not_been_set_up', { strategy: 'OidcStrategy' });
       return next(error);
       return next(error);
     }
     }
@@ -466,7 +464,7 @@ module.exports = function(crowi, app) {
       response = await promisifiedPassportAuthentication(strategyName, req, res);
       response = await promisifiedPassportAuthentication(strategyName, req, res);
     }
     }
     catch (err) {
     catch (err) {
-      debug(err);
+      logger.debug(err);
       return next(new ExternalAccountLoginError(err.message));
       return next(new ExternalAccountLoginError(err.message));
     }
     }
 
 
@@ -476,7 +474,7 @@ module.exports = function(crowi, app) {
       name: response[attrMapName],
       name: response[attrMapName],
       email: response[attrMapMail],
       email: response[attrMapMail],
     };
     };
-    debug('mapping response to userInfo', userInfo, response, attrMapId, attrMapUserName, attrMapMail);
+    logger.debug('mapping response to userInfo', userInfo, response, attrMapId, attrMapUserName, attrMapMail);
 
 
     const externalAccount = await externalAccountService.getOrCreateUser(userInfo, providerId);
     const externalAccount = await externalAccountService.getOrCreateUser(userInfo, providerId);
     if (!externalAccount) {
     if (!externalAccount) {
@@ -486,7 +484,7 @@ module.exports = function(crowi, app) {
     // login
     // login
     const user = (await externalAccount.populate('user')).user;
     const user = (await externalAccount.populate('user')).user;
     req.logIn(user, async(err) => {
     req.logIn(user, async(err) => {
-      if (err) { debug(err.message); return next(new ExternalAccountLoginError(err.message)) }
+      if (err) { logger.debug(err.message); return next(new ExternalAccountLoginError(err.message)) }
 
 
       return loginSuccessHandler(req, res, user, SupportedAction.ACTION_USER_LOGIN_WITH_OIDC, true);
       return loginSuccessHandler(req, res, user, SupportedAction.ACTION_USER_LOGIN_WITH_OIDC, true);
     });
     });
@@ -494,7 +492,7 @@ module.exports = function(crowi, app) {
 
 
   const loginWithSaml = function(req, res, next) {
   const loginWithSaml = function(req, res, next) {
     if (!passportService.isSamlStrategySetup) {
     if (!passportService.isSamlStrategySetup) {
-      debug('SamlStrategy has not been set up');
+      logger.debug('SamlStrategy has not been set up');
       const error = new ExternalAccountLoginError('message.strategy_has_not_been_set_up', { strategy: 'SamlStrategy' });
       const error = new ExternalAccountLoginError('message.strategy_has_not_been_set_up', { strategy: 'SamlStrategy' });
       return next(error);
       return next(error);
     }
     }

+ 1 - 2
apps/app/src/server/routes/login.js

@@ -6,7 +6,6 @@ import loggerFactory from '~/utils/logger';
 // because this file is a deprecated legacy of Crowi
 // because this file is a deprecated legacy of Crowi
 
 
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
-  const debug = require('debug')('growi:routes:login');
   const logger = loggerFactory('growi:routes:login');
   const logger = loggerFactory('growi:routes:login');
   const path = require('path');
   const path = require('path');
   const User = crowi.model('User');
   const User = crowi.model('User');
@@ -161,7 +160,7 @@ module.exports = function(crowi, app) {
         }
         }
       }
       }
       if (errors.length > 0) {
       if (errors.length > 0) {
-        debug('isError user register error', errOn);
+        logger.debug('isError user register error', errOn);
         return res.apiv3Err(errors, 400);
         return res.apiv3Err(errors, 400);
       }
       }
 
 

+ 5 - 71
apps/app/src/server/routes/page.js

@@ -19,71 +19,6 @@ import UpdatePost from '../models/update-post';
  *
  *
  *  components:
  *  components:
  *    schemas:
  *    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: /
- *          revision:
- *            $ref: '#/components/schemas/Revision'
- *          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
  *
  *
  *      UpdatePost:
  *      UpdatePost:
  *        description: UpdatePost
  *        description: UpdatePost
@@ -132,7 +67,6 @@ import UpdatePost from '../models/update-post';
  * @type { (crowi: import('../crowi').default, app) => any }
  * @type { (crowi: import('../crowi').default, app) => any }
  */
  */
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
-  const debug = require('debug')('growi:routes:page');
   const logger = loggerFactory('growi:routes:page');
   const logger = loggerFactory('growi:routes:page');
 
 
   const { pagePathUtils } = require('@growi/core/dist/utils');
   const { pagePathUtils } = require('@growi/core/dist/utils');
@@ -257,7 +191,7 @@ module.exports = function(crowi, app) {
    *
    *
    *    /pages.updatePost:
    *    /pages.updatePost:
    *      get:
    *      get:
-   *        tags: [Pages, CrowiCompatibles]
+   *        tags: [Pages]
    *        operationId: getUpdatePostPage
    *        operationId: getUpdatePostPage
    *        summary: /pages.updatePost
    *        summary: /pages.updatePost
    *        description: Get UpdatePost setting list
    *        description: Get UpdatePost setting list
@@ -302,12 +236,12 @@ module.exports = function(crowi, app) {
         data = data.map((e) => {
         data = data.map((e) => {
           return e.channel;
           return e.channel;
         });
         });
-        debug('Found updatePost data', data);
+        logger.debug('Found updatePost data', data);
         const result = { updatePost: data };
         const result = { updatePost: data };
         return res.json(ApiResponse.success(result));
         return res.json(ApiResponse.success(result));
       })
       })
       .catch((err) => {
       .catch((err) => {
-        debug('Error occured while get setting', err);
+        logger.debug('Error occured while get setting', err);
         return res.json(ApiResponse.error({}));
         return res.json(ApiResponse.error({}));
       });
       });
   };
   };
@@ -355,7 +289,7 @@ module.exports = function(crowi, app) {
 
 
     const creatorId = await crowi.pageService.getCreatorIdForCanDelete(page);
     const creatorId = await crowi.pageService.getCreatorIdForCanDelete(page);
 
 
-    debug('Delete page', page._id, page.path);
+    logger.debug('Delete page', page._id, page.path);
 
 
     try {
     try {
       if (isCompletely) {
       if (isCompletely) {
@@ -408,7 +342,7 @@ module.exports = function(crowi, app) {
       return res.json(ApiResponse.error('Failed to delete page.', err.message));
       return res.json(ApiResponse.error('Failed to delete page.', err.message));
     }
     }
 
 
-    debug('Page deleted', page.path);
+    logger.debug('Page deleted', page.path);
     const result = {};
     const result = {};
     result.path = page.path;
     result.path = page.path;
     result.isRecursively = isRecursively;
     result.isRecursively = isRecursively;

+ 1 - 2
apps/app/src/server/routes/search.ts

@@ -35,7 +35,6 @@ const logger = loggerFactory('growi:routes:search');
  *
  *
  */
  */
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
-  // var debug = require('debug')('growi:routes:search')
   const ApiResponse = require('../util/apiResponse');
   const ApiResponse = require('../util/apiResponse');
   const ApiPaginate = require('../util/apiPaginate');
   const ApiPaginate = require('../util/apiPaginate');
 
 
@@ -47,7 +46,7 @@ module.exports = function(crowi, app) {
    *
    *
    *   /search:
    *   /search:
    *     get:
    *     get:
-   *       tags: [Search, CrowiCompatibles]
+   *       tags: [Search]
    *       operationId: searchPages
    *       operationId: searchPages
    *       summary: /search
    *       summary: /search
    *       description: Search pages
    *       description: Search pages

+ 7 - 8
apps/app/src/server/service/page/index.ts

@@ -2,15 +2,16 @@ import type EventEmitter from 'events';
 import pathlib from 'path';
 import pathlib from 'path';
 import { Readable, Writable } from 'stream';
 import { Readable, Writable } from 'stream';
 
 
+import {
+  PageStatus, YDocStatus, getIdForRef,
+  getIdStringForRef,
+} from '@growi/core';
+import { PageGrant } from '@growi/core/dist/interfaces';
 import type {
 import type {
   Ref, HasObjectId, IUserHasId, IUser,
   Ref, HasObjectId, IUserHasId, IUser,
   IPage, IPageInfo, IPageInfoAll, IPageInfoForEntity, IGrantedGroup, IRevisionHasId,
   IPage, IPageInfo, IPageInfoAll, IPageInfoForEntity, IGrantedGroup, IRevisionHasId,
   IDataWithMeta,
   IDataWithMeta,
-} from '@growi/core';
-import {
-  PageGrant, PageStatus, YDocStatus, getIdForRef,
-  getIdStringForRef,
-} from '@growi/core';
+} from '@growi/core/dist/interfaces';
 import {
 import {
   pagePathUtils, pathUtils,
   pagePathUtils, pathUtils,
 } from '@growi/core/dist/utils';
 } from '@growi/core/dist/utils';
@@ -76,8 +77,6 @@ import { shouldUseV4Process } from './should-use-v4-process';
 export * from './page-service';
 export * from './page-service';
 
 
 
 
-const debug = require('debug')('growi:services:page');
-
 const logger = loggerFactory('growi:services:page');
 const logger = loggerFactory('growi:services:page');
 const {
 const {
   isTrashPage, isTopPage, omitDuplicateAreaPageFromPages, getUsernameByPath,
   isTrashPage, isTopPage, omitDuplicateAreaPageFromPages, getUsernameByPath,
@@ -2378,7 +2377,7 @@ class PageService implements IPageService {
 
 
     page.status = Page.STATUS_PUBLISHED;
     page.status = Page.STATUS_PUBLISHED;
     page.lastUpdateUser = user;
     page.lastUpdateUser = user;
-    debug('Revert deleted the page', page, newPath);
+    logger.debug('Revert deleted the page', page, newPath);
     const updatedPage = await Page.findByIdAndUpdate(page._id, {
     const updatedPage = await Page.findByIdAndUpdate(page._id, {
       $set: {
       $set: {
         path: newPath, status: Page.STATUS_PUBLISHED, lastUpdateUser: user._id, deleteUser: null, deletedAt: null,
         path: newPath, status: Page.STATUS_PUBLISHED, lastUpdateUser: user._id, deleteUser: null, deletedAt: null,

Some files were not shown because too many files changed in this diff