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

Merge branch 'master' into imprv/refactor-i18n

# Conflicts:
#	src/client/js/components/Admin/AdminHome/AdminHome.jsx
#	src/client/js/components/Admin/App/AppSettingsPage.jsx
itizawa 6 лет назад
Родитель
Сommit
d09a509fc5
38 измененных файлов с 1375 добавлено и 521 удалено
  1. 3 2
      .github/workflows/build.yml
  2. 1 0
      .github/workflows/release.yml
  3. 167 160
      CHANGES.md
  4. 23 2
      config/swagger-definition.js
  5. 4 4
      package.json
  6. 8 5
      src/client/js/components/Admin/AdminHome/AdminHome.jsx
  7. 9 9
      src/client/js/components/Admin/App/AppSettingsPage.jsx
  8. 3 0
      src/client/styles/agile-admin/inverse/colors/_apply-colors-dark.scss
  9. 0 4
      src/client/styles/agile-admin/inverse/colors/blue-night.scss
  10. 0 4
      src/client/styles/agile-admin/inverse/colors/default-dark.scss
  11. 0 4
      src/client/styles/agile-admin/inverse/colors/future.scss
  12. 0 4
      src/client/styles/agile-admin/inverse/colors/halloween.scss
  13. 19 0
      src/server/models/vo/error-apiv3.js
  14. 3 1
      src/server/routes/apiv3/admin-home.js
  15. 18 18
      src/server/routes/apiv3/app-settings.js
  16. 27 27
      src/server/routes/apiv3/customize-setting.js
  17. 9 9
      src/server/routes/apiv3/export.js
  18. 87 18
      src/server/routes/apiv3/healthcheck.js
  19. 12 12
      src/server/routes/apiv3/import.js
  20. 12 12
      src/server/routes/apiv3/markdown-setting.js
  21. 3 3
      src/server/routes/apiv3/mongo.js
  22. 2 2
      src/server/routes/apiv3/response.js
  23. 3 3
      src/server/routes/apiv3/statistics.js
  24. 3 3
      src/server/routes/apiv3/user-group-relation.js
  25. 30 30
      src/server/routes/apiv3/user-group.js
  26. 27 27
      src/server/routes/apiv3/users.js
  27. 193 13
      src/server/routes/attachment.js
  28. 9 48
      src/server/routes/bookmark.js
  29. 12 12
      src/server/routes/comment.js
  30. 128 0
      src/server/routes/hackmd.js
  31. 77 0
      src/server/routes/me.js
  32. 181 27
      src/server/routes/page.js
  33. 12 12
      src/server/routes/revision.js
  34. 80 0
      src/server/routes/search.js
  35. 132 0
      src/server/routes/tag.js
  36. 50 3
      src/server/routes/user.js
  37. 27 42
      src/server/service/search-delegator/elasticsearch.js
  38. 1 1
      src/server/service/search.js

+ 3 - 2
.github/workflows/build.yml

@@ -2,8 +2,9 @@ name: Release Docker Images
 
 
 on:
 on:
   push:
   push:
-    tags:
-      - v3.*.*
+    branches:
+      - tmp/release-**
+
 
 
 jobs:
 jobs:
 
 

+ 1 - 0
.github/workflows/release.yml

@@ -41,5 +41,6 @@ jobs:
       uses: Roang-zero1/github-create-release-action@master
       uses: Roang-zero1/github-create-release-action@master
       with:
       with:
         created_tag: v${{ env.RELEASE_VERSION }}
         created_tag: v${{ env.RELEASE_VERSION }}
+        changelog_file: CHANGES.md
       env:
       env:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

+ 167 - 160
CHANGES.md

@@ -1,10 +1,17 @@
 # CHANGES
 # CHANGES
 
 
-## v3.6.4-RC
+## v3.6.5-RC
+
+* Impromvement: Add `checkMiddlewaresStrictly` query option to Healthcheck API
+
+## v3.6.4
 
 
 * Feature: Alert for stale page
 * Feature: Alert for stale page
+* Improvement: Reactify admin pages (Home)
 * Improvement: Reactify admin pages (App)
 * Improvement: Reactify admin pages (App)
 * Improvement: Accessibility for editor icons of dark themes
 * Improvement: Accessibility for editor icons of dark themes
+* Improvement: Accessibility for importing table data pane
+* Improvement: Resolve username and email when logging in with Google OAuth
 
 
 ## v3.6.3
 ## v3.6.3
 
 
@@ -16,7 +23,7 @@
     * file-loader
     * file-loader
     * mini-css-extract-plugin
     * mini-css-extract-plugin
 
 
-## 3.6.2
+## v3.6.2
 
 
 * Improvement: Reactify admin pages (Customize)
 * Improvement: Reactify admin pages (Customize)
 * Improvement: Ensure not to consider `[text|site](https://example.com]` as a row in the table
 * Improvement: Ensure not to consider `[text|site](https://example.com]` as a row in the table
@@ -26,7 +33,7 @@
 * Fix: Emoji Autocomplete window does not float correctly
 * Fix: Emoji Autocomplete window does not float correctly
     * Introduced by 3.5.0
     * Introduced by 3.5.0
 
 
-## 3.6.1
+## v3.6.1
 
 
 ### BREAKING CHANGES
 ### BREAKING CHANGES
 
 
@@ -51,19 +58,19 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
 * Support: Upgrade libs
 * Support: Upgrade libs
     * growi-commons
     * growi-commons
 
 
-## 3.6.0 (Missing number)
+## v3.6.0 (Missing number)
 
 
-## 3.5.25
+## v3.5.25
 
 
 * Improvement: Disable ESC key to close Handsontable Modal
 * Improvement: Disable ESC key to close Handsontable Modal
 * Fix: Exported data of empty collection is broken
 * Fix: Exported data of empty collection is broken
 * Fix: Some components crash after when the page with attachment has exported/imported
 * Fix: Some components crash after when the page with attachment has exported/imported
 
 
-## 3.5.24
+## v3.5.24
 
 
 * Fix: Plugins are not working on Heroku
 * Fix: Plugins are not working on Heroku
 
 
-## 3.5.23
+## v3.5.23
 
 
 * Fix: Global Notification failed to send e-mail
 * Fix: Global Notification failed to send e-mail
 * Fix: Pagination is not working for trash list
 * Fix: Pagination is not working for trash list
@@ -71,17 +78,17 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
 * Support: Upgrade libs
 * Support: Upgrade libs
     * growi-commons
     * growi-commons
 
 
-## 3.5.22
+## v3.5.22
 
 
 * Improvement: Add `FILE_UPLOAD_DISABLED` env var
 * Improvement: Add `FILE_UPLOAD_DISABLED` env var
 
 
-## 3.5.21
+## v3.5.21
 
 
 * Improvement: Cache control when retrieving attachment data
 * Improvement: Cache control when retrieving attachment data
 * Fix: Inviting user doesn't work
 * Fix: Inviting user doesn't work
     * Introduced by 3.5.20
     * Introduced by 3.5.20
 
 
-## 3.5.20
+## v3.5.20
 
 
 * Improvement: Organize MongoDB collection indexes uniqueness
 * Improvement: Organize MongoDB collection indexes uniqueness
 * Improvement: Reactify admin pages (External Account Management)
 * Improvement: Reactify admin pages (External Account Management)
@@ -96,9 +103,9 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
     * react-i18next
     * react-i18next
     * validator
     * validator
 
 
-## 3.5.19 (Missing number)
+## v3.5.19 (Missing number)
 
 
-## 3.5.18
+## v3.5.18
 
 
 * Improvement: Import GROWI Archive
 * Improvement: Import GROWI Archive
     * Process asynchronously
     * Process asynchronously
@@ -111,7 +118,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
 * Improvement: Add link to [docs.growi.org](https://docs.growi.org)
 * Improvement: Add link to [docs.growi.org](https://docs.growi.org)
 * Fix: Monospace font code is broken when printing on Mac
 * Fix: Monospace font code is broken when printing on Mac
 
 
-## 3.5.17
+## v3.5.17
 
 
 * Feature: Upload to GCS (Google Cloud Storage)
 * Feature: Upload to GCS (Google Cloud Storage)
 * Feature: Statistics API
 * Feature: Statistics API
@@ -124,21 +131,21 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
 * Fix: Config default values
 * Fix: Config default values
 * Support: REPL with `console` npm scripts
 * Support: REPL with `console` npm scripts
 
 
-## 3.5.16
+## v3.5.16
 
 
 * Fix: Full Text Search doesn't work after when building indices
 * Fix: Full Text Search doesn't work after when building indices
     * Introduced by 3.5.12
     * Introduced by 3.5.12
 
 
-## 3.5.15
+## v3.5.15
 
 
 * Feature: Import/Export Page data
 * Feature: Import/Export Page data
 * Fix: The link to Sandbox on Markdown Help Modal doesn't work
 * Fix: The link to Sandbox on Markdown Help Modal doesn't work
 * Support: Upgrade libs
 * Support: Upgrade libs
     * codemirror
     * codemirror
 
 
-## 3.5.14 (Missing number)
+## v3.5.14 (Missing number)
 
 
-## 3.5.13
+## v3.5.13
 
 
 * Feature: Re-edit comments
 * Feature: Re-edit comments
 * Support: [growi-plugin-attachment-refs](https://github.com/weseek/growi-plugin-attachment-refs)
 * Support: [growi-plugin-attachment-refs](https://github.com/weseek/growi-plugin-attachment-refs)
@@ -146,7 +153,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
     * entities
     * entities
     * markdown-it
     * markdown-it
 
 
-## 3.5.12
+## v3.5.12
 
 
 * Improvement: Use Elasticsearch Alias
 * Improvement: Use Elasticsearch Alias
 * Improvement: Connect to HTTPS PlantUML URL in default
 * Improvement: Connect to HTTPS PlantUML URL in default
@@ -155,7 +162,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
 * Support: Upgrade libs
 * Support: Upgrade libs
     * terser-webpack-plugin
     * terser-webpack-plugin
 
 
-## 3.5.11
+## v3.5.11
 
 
 * Fix: HackMD Editor shows 404 error when HackMD redirect to fqdn URI
 * Fix: HackMD Editor shows 404 error when HackMD redirect to fqdn URI
     * Introduced by 3.5.8
     * Introduced by 3.5.8
@@ -169,7 +176,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
     * webpack-cli
     * webpack-cli
     * webpack-merge
     * webpack-merge
 
 
-## 3.5.10
+## v3.5.10
 
 
 * Feature: Send Global Notification with Slack
 * Feature: Send Global Notification with Slack
 * Improvement: Show loading spinner when fetching page history data
 * Improvement: Show loading spinner when fetching page history data
@@ -180,7 +187,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
     * date-fns
     * date-fns
     * eslint-config-weseek
     * eslint-config-weseek
 
 
-## 3.5.9
+## v3.5.9
 
 
 * Fix: Editing table with Spreadsheet like GUI (Handsontable) is failed
 * Fix: Editing table with Spreadsheet like GUI (Handsontable) is failed
 * Fix: Plugins are not initialized when first launching
 * Fix: Plugins are not initialized when first launching
@@ -192,7 +199,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
     * rimraf
     * rimraf
     * style-loader
     * style-loader
 
 
-## 3.5.8
+## v3.5.8
 
 
 * Improvement: Controls when HackMD/CodiMD has unsaved draft
 * Improvement: Controls when HackMD/CodiMD has unsaved draft
 * Improvement: Show hints if HackMD/CodiMD integration is not working
 * Improvement: Show hints if HackMD/CodiMD integration is not working
@@ -200,15 +207,15 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
 * Improvement: Comment Thread Layout
 * Improvement: Comment Thread Layout
 * Improvement: Show commented date with date distance format
 * Improvement: Show commented date with date distance format
 
 
-## 3.5.7 (Missing number)
+## v3.5.7 (Missing number)
 
 
-## 3.5.6
+## v3.5.6
 
 
 * Fix: Saving new page is failed when empty string tag is set
 * Fix: Saving new page is failed when empty string tag is set
 * Fix: Link of Create template page button in New Page Modal is broken
 * Fix: Link of Create template page button in New Page Modal is broken
 * Fix: Global Notification dows not work when creating/moving/deleting/like/comment
 * Fix: Global Notification dows not work when creating/moving/deleting/like/comment
 
 
-## 3.5.5
+## v3.5.5
 
 
 * Feature: Support S3-compatible object storage (e.g. MinIO)
 * Feature: Support S3-compatible object storage (e.g. MinIO)
 * Feature: Enable/Disable ID/Password Authentication
 * Feature: Enable/Disable ID/Password Authentication
@@ -223,13 +230,13 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
     * mini-css-extract-plugin
     * mini-css-extract-plugin
     * react-hotkeys
     * react-hotkeys
 
 
-## 3.5.4
+## v3.5.4
 
 
 * Fix: List private pages wrongly
 * Fix: List private pages wrongly
 * Fix: Global Notification Trigger Path does not parse glob correctly
 * Fix: Global Notification Trigger Path does not parse glob correctly
 * Fix: Consecutive page deletion requests cause unexpected complete page deletion
 * Fix: Consecutive page deletion requests cause unexpected complete page deletion
 
 
-## 3.5.3
+## v3.5.3
 
 
 * Improvement: Calculate string width when save with Spreadsheet like GUI (Handsontable)
 * Improvement: Calculate string width when save with Spreadsheet like GUI (Handsontable)
 * Fix: Search Result Page doesn't work
 * Fix: Search Result Page doesn't work
@@ -237,7 +244,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
 * Fix: Dropdown to copy page path/URL/MarkdownLink shows under CodeMirror vscrollbar
 * Fix: Dropdown to copy page path/URL/MarkdownLink shows under CodeMirror vscrollbar
 * Fix: Link to /trash in Dropdown menu
 * Fix: Link to /trash in Dropdown menu
 
 
-## 3.5.2
+## v3.5.2
 
 
 * Feature: Remain metadata option when Move/Rename page
 * Feature: Remain metadata option when Move/Rename page
 * Improvement: Support code highlight for Swift and Kotlin
 * Improvement: Support code highlight for Swift and Kotlin
@@ -248,7 +255,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
 * Support: Upgrade libs
 * Support: Upgrade libs
     * growi-commons
     * growi-commons
 
 
-## 3.5.1
+## v3.5.1
 
 
 ### BREAKING CHANGES
 ### BREAKING CHANGES
 
 
@@ -304,9 +311,9 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/35x.html>
     * mongoose-unique-validator
     * mongoose-unique-validator
     * null-loader
     * null-loader
 
 
-## 3.5.0 (Missing number)
+## v3.5.0 (Missing number)
 
 
-## 3.4.7
+## v3.4.7
 
 
 * Improvement: Handle private pages on group deletion
 * Improvement: Handle private pages on group deletion
 * Fix: Searching with `tag:xxx` syntax doesn't work
 * Fix: Searching with `tag:xxx` syntax doesn't work
@@ -315,7 +322,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/35x.html>
 * I18n: Import data page
 * I18n: Import data page
 * I18n: Group Management page
 * I18n: Group Management page
 
 
-## 3.4.6
+## v3.4.6
 
 
 * Feature: Tags
 * Feature: Tags
 * Feature: Dropdown to copy page path/URL/MarkdownLink
 * Feature: Dropdown to copy page path/URL/MarkdownLink
@@ -333,7 +340,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/35x.html>
     * null-loader
     * null-loader
     * react-codemirror
     * react-codemirror
 
 
-## 3.4.5
+## v3.4.5
 
 
 * Improvement: Pass autolink through the XSS filter according to CommonMark Spec
 * Improvement: Pass autolink through the XSS filter according to CommonMark Spec
 * Fix: Update ElasticSearch index when deleting/duplicating pages
 * Fix: Update ElasticSearch index when deleting/duplicating pages
@@ -343,11 +350,11 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/35x.html>
     * growi-commons
     * growi-commons
     * xss
     * xss
 
 
-## 3.4.4
+## v3.4.4
 
 
 * Fix: Comment component doesn't work
 * Fix: Comment component doesn't work
 
 
-## 3.4.3
+## v3.4.3
 
 
 * Improvement: Add 'antarctic' theme
 * Improvement: Add 'antarctic' theme
 * Support Apply eslint-config-airbnb based rules
 * Support Apply eslint-config-airbnb based rules
@@ -366,16 +373,16 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/35x.html>
     * react-i18next
     * react-i18next
     * string-width
     * string-width
 
 
-## 3.4.2
+## v3.4.2
 
 
 * Fix: Nofitication to Slack doesn't work
 * Fix: Nofitication to Slack doesn't work
     * Introduced by 3.4.0
     * Introduced by 3.4.0
 
 
-## 3.4.1
+## v3.4.1
 
 
 * Fix: "Cannot find module 'stream-to-promise'" occured when build client with `FILE_UPLOAD=local`
 * Fix: "Cannot find module 'stream-to-promise'" occured when build client with `FILE_UPLOAD=local`
 
 
-## 3.4.0
+## v3.4.0
 
 
 ### BREAKING CHANGES
 ### BREAKING CHANGES
 
 
@@ -404,7 +411,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * react-dom
     * react-dom
 
 
 
 
-## 3.3.10
+## v3.3.10
 
 
 * Feature: PlantUML and Blockdiag on presentation
 * Feature: PlantUML and Blockdiag on presentation
 * Improvement: Render slides of presentation with GrowiRenderer
 * Improvement: Render slides of presentation with GrowiRenderer
@@ -423,7 +430,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * webpack-cli
     * webpack-cli
     * webpack-merge
     * webpack-merge
 
 
-## 3.3.9
+## v3.3.9
 
 
 * Fix: Import from Qiita:Team doesn't work
 * Fix: Import from Qiita:Team doesn't work
     * Introduced by 3.3.0
     * Introduced by 3.3.0
@@ -432,7 +439,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Support: Upgrade libs
 * Support: Upgrade libs
     * react-bootstrap-typeahead
     * react-bootstrap-typeahead
 
 
-## 3.3.8
+## v3.3.8
 
 
 * Fix: Move/Duplicate don't work
 * Fix: Move/Duplicate don't work
     * Introduced by 3.3.7
     * Introduced by 3.3.7
@@ -441,7 +448,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * react
     * react
     * react-bootstrap-typeahead
     * react-bootstrap-typeahead
 
 
-## 3.3.7
+## v3.3.7
 
 
 * Feature: Editor toolbar
 * Feature: Editor toolbar
 * Feature: `prefix:/path` searching syntax to filter with page path prefix
 * Feature: `prefix:/path` searching syntax to filter with page path prefix
@@ -454,7 +461,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Support: Upgrade libs
 * Support: Upgrade libs
     * node-sass
     * node-sass
 
 
-## 3.3.6
+## v3.3.6
 
 
 * Improvement: Site URL settings must be set
 * Improvement: Site URL settings must be set
 * Improvement: Site URL settings can be set with environment variable
 * Improvement: Site URL settings can be set with environment variable
@@ -476,9 +483,9 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * sinon
     * sinon
     * sinon-chai
     * sinon-chai
 
 
-## 3.3.5 (Missing number)
+## v3.3.5 (Missing number)
 
 
-## 3.3.4
+## v3.3.4
 
 
 * Improvement: SAML configuration with environment variables
 * Improvement: SAML configuration with environment variables
 * Improvement: Upload file with pasting from clipboard
 * Improvement: Upload file with pasting from clipboard
@@ -487,7 +494,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Fix: Connecting to MongoDB failed when processing migration
 * Fix: Connecting to MongoDB failed when processing migration
 * Support: Get ready to use new config management system
 * Support: Get ready to use new config management system
 
 
-## 3.3.3
+## v3.3.3
 
 
 * Feature: Show line numbers to a code block
 * Feature: Show line numbers to a code block
 * Feature: Bulk update the scope of descendant pages when create/update page
 * Feature: Bulk update the scope of descendant pages when create/update page
@@ -502,12 +509,12 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * migrate-mongo
     * migrate-mongo
     * string-width
     * string-width
 
 
-## 3.3.2
+## v3.3.2
 
 
 * Fix: Specified Group ACL is not persisted correctly
 * Fix: Specified Group ACL is not persisted correctly
     * Introduced by 3.3.0
     * Introduced by 3.3.0
 
 
-## 3.3.1
+## v3.3.1
 
 
 * Feature: NO_CDN Mode
 * Feature: NO_CDN Mode
 * Feature: Add option to show/hide restricted pages in list
 * Feature: Add option to show/hide restricted pages in list
@@ -522,9 +529,9 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * googleapis
     * googleapis
     * passport-saml
     * passport-saml
 
 
-## 3.3.0 (Missing number)
+## v3.3.0 (Missing number)
 
 
-## 3.2.10
+## v3.2.10
 
 
 * Fix: Pages in trash are available to create
 * Fix: Pages in trash are available to create
 * Fix: Couldn't create portal page under Crowi Classic Behavior
 * Fix: Couldn't create portal page under Crowi Classic Behavior
@@ -532,7 +539,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * I18n: Installer
 * I18n: Installer
 
 
 
 
-## 3.2.9
+## v3.2.9
 
 
 * Feature: Attachment Storing to MongoDB GridFS
 * Feature: Attachment Storing to MongoDB GridFS
 * Fix: row/col moving of Spreadsheet like GUI (Handsontable) doesn't work
 * Fix: row/col moving of Spreadsheet like GUI (Handsontable) doesn't work
@@ -541,7 +548,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * codemirror
     * codemirror
     * react-codemirror2
     * react-codemirror2
 
 
-## 3.2.8
+## v3.2.8
 
 
 * Improvement: Add an option to use email for account link when using SAML federation
 * Improvement: Add an option to use email for account link when using SAML federation
 * Fix: Editor layout is sometimes broken
 * Fix: Editor layout is sometimes broken
@@ -551,14 +558,14 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * googleapis
     * googleapis
     * react-dropzone
     * react-dropzone
 
 
-## 3.2.7
+## v3.2.7
 
 
 * Feature: Import CSV/TSV/HTML table on Spreadsheet like GUI (Handsontable)
 * Feature: Import CSV/TSV/HTML table on Spreadsheet like GUI (Handsontable)
 * Fix: Pasting table data copied from Excel includes unnecessary line breaks
 * Fix: Pasting table data copied from Excel includes unnecessary line breaks
 * Fix: Page break Preset 1 for Presentation mode is broken
 * Fix: Page break Preset 1 for Presentation mode is broken
 * Fix: Login Form when LDAP login failed caused 500 Internal Server Error
 * Fix: Login Form when LDAP login failed caused 500 Internal Server Error
 
 
-## 3.2.6
+## v3.2.6
 
 
 * Feature: Add select alignment buttons of Spreadsheet like GUI (Handsontable)
 * Feature: Add select alignment buttons of Spreadsheet like GUI (Handsontable)
 * Improvement: Shrink the rows that have no diff of revision history page
 * Improvement: Shrink the rows that have no diff of revision history page
@@ -570,7 +577,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * i18next-node-fs-backend
     * i18next-node-fs-backend
     * i18next-sprintf-postprocessor
     * i18next-sprintf-postprocessor
 
 
-## 3.2.5
+## v3.2.5
 
 
 * Improvement: Expandable Spreadsheet like GUI (Handsontable)
 * Improvement: Expandable Spreadsheet like GUI (Handsontable)
 * Improvement: Move/Resize rows/columns of Spreadsheet like GUI (Handsontable)
 * Improvement: Move/Resize rows/columns of Spreadsheet like GUI (Handsontable)
@@ -583,7 +590,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * metismenu
     * metismenu
     * sinon
     * sinon
 
 
-## 3.2.4
+## v3.2.4
 
 
 * Feature: Edit table with Spreadsheet like GUI (Handsontable)
 * Feature: Edit table with Spreadsheet like GUI (Handsontable)
 * Feature: Paging recent created in users home
 * Feature: Paging recent created in users home
@@ -602,13 +609,13 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * mongoose-unique-validator
     * mongoose-unique-validator
     * multer
     * multer
 
 
-## 3.2.3
+## v3.2.3
 
 
 * Feature: Kibela like layout
 * Feature: Kibela like layout
 * Improvement: Custom newpage separator for presentation view
 * Improvement: Custom newpage separator for presentation view
 * Support: Shrink image size for themes which recently added
 * Support: Shrink image size for themes which recently added
 
 
-## 3.2.2
+## v3.2.2
 
 
 * Feature: SAML Authentication (SSO)
 * Feature: SAML Authentication (SSO)
 * Improvement: Add 'wood' theme
 * Improvement: Add 'wood' theme
@@ -618,7 +625,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Support Upgrade libs
 * Support Upgrade libs
     * style-loader
     * style-loader
 
 
-## 3.2.1
+## v3.2.1
 
 
 * Feature: Import data from esa.io
 * Feature: Import data from esa.io
 * Feature: Import data from Qiita:Team
 * Feature: Import data from Qiita:Team
@@ -633,20 +640,20 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * sass-loader
     * sass-loader
     * style-loader
     * style-loader
 
 
-## 3.2.0
+## v3.2.0
 
 
 * Feature: HackMD integration so that user will be able to simultaneously edit with multiple people
 * Feature: HackMD integration so that user will be able to simultaneously edit with multiple people
 * Feature: Login with Twitter Account (OAuth)
 * Feature: Login with Twitter Account (OAuth)
 * Fix: The Initial scroll position is wrong when reloading the page
 * Fix: The Initial scroll position is wrong when reloading the page
 
 
-## 3.1.14
+## v3.1.14
 
 
 * Improvement: Show help for header search box
 * Improvement: Show help for header search box
 * Improvement: Add Markdown Cheatsheet to Editor component
 * Improvement: Add Markdown Cheatsheet to Editor component
 * Fix: Couldn't delete page completely from search result page
 * Fix: Couldn't delete page completely from search result page
 * Fix: Tabs of trash page are broken
 * Fix: Tabs of trash page are broken
 
 
-## 3.1.13
+## v3.1.13
 
 
 * Feature: Global Notification
 * Feature: Global Notification
 * Feature: Send Global Notification with E-mail
 * Feature: Send Global Notification with E-mail
@@ -661,7 +668,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * react-dom
     * react-dom
 
 
 
 
-## 3.1.12
+## v3.1.12
 
 
 * Feature: Add XSS Settings
 * Feature: Add XSS Settings
 * Feature: Notify to Slack when comment
 * Feature: Notify to Slack when comment
@@ -673,19 +680,19 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Fix: Invitation mail do not be sent
 * Fix: Invitation mail do not be sent
 * Fix: Edit template button on New Page modal doesn't work
 * Fix: Edit template button on New Page modal doesn't work
 
 
-## 3.1.11
+## v3.1.11
 
 
 * Fix: OAuth doesn't work in production because callback URL field cannot be specified
 * Fix: OAuth doesn't work in production because callback URL field cannot be specified
     * Introduced by 3.1.9
     * Introduced by 3.1.9
 
 
-## 3.1.10
+## v3.1.10
 
 
 * Fix: Enter key on react-bootstrap-typeahead doesn't submit
 * Fix: Enter key on react-bootstrap-typeahead doesn't submit
     * Introduced by 3.1.9
     * Introduced by 3.1.9
 * Fix: CodeMirror of `/admin/customize` is broken
 * Fix: CodeMirror of `/admin/customize` is broken
     * Introduced by 3.1.9
     * Introduced by 3.1.9
 
 
-## 3.1.9
+## v3.1.9
 
 
 * Feature: Login with Google Account (OAuth)
 * Feature: Login with Google Account (OAuth)
 * Feature: Login with GitHub Account (OAuth)
 * Feature: Login with GitHub Account (OAuth)
@@ -701,9 +708,9 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * react-codemirror2
     * react-codemirror2
     * webpack
     * webpack
 
 
-## 3.1.8 (Missing number)
+## v3.1.8 (Missing number)
 
 
-## 3.1.7
+## v3.1.7
 
 
 * Fix: Update hidden input 'pageForm[grant]' when save with `Ctrl-S`
 * Fix: Update hidden input 'pageForm[grant]' when save with `Ctrl-S`
 * Fix: Show alert message when conflict
 * Fix: Show alert message when conflict
@@ -714,7 +721,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * sinon
     * sinon
     * sinon-chai
     * sinon-chai
 
 
-## 3.1.6
+## v3.1.6
 
 
 * Feature: Support [blockdiag](http://blockdiag.com)
 * Feature: Support [blockdiag](http://blockdiag.com)
 * Feature: Add `BLOCKDIAG_URI` environment variable
 * Feature: Add `BLOCKDIAG_URI` environment variable
@@ -723,7 +730,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * googleapis
     * googleapis
     * throttle-debounce
     * throttle-debounce
 
 
-## 3.1.5
+## v3.1.5
 
 
 * Feature: Write comment with Markdown
 * Feature: Write comment with Markdown
 * Improvement: Support some placeholders for template page
 * Improvement: Support some placeholders for template page
@@ -743,13 +750,13 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * markdown-it-toc-and-anchor-with-slugid
     * markdown-it-toc-and-anchor-with-slugid
 
 
 
 
-## 3.1.4 (Missing number)
+## v3.1.4 (Missing number)
 
 
 
 
-## 3.1.3 (Missing number)
+## v3.1.3 (Missing number)
 
 
 
 
-## 3.1.2
+## v3.1.2
 
 
 * Feature: Template page
 * Feature: Template page
 * Improvement: Add 'future' theme
 * Improvement: Add 'future' theme
@@ -777,14 +784,14 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * react-clipboard.js
     * react-clipboard.js
     * xss
     * xss
 
 
-## 3.1.1
+## v3.1.1
 
 
 * Improvement: Add 'blue-night' theme
 * Improvement: Add 'blue-night' theme
 * Improvement: List up pages which restricted for Group ACL
 * Improvement: List up pages which restricted for Group ACL
 * Fix: PageGroupRelation didn't remove when page is removed completely
 * Fix: PageGroupRelation didn't remove when page is removed completely
 
 
 
 
-## 3.1.0
+## v3.1.0
 
 
 * Improvement: Group Access Control List - Select group modal
 * Improvement: Group Access Control List - Select group modal
 * Improvement: Better input on mobile
 * Improvement: Better input on mobile
@@ -804,7 +811,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * elasticsearch
     * elasticsearch
     * googleapis
     * googleapis
 
 
-## 3.0.13
+## v3.0.13
 
 
 * Improvement: Add Vim/Emacs/Sublime-Text icons for keybindings menu
 * Improvement: Add Vim/Emacs/Sublime-Text icons for keybindings menu
 * Improvement: Add 'mono-blue' theme
 * Improvement: Add 'mono-blue' theme
@@ -817,14 +824,14 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * upgrade 'markdown-it-toc-and-anchor-with-slugid' and omit 'uslug'
     * upgrade 'markdown-it-toc-and-anchor-with-slugid' and omit 'uslug'
 * Support: Optimize .eslintrc.js
 * Support: Optimize .eslintrc.js
 
 
-## 3.0.12
+## v3.0.12
 
 
 * Feature: Support Vim/Emacs/Sublime-Text keybindings
 * Feature: Support Vim/Emacs/Sublime-Text keybindings
 * Improvement: Add some CodeMirror themes (Eclipse, Dracula)
 * Improvement: Add some CodeMirror themes (Eclipse, Dracula)
 * Improvement: Dynamic loading for CodeMirror theme files from CDN
 * Improvement: Dynamic loading for CodeMirror theme files from CDN
 * Improvement: Prevent XSS when move/redirect/duplicate
 * Improvement: Prevent XSS when move/redirect/duplicate
 
 
-## 3.0.11
+## v3.0.11
 
 
 * Fix: login.html is broken in iOS
 * Fix: login.html is broken in iOS
 * Fix: Removing attachment is crashed
 * Fix: Removing attachment is crashed
@@ -835,14 +842,14 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * googleapis
     * googleapis
     * sinon
     * sinon
 
 
-## 3.0.10
+## v3.0.10
 
 
 * Improvement: Add 'nature' theme
 * Improvement: Add 'nature' theme
 * Fix: Page list and Timeline layout for layout-growi
 * Fix: Page list and Timeline layout for layout-growi
 * Fix: Adjust theme colors
 * Fix: Adjust theme colors
     * Introduced by 3.0.9
     * Introduced by 3.0.9
 
 
-## 3.0.9
+## v3.0.9
 
 
 * Fix: Registering new LDAP User is failed
 * Fix: Registering new LDAP User is failed
     * Introduced by 3.0.6
     * Introduced by 3.0.6
@@ -853,13 +860,13 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * normalize-path
     * normalize-path
     * style-loader
     * style-loader
 
 
-## 3.0.8
+## v3.0.8
 
 
 * Improvement: h1#revision-path occupies most of the screen when the page path is long
 * Improvement: h1#revision-path occupies most of the screen when the page path is long
 * Improvement: Ensure not to save concealed email field to localStorage
 * Improvement: Ensure not to save concealed email field to localStorage
 * Fix: Cannot input "c" and "e" on iOS
 * Fix: Cannot input "c" and "e" on iOS
 
 
-## 3.0.7
+## v3.0.7
 
 
 * Improvement: Enable to download an attached file with original name
 * Improvement: Enable to download an attached file with original name
 * Improvement: Use MongoDB for session store instead of Redis
 * Improvement: Use MongoDB for session store instead of Redis
@@ -869,7 +876,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Fix: Broken page path of timeline
 * Fix: Broken page path of timeline
     * Introduced by 3.0.4
     * Introduced by 3.0.4
 
 
-## 3.0.6
+## v3.0.6
 
 
 * Improvement: Automatically bind external accounts newly logged in to local accounts when username match
 * Improvement: Automatically bind external accounts newly logged in to local accounts when username match
 * Improvement: Simplify configuration for Slack Web API
 * Improvement: Simplify configuration for Slack Web API
@@ -882,18 +889,18 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * sass-loader
     * sass-loader
     * uglifycss
     * uglifycss
 
 
-## 3.0.5
+## v3.0.5
 
 
 * Improvement: Update lsx icons and styles
 * Improvement: Update lsx icons and styles
 * Fix: lsx plugins doesn't show page names
 * Fix: lsx plugins doesn't show page names
 
 
-## 3.0.4
+## v3.0.4
 
 
 * Improvement: The option that switch whether add h1 section when create new page
 * Improvement: The option that switch whether add h1 section when create new page
 * Improvement: Encode page path that includes special character
 * Improvement: Encode page path that includes special character
 * Fix: Page-saving error after new page creation
 * Fix: Page-saving error after new page creation
 
 
-## 3.0.3
+## v3.0.3
 
 
 * Fix: Login page is broken in iOS
 * Fix: Login page is broken in iOS
 * Fix: Hide presentation tab if portal page
 * Fix: Hide presentation tab if portal page
@@ -904,7 +911,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Fix: Activating invited user form url is wrong
 * Fix: Activating invited user form url is wrong
 * Support: Use postcss-loader and autoprefixer
 * Support: Use postcss-loader and autoprefixer
 
 
-## 3.0.2
+## v3.0.2
 
 
 * Feature: Group Access Control List
 * Feature: Group Access Control List
 * Feature: Add site theme selector
 * Feature: Add site theme selector
@@ -920,11 +927,11 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * react-bootstrap-typeahead
     * react-bootstrap-typeahead
     * react-clipboard.js
     * react-clipboard.js
 
 
-## 3.0.1 (Missing number)
+## v3.0.1 (Missing number)
 
 
-## 3.0.0 (Missing number)
+## v3.0.0 (Missing number)
 
 
-## 2.4.4
+## v2.4.4
 
 
 * Feature: Autoformat Markdown Table
 * Feature: Autoformat Markdown Table
 * Feature: highlight.js Theme Selector
 * Feature: highlight.js Theme Selector
@@ -936,7 +943,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * react, react-dom
     * react, react-dom
     * codemirror, react-codemirror2
     * codemirror, react-codemirror2
 
 
-## 2.4.3
+## v2.4.3
 
 
 * Improvement: i18n in `/admin`
 * Improvement: i18n in `/admin`
 * Improvement: Add `SESSION_NAME` environment variable
 * Improvement: Add `SESSION_NAME` environment variable
@@ -945,7 +952,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * uglifycss
     * uglifycss
     * sinon-chai
     * sinon-chai
 
 
-## 2.4.2
+## v2.4.2
 
 
 * Improvement: Ensure to set absolute url from root when attaching files when `FILE_UPLOAD=local`
 * Improvement: Ensure to set absolute url from root when attaching files when `FILE_UPLOAD=local`
 * Fix: Inline code blocks that includes doller sign are broken
 * Fix: Inline code blocks that includes doller sign are broken
@@ -955,7 +962,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * googleapis
     * googleapis
     * markdown-it-plantuml
     * markdown-it-plantuml
 
 
-## 2.4.1
+## v2.4.1
 
 
 * Feature: Custom Header HTML
 * Feature: Custom Header HTML
 * Improvement: Add highlight.js languages
 * Improvement: Add highlight.js languages
@@ -968,7 +975,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * axios
     * axios
     * diff2html
     * diff2html
 
 
-## 2.4.0
+## v2.4.0
 
 
 * Feature: Support Footnotes
 * Feature: Support Footnotes
 * Feature: Support Task lists
 * Feature: Support Task lists
@@ -981,7 +988,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Improvement: Update `#revision-body` tab contents after saving with `Ctrl-S`
 * Improvement: Update `#revision-body` tab contents after saving with `Ctrl-S`
 * Fix: 500 Internal Server Error occures when basic-auth configuration is set
 * Fix: 500 Internal Server Error occures when basic-auth configuration is set
 
 
-## 2.3.9
+## v2.3.9
 
 
 * Fix: `Ctrl-/` doesn't work on Chrome
 * Fix: `Ctrl-/` doesn't work on Chrome
 * Fix: Close Shortcuts help with `Ctrl-/`, ESC key
 * Fix: Close Shortcuts help with `Ctrl-/`, ESC key
@@ -989,7 +996,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Support: Upgrade libs
 * Support: Upgrade libs
     * googleapis
     * googleapis
 
 
-## 2.3.8
+## v2.3.8
 
 
 * Feature: Suggest page path when creating pages
 * Feature: Suggest page path when creating pages
 * Improvement: Prevent keyboard shortcuts when modal is opened
 * Improvement: Prevent keyboard shortcuts when modal is opened
@@ -1000,19 +1007,19 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * style-loader
     * style-loader
     * react-codemirror2
     * react-codemirror2
 
 
-## 2.3.7
+## v2.3.7
 
 
 * Fix: Open popups when `Ctrl+C` pressed
 * Fix: Open popups when `Ctrl+C` pressed
     * Introduced by 2.3.5
     * Introduced by 2.3.5
 
 
-## 2.3.6
+## v2.3.6
 
 
 * Feature: Theme Selector for Editor
 * Feature: Theme Selector for Editor
 * Improvement: Remove unportalize button from crowi-plus layout
 * Improvement: Remove unportalize button from crowi-plus layout
 * Fix: CSS for admin pages
 * Fix: CSS for admin pages
 * Support: Shrink the size of libraries to include
 * Support: Shrink the size of libraries to include
 
 
-## 2.3.5
+## v2.3.5
 
 
 * Feature: Enhanced Editor by CodeMirror
 * Feature: Enhanced Editor by CodeMirror
 * Feature: Emoji AutoComplete
 * Feature: Emoji AutoComplete
@@ -1028,26 +1035,26 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * mongoose-unique-validator
     * mongoose-unique-validator
     * etc..
     * etc..
 
 
-## 2.3.4 (Missing number)
+## v2.3.4 (Missing number)
 
 
-## 2.3.3
+## v2.3.3
 
 
 * Fix: The XSS Library escapes inline code blocks
 * Fix: The XSS Library escapes inline code blocks
     * Degraded by 2.3.0
     * Degraded by 2.3.0
 * Fix: NPE occurs on Elasticsearch when initial access
 * Fix: NPE occurs on Elasticsearch when initial access
 * Fix: Couldn't invite users(failed to create)
 * Fix: Couldn't invite users(failed to create)
 
 
-## 2.3.2
+## v2.3.2
 
 
 * Improvement: Add LDAP group search options
 * Improvement: Add LDAP group search options
 
 
-## 2.3.1
+## v2.3.1
 
 
 * Fix: Blockquote doesn't work
 * Fix: Blockquote doesn't work
     * Degraded by 2.3.0
     * Degraded by 2.3.0
 * Fix: Couldn't create user with first LDAP logging in
 * Fix: Couldn't create user with first LDAP logging in
 
 
-## 2.3.0
+## v2.3.0
 
 
 * Feature: LDAP Authentication
 * Feature: LDAP Authentication
 * Improvement: Prevent XSS
 * Improvement: Prevent XSS
@@ -1055,14 +1062,14 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Support: Upgrade libs
 * Support: Upgrade libs
     * express-pino-logger
     * express-pino-logger
 
 
-## 2.2.4
+## v2.2.4
 
 
 * Fix: googleapis v23.0.0 lost the function `oauth2Client.setCredentials`
 * Fix: googleapis v23.0.0 lost the function `oauth2Client.setCredentials`
     * Degraded by 2.2.2 updates
     * Degraded by 2.2.2 updates
 * Fix: HeaderSearchBox didn't append 'q=' param when searching
 * Fix: HeaderSearchBox didn't append 'q=' param when searching
     * Degraded by 2.2.3 updates
     * Degraded by 2.2.3 updates
 
 
-## 2.2.3
+## v2.2.3
 
 
 * Fix: The server responds anything when using passport
 * Fix: The server responds anything when using passport
     * Degraded by 2.2.2 updates
     * Degraded by 2.2.2 updates
@@ -1071,9 +1078,9 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Support: Upgrade react-bootstrap-typeahead
 * Support: Upgrade react-bootstrap-typeahead
 * Improvement: Replace emojify.js with emojione
 * Improvement: Replace emojify.js with emojione
 
 
-## 2.2.2 (Missing number)
+## v2.2.2 (Missing number)
 
 
-## 2.2.1
+## v2.2.1
 
 
 * Feature: Duplicate page
 * Feature: Duplicate page
 * Improve: Ensure that admin users can remove users waiting for approval
 * Improve: Ensure that admin users can remove users waiting for approval
@@ -1081,22 +1088,22 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Support: Upgrade React to 16
 * Support: Upgrade React to 16
 * Support: Upgrade outdated libs
 * Support: Upgrade outdated libs
 
 
-## 2.2.0
+## v2.2.0
 
 
 * Support: Merge official Crowi v1.6.3
 * Support: Merge official Crowi v1.6.3
 
 
-## 2.1.2
+## v2.1.2
 
 
 * Improvement: Ensure to prevent suspending own account
 * Improvement: Ensure to prevent suspending own account
 * Fix: Ensure to be able to use `.` for username when invited
 * Fix: Ensure to be able to use `.` for username when invited
 * Fix: monospace font for `<code></code>`
 * Fix: monospace font for `<code></code>`
 
 
-## 2.1.1
+## v2.1.1
 
 
 * Fix: The problem that React Modal doesn't work
 * Fix: The problem that React Modal doesn't work
 * Support: Lock some packages(react, react-dom, mongoose)
 * Support: Lock some packages(react, react-dom, mongoose)
 
 
-## 2.1.0
+## v2.1.0
 
 
 * Feature: Adopt Passport the authentication middleware
 * Feature: Adopt Passport the authentication middleware
 * Feature: Selective batch deletion in search result page
 * Feature: Selective batch deletion in search result page
@@ -1104,98 +1111,98 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 * Fix: The problem that couldn't update user data in /me
 * Fix: The problem that couldn't update user data in /me
 * Support: Upgrade outdated libs
 * Support: Upgrade outdated libs
 
 
-## 2.0.9
+## v2.0.9
 
 
 * Fix: Server is down when a guest user accesses to someone's private pages
 * Fix: Server is down when a guest user accesses to someone's private pages
 * Support: Merge official Crowi (master branch)
 * Support: Merge official Crowi (master branch)
 * Support: Upgrade outdated libs
 * Support: Upgrade outdated libs
 
 
-## 2.0.8
+## v2.0.8
 
 
 * Fix: The problem that path including round bracket makes something bad
 * Fix: The problem that path including round bracket makes something bad
 * Fix: Recursively option processes also unexpedted pages
 * Fix: Recursively option processes also unexpedted pages
 * Fix: en-US translation
 * Fix: en-US translation
 
 
-## 2.0.7
+## v2.0.7
 
 
 * Improvement: Add recursively option for Delete/Move/Putback operation
 * Improvement: Add recursively option for Delete/Move/Putback operation
 * Improvement: Comment layout and sort order (crowi-plus Enhanced Layout)
 * Improvement: Comment layout and sort order (crowi-plus Enhanced Layout)
 
 
-## 2.0.6
+## v2.0.6
 
 
 * Fix: check whether `$APP_DIR/public/uploads` exists before creating symlink
 * Fix: check whether `$APP_DIR/public/uploads` exists before creating symlink
     * Fixed in weseek/crowi-plus-docker
     * Fixed in weseek/crowi-plus-docker
 
 
-## 2.0.5
+## v2.0.5
 
 
 * Improvement: Adjust styles for CodeMirror
 * Improvement: Adjust styles for CodeMirror
 * Fix: File upload does not work when using crowi-plus-docker-compose and `FILE_UPLOAD=local` is set  
 * Fix: File upload does not work when using crowi-plus-docker-compose and `FILE_UPLOAD=local` is set  
     * Fixed in weseek/crowi-plus-docker
     * Fixed in weseek/crowi-plus-docker
 
 
-## 2.0.2 - 2.0.4 (Missing number)
+## v2.0.2 - 2.0.4 (Missing number)
 
 
-## 2.0.1
+## v2.0.1
 
 
 * Feature: Custom Script
 * Feature: Custom Script
 * Improvement: Adjust layout and styles for admin pages
 * Improvement: Adjust layout and styles for admin pages
 * Improvement: Record and show last updated date in user list page
 * Improvement: Record and show last updated date in user list page
 * Fix: Ignore Ctrl+(Shift+)Tab when editing (cherry-pick from the official)
 * Fix: Ignore Ctrl+(Shift+)Tab when editing (cherry-pick from the official)
 
 
-## 2.0.0
+## v2.0.0
 
 
 * Feature: Enabled to integrate with Slack using Incoming Webhooks
 * Feature: Enabled to integrate with Slack using Incoming Webhooks
 * Support: Upgrade all outdated libs
 * Support: Upgrade all outdated libs
 
 
-## 1.2.16
+## v1.2.16
 
 
 * Improvement: Condition for creating portal
 * Improvement: Condition for creating portal
 * Fix: Couldn't create new page after installation cleanly
 * Fix: Couldn't create new page after installation cleanly
 
 
-## 1.2.15
+## v1.2.15
 
 
 * Improvement: Optimize cache settings for express server
 * Improvement: Optimize cache settings for express server
 * Improvement: Add a logo link to the affix header
 * Improvement: Add a logo link to the affix header
 * Fix: Child pages under `/trash` are not shown when applying crowi-plus Simplified Behavior
 * Fix: Child pages under `/trash` are not shown when applying crowi-plus Simplified Behavior
 
 
-## 1.2.14
+## v1.2.14
 
 
 * Fix: Tabs(`a[data-toggle="tab"][href="#..."]`) push browser history twice
 * Fix: Tabs(`a[data-toggle="tab"][href="#..."]`) push browser history twice
 * Fix: `a[href="#edit-form"]` still save history even when disabling pushing states option
 * Fix: `a[href="#edit-form"]` still save history even when disabling pushing states option
 
 
-## 1.2.13
+## v1.2.13
 
 
 * Improvement: Enabled to switch whether to push states with History API when tabs changes
 * Improvement: Enabled to switch whether to push states with History API when tabs changes
 * Fix: Layout of the Not Found page
 * Fix: Layout of the Not Found page
 
 
-## 1.2.12 (Missing number)
+## v1.2.12 (Missing number)
 
 
-## 1.2.11
+## v1.2.11
 
 
 * Improvement: Enabled to open editing form from affix header
 * Improvement: Enabled to open editing form from affix header
 * Improvement: Enabled to open editing form from each section headers
 * Improvement: Enabled to open editing form from each section headers
 
 
-## 1.2.10
+## v1.2.10
 
 
 * Fix: Revise `server:prod:container` script for backward compatibility
 * Fix: Revise `server:prod:container` script for backward compatibility
 
 
-## 1.2.9
+## v1.2.9
 
 
 * Improvement: Enabled to save with <kbd>⌘+S</kbd> on Mac
 * Improvement: Enabled to save with <kbd>⌘+S</kbd> on Mac
 * Improvement: Adopt the fastest logger 'pino'
 * Improvement: Adopt the fastest logger 'pino'
 * Fix: The problem that can't upload profile image
 * Fix: The problem that can't upload profile image
 
 
-## 1.2.8
+## v1.2.8
 
 
 * Fix: The problem that redirect doesn't work when using 'crowi-plus Simplified Behavior'
 * Fix: The problem that redirect doesn't work when using 'crowi-plus Simplified Behavior'
 
 
-## 1.2.7 (Missing number)
+## v1.2.7 (Missing number)
 
 
-## 1.2.6
+## v1.2.6
 
 
 * Fix: The problem that page_list widget doesn't show the picture of revision.author
 * Fix: The problem that page_list widget doesn't show the picture of revision.author
 * Fix: Change implementation of Bootstrap3 toggle switch for admin pages
 * Fix: Change implementation of Bootstrap3 toggle switch for admin pages
 
 
-## 1.2.5
+## v1.2.5
 
 
 * Feature: crowi-plus Simplified Behavior
 * Feature: crowi-plus Simplified Behavior
     * `/page` and `/page/` both shows the page
     * `/page` and `/page/` both shows the page
@@ -1203,136 +1210,136 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
     * All pages shows the list of sub pages
     * All pages shows the list of sub pages
 * Improvement: Ensure to be able to disable Timeline feature
 * Improvement: Ensure to be able to disable Timeline feature
 
 
-## 1.2.4
+## v1.2.4
 
 
 * Fix: Internal Server Error has occurred when a guest user visited the page someone added "liked"
 * Fix: Internal Server Error has occurred when a guest user visited the page someone added "liked"
 
 
-## 1.2.3
+## v1.2.3
 
 
 * Improvement: Ensure to be able to use Presentation Mode even when not logged in
 * Improvement: Ensure to be able to use Presentation Mode even when not logged in
 * Improvement: Presentation Mode on IE11 (Experimental)
 * Improvement: Presentation Mode on IE11 (Experimental)
 * Fix: Broken Presentation Mode
 * Fix: Broken Presentation Mode
 
 
-## 1.2.2
+## v1.2.2
 
 
 * Support: Merge official Crowi (master branch)
 * Support: Merge official Crowi (master branch)
 
 
-## 1.2.1
+## v1.2.1
 
 
 * Fix: buildIndex error occured when access to installer
 * Fix: buildIndex error occured when access to installer
 
 
-## 1.2.0
+## v1.2.0
 
 
 * Support: Merge official Crowi v1.6.2
 * Support: Merge official Crowi v1.6.2
 
 
-## 1.1.12
+## v1.1.12
 
 
 * Feature: Remove Comment Button
 * Feature: Remove Comment Button
 
 
-## 1.1.11
+## v1.1.11
 
 
 * Fix: Omit Comment form from page_list (crowi-plus Enhanced Layout)
 * Fix: Omit Comment form from page_list (crowi-plus Enhanced Layout)
 * Fix: .search-box is broken on sm/xs screen
 * Fix: .search-box is broken on sm/xs screen
 
 
-## 1.1.10
+## v1.1.10
 
 
 * Fix: .search-box is broken on sm/xs screen
 * Fix: .search-box is broken on sm/xs screen
 * Support: Browsable with IE11 (Experimental)
 * Support: Browsable with IE11 (Experimental)
 
 
-## 1.1.9
+## v1.1.9
 
 
 * Improvement: Ensure to generate indices of Elasticsearch when installed
 * Improvement: Ensure to generate indices of Elasticsearch when installed
 * Fix: Specify the version of Bonsai Elasticsearch on Heroku
 * Fix: Specify the version of Bonsai Elasticsearch on Heroku
 
 
-## 1.1.8
+## v1.1.8
 
 
 * Fix: Depth of dropdown-menu when `.on-edit`
 * Fix: Depth of dropdown-menu when `.on-edit`
 * Fix: Error occured on saveing with `Ctrl-S`
 * Fix: Error occured on saveing with `Ctrl-S`
 * Fix: Guest users browsing
 * Fix: Guest users browsing
 
 
-## 1.1.7
+## v1.1.7
 
 
 * Feature: Add option to allow guest users to browse
 * Feature: Add option to allow guest users to browse
 * Fix: crowi-plus Enhanced Layout
 * Fix: crowi-plus Enhanced Layout
 
 
-## 1.1.6
+## v1.1.6
 
 
 * Fix: crowi-plus Enhanced Layout
 * Fix: crowi-plus Enhanced Layout
 
 
-## 1.1.5
+## v1.1.5
 
 
 * Fix: crowi-plus Enhanced Layout
 * Fix: crowi-plus Enhanced Layout
 * Support: Merge official Crowi v1.6.1 master branch [573144b]
 * Support: Merge official Crowi v1.6.1 master branch [573144b]
 
 
-## 1.1.4
+## v1.1.4
 
 
 * Feature: Ensure to select layout type from Admin Page
 * Feature: Ensure to select layout type from Admin Page
 * Feature: Add crowi-plus Enhanced Layout
 * Feature: Add crowi-plus Enhanced Layout
 
 
-## 1.1.3
+## v1.1.3
 
 
 * Improvement: Use POSIX-style paths (bollowed crowi/crowi#219 by @Tomasom)
 * Improvement: Use POSIX-style paths (bollowed crowi/crowi#219 by @Tomasom)
 
 
-## 1.1.2
+## v1.1.2
 
 
 * Imprv: Brushup fonts and styles
 * Imprv: Brushup fonts and styles
 * Fix: Ensure to specity revision id when saving with `Ctrl-S`
 * Fix: Ensure to specity revision id when saving with `Ctrl-S`
 
 
-## 1.1.1
+## v1.1.1
 
 
 * Feature: Save with `Ctrl-S`
 * Feature: Save with `Ctrl-S`
 * Imprv: Brushup fonts and styles
 * Imprv: Brushup fonts and styles
 
 
-## 1.1.0
+## v1.1.0
 
 
 * Support: Merge official Crowi v1.6.1
 * Support: Merge official Crowi v1.6.1
 
 
-## 1.0.9
+## v1.0.9
 
 
 * Feature: Delete user
 * Feature: Delete user
 * Feature: Upload other than images
 * Feature: Upload other than images
 
 
-## 1.0.8
+## v1.0.8
 
 
 * Feature: Ensure to delete page completely
 * Feature: Ensure to delete page completely
 * Feature: Ensure to delete redirect page
 * Feature: Ensure to delete redirect page
 * Fix: https access to Gravatar (this time for sure)
 * Fix: https access to Gravatar (this time for sure)
 
 
-## 1.0.7
+## v1.0.7
 
 
 * Feature: Keyboard navigation for search box
 * Feature: Keyboard navigation for search box
 * Improvement: Intelligent Search
 * Improvement: Intelligent Search
 
 
-## 1.0.6
+## v1.0.6
 
 
 * Feature: Copy button that copies page path to clipboard
 * Feature: Copy button that copies page path to clipboard
 * Fix: https access to Gravatar
 * Fix: https access to Gravatar
 * Fix: server watching crash with `Error: read ECONNRESET` on Google Chrome
 * Fix: server watching crash with `Error: read ECONNRESET` on Google Chrome
 
 
-## 1.0.5
+## v1.0.5
 
 
 * Feature: Ensure to use Gravatar for profile image
 * Feature: Ensure to use Gravatar for profile image
 
 
-## 1.0.4
+## v1.0.4
 
 
 * Improvement: Detach code blocks before preProcess
 * Improvement: Detach code blocks before preProcess
 * Support: Ensure to deploy to Heroku with INSTALL_PLUGINS env
 * Support: Ensure to deploy to Heroku with INSTALL_PLUGINS env
 * Support: Ensure to load plugins easily when development
 * Support: Ensure to load plugins easily when development
 
 
-## 1.0.3
+## v1.0.3
 
 
 * Improvement: Adjust styles
 * Improvement: Adjust styles
 
 
-## 1.0.2
+## v1.0.2
 
 
 * Improvement: For lsx
 * Improvement: For lsx
 
 
-## 1.0.1
+## v1.0.1
 
 
 * Feature: Custom CSS
 * Feature: Custom CSS
 * Support: Notify build failure to Slask
 * Support: Notify build failure to Slask
 
 
-## 1.0.0
+## v1.0.0
 
 
 * Feature: Plugin mechanism
 * Feature: Plugin mechanism
 * Feature: Switchable LineBreaks ON/OFF from admin page
 * Feature: Switchable LineBreaks ON/OFF from admin page

+ 23 - 2
config/swagger-definition.js

@@ -1,6 +1,7 @@
 const pkg = require('../package.json');
 const pkg = require('../package.json');
 
 
-const apiVersion = process.env.API_VERSION || 3;
+const apiVersion = process.env.API_VERSION || '3';
+const basePath = (apiVersion === '1' ? '/_api' : `/_api/v${apiVersion}`);
 
 
 module.exports = {
 module.exports = {
   openapi: '3.0.1',
   openapi: '3.0.1',
@@ -10,7 +11,27 @@ module.exports = {
   },
   },
   servers: [
   servers: [
     {
     {
-      url: 'https://demo.growi.org',
+      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',
+      },
+    },
+  },
 };
 };

+ 4 - 4
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "growi",
   "name": "growi",
-  "version": "3.6.4-RC",
+  "version": "3.6.5-RC",
   "description": "Team collaboration software using markdown",
   "description": "Team collaboration software using markdown",
   "tags": [
   "tags": [
     "wiki",
     "wiki",
@@ -20,9 +20,9 @@
     "url": "https://github.com/weseek/growi/issues"
     "url": "https://github.com/weseek/growi/issues"
   },
   },
   "scripts": {
   "scripts": {
-    "build:api:jsdoc": "swagger-jsdoc -o tmp/swagger.json -d config/swagger-definition.js \"src/server/**/*.js\"",
-    "build:apiv3:jsdoc": "cross-env API_VERSION=3 npm run build:api:jsdoc",
-    "build:apiv1:jsdoc": "cross-env API_VERSION=1 npm run build:api:jsdoc",
+    "build:api:jsdoc": "swagger-jsdoc -o tmp/swagger.json -d config/swagger-definition.js",
+    "build:apiv3:jsdoc": "cross-env API_VERSION=3 npm run build:api:jsdoc -- \"src/server/routes/apiv3/**/*.js\" \"src/server/models/**/*.js\"",
+    "build:apiv1:jsdoc": "cross-env API_VERSION=1 npm run build:api:jsdoc -- \"src/server/*/*.js\" \"src/server/models/**/*.js\"",
     "build:dev:app:watch": "npm run build:dev:app -- --watch",
     "build:dev:app:watch": "npm run build:dev:app -- --watch",
     "build:dev:app": "env-cmd -f config/env.dev.js webpack --config config/webpack.dev.js --progress",
     "build:dev:app": "env-cmd -f config/env.dev.js webpack --config config/webpack.dev.js --progress",
     "build:dev:watch": "npm run build:dev:app:watch",
     "build:dev:watch": "npm run build:dev:app:watch",

+ 8 - 5
src/client/js/components/Admin/AdminHome/AdminHome.jsx

@@ -40,14 +40,17 @@ class AdminHome extends React.Component {
         </p>
         </p>
 
 
         <div className="row mb-5">
         <div className="row mb-5">
-          <h2>{t('admin_top:system_information')}</h2>
-          <SystemInfomationTable />
+          <div className="col-md-12">
+            <h2 className="admin-setting-header">{t('admin_top:system_information')}</h2>
+            <SystemInfomationTable />
+          </div>
         </div>
         </div>
 
 
         <div className="row mb-5">
         <div className="row mb-5">
-          <h2>{t('admin_top:list_of_installed_plugins')}</h2>
-          <InstalledPluginTable />
-
+          <div className="col-md-12">
+            <h2 className="admin-setting-header">{t('admin_top:list_of_installed_plugins')}</h2>
+            <InstalledPluginTable />
+          </div>
         </div>
         </div>
       </Fragment>
       </Fragment>
     );
     );

+ 9 - 9
src/client/js/components/Admin/App/AppSettingsPage.jsx

@@ -39,35 +39,35 @@ class AppSettingsPage extends React.Component {
       <Fragment>
       <Fragment>
         <div className="row">
         <div className="row">
           <div className="col-md-12">
           <div className="col-md-12">
-            <h2>{t('App Settings')}</h2>
+            <h2 className="admin-setting-header">{t('App Settings')}</h2>
             <AppSetting />
             <AppSetting />
           </div>
           </div>
         </div>
         </div>
 
 
-        <div className="row">
+        <div className="row mt-5">
           <div className="col-md-12">
           <div className="col-md-12">
-            <h2>{t('Site URL settings')}</h2>
+            <h2 className="admin-setting-header">{t('Site URL settings')}</h2>
             <SiteUrlSetting />
             <SiteUrlSetting />
           </div>
           </div>
         </div>
         </div>
 
 
-        <div className="row">
+        <div className="row mt-5">
           <div className="col-md-12">
           <div className="col-md-12">
-            <h2>{t('app_setting:mail_settings')}</h2>
+            <h2 className="admin-setting-header">{t('app_setting:mail_settings')}</h2>
             <MailSetting />
             <MailSetting />
           </div>
           </div>
         </div>
         </div>
 
 
-        <div className="row">
+        <div className="row mt-5">
           <div className="col-md-12">
           <div className="col-md-12">
-            <h2>{t('app_setting:aws_settings')}</h2>
+            <h2 className="admin-setting-header">{t('app_setting:aws_settings')}</h2>
             <AwsSetting />
             <AwsSetting />
           </div>
           </div>
         </div>
         </div>
 
 
-        <div className="row">
+        <div className="row mt-5">
           <div className="col-md-12">
           <div className="col-md-12">
-            <h2>{t('app_setting:plugin_settings')}</h2>
+            <h2 className="admin-setting-header">{t('app_setting:plugin_settings')}</h2>
             <PluginSetting />
             <PluginSetting />
           </div>
           </div>
         </div>
         </div>

+ 3 - 0
src/client/styles/agile-admin/inverse/colors/_apply-colors-dark.scss

@@ -150,6 +150,9 @@ legend {
     border-color: $border;
     border-color: $border;
   }
   }
 }
 }
+.editor-container .navbar-editor svg {
+  fill: $bodytext;
+}
 
 
 /*
 /*
  * GROWI admin page #themeOptions
  * GROWI admin page #themeOptions

+ 0 - 4
src/client/styles/agile-admin/inverse/colors/blue-night.scss

@@ -47,7 +47,3 @@ $inline-code-bg: #0a121b;
     }
     }
   }
   }
 }
 }
-
-.editor-container .navbar-editor svg {
-  fill: $bodytext;
-}

+ 0 - 4
src/client/styles/agile-admin/inverse/colors/default-dark.scss

@@ -25,9 +25,5 @@ $active-navbar-border: darken($border, 3%);
 $btn-default-bgcolor: darken($basecolor, 10%);
 $btn-default-bgcolor: darken($basecolor, 10%);
 $inline-code-bg: darken($bodycolor, 5%);
 $inline-code-bg: darken($bodycolor, 5%);
 
 
-.editor-container .navbar-editor svg {
-  fill: $bodytext;
-}
-
 @import 'apply-colors';
 @import 'apply-colors';
 @import 'apply-colors-dark';
 @import 'apply-colors-dark';

+ 0 - 4
src/client/styles/agile-admin/inverse/colors/future.scss

@@ -35,7 +35,3 @@ $inline-code-bg: darken($bodycolor, 5%);
     border-bottom: 1px solid rgb(131, 228, 215);
     border-bottom: 1px solid rgb(131, 228, 215);
   }
   }
 }
 }
-
-.editor-container .navbar-editor svg {
-  fill: $bodytext;
-}

+ 0 - 4
src/client/styles/agile-admin/inverse/colors/halloween.scss

@@ -74,10 +74,6 @@ $inline-code-bg: #0a121b;
   background-color: rgba(0, 0, 0, 0.3);
   background-color: rgba(0, 0, 0, 0.3);
 }
 }
 
 
-.editor-container .navbar-editor svg {
-  fill: $bodytext;
-}
-
 /*
 /*
  * Tabs
  * Tabs
  */
  */

+ 19 - 0
src/server/models/vo/error-apiv3.js

@@ -1,3 +1,22 @@
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      ErrorV3:
+ *        description: Error for APIv3
+ *        type: object
+ *        properties:
+ *          message:
+ *            type: string
+ *            example: 'error message'
+ *          code:
+ *            type: string
+ *            example: 'someapi-error-with-something'
+ *          stack:
+ *            type: object
+ */
+
 class ErrorV3 extends Error {
 class ErrorV3 extends Error {
 
 
   constructor(message = '', code = '', stack = undefined) {
   constructor(message = '', code = '', stack = undefined) {

+ 3 - 1
src/server/routes/apiv3/admin-home.js

@@ -48,7 +48,9 @@ module.exports = (crowi) => {
    *
    *
    *    /admin-home/:
    *    /admin-home/:
    *      get:
    *      get:
-   *        tags: [adminHome]
+   *        tags: [AdminHome]
+   *        operationId: getAdminHome
+   *        summary: /admin-home
    *        description: Get adminHome parameters
    *        description: Get adminHome parameters
    *        responses:
    *        responses:
    *          200:
    *          200:

+ 18 - 18
src/server/routes/apiv3/app-settings.js

@@ -136,11 +136,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/app-settings:
+   *    /app-settings:
    *      get:
    *      get:
-   *        tags: [AppSettings, apiv3]
+   *        tags: [AppSettings]
    *        operationId: getAppSettings
    *        operationId: getAppSettings
-   *        summary: /_api/v3/app-settings
+   *        summary: /app-settings
    *        description: get app setting params
    *        description: get app setting params
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -181,10 +181,10 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/app-settings/app-setting:
+   *    /app-settings/app-setting:
    *      put:
    *      put:
-   *        tags: [AppSettings, apiv3]
-   *        summary: /_api/v3/app-settings/app-setting
+   *        tags: [AppSettings]
+   *        summary: /app-settings/app-setting
    *        operationId: updateAppSettings
    *        operationId: updateAppSettings
    *        description: Update app setting
    *        description: Update app setting
    *        requestBody:
    *        requestBody:
@@ -230,11 +230,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/app-settings/site-url-setting:
+   *    /app-settings/site-url-setting:
    *      put:
    *      put:
-   *        tags: [AppSettings, apiv3]
+   *        tags: [AppSettings]
    *        operationId: updateAppSettingSiteUrlSetting
    *        operationId: updateAppSettingSiteUrlSetting
-   *        summary: /_api/v3/app-settings/site-url-setting
+   *        summary: /app-settings/site-url-setting
    *        description: Update site url setting
    *        description: Update site url setting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -322,11 +322,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/app-settings/mail-setting:
+   *    /app-settings/mail-setting:
    *      put:
    *      put:
-   *        tags: [AppSettings, apiv3]
+   *        tags: [AppSettings]
    *        operationId: updateAppSettingMailSetting
    *        operationId: updateAppSettingMailSetting
-   *        summary: /_api/v3/app-settings/site-url-setting
+   *        summary: /app-settings/site-url-setting
    *        description: Update mail setting
    *        description: Update mail setting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -384,11 +384,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/app-settings/aws-setting:
+   *    /app-settings/aws-setting:
    *      put:
    *      put:
-   *        tags: [AppSettings, apiv3]
+   *        tags: [AppSettings]
    *        operationId: updateAppSettingAwsSetting
    *        operationId: updateAppSettingAwsSetting
-   *        summary: /_api/v3/app-settings/aws-setting
+   *        summary: /app-settings/aws-setting
    *        description: Update aws setting
    *        description: Update aws setting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -435,11 +435,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/app-settings/plugin-setting:
+   *    /app-settings/plugin-setting:
    *      put:
    *      put:
-   *        tags: [AppSettings, apiv3]
+   *        tags: [AppSettings]
    *        operationId: updateAppSettingPluginSetting
    *        operationId: updateAppSettingPluginSetting
-   *        summary: /_api/v3/app-settings/plugin-setting
+   *        summary: /app-settings/plugin-setting
    *        description: Update plugin setting
    *        description: Update plugin setting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true

+ 27 - 27
src/server/routes/apiv3/customize-setting.js

@@ -131,11 +131,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/customize-setting:
+   *    /customize-setting:
    *      get:
    *      get:
-   *        tags: [CustomizeSetting, apiv3]
+   *        tags: [CustomizeSetting]
    *        operationId: getCustomizeSetting
    *        operationId: getCustomizeSetting
-   *        summary: /_api/v3/customize-setting
+   *        summary: /customize-setting
    *        description: Get customize parameters
    *        description: Get customize parameters
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -173,11 +173,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/customize-setting/layoutTheme:
+   *    /customize-setting/layoutTheme:
    *      put:
    *      put:
-   *        tags: [CustomizeSetting, apiv3]
+   *        tags: [CustomizeSetting]
    *        operationId: updateLayoutThemeCustomizeSetting
    *        operationId: updateLayoutThemeCustomizeSetting
-   *        summary: /_api/v3/customize-setting/layoutTheme
+   *        summary: /customize-setting/layoutTheme
    *        description: Update layout and theme
    *        description: Update layout and theme
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -217,11 +217,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/customize-setting/behavior:
+   *    /customize-setting/behavior:
    *      put:
    *      put:
-   *        tags: [CustomizeSetting, apiv3]
+   *        tags: [CustomizeSetting]
    *        operationId: updateBehaviorCustomizeSetting
    *        operationId: updateBehaviorCustomizeSetting
-   *        summary: /_api/v3/customize-setting/behavior
+   *        summary: /customize-setting/behavior
    *        description: Update behavior
    *        description: Update behavior
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -259,11 +259,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/customize-setting/function:
+   *    /customize-setting/function:
    *      put:
    *      put:
-   *        tags: [CustomizeSetting, apiv3]
+   *        tags: [CustomizeSetting]
    *        operationId: updateFunctionCustomizeSetting
    *        operationId: updateFunctionCustomizeSetting
-   *        summary: /_api/v3/customize-setting/function
+   *        summary: /customize-setting/function
    *        description: Update function
    *        description: Update function
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -309,11 +309,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/customize-setting/highlight:
+   *    /customize-setting/highlight:
    *      put:
    *      put:
-   *        tags: [CustomizeSetting, apiv3]
+   *        tags: [CustomizeSetting]
    *        operationId: updateHighlightCustomizeSetting
    *        operationId: updateHighlightCustomizeSetting
-   *        summary: /_api/v3/customize-setting/highlight
+   *        summary: /customize-setting/highlight
    *        description: Update highlight
    *        description: Update highlight
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -353,11 +353,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/customize-setting/customizeTitle:
+   *    /customize-setting/customizeTitle:
    *      put:
    *      put:
-   *        tags: [CustomizeSetting, apiv3]
+   *        tags: [CustomizeSetting]
    *        operationId: updateCustomizeTitleCustomizeSetting
    *        operationId: updateCustomizeTitleCustomizeSetting
-   *        summary: /_api/v3/customize-setting/customizeTitle
+   *        summary: /customize-setting/customizeTitle
    *        description: Update customizeTitle
    *        description: Update customizeTitle
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -396,11 +396,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/customize-setting/customizeHeader:
+   *    /customize-setting/customizeHeader:
    *      put:
    *      put:
-   *        tags: [CustomizeSetting, apiv3]
+   *        tags: [CustomizeSetting]
    *        operationId: updateCustomizeHeaderCustomizeSetting
    *        operationId: updateCustomizeHeaderCustomizeSetting
-   *        summary: /_api/v3/customize-setting/customizeHeader
+   *        summary: /customize-setting/customizeHeader
    *        description: Update customizeHeader
    *        description: Update customizeHeader
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -437,11 +437,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/customize-setting/customizeCss:
+   *    /customize-setting/customizeCss:
    *      put:
    *      put:
-   *        tags: [CustomizeSetting, apiv3]
+   *        tags: [CustomizeSetting]
    *        operationId: updateCustomizeCssCustomizeSetting
    *        operationId: updateCustomizeCssCustomizeSetting
-   *        summary: /_api/v3/customize-setting/customizeCss
+   *        summary: /customize-setting/customizeCss
    *        description: Update customizeCss
    *        description: Update customizeCss
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -479,11 +479,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/customize-setting/customizeScript:
+   *    /customize-setting/customizeScript:
    *      put:
    *      put:
-   *        tags: [CustomizeSetting, apiv3]
+   *        tags: [CustomizeSetting]
    *        operationId: updateCustomizeScriptCustomizeSetting
    *        operationId: updateCustomizeScriptCustomizeSetting
-   *        summary: /_api/v3/customize-setting/customizeScript
+   *        summary: /customize-setting/customizeScript
    *        description: Update customizeScript
    *        description: Update customizeScript
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true

+ 9 - 9
src/server/routes/apiv3/export.js

@@ -62,11 +62,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/export/status:
+   *  /export/status:
    *    get:
    *    get:
-   *      tags: [Export, apiv3]
+   *      tags: [Export]
    *      operationId: getExportStatus
    *      operationId: getExportStatus
-   *      summary: /_api/v3/export/status
+   *      summary: /export/status
    *      description: get properties of stored zip files for export
    *      description: get properties of stored zip files for export
    *      responses:
    *      responses:
    *        200:
    *        200:
@@ -91,11 +91,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/export:
+   *  /export:
    *    post:
    *    post:
-   *      tags: [Export, apiv3]
+   *      tags: [Export]
    *      operationId: createExport
    *      operationId: createExport
-   *      summary: /_api/v3/export
+   *      summary: /export
    *      description: generate zipped jsons for collections
    *      description: generate zipped jsons for collections
    *      responses:
    *      responses:
    *        200:
    *        200:
@@ -129,11 +129,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/export/{fileName}:
+   *  /export/{fileName}:
    *    delete:
    *    delete:
-   *      tags: [Export, apiv3]
+   *      tags: [Export]
    *      operationId: deleteExport
    *      operationId: deleteExport
-   *      summary: /_api/v3/export/{fileName}
+   *      summary: /export/{fileName}
    *      description: delete the file
    *      description: delete the file
    *      parameters:
    *      parameters:
    *        - name: fileName
    *        - name: fileName

+ 87 - 18
src/server/routes/apiv3/healthcheck.js

@@ -7,6 +7,7 @@ const express = require('express');
 const router = express.Router();
 const router = express.Router();
 
 
 const helmet = require('helmet');
 const helmet = require('helmet');
+const ErrorV3 = require('../../models/vo/error-apiv3');
 
 
 /**
 /**
  * @swagger
  * @swagger
@@ -14,57 +15,125 @@ const helmet = require('helmet');
  *    name: Healthcheck
  *    name: Healthcheck
  */
  */
 
 
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      HealthcheckInfo:
+ *        description: Information of middlewares
+ *        type: object
+ *        properties:
+ *          mongo:
+ *            type: string
+ *            description: 'OK'
+ *            example: 'OK'
+ *          searchInfo:
+ *            type: object
+ *            example: {
+ *              "esVersion":"6.6.1",
+ *              "esNodeInfos":{
+ *                "6pnILIqFT_Cjbs4mwQfcmA": {
+ *                  "name":"6pnILIq",
+ *                  "version":"6.6.1",
+ *                  "plugins":[
+ *                    {"name":"analysis-icu","version":"6.6.1"},
+ *                    {"name":"analysis-kuromoji","version":"6.6.1"},
+ *                    {"name":"ingest-geoip","version":"6.6.1"},
+ *                    {"name":"ingest-user-agent","version":"6.6.1"}
+ *                  ]
+ *                }
+ *              }
+ *            }
+ */
+
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/healthcheck:
+   *  /healthcheck:
    *    get:
    *    get:
-   *      tags: [Healthcheck, apiv3]
+   *      tags: [Healthcheck]
    *      operationId: getHealthcheck
    *      operationId: getHealthcheck
-   *      summary: /_api/v3/healthcheck
+   *      summary: /healthcheck
    *      description: Check whether the server is healthy or not
    *      description: Check whether the server is healthy or not
    *      parameters:
    *      parameters:
    *        - name: connectToMiddlewares
    *        - name: connectToMiddlewares
    *          in: query
    *          in: query
-   *          description: Check also MongoDB and SearchService
+   *          description: Check MongoDB and SearchService (consider as healthy even if any of middleware is available or not)
+   *          schema:
+   *            type: boolean
+   *        - name: checkMiddlewaresStrictly
+   *          in: query
+   *          description: Check MongoDB and SearchService and responds 503 if either of these is unhealthy
    *          schema:
    *          schema:
    *            type: boolean
    *            type: boolean
    *      responses:
    *      responses:
    *        200:
    *        200:
-   *          description: Resources are available
+   *          description: Healthy
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  info:
+   *                    $ref: '#/components/schemas/HealthcheckInfo'
+   *        503:
+   *          description: Unhealthy
    *          content:
    *          content:
    *            application/json:
    *            application/json:
    *              schema:
    *              schema:
    *                properties:
    *                properties:
-   *                  mongo:
-   *                    type: string
-   *                    description: 'OK'
-   *                  searchInfo:
-   *                    type: object
+   *                  errors:
+   *                    type: array
+   *                    description: Errors
+   *                    items:
+   *                      $ref: '#/components/schemas/ErrorV3'
+   *                  info:
+   *                    $ref: '#/components/schemas/HealthcheckInfo'
    */
    */
   router.get('/', helmet.noCache(), async(req, res) => {
   router.get('/', helmet.noCache(), async(req, res) => {
-    const connectToMiddlewares = req.query.connectToMiddlewares;
+    const connectToMiddlewares = req.query.connectToMiddlewares != null;
+    const checkMiddlewaresStrictly = req.query.checkMiddlewaresStrictly != null;
 
 
     // return 200 w/o connecting to MongoDB and SearchService
     // return 200 w/o connecting to MongoDB and SearchService
-    if (connectToMiddlewares == null) {
+    if (!connectToMiddlewares && !checkMiddlewaresStrictly) {
       res.status(200).send({ status: 'OK' });
       res.status(200).send({ status: 'OK' });
       return;
       return;
     }
     }
 
 
+    const errors = [];
+    const info = {};
+
+    // connect to MongoDB
     try {
     try {
-      // connect to MongoDB
       const Config = crowi.models.Config;
       const Config = crowi.models.Config;
       await Config.findOne({});
       await Config.findOne({});
-      // connect to Elasticsearch
-      const search = crowi.getSearcher();
-      const searchInfo = await search.getInfo();
 
 
-      res.status(200).send({ mongo: 'OK', searchInfo });
+      info.mongo = 'OK';
     }
     }
     catch (err) {
     catch (err) {
-      res.status(503).send({ err });
+      errors.push(new ErrorV3(`MongoDB is not connectable - ${err.message}`, 'healthcheck-mongodb-unhealthy', err.stack));
+    }
+
+    // connect to search service
+    try {
+      const search = crowi.getSearcher();
+      info.searchInfo = await search.getInfo();
     }
     }
+    catch (err) {
+      errors.push(new ErrorV3(`The Search Service is not connectable - ${err.message}`, 'healthcheck-search-unhealthy', err.stack));
+    }
+
+    if (errors.length > 0) {
+      let httpStatus = 200;
+      if (checkMiddlewaresStrictly) {
+        httpStatus = 503;
+      }
+
+      return res.apiv3Err(errors, httpStatus, info);
+    }
+
+    res.status(200).send({ info });
   });
   });
 
 
   return router;
   return router;

+ 12 - 12
src/server/routes/apiv3/import.js

@@ -101,11 +101,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/import/status:
+   *  /import/status:
    *    get:
    *    get:
-   *      tags: [Import, apiv3]
+   *      tags: [Import]
    *      operationId: getImportStatus
    *      operationId: getImportStatus
-   *      summary: /_api/v3/import/status
+   *      summary: /import/status
    *      description: Get properties of stored zip files for import
    *      description: Get properties of stored zip files for import
    *      responses:
    *      responses:
    *        200:
    *        200:
@@ -130,11 +130,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/import:
+   *  /import:
    *    post:
    *    post:
-   *      tags: [Import, apiv3]
+   *      tags: [Import]
    *      operationId: executeImport
    *      operationId: executeImport
-   *      summary: /_api/v3/import
+   *      summary: /import
    *      description: import a collection from a zipped json
    *      description: import a collection from a zipped json
    *      requestBody:
    *      requestBody:
    *        required: true
    *        required: true
@@ -241,11 +241,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/import/upload:
+   *  /import/upload:
    *    post:
    *    post:
-   *      tags: [Import, apiv3]
+   *      tags: [Import]
    *      operationId: uploadImport
    *      operationId: uploadImport
-   *      summary: /_api/v3/import/upload
+   *      summary: /import/upload
    *      description: upload a zip file
    *      description: upload a zip file
    *      responses:
    *      responses:
    *        200:
    *        200:
@@ -288,11 +288,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/import/all:
+   *  /import/all:
    *    delete:
    *    delete:
-   *      tags: [Import, apiv3]
+   *      tags: [Import]
    *      operationId: deleteImportAll
    *      operationId: deleteImportAll
-   *      summary: /_api/v3/import/all
+   *      summary: /import/all
    *      description: Delete all zip files
    *      description: Delete all zip files
    *      responses:
    *      responses:
    *        200:
    *        200:

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

@@ -92,11 +92,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/markdown-setting:
+   *    /markdown-setting:
    *      get:
    *      get:
-   *        tags: [MarkDownSetting, apiv3]
+   *        tags: [MarkDownSetting]
    *        operationId: getMarkdownSetting
    *        operationId: getMarkdownSetting
-   *        summary: /_api/v3/markdown-setting
+   *        summary: /markdown-setting
    *        description: Get markdown parameters
    *        description: Get markdown parameters
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -127,11 +127,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/markdown-setting/lineBreak:
+   *    /markdown-setting/lineBreak:
    *      put:
    *      put:
-   *        tags: [MarkDownSetting, apiv3]
+   *        tags: [MarkDownSetting]
    *        operationId: updateLineBreakMarkdownSetting
    *        operationId: updateLineBreakMarkdownSetting
-   *        summary: /_api/v3/markdown-setting/lineBreak
+   *        summary: /markdown-setting/lineBreak
    *        description: Update lineBreak setting
    *        description: Update lineBreak setting
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -173,11 +173,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/markdown-setting/presentation:
+   *    /markdown-setting/presentation:
    *      put:
    *      put:
-   *        tags: [MarkDownSetting, apiv3]
+   *        tags: [MarkDownSetting]
    *        operationId: updatePresentationMarkdownSetting
    *        operationId: updatePresentationMarkdownSetting
-   *        summary: /_api/v3/markdown-setting/presentation
+   *        summary: /markdown-setting/presentation
    *        description: Update presentation
    *        description: Update presentation
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -222,11 +222,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/v3/markdown-setting/xss:
+   *    /markdown-setting/xss:
    *      put:
    *      put:
-   *        tags: [MarkDownSetting, apiv3]
+   *        tags: [MarkDownSetting]
    *        operationId: updateXssMarkdownSetting
    *        operationId: updateXssMarkdownSetting
-   *        summary: /_api/v3/markdown-setting/xss
+   *        summary: /markdown-setting/xss
    *        description: Update xss
    *        description: Update xss
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true

+ 3 - 3
src/server/routes/apiv3/mongo.js

@@ -17,11 +17,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/mongo/collections:
+   *  /mongo/collections:
    *    get:
    *    get:
-   *      tags: [Mongo, apiv3]
+   *      tags: [Mongo]
    *      operationId: getMongoCollections
    *      operationId: getMongoCollections
-   *      summary: /_api/v3/mongo/collections
+   *      summary: /mongo/collections
    *      description: get mongodb collections names
    *      description: get mongodb collections names
    *      responses:
    *      responses:
    *        200:
    *        200:

+ 2 - 2
src/server/routes/apiv3/response.js

@@ -13,7 +13,7 @@ const addCustomFunctionToResponse = (express, crowi) => {
     this.json({ data: obj });
     this.json({ data: obj });
   };
   };
 
 
-  express.response.apiv3Err = function(_err, status = 400) { // not arrow function
+  express.response.apiv3Err = function(_err, status = 400, info) { // not arrow function
     if (!Number.isInteger(status)) {
     if (!Number.isInteger(status)) {
       throw new Error('invalid status supplied to res.apiv3Err');
       throw new Error('invalid status supplied to res.apiv3Err');
     }
     }
@@ -33,7 +33,7 @@ const addCustomFunctionToResponse = (express, crowi) => {
       throw new Error('invalid error supplied to res.apiv3Err');
       throw new Error('invalid error supplied to res.apiv3Err');
     });
     });
 
 
-    this.status(status).json({ errors });
+    this.status(status).json({ errors, info });
   };
   };
 };
 };
 
 

+ 3 - 3
src/server/routes/apiv3/statistics.js

@@ -83,11 +83,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *  /_api/v3/statistics/user:
+   *  /statistics/user:
    *    get:
    *    get:
-   *      tags: [Statistics, apiv3]
+   *      tags: [Statistics]
    *      operationId: getStatisticsUser
    *      operationId: getStatisticsUser
-   *      summary: /_api/v3/statistics/user
+   *      summary: /statistics/user
    *      description: Get statistics for user
    *      description: Get statistics for user
    *      responses:
    *      responses:
    *        200:
    *        200:

+ 3 - 3
src/server/routes/apiv3/user-group-relation.js

@@ -23,11 +23,11 @@ module.exports = (crowi) => {
   /**
   /**
    * @swagger
    * @swagger
    *  paths:
    *  paths:
-   *    /_api/v3/user-group-relations:
+   *    /user-group-relations:
    *      get:
    *      get:
-   *        tags: [UserGroupRelation, apiv3]
+   *        tags: [UserGroupRelation]
    *        operationId: listUserGroupRelations
    *        operationId: listUserGroupRelations
-   *        summary: /_api/v3/user-group-relations
+   *        summary: /user-group-relations
    *        description: Gets the user group relations
    *        description: Gets the user group relations
    *        responses:
    *        responses:
    *          200:
    *          200:

+ 30 - 30
src/server/routes/apiv3/user-group.js

@@ -43,11 +43,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups:
+   *    /user-groups:
    *      get:
    *      get:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: getUserGroup
    *        operationId: getUserGroup
-   *        summary: /_api/v3/user-groups
+   *        summary: /user-groups
    *        description: Get usergroups
    *        description: Get usergroups
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -83,11 +83,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups:
+   *    /user-groups:
    *      post:
    *      post:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: createUserGroup
    *        operationId: createUserGroup
-   *        summary: /_api/v3/user-groups
+   *        summary: /user-groups
    *        description: Adds userGroup
    *        description: Adds userGroup
    *        requestBody:
    *        requestBody:
    *          required: true
    *          required: true
@@ -135,11 +135,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups/{id}:
+   *    /user-groups/{id}:
    *      delete:
    *      delete:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: deleteUserGroup
    *        operationId: deleteUserGroup
-   *        summary: /_api/v3/user-groups/{id}
+   *        summary: /user-groups/{id}
    *        description: Deletes userGroup
    *        description: Deletes userGroup
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -197,11 +197,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups/{id}:
+   *    /user-groups/{id}:
    *      put:
    *      put:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: updateUserGroups
    *        operationId: updateUserGroups
-   *        summary: /_api/v3/user-groups/{id}
+   *        summary: /user-groups/{id}
    *        description: Update userGroup
    *        description: Update userGroup
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -254,11 +254,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups/{id}/users:
+   *    /user-groups/{id}/users:
    *      get:
    *      get:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: getUsersUserGroups
    *        operationId: getUsersUserGroups
-   *        summary: /_api/v3/user-groups/{id}/users
+   *        summary: /user-groups/{id}/users
    *        description: Get users related to the userGroup
    *        description: Get users related to the userGroup
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -304,11 +304,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups/{id}/unrelated-users:
+   *    /user-groups/{id}/unrelated-users:
    *      get:
    *      get:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: getUnrelatedUsersUserGroups
    *        operationId: getUnrelatedUsersUserGroups
-   *        summary: /_api/v3/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
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -362,11 +362,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups/{id}/users:
+   *    /user-groups/{id}/users:
    *      post:
    *      post:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: addUserUserGroups
    *        operationId: addUserUserGroups
-   *        summary: /_api/v3/user-groups/{id}/users
+   *        summary: /user-groups/{id}/users
    *        description: Add a user to the userGroup
    *        description: Add a user to the userGroup
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -431,11 +431,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups/{id}/users:
+   *    /user-groups/{id}/users:
    *      delete:
    *      delete:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: deleteUsersUserGroups
    *        operationId: deleteUsersUserGroups
-   *        summary: /_api/v3/user-groups/{id}/users
+   *        summary: /user-groups/{id}/users
    *        description: remove a user from the userGroup
    *        description: remove a user from the userGroup
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -493,11 +493,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups/{id}/user-group-relations:
+   *    /user-groups/{id}/user-group-relations:
    *      get:
    *      get:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: getUserGroupRelationsUserGroups
    *        operationId: getUserGroupRelationsUserGroups
-   *        summary: /_api/v3/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
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -547,11 +547,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/user-groups/{id}/pages:
+   *    /user-groups/{id}/pages:
    *      get:
    *      get:
-   *        tags: [UserGroup, apiv3]
+   *        tags: [UserGroup]
    *        operationId: getPagesUserGroups
    *        operationId: getPagesUserGroups
-   *        summary: /_api/v3/user-groups/{id}/pages
+   *        summary: /user-groups/{id}/pages
    *        description: Get closed pages for the userGroup
    *        description: Get closed pages for the userGroup
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id

+ 27 - 27
src/server/routes/apiv3/users.js

@@ -81,11 +81,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/users:
+   *    /users:
    *      get:
    *      get:
-   *        tags: [Users, apiv3]
+   *        tags: [Users]
    *        operationId: listUsers
    *        operationId: listUsers
-   *        summary: /_api/v3/users
+   *        summary: /users
    *        description: Get users
    *        description: Get users
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -133,11 +133,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/users/invite:
+   *    /users/invite:
    *      post:
    *      post:
-   *        tags: [Users, apiv3]
+   *        tags: [Users]
    *        operationId: inviteUser
    *        operationId: inviteUser
-   *        summary: /_api/v3/users/invite
+   *        summary: /users/invite
    *        description: Create new users and send Emails
    *        description: Create new users and send Emails
    *        parameters:
    *        parameters:
    *          - name: shapedEmailList
    *          - name: shapedEmailList
@@ -178,11 +178,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/users/{id}/giveAdmin:
+   *    /users/{id}/giveAdmin:
    *      put:
    *      put:
-   *        tags: [Users, apiv3]
+   *        tags: [Users]
    *        operationId: giveAdminUser
    *        operationId: giveAdminUser
-   *        summary: /_api/v3/users/{id}/giveAdmin
+   *        summary: /users/{id}/giveAdmin
    *        description: Give user admin
    *        description: Give user admin
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -219,11 +219,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/users/{id}/removeAdmin:
+   *    /users/{id}/removeAdmin:
    *      put:
    *      put:
-   *        tags: [Users, apiv3]
+   *        tags: [Users]
    *        operationId: removeAdminUser
    *        operationId: removeAdminUser
-   *        summary: /_api/v3/users/{id}/removeAdmin
+   *        summary: /users/{id}/removeAdmin
    *        description: Remove user admin
    *        description: Remove user admin
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -260,11 +260,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/users/{id}/activate:
+   *    /users/{id}/activate:
    *      put:
    *      put:
-   *        tags: [Users, apiv3]
+   *        tags: [Users]
    *        operationId: activateUser
    *        operationId: activateUser
-   *        summary: /_api/v3/users/{id}/activate
+   *        summary: /users/{id}/activate
    *        description: Activate user
    *        description: Activate user
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -309,11 +309,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/users/{id}/deactivate:
+   *    /users/{id}/deactivate:
    *      put:
    *      put:
-   *        tags: [Users, apiv3]
+   *        tags: [Users]
    *        operationId: deactivateUser
    *        operationId: deactivateUser
-   *        summary: /_api/v3/users/{id}/deactivate
+   *        summary: /users/{id}/deactivate
    *        description: Deactivate user
    *        description: Deactivate user
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -350,11 +350,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/users/{id}/remove:
+   *    /users/{id}/remove:
    *      delete:
    *      delete:
-   *        tags: [Users, apiv3]
+   *        tags: [Users]
    *        operationId: removeUser
    *        operationId: removeUser
-   *        summary: /_api/v3/users/{id}/remove
+   *        summary: /users/{id}/remove
    *        description: Delete user
    *        description: Delete user
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id
@@ -395,11 +395,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/users/external-accounts:
+   *    /users/external-accounts:
    *      get:
    *      get:
-   *        tags: [Users, apiv3]
+   *        tags: [Users]
    *        operationId: listExternalAccountsUsers
    *        operationId: listExternalAccountsUsers
-   *        summary: /_api/v3/users/external-accounts
+   *        summary: /users/external-accounts
    *        description: Get external-account
    *        description: Get external-account
    *        responses:
    *        responses:
    *          200:
    *          200:
@@ -429,11 +429,11 @@ module.exports = (crowi) => {
    * @swagger
    * @swagger
    *
    *
    *  paths:
    *  paths:
-   *    /_api/v3/users/external-accounts/{id}/remove:
+   *    /users/external-accounts/{id}/remove:
    *      delete:
    *      delete:
-   *        tags: [Users, apiv3]
+   *        tags: [Users]
    *        operationId: removeExternalAccountUser
    *        operationId: removeExternalAccountUser
-   *        summary: /_api/v3/users/external-accounts/{id}/remove
+   *        summary: /users/external-accounts/{id}/remove
    *        description: Delete ExternalAccount
    *        description: Delete ExternalAccount
    *        parameters:
    *        parameters:
    *          - name: id
    *          - name: id

+ 193 - 13
src/server/routes/attachment.js

@@ -42,10 +42,6 @@ const ApiResponse = require('../util/apiResponse');
  *            type: string
  *            type: string
  *            description: original file name
  *            description: original file name
  *            example: file.txt
  *            example: file.txt
- *          filePath:
- *            type: string
- *            description: file path
- *            example: attachment/5e07345972560e001761fa63/6b0b3facf3628699263d760e18efd446.txt
  *          creator:
  *          creator:
  *            $ref: '#/components/schemas/User'
  *            $ref: '#/components/schemas/User'
  *          page:
  *          page:
@@ -64,6 +60,71 @@ const ApiResponse = require('../util/apiResponse');
  *            type: string
  *            type: string
  *            description: attachment URL
  *            description: attachment URL
  *            example: http://localhost/files/5e0734e072560e001761fa67
  *            example: http://localhost/files/5e0734e072560e001761fa67
+ *          filePathProxied:
+ *            type: string
+ *            description: file path proxied
+ *            example: "/attachment/5e0734e072560e001761fa67"
+ *          downloadPathProxied:
+ *            type: string
+ *            description: download path proxied
+ *            example: "/download/5e0734e072560e001761fa67"
+ */
+
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      AttachmentProfile:
+ *        description: Attachment
+ *        type: object
+ *        properties:
+ *          id:
+ *            type: string
+ *            description: attachment ID
+ *            example: 5e0734e072560e001761fa67
+ *          _id:
+ *            type: string
+ *            description: attachment ID
+ *            example: 5e0734e072560e001761fa67
+ *          __v:
+ *            type: number
+ *            description: attachment version
+ *            example: 0
+ *          fileFormat:
+ *            type: string
+ *            description: file format in MIME
+ *            example: image/png
+ *          fileName:
+ *            type: string
+ *            description: file name
+ *            example: 601b7c59d43a042c0117e08dd37aad0a.png
+ *          originalName:
+ *            type: string
+ *            description: original file name
+ *            example: profile.png
+ *          creator:
+ *            $ref: '#/components/schemas/User/properties/_id'
+ *          page:
+ *            type: string
+ *            description: page ID attached at
+ *            example: null
+ *          createdAt:
+ *            type: string
+ *            description: date created at
+ *            example: 2010-01-01T00:00:00.000Z
+ *          fileSize:
+ *            type: number
+ *            description: file size
+ *            example: 3494332
+ *          filePathProxied:
+ *            type: string
+ *            description: file path proxied
+ *            example: "/attachment/5e0734e072560e001761fa67"
+ *          downloadPathProxied:
+ *            type: string
+ *            description: download path proxied
+ *            example: "/download/5e0734e072560e001761fa67"
  */
  */
 
 
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
@@ -247,11 +308,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/attachments.list:
+   *    /attachments.list:
    *      get:
    *      get:
-   *        tags: [Attachments, apiv1]
+   *        tags: [Attachments, CrowiCompatibles]
    *        operationId: listAttachments
    *        operationId: listAttachments
-   *        summary: /_api/attachments.list
+   *        summary: /attachments.list
    *        description: Get list of attachments in page
    *        description: Get list of attachments in page
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query
@@ -302,6 +363,41 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success({ attachments }));
     return res.json(ApiResponse.success({ attachments }));
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /attachments.limit:
+   *      get:
+   *        tags: [Attachments]
+   *        operationId: getAttachmentsLimit
+   *        summary: /attachments.limit
+   *        description: Get available capacity of uploaded file with GridFS
+   *        parameters:
+   *          - in: query
+   *            name: fileSize
+   *            schema:
+   *              type: number
+   *              description: file size
+   *              example: 23175
+   *            required: true
+   *        responses:
+   *          200:
+   *            description: Succeeded to get available capacity of uploaded file with GridFS.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    isUploadable:
+   *                      type: boolean
+   *                      description: uploadable
+   *                      example: true
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {get} /attachments.limit get available capacity of uploaded file with GridFS
    * @api {get} /attachments.limit get available capacity of uploaded file with GridFS
    * @apiName AddAttachments
    * @apiName AddAttachments
@@ -315,11 +411,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/attachments.add:
+   *    /attachments.add:
    *      post:
    *      post:
-   *        tags: [Attachments, apiv1]
+   *        tags: [Attachments, CrowiCompatibles]
    *        operationId: addAttachment
    *        operationId: addAttachment
-   *        summary: /_api/attachments.add
+   *        summary: /attachments.add
    *        description: Add attachment to the page
    *        description: Add attachment to the page
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -438,6 +534,59 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success(result));
     return res.json(ApiResponse.success(result));
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /attachments.uploadProfileImage:
+   *      post:
+   *        tags: [Attachments]
+   *        operationId: uploadProfileImage
+   *        summary: /attachments.uploadProfileImage
+   *        description: Upload profile image
+   *        requestBody:
+   *          content:
+   *            "multipart/form-data":
+   *              schema:
+   *                properties:
+   *                  file:
+   *                    type: string
+   *                    format: binary
+   *                    description: attachment data
+   *                  user:
+   *                    type: string
+   *                    description: user to set profile image
+   *              encoding:
+   *                path:
+   *                  contentType: application/x-www-form-urlencoded
+   *            "*\/*":
+   *              schema:
+   *                properties:
+   *                  file:
+   *                    type: string
+   *                    format: binary
+   *                    description: attachment data
+   *                  user:
+   *                    type: string
+   *                    description: user to set profile
+   *              encoding:
+   *                path:
+   *                  contentType: application/x-www-form-urlencoded
+   *        responses:
+   *          200:
+   *            description: Succeeded to add attachment.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    attachment:
+   *                      $ref: '#/components/schemas/AttachmentProfile'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {post} /attachments.uploadProfileImage Add attachment for profile image
    * @api {post} /attachments.uploadProfileImage Add attachment for profile image
    * @apiName UploadProfileImage
    * @apiName UploadProfileImage
@@ -483,11 +632,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/attachments.remove:
+   *    /attachments.remove:
    *      post:
    *      post:
-   *        tags: [Attachments, apiv1]
+   *        tags: [Attachments, CrowiCompatibles]
    *        operationId: removeAttachment
    *        operationId: removeAttachment
-   *        summary: /_api/attachments.remove
+   *        summary: /attachments.remove
    *        description: Remove attachment
    *        description: Remove attachment
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -544,6 +693,37 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success({}));
     return res.json(ApiResponse.success({}));
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /attachments.removeProfileImage:
+   *      post:
+   *        tags: [Attachments]
+   *        operationId: removeProfileImage
+   *        summary: /attachments.removeProfileImage
+   *        description: Remove profile image
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  user:
+   *                    type: string
+   *                    description: user to remove profile image
+   *        responses:
+   *          200:
+   *            description: Succeeded to add attachment.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {post} /attachments.removeProfileImage Remove profile image attachments
    * @api {post} /attachments.removeProfileImage Remove profile image attachments
    * @apiGroup Attachment
    * @apiGroup Attachment

+ 9 - 48
src/server/routes/bookmark.js

@@ -43,11 +43,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/bookmarks.get:
+   *    /bookmarks.get:
    *      get:
    *      get:
-   *        tags: [Bookmarks, apiv1]
+   *        tags: [Bookmarks, CrowiCompatibles]
    *        operationId: getBookmark
    *        operationId: getBookmark
-   *        summary: /_api/bookmarks.get
+   *        summary: /bookmarks.get
    *        description: Get bookmark of the page with the user
    *        description: Get bookmark of the page with the user
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query
@@ -94,45 +94,6 @@ module.exports = function(crowi, app) {
       });
       });
   };
   };
 
 
-
-  /**
-   * @swagger
-   *
-   *    /_api/bookmarks.list:
-   *      get:
-   *        tags: [Bookmarks, apiv1]
-   *        operationId: listBookmarks
-   *        summary: /_api/bookmarks.list
-   *        description: Get bookmark list of the page with the user
-   *        parameters:
-   *          - in: query
-   *            name: limit
-   *            schema:
-   *              $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/limit'
-   *          - in: query
-   *            name: offset
-   *            schema:
-   *              $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/offset'
-   *        responses:
-   *          200:
-   *            description: Succeeded to get bookmark of the page with the user.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    meta:
-   *                      $ref: '#/components/schemas/V1PaginateResult/properties/meta'
-   *                    data:
-   *                      type: array
-   *                      items:
-   *                        $ref: '#/components/schemas/V1PaginateResult/properties/meta'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
   actions.api.list = function(req, res) {
   actions.api.list = function(req, res) {
     const paginateOptions = ApiPaginate.parseOptions(req.query);
     const paginateOptions = ApiPaginate.parseOptions(req.query);
 
 
@@ -149,11 +110,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/bookmarks.add:
+   *    /bookmarks.add:
    *      post:
    *      post:
-   *        tags: [Bookmarks, apiv1]
+   *        tags: [Bookmarks, CrowiCompatibles]
    *        operationId: addBookmark
    *        operationId: addBookmark
-   *        summary: /_api/bookmarks.add
+   *        summary: /bookmarks.add
    *        description: Add bookmark of the page
    *        description: Add bookmark of the page
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query
@@ -204,11 +165,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/bookmarks.remove:
+   *    /bookmarks.remove:
    *      post:
    *      post:
-   *        tags: [Bookmarks, apiv1]
+   *        tags: [Bookmarks, CrowiCompatibles]
    *        operationId: removeBookmark
    *        operationId: removeBookmark
-   *        summary: /_api/bookmarks.remove
+   *        summary: /bookmarks.remove
    *        description: Remove bookmark of the page
    *        description: Remove bookmark of the page
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:

+ 12 - 12
src/server/routes/comment.js

@@ -62,11 +62,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/comments.get:
+   *    /comments.get:
    *      get:
    *      get:
-   *        tags: [Comments, apiv1]
+   *        tags: [Comments, CrowiCompatibles]
    *        operationId: getComments
    *        operationId: getComments
-   *        summary: /_api/comments.get
+   *        summary: /comments.get
    *        description: Get comments of the page of the revision
    *        description: Get comments of the page of the revision
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query
@@ -156,11 +156,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/comments.add:
+   *    /comments.add:
    *      post:
    *      post:
-   *        tags: [Comments, apiv1]
+   *        tags: [Comments, CrowiCompatibles]
    *        operationId: addComment
    *        operationId: addComment
-   *        summary: /_api/comments.add
+   *        summary: /comments.add
    *        description: Post comment for the page
    *        description: Post comment for the page
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -285,11 +285,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/comments.update:
+   *    /comments.update:
    *      post:
    *      post:
-   *        tags: [Comments, apiv1]
+   *        tags: [Comments, CrowiCompatibles]
    *        operationId: updateComment
    *        operationId: updateComment
-   *        summary: /_api/comments.update
+   *        summary: /comments.update
    *        description: Update comment dody
    *        description: Update comment dody
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -377,11 +377,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/comments.remove:
+   *    /comments.remove:
    *      post:
    *      post:
-   *        tags: [Comments, apiv1]
+   *        tags: [Comments, CrowiCompatibles]
    *        operationId: removeComment
    *        operationId: removeComment
-   *        summary: /_api/comments.remove
+   *        summary: /comments.remove
    *        description: Remove specified comment
    *        description: Remove specified comment
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:

+ 128 - 0
src/server/routes/hackmd.js

@@ -8,6 +8,26 @@ const axios = require('axios');
 
 
 const ApiResponse = require('../util/apiResponse');
 const ApiResponse = require('../util/apiResponse');
 
 
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      Hackmd:
+ *        description: Hackmd
+ *        type: object
+ *        properties:
+ *          pageIdOnHackmd:
+ *            type: string
+ *            description: page ID on HackMD
+ *            example: qLnodHLxT6C3hVEVczvbDQ
+ *          revisionIdHackmdSynced:
+ *            $ref: '#/components/schemas/Revision/properties/_id'
+ *          hasDraftOnHackmd:
+ *            type: boolean
+ *            description: has draft on HackMD
+ *            example: false
+ */
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
   const Page = crowi.models.Page;
   const Page = crowi.models.Page;
   const pageEvent = crowi.event('page');
   const pageEvent = crowi.event('page');
@@ -105,6 +125,44 @@ module.exports = function(crowi, app) {
     next();
     next();
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /hackmd.integrate:
+   *      post:
+   *        tags: [Hackmd]
+   *        operationId: integrateHackmd
+   *        summary: /hackmd.integrate
+   *        description: Integrate hackmd
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  pageId:
+   *                    $ref: '#/components/schemas/Page/properties/_id'
+   *                  page:
+   *                    $ref: '#/components/schemas/Hackmd'
+   *        responses:
+   *          200:
+   *            description: Succeeded to integrate HackMD.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    pageIdOnHackmd:
+   *                      $ref: '#/components/schemas/Hackmd/properties/pageIdOnHackmd'
+   *                    revisionIdHackmdSynced:
+   *                      $ref: '#/components/schemas/Hackmd/properties/revisionIdHackmdSynced'
+   *                    hasDraftOnHackmd:
+   *                      $ref: '#/components/schemas/Hackmd/properties/hasDraftOnHackmd'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * POST /_api/hackmd.integrate
    * POST /_api/hackmd.integrate
    *
    *
@@ -180,6 +238,44 @@ module.exports = function(crowi, app) {
     }
     }
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /hackmd.discard:
+   *      post:
+   *        tags: [Hackmd]
+   *        operationId: discardHackmd
+   *        summary: /hackmd.discard
+   *        description: Discard hackmd
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  pageId:
+   *                    $ref: '#/components/schemas/Page/properties/_id'
+   *                  page:
+   *                    $ref: '#/components/schemas/Hackmd'
+   *        responses:
+   *          200:
+   *            description: Succeeded to integrate HackMD.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    pageIdOnHackmd:
+   *                      $ref: '#/components/schemas/Hackmd/properties/pageIdOnHackmd'
+   *                    revisionIdHackmdSynced:
+   *                      $ref: '#/components/schemas/Hackmd/properties/revisionIdHackmdSynced'
+   *                    hasDraftOnHackmd:
+   *                      $ref: '#/components/schemas/Hackmd/properties/hasDraftOnHackmd'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * POST /_api/hackmd.discard
    * POST /_api/hackmd.discard
    *
    *
@@ -206,6 +302,38 @@ module.exports = function(crowi, app) {
     }
     }
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /hackmd.saveOnHackmd:
+   *      post:
+   *        tags: [Hackmd]
+   *        operationId: saveOnHackmd
+   *        summary: /hackmd.saveOnHackmd
+   *        description: Receive when save operation triggered on HackMD
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  pageId:
+   *                    $ref: '#/components/schemas/Page/properties/_id'
+   *                  page:
+   *                    $ref: '#/components/schemas/Hackmd'
+   *        responses:
+   *          200:
+   *            description: Succeeded to receive when save operation triggered on HackMD.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * POST /_api/hackmd.saveOnHackmd
    * POST /_api/hackmd.saveOnHackmd
    *
    *

+ 77 - 0
src/server/routes/me.js

@@ -1,3 +1,53 @@
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      UserGroup:
+ *        description: UserGroup
+ *        type: object
+ *        properties:
+ *          __v:
+ *            type: number
+ *            description: record version
+ *            example: 0
+ *          _id:
+ *            type: string
+ *            description: user group ID
+ *            example: 5e2d56c1e35da4004ef7e0b0
+ *          createdAt:
+ *            type: string
+ *            description: date created at
+ *            example: 2010-01-01T00:00:00.000Z
+ */
+
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      UserGroupRelation:
+ *        description: UserGroupRelation
+ *        type: object
+ *        properties:
+ *          __v:
+ *            type: number
+ *            description: record version
+ *            example: 0
+ *          _id:
+ *            type: string
+ *            description: user group relation ID
+ *            example: 5e2d56cbe35da4004ef7e0b1
+ *          relatedGroup:
+ *            $ref: '#/components/schemas/UserGroup'
+ *          relatedUser:
+ *            $ref: '#/components/schemas/User/properties/_id'
+ *          createdAt:
+ *            type: string
+ *            description: date created at
+ *            example: 2010-01-01T00:00:00.000Z
+ */
+
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
   const debug = require('debug')('growi:routes:me');
   const debug = require('debug')('growi:routes:me');
   const logger = require('@alias/logger')('growi:routes:me');
   const logger = require('@alias/logger')('growi:routes:me');
@@ -14,6 +64,33 @@ module.exports = function(crowi, app) {
   const api = {};
   const api = {};
   actions.api = api;
   actions.api = api;
 
 
+  /**
+   * @swagger
+   *
+   *   /me/user-group-relations:
+   *     get:
+   *       tags: [Me, CrowiCompatibles]
+   *       operationId: getUserGroupRelations
+   *       summary: /me/user-group-relations
+   *       description: Get user group relations
+   *       responses:
+   *         200:
+   *           description: Succeeded to get user group relations.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 properties:
+   *                   ok:
+   *                     $ref: '#/components/schemas/V1Response/properties/ok'
+   *                   userGroupRelations:
+   *                     type: array
+   *                     items:
+   *                       $ref: '#/components/schemas/UserGroupRelation'
+   *         403:
+   *           $ref: '#/components/responses/403'
+   *         500:
+   *           $ref: '#/components/responses/500'
+   */
   /**
   /**
    * retrieve user-group-relation documents
    * retrieve user-group-relation documents
    * @param {object} req
    * @param {object} req

+ 181 - 27
src/server/routes/page.js

@@ -645,11 +645,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/pages.list:
+   *    /pages.list:
    *      get:
    *      get:
-   *        tags: [Pages, apiv1]
+   *        tags: [Pages, CrowiCompatibles]
    *        operationId: listPages
    *        operationId: listPages
-   *        summary: /_api/pages.list
+   *        summary: /pages.list
    *        description: Get list of pages
    *        description: Get list of pages
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query
@@ -661,6 +661,10 @@ module.exports = function(crowi, app) {
    *            schema:
    *            schema:
    *              $ref: '#/components/schemas/User/properties/username'
    *              $ref: '#/components/schemas/User/properties/username'
    *          - in: query
    *          - in: query
+   *            name: limit
+   *            schema:
+   *              $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/limit'
+   *          - in: query
    *            name: offset
    *            name: offset
    *            schema:
    *            schema:
    *              $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/offset'
    *              $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/offset'
@@ -735,11 +739,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/pages.create:
+   *    /pages.create:
    *      post:
    *      post:
-   *        tags: [Pages, apiv1]
+   *        tags: [Pages, CrowiCompatibles]
    *        operationId: createPage
    *        operationId: createPage
-   *        summary: /_api/pages.create
+   *        summary: /pages.create
    *        description: Create page
    *        description: Create page
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -844,11 +848,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/pages.update:
+   *    /pages.update:
    *      post:
    *      post:
-   *        tags: [Pages, apiv1]
+   *        tags: [Pages, CrowiCompatibles]
    *        operationId: updatePage
    *        operationId: updatePage
-   *        summary: /_api/pages.update
+   *        summary: /pages.update
    *        description: Update page
    *        description: Update page
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -972,11 +976,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/pages.get:
+   *    /pages.get:
    *      get:
    *      get:
-   *        tags: [Pages, apiv1]
+   *        tags: [Pages, CrowiCompatibles]
    *        operationId: getPage
    *        operationId: getPage
-   *        summary: /_api/pages.get
+   *        summary: /pages.get
    *        description: Get page data
    *        description: Get page data
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query
@@ -1052,6 +1056,40 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success(result));
     return res.json(ApiResponse.success(result));
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /pages.exist:
+   *      get:
+   *        tags: [Pages]
+   *        operationId: getPageExistence
+   *        summary: /pages.exist
+   *        description: Get page existence
+   *        parameters:
+   *          - in: query
+   *            name: pages
+   *            schema:
+   *              type: string
+   *              description: Page paths specified by hash key in JSON format
+   *              example: '{"/": "unused value", "/user/unknown": "unused value"}'
+   *        responses:
+   *          200:
+   *            description: Succeeded to get page existence.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    pages:
+   *                      type: string
+   *                      description: Properties of page path and existence
+   *                      example: '{"/": true, "/user/unknown": false}'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {get} /pages.exist Get if page exists
    * @api {get} /pages.exist Get if page exists
    * @apiName GetPage
    * @apiName GetPage
@@ -1075,6 +1113,36 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success(result));
     return res.json(ApiResponse.success(result));
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /pages.getPageTag:
+   *      get:
+   *        tags: [Pages]
+   *        operationId: getPageTag
+   *        summary: /pages.getPageTag
+   *        description: Get page tag
+   *        parameters:
+   *          - in: query
+   *            name: pageId
+   *            schema:
+   *              $ref: '#/components/schemas/Page/properties/_id'
+   *        responses:
+   *          200:
+   *            description: Succeeded to get page tags.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    tags:
+   *                      $ref: '#/components/schemas/Tags'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {get} /pages.getPageTag get page tags
    * @api {get} /pages.getPageTag get page tags
    * @apiName GetPageTag
    * @apiName GetPageTag
@@ -1096,11 +1164,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/pages.seen:
+   *    /pages.seen:
    *      post:
    *      post:
-   *        tags: [Pages, apiv1]
+   *        tags: [Pages, CrowiCompatibles]
    *        operationId: seenPage
    *        operationId: seenPage
-   *        summary: /_api/pages.seen
+   *        summary: /pages.seen
    *        description: Mark as seen user
    *        description: Mark as seen user
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -1165,11 +1233,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/likes.add:
+   *    /likes.add:
    *      post:
    *      post:
-   *        tags: [Pages, apiv1]
+   *        tags: [Likes, CrowiCompatibles]
    *        operationId: addLike
    *        operationId: addLike
-   *        summary: /_api/likes.add
+   *        summary: /likes.add
    *        description: Like page
    *        description: Like page
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -1241,11 +1309,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/likes.remove:
+   *    /likes.remove:
    *      post:
    *      post:
-   *        tags: [Pages, apiv1]
+   *        tags: [Likes, CrowiCompatibles]
    *        operationId: removeLike
    *        operationId: removeLike
-   *        summary: /_api/likes.remove
+   *        summary: /likes.remove
    *        description: Unlike page
    *        description: Unlike page
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -1309,11 +1377,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/pages.updatePost:
+   *    /pages.updatePost:
    *      get:
    *      get:
-   *        tags: [Pages, apiv1]
+   *        tags: [Pages, CrowiCompatibles]
    *        operationId: getUpdatePostPage
    *        operationId: getUpdatePostPage
-   *        summary: /_api/pages.updatePost
+   *        summary: /pages.updatePost
    *        description: Get UpdatePost setting list
    *        description: Get UpdatePost setting list
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query
@@ -1477,11 +1545,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/pages.rename:
+   *    /pages.rename:
    *      post:
    *      post:
-   *        tags: [Pages, apiv1]
+   *        tags: [Pages, CrowiCompatibles]
    *        operationId: renamePage
    *        operationId: renamePage
-   *        summary: /_api/pages.rename
+   *        summary: /pages.rename
    *        description: Rename page
    *        description: Rename page
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
@@ -1592,6 +1660,44 @@ module.exports = function(crowi, app) {
     return page;
     return page;
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /pages.duplicate:
+   *      post:
+   *        tags: [Pages]
+   *        operationId: duplicatePage
+   *        summary: /pages.duplicate
+   *        description: Duplicate page
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  page_id:
+   *                    $ref: '#/components/schemas/Page/properties/_id'
+   *                  new_path:
+   *                    $ref: '#/components/schemas/Page/properties/path'
+   *                required:
+   *                  - page_id
+   *        responses:
+   *          200:
+   *            description: Succeeded to duplicate page.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    page:
+   *                      $ref: '#/components/schemas/Page'
+   *                    tags:
+   *                      $ref: '#/components/schemas/Tags'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {post} /pages.duplicate Duplicate page
    * @api {post} /pages.duplicate Duplicate page
    * @apiName DuplicatePage
    * @apiName DuplicatePage
@@ -1650,6 +1756,54 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success(result));
     return res.json(ApiResponse.success(result));
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /pages.recentCreated:
+   *      get:
+   *        tags: [Pages]
+   *        operationId: getRecentCreatedPages
+   *        summary: /pages.recentCreated
+   *        description: Get recent created page list
+   *        parameters:
+   *          - in: query
+   *            name: page_id
+   *            required: true
+   *            schema:
+   *              $ref: '#/components/schemas/Page/properties/_id'
+   *          - in: query
+   *            name: offset
+   *            schema:
+   *              $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/offset'
+   *          - in: query
+   *            name: limit
+   *            schema:
+   *              $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/limit'
+   *        responses:
+   *          200:
+   *            description: Succeeded to get recent created page list.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    pages:
+   *                      type: array
+   *                      description: recent created page list
+   *                      items:
+   *                        $ref: '#/components/schemas/Page'
+   *                    totalCount:
+   *                      $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/total'
+   *                    offset:
+   *                      $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/offset'
+   *                    limit:
+   *                      $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/limit'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   api.recentCreated = async function(req, res) {
   api.recentCreated = async function(req, res) {
     const pageId = req.query.page_id;
     const pageId = req.query.page_id;
 
 

+ 12 - 12
src/server/routes/revision.js

@@ -58,11 +58,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/revisions.get:
+   *    /revisions.get:
    *      get:
    *      get:
-   *        tags: [Revisions, apiv1]
-   *        operationId: /_api/revisions.get
-   *        summary: /_api/revisions.get
+   *        tags: [Revisions, CrowiCompatibles]
+   *        operationId: revisions.get
+   *        summary: /revisions.get
    *        description: Get revision
    *        description: Get revision
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query
@@ -126,11 +126,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/revisions.ids:
+   *    /revisions.ids:
    *      get:
    *      get:
-   *        tags: [Revisions, apiv1]
-   *        operationId: /_api/revisions.ids
-   *        summary: /_api/revisions.ids
+   *        tags: [Revisions, CrowiCompatibles]
+   *        operationId: revisions.ids
+   *        summary: /revisions.ids
    *        description: Get revision id list of the page
    *        description: Get revision id list of the page
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query
@@ -187,11 +187,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/revisions.list:
+   *    /revisions.list:
    *      get:
    *      get:
-   *        tags: [Revisions, apiv1]
-   *        operationId: /_api/revisions.list
-   *        summary: /_api/revisions.list
+   *        tags: [Revisions, CrowiCompatibles]
+   *        operationId: revisions.list
+   *        summary: /revisions.list
    *        description: Get revisions
    *        description: Get revisions
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query

+ 80 - 0
src/server/routes/search.js

@@ -1,3 +1,29 @@
+/**
+ * @swagger
+ *
+ *   components:
+ *     schemas:
+ *       ElasticsearchResult:
+ *         description: Elasticsearch result v1
+ *         type: object
+ *         properties:
+ *           meta:
+ *             type: object
+ *             properties:
+ *               took:
+ *                 type: number
+ *                 description: Time Elasticsearch took to execute a search(milliseconds)
+ *                 example: 34
+ *               total:
+ *                 type: number
+ *                 description: Number of documents matching search criteria
+ *                 example: 2
+ *               results:
+ *                 type: number
+ *                 description: Actual array length of search results
+ *                 example: 2
+ *
+ */
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
   // var debug = require('debug')('growi:routes:search')
   // var debug = require('debug')('growi:routes:search')
   const Page = crowi.model('Page');
   const Page = crowi.model('Page');
@@ -19,6 +45,60 @@ module.exports = function(crowi, app) {
     });
     });
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *   /search:
+   *     get:
+   *       tags: [Search, CrowiCompatibles]
+   *       operationId: searchPages
+   *       summary: /search
+   *       description: Search pages
+   *       parameters:
+   *         - in: query
+   *           name: q
+   *           schema:
+   *             type: string
+   *             description: keyword
+   *             example: daily report
+   *           required: true
+   *         - in: query
+   *           name: path
+   *           schema:
+   *             $ref: '#/components/schemas/Page/properties/path'
+   *         - in: query
+   *           name: offset
+   *           schema:
+   *             $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/offset'
+   *         - in: query
+   *           name: limit
+   *           schema:
+   *             $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/limit'
+   *       responses:
+   *         200:
+   *           description: Succeeded to get list of pages.
+   *           content:
+   *             application/json:
+   *               schema:
+   *                 properties:
+   *                   ok:
+   *                     $ref: '#/components/schemas/V1Response/properties/ok'
+   *                   meta:
+   *                     $ref: '#/components/schemas/ElasticsearchResult/properties/meta'
+   *                   totalCount:
+   *                     type: integer
+   *                     description: total count of pages
+   *                     example: 35
+   *                   data:
+   *                     type: array
+   *                     items:
+   *                       $ref: '#/components/schemas/Page'
+   *                     description: page list
+   *         403:
+   *           $ref: '#/components/responses/403'
+   *         500:
+   *           $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {get} /search search page
    * @api {get} /search search page
    * @apiName Search
    * @apiName Search

+ 132 - 0
src/server/routes/tag.js

@@ -1,3 +1,32 @@
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      Tags:
+ *        description: Tags
+ *        type: array
+ *        items:
+ *          $ref: '#/components/schemas/Tag/properties/name'
+ *        example: ['daily', 'report', 'tips']
+ *
+ *      Tag:
+ *        description: Tag
+ *        type: object
+ *        properties:
+ *          _id:
+ *            type: string
+ *            description: tag ID
+ *            example: 5e2d6aede35da4004ef7e0b7
+ *          name:
+ *            type: string
+ *            description: tag name
+ *            example: daily
+ *          count:
+ *            type: number
+ *            description: Count of tagged pages
+ *            example: 3
+ */
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
 
 
   const Tag = crowi.model('Tag');
   const Tag = crowi.model('Tag');
@@ -12,6 +41,39 @@ module.exports = function(crowi, app) {
     return res.render('tags');
     return res.render('tags');
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /tags.search:
+   *      get:
+   *        tags: [Tags]
+   *        operationId: searchTags
+   *        summary: /tags.search
+   *        description: Search tags
+   *        parameters:
+   *          - in: query
+   *            name: q
+   *            schema:
+   *              type: string
+   *              description: keyword
+   *              example: daily
+   *            description: keyword to search
+   *        responses:
+   *          200:
+   *            description: Succeeded to tag list.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    tags:
+   *                      $ref: '#/components/schemas/Tags'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {get} /tags.search search tags
    * @api {get} /tags.search search tags
    * @apiName SearchTag
    * @apiName SearchTag
@@ -25,6 +87,40 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success({ tags }));
     return res.json(ApiResponse.success({ tags }));
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /tags.update:
+   *      post:
+   *        tags: [Tags]
+   *        operationId: updateTag
+   *        summary: /tags.update
+   *        description: Update tag
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  pageId:
+   *                    $ref: '#/components/schemas/Page/properties/_id'
+   *                  tags:
+   *                    $ref: '#/components/schemas/Tags'
+   *        responses:
+   *          200:
+   *            description: Succeeded to update tag.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    tags:
+   *                      $ref: '#/components/schemas/Tags'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {post} /tags.update update tags on view-mode (not edit-mode)
    * @api {post} /tags.update update tags on view-mode (not edit-mode)
    * @apiName UpdateTag
    * @apiName UpdateTag
@@ -55,6 +151,42 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success(result));
     return res.json(ApiResponse.success(result));
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /tags.list:
+   *      get:
+   *        tags: [Tags]
+   *        operationId: listTags
+   *        summary: /tags.list
+   *        description: Get tags
+   *        parameters:
+   *          - in: query
+   *            name: limit
+   *            schema:
+   *              $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/limit'
+   *          - in: query
+   *            name: offset
+   *            schema:
+   *              $ref: '#/components/schemas/V1PaginateResult/properties/meta/properties/offset'
+   *        responses:
+   *          200:
+   *            description: Succeeded to tag list.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    ok:
+   *                      $ref: '#/components/schemas/V1Response/properties/ok'
+   *                    data:
+   *                      type: array
+   *                      items:
+   *                        $ref: '#/components/schemas/Tag'
+   *          403:
+   *            $ref: '#/components/responses/403'
+   *          500:
+   *            $ref: '#/components/responses/500'
+   */
   /**
   /**
    * @api {get} /tags.list get tagnames and count pages relate each tag
    * @api {get} /tags.list get tagnames and count pages relate each tag
    * @apiName tagList
    * @apiName tagList

+ 50 - 3
src/server/routes/user.js

@@ -1,3 +1,50 @@
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      User:
+ *        description: User
+ *        type: object
+ *        properties:
+ *          __v:
+ *            type: number
+ *            description: record version
+ *            example: 0
+ *          _id:
+ *            type: string
+ *            description: user ID
+ *            example: 5ae5fccfc5577b0004dbd8ab
+ *          lang:
+ *            type: string
+ *            description: language
+ *            example: 'en-US'
+ *          status:
+ *            type: integer
+ *            description: status
+ *            example: 0
+ *          admin:
+ *            type: boolean
+ *            description: whether the admin
+ *            example: false
+ *          email:
+ *            type: string
+ *            description: E-Mail address
+ *            example: alice@aaa.aaa
+ *          username:
+ *            type: string
+ *            description: username
+ *            example: alice
+ *          name:
+ *            type: string
+ *            description: full name
+ *            example: Alice
+ *          createdAt:
+ *            type: string
+ *            description: date created at
+ *            example: 2010-01-01T00:00:00.000Z
+ */
+
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
   const User = crowi.model('User');
   const User = crowi.model('User');
   const Bookmark = crowi.model('Bookmark');
   const Bookmark = crowi.model('Bookmark');
@@ -39,11 +86,11 @@ module.exports = function(crowi, app) {
   /**
   /**
    * @swagger
    * @swagger
    *
    *
-   *    /_api/users.list:
+   *    /users.list:
    *      get:
    *      get:
-   *        tags: [Users, apiv1]
+   *        tags: [Users, CrowiCompatibles]
    *        operationId: listUsersV1
    *        operationId: listUsersV1
-   *        summary: /_api/users.list
+   *        summary: /users.list
    *        description: Get list of users
    *        description: Get list of users
    *        parameters:
    *        parameters:
    *          - in: query
    *          - in: query

+ 27 - 42
src/server/service/search-delegator/elasticsearch.js

@@ -21,9 +21,6 @@ class ElasticsearchDelegator {
     this.configManager = configManager;
     this.configManager = configManager;
     this.searchEvent = searchEvent;
     this.searchEvent = searchEvent;
 
 
-    this.esVersion = 'unknown';
-    this.esNodeInfos = {};
-
     this.client = null;
     this.client = null;
 
 
     // In Elasticsearch RegExp, we don't need to used ^ and $.
     // In Elasticsearch RegExp, we don't need to used ^ and $.
@@ -68,11 +65,33 @@ class ElasticsearchDelegator {
     this.indexName = indexName;
     this.indexName = indexName;
   }
   }
 
 
-  getInfo() {
-    return {
-      esVersion: this.esVersion,
-      esNodeInfos: this.esNodeInfos,
-    };
+  async getInfo() {
+    const info = await this.client.nodes.info();
+    if (!info._nodes || !info.nodes) {
+      throw new Error('There is no nodes');
+    }
+
+    let esVersion = 'unknown';
+    const esNodeInfos = {};
+
+    for (const [nodeName, nodeInfo] of Object.entries(info.nodes)) {
+      esVersion = nodeInfo.version;
+
+      const filteredInfo = {
+        name: nodeInfo.name,
+        version: nodeInfo.version,
+        plugins: nodeInfo.plugins.map((pluginInfo) => {
+          return {
+            name: pluginInfo.name,
+            version: pluginInfo.version,
+          };
+        }),
+      };
+
+      esNodeInfos[nodeName] = filteredInfo;
+    }
+
+    return { esVersion, esNodeInfos };
   }
   }
 
 
   /**
   /**
@@ -156,41 +175,7 @@ class ElasticsearchDelegator {
     await client.indices.delete({ index: tmpIndexName });
     await client.indices.delete({ index: tmpIndexName });
   }
   }
 
 
-  /**
-   * retrieve elasticsearch node information
-   */
-  async checkESVersion() {
-    try {
-      const info = await this.client.nodes.info();
-      if (!info._nodes || !info.nodes) {
-        throw new Error('no nodes info');
-      }
-
-      for (const [nodeName, nodeInfo] of Object.entries(info.nodes)) {
-        this.esVersion = nodeInfo.version;
-
-        const filteredInfo = {
-          name: nodeInfo.name,
-          version: nodeInfo.version,
-          plugins: nodeInfo.plugins.map((pluginInfo) => {
-            return {
-              name: pluginInfo.name,
-              version: pluginInfo.version,
-            };
-          }),
-        };
-
-        this.esNodeInfos[nodeName] = filteredInfo;
-      }
-    }
-    catch (error) {
-      logger.error('Couldn\'t check ES version:', error);
-    }
-  }
-
   async initIndices() {
   async initIndices() {
-    await this.checkESVersion();
-
     const { client, indexName, aliasName } = this;
     const { client, indexName, aliasName } = this;
 
 
     const tmpIndexName = `${indexName}-tmp`;
     const tmpIndexName = `${indexName}-tmp`;

+ 1 - 1
src/server/service/search.js

@@ -64,7 +64,7 @@ class SearchService {
     tagEvent.on('update', this.delegator.syncTagChanged.bind(this.delegator));
     tagEvent.on('update', this.delegator.syncTagChanged.bind(this.delegator));
   }
   }
 
 
-  getInfo() {
+  async getInfo() {
     return this.delegator.getInfo();
     return this.delegator.getInfo();
   }
   }