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

Merge remote-tracking branch 'origin/imprv/abolish-old-config-api' into imprv/normalize-test

# Conflicts:
#	yarn.lock
Yuki Takei 6 лет назад
Родитель
Сommit
efeb9bb050
73 измененных файлов с 208 добавлено и 1003 удалено
  1. 3 0
      config/migrate.js
  2. 0 1
      package.json
  3. 3 38
      resource/locales/en-US/translation.json
  4. 2 37
      resource/locales/ja/translation.json
  5. 12 0
      src/lib/util/mongoose-utils.js
  6. 3 2
      src/migrations/20180926134048-make-email-unique.js
  7. 4 3
      src/migrations/20180927102719-init-serverurl.js
  8. 6 5
      src/migrations/20181019114028-abolish-page-group-relation.js
  9. 31 0
      src/migrations/20190618055300-abolish-crowi-classic-auth.js
  10. 5 10
      src/migrations/20190618104011-add-config-app-installed.js
  11. 4 12
      src/server/crowi/express-init.js
  12. 0 7
      src/server/crowi/index.js
  13. 0 8
      src/server/form/admin/securityGoogle.js
  14. 0 7
      src/server/form/admin/securityMechanism.js
  15. 0 2
      src/server/form/index.js
  16. 0 2
      src/server/form/register.js
  17. 0 1
      src/server/models/config.js
  18. 1 0
      src/server/models/index.js
  19. 5 6
      src/server/models/user.js
  20. 11 13
      src/server/routes/admin.js
  21. 12 26
      src/server/routes/index.js
  22. 7 118
      src/server/routes/login.js
  23. 0 67
      src/server/routes/me.js
  24. 0 70
      src/server/util/googleAuth.js
  25. 0 20
      src/server/util/middlewares.js
  26. 0 1
      src/server/util/slack.js
  27. 4 70
      src/server/util/swigFunctions.js
  28. 3 3
      src/server/views/admin/app.html
  29. 7 7
      src/server/views/admin/customize.html
  30. 1 1
      src/server/views/admin/external-accounts.html
  31. 1 1
      src/server/views/admin/global-notification-detail.html
  32. 1 1
      src/server/views/admin/importer.html
  33. 1 1
      src/server/views/admin/index.html
  34. 1 1
      src/server/views/admin/markdown.html
  35. 1 1
      src/server/views/admin/notification.html
  36. 1 1
      src/server/views/admin/search.html
  37. 4 141
      src/server/views/admin/security.html
  38. 1 1
      src/server/views/admin/user-group-detail.html
  39. 1 1
      src/server/views/admin/user-groups.html
  40. 1 1
      src/server/views/admin/users.html
  41. 1 2
      src/server/views/admin/widget/passport/github.html
  42. 1 2
      src/server/views/admin/widget/passport/google-oauth.html
  43. 1 2
      src/server/views/admin/widget/passport/oidc.html
  44. 1 2
      src/server/views/admin/widget/passport/saml.html
  45. 1 2
      src/server/views/admin/widget/passport/twitter.html
  46. 2 2
      src/server/views/customlayout-selector/forbidden.html
  47. 2 2
      src/server/views/customlayout-selector/not_creatable.html
  48. 2 2
      src/server/views/customlayout-selector/not_found.html
  49. 2 2
      src/server/views/customlayout-selector/page.html
  50. 2 2
      src/server/views/customlayout-selector/page_list.html
  51. 2 2
      src/server/views/customlayout-selector/user_page.html
  52. 3 3
      src/server/views/installer.html
  53. 2 2
      src/server/views/invited.html
  54. 1 1
      src/server/views/layout-crowi/base/layout.html
  55. 1 1
      src/server/views/layout-growi/page.html
  56. 1 1
      src/server/views/layout-growi/user_page.html
  57. 1 1
      src/server/views/layout-growi/widget/header.html
  58. 1 1
      src/server/views/layout-kibela/page.html
  59. 1 1
      src/server/views/layout-kibela/user_page.html
  60. 1 1
      src/server/views/layout-kibela/widget/header.html
  61. 6 6
      src/server/views/layout/layout.html
  62. 16 49
      src/server/views/login.html
  63. 1 1
      src/server/views/login/error.html
  64. 1 3
      src/server/views/me/api_token.html
  65. 1 1
      src/server/views/me/external-accounts.html
  66. 1 52
      src/server/views/me/index.html
  67. 1 3
      src/server/views/me/password.html
  68. 3 3
      src/server/views/page_presentation.html
  69. 0 7
      src/server/views/widget/alert_breaking_changes.html
  70. 2 2
      src/server/views/widget/page_content.html
  71. 2 2
      src/server/views/widget/page_list_and_timeline.html
  72. 2 2
      src/server/views/widget/page_list_and_timeline_kibela.html
  73. 6 151
      yarn.lock

+ 3 - 0
config/migrate.js

@@ -5,6 +5,8 @@
  * @author Yuki Takei <yuki@weseek.co.jp>
  */
 
+require('module-alias/register');
+
 function getMongoUri(env) {
   return env.MONGOLAB_URI // for B.C.
     || env.MONGODB_URI // MONGOLAB changes their env name
@@ -15,6 +17,7 @@ function getMongoUri(env) {
 
 const mongoUri = getMongoUri(process.env);
 const match = mongoUri.match(/^(.+)\/([^/]+)$/);
+
 module.exports = {
   mongoUri,
   mongodb: {

+ 0 - 1
package.json

@@ -88,7 +88,6 @@
     "express-session": "^1.16.1",
     "express-validator": "^5.3.1",
     "express-webpack-assets": "^0.1.0",
-    "googleapis": "^40.0.0",
     "graceful-fs": "^4.1.11",
     "growi-commons": "^4.0.1",
     "helmet": "^3.13.0",

+ 3 - 38
resource/locales/en-US/translation.json

@@ -81,9 +81,7 @@
   "Delete this image?": "Delete this image?",
   "Updated": "Updated",
   "Upload new image": "Upload new image",
-  "Google Setting": "Google Setting",
   "Connected": "Connected",
-  "Disconnect": "Disconnect",
   "Show": "Show",
   "Hide": "Hide",
   "Disclose E-mail": "Disclose E-mail",
@@ -124,7 +122,6 @@
   "Reselect the group": "Reselect the group",
   "Shareable link": "Shareable link",
   "The whitelist of registration permission E-mail address": "The whitelist of registration permission E-mail address",
-  "Selecting authentication mechanism": "Selecting authentication mechanism",
   "Add tags for this page": "Add tags for this page",
   "Edit tags for this page": "Edit tags for this page",
   "You have no tag, You can set tags on pages": "You have no tag, You can set tags on pages",
@@ -149,15 +146,13 @@
   },
 
   "breaking_changes": {
-    "v346_passport_is_not_enabled": "Crowi Classic Authentication mechanism currently in use will <strong>no longer be supported</strong> in the near future. Switch to Passport from %s",
     "v346_using_basic_auth": "Basic Authentication currently in use will <strong>no longer be available</strong> in the near future. Remove settings from %s"
   },
 
   "page_register": {
     "notice": {
       "restricted": "Admin approval required.",
-      "restricted_defail": "Once the admin approves your sign up, you'll be able to access this wiki.",
-      "google_account_continue": "Enter your user ID, name and password to continue."
+      "restricted_defail": "Once the admin approves your sign up, you'll be able to access this wiki."
     },
     "form_help": {
       "email": "You must have email address which listed below to sign up to this wiki.",
@@ -169,11 +164,7 @@
   "page_me": {
     "form_help": {
       "profile_image1": "Image upload settings not completed.",
-      "profile_image2": "Set up AWS or enable local uploads.",
-      "google_connect1": "With Google Connect, you can sign in with your Google Account.",
-      "google_connect2": "Only Google Apps accounts with the following email addresses are connectable Google accounts:",
-      "google_disconnect1": "If you disconnect your Google account, you will be unable to sign in using Google Authentication",
-      "google_disconnect2": "After disconnecting your Google account, you can sign in normally using your email and password"
+      "profile_image2": "Set up AWS or enable local uploads."
     }
   },
   "page_me_apitoken": {
@@ -445,7 +436,6 @@
 		"Guest users access": "Guest users access",
 		"Register limitation": "Register limitation",
 		"The whitelist of registration permission E-mail address": "The whitelist of registration permission E-mail address",
-		"Selecting authentication mechanism": "Selecting authentication mechanism",
 		"common_authentication": "If you set the basic authentication, common authentication is applied on the whole page.",
 		"without_encryption": "Please be noted that your ID and Password will be sent wihtout encryption.",
 		"basic_acl_disable": "Because of Public Wiki  setting, basic authentication can not be used.",
@@ -460,33 +450,8 @@
     "page_listing_2": "Page listing/searching<br>restricted by User Group",
     "page_listing_2_desc": "Show pages that are restricted by User Group when listing/searching",
 
-		"Authentication mechanism settings": "Authentication mechanism settings",
-    "note": "Note",
-    "require_server_restart_change_auth": "Restarting the server is required if you switch the auth mechanism.",
-    "auth_mechanism": "authentication mechanism",
-    "recommended": "Recommended",
-    "username_email_password": "Username, Email and Password authentication",
+		"Authentication mechanism settings": "Authentication Mechanism Settings",
     "alert_siteUrl_is_not_set": "'Site URL' is NOT set. Set it from the %s",
-    "ldap_auth": "LDAP authentication",
-    "saml_auth": "SAML authentication",
-    "google_auth2": "Google OAuth authentication",
-    "google_auth2_by_crowi_desc": "However, this feature does not create new users, butit only makes it possible to login to the existing user who set up the association.",
-    "facebook_auth2": "Facebook OAuth authentication",
-    "twitter_auth2": "Twitter OAuth authentication",
-    "github_auth2": "GitHub OAuth authentication",
-    "crowi_auth": "Crowi classic authentication mechanism",
-		"require_server_restart": "Restarting the server is required.",
-		"server_on_passport_auth": "The server is running with Passport authentication mechanism.",
-		"server_on_crowi_auth": "The server is running with official Crowi authentication mechanism.",
-		"google_setting": "Google Setting",
-    "connect_api_manager": "You can use your Google account to sign up and login after creating OAuth2 ClientId at <a href=\"https://console.cloud.google.com/apis/credentials\" target=\"_blank\">API Manager on Google Cloud Platform</a>",
-		"access_api_manager": "Access <a href=\"%s\" target=\"_blank\">%s</a>",
-		"create_project": "Create Project if no projects have been created.",
-		"create_auth_to_oauth": "\"Create credentials\" -> \"OAuth clientID\"",
-		"select_webapp": "Select \"Web Application\"",
-    "change_redirect_url": "Enter <code>https://${crowi.host}/google/callback</code> <br>(where <code>${crowi.host}</code> is your host name) for \"Authorized redirect URIs\".",
-    "clientID": "Client ID",
-    "client_secret": "Client Secret",
     "xss_prevent_setting":"Prevent XSS(Cross Site Scripting)",
     "xss_prevent_setting_link":"Go to Markdown settings",
     "callback_URL": "Callback URL",

+ 2 - 37
resource/locales/ja/translation.json

@@ -81,9 +81,7 @@
   "Delete this image?": "削除してよろしいですか?",
   "Updated": "更新しました",
   "Upload new image": "新しい画像をアップロード",
-  "Google Setting": "Google設定",
   "Connected": "接続されています",
-  "Disconnect": "接続を解除",
   "Show": "公開",
   "Hide": "非公開",
   "Disclose E-mail": "メールアドレスの公開",
@@ -124,7 +122,6 @@
   "Reselect the group": "グループの再選択",
   "Shareable link": "このページの共有用URL",
   "The whitelist of registration permission E-mail address": "登録許可メールアドレスの<br>ホワイトリスト",
-  "Selecting authentication mechanism": "認証機構選択",
   "Add tags for this page": "タグを付ける",
   "Edit tags for this page": "タグを編集する",
   "You have no tag, You can set tags on pages": "使用中のタグがありません",
@@ -149,15 +146,13 @@
   },
 
   "breaking_changes": {
-    "v346_passport_is_not_enabled": "現在利用中の Crowi Classic Authentication mechanism は、近い将来<strong>サポートされなくなります</strong>。%s から Passport に切り替えてください。",
     "v346_using_basic_auth": "現在利用中の Basic 認証機能は、近い将来<strong>廃止されます</strong>。%s から設定を削除してください。"
   },
 
   "page_register": {
     "notice": {
        "restricted": "この Wiki への新規登録は制限されています。",
-       "restricted_defail": "利用を開始するには、新規登録後、管理者による承認が必要です。",
-       "google_account_continue": "ユーザーID、名前、パスワードを決めて登録を継続してください。"
+       "restricted_defail": "利用を開始するには、新規登録後、管理者による承認が必要です。"
     },
     "form_help": {
       "email": "この Wiki では以下のメールアドレスのみ登録可能です。",
@@ -169,11 +164,7 @@
   "page_me": {
     "form_help": {
       "profile_image1": "画像をアップロードをするための設定がされていません。",
-      "profile_image2": "アップロードできるようにするには、AWS またはローカルアップロードの設定をしてください。",
-      "google_connect1": "Googleコネクトをすると、Googleアカウントでログイン可能になります。",
-      "google_connect2": "コネクト可能なGoogleアカウントは、以下のメールアドレスの発行できるGoogle Appsアカウントに限られます。",
-      "google_disconnect1": "接続を解除すると、Googleでログインができなくなります。",
-      "google_disconnect2": "解除後はメールアドレスとパスワードでログインすることができます。"
+      "profile_image2": "アップロードできるようにするには、AWS またはローカルアップロードの設定をしてください。"
     }
   },
   "page_me_apitoken": {
@@ -445,7 +436,6 @@
     "Guest users access": "ゲストユーザーのアクセス",
     "Register limitation": "登録の制限",
     "The whitelist of registration permission E-mail address": "登録許可メールアドレスの<br>ホワイトリスト",
-    "Selecting authentication mechanism": "認証機構選択",
     "common_authentication": "Basic認証を設定すると、ページ全体に共通の認証がかかります。",
     "without_encryption": "IDとパスワードは暗号化されずに送信されるのでご注意下さい。",
     "basic_acl_disable": "Public Wiki の設定のため、Basic認証は利用できません。",
@@ -461,32 +451,7 @@
     "page_listing_2_desc": "ページのリスト表示や検索結果において、特定グループにのみ閲覧制限をしているページをアクセス権のないユーザーにも表示します。",
 
     "Authentication mechanism settings":"認証機構設定",
-    "note": "メモ",
-    "require_server_restart_change_auth": "認証機構の変更後はサーバーを再起動してください。",
-    "auth_mechanism": "認証機構",
-    "recommended": "推奨",
-    "username_email_password": "ユーザー名、Eメール、パスワードでの認証",
     "alert_siteUrl_is_not_set": "'サイトURL' が設定されていません。%s から設定してください。",
-    "ldap_auth": "LDAP 認証",
-    "saml_auth": "SAML 認証",
-    "google_auth2": "Google OAuth 認証",
-    "google_auth2_by_crowi_desc": "ただし、この機能では新たなユーザーは作成されず、関連付け設定を行った既存ユーザーをログインできるようにするだけです。",
-    "facebook_auth2": "Facebook OAuth 認証",
-    "twitter_auth2": "Twitter OAuth 認証",
-    "github_auth2": "GitHub OAuth 認証",
-    "crowi_auth": "Crowi Classic OAuth 認証",
-    "require_server_restart": "サーバーを再起動してください。",
-    "server_on_passport_auth": "Passport 認証機構でサーバーが稼働しています。",
-    "server_on_crowi_auth": "Crowi Classic 認証機構でサーバーが稼働しています。",
-    "google_setting": "Google 設定",
-    "connect_api_manager": "Google Cloud Platform の <a href=\"https://console.cloud.google.com/apis/credentials\" target=\"_blank\">API Manager</a>から OAuth2 Client ID を作成すると、Google アカウントにコネクトして登録やログインが可能になります。",
-    "access_api_manager": "<a href=\"%s\" target=\"_blank\">%s</a> へアクセス",
-    "create_project": "プロジェクトを作成していない場合は作成してください",
-    "create_auth_to_oauth": "「認証情報を作成」-> OAuthクライアントID",
-    "select_webapp": "「ウェブアプリケーション」を選択",
-    "change_redirect_url": "承認済みのリダイレクトURLに、 <code>https://${crowi.host}/google/callback</code> を入力<br>(<code>${crowi.host}</code>は環境に合わせて変更してください)",
-    "clientID": "クライアントID",
-    "client_secret": "クライアントシークレット",
     "xss_prevent_setting":"XSS(Cross Site Scripting)対策設定",
     "xss_prevent_setting_link":"マークダウン設定ページに移動",
     "callback_URL": "コールバックURL",

+ 12 - 0
src/lib/util/mongoose-utils.js

@@ -0,0 +1,12 @@
+const mongoose = require('mongoose');
+
+const getModelSafely = (modelName) => {
+  if (mongoose.modelNames().includes(modelName)) {
+    return mongoose.model(modelName);
+  }
+  return null;
+};
+
+module.exports = {
+  getModelSafely,
+};

+ 3 - 2
src/migrations/20180926134048-make-email-unique.js

@@ -1,16 +1,17 @@
-require('module-alias/register');
 const logger = require('@alias/logger')('growi:migrate:make-email-unique');
 
 const mongoose = require('mongoose');
 const config = require('@root/config/migrate');
 
+const { getModelSafely } = require('@commons/util/mongoose-utils');
+
 module.exports = {
 
   async up(db, next) {
     logger.info('Start migration');
     mongoose.connect(config.mongoUri, config.mongodb.options);
 
-    const User = require('@server/models/user')();
+    const User = getModelSafely('User') || require('@server/models/user')();
 
     // get all users who has 'deleted@deleted' email
     const users = await User.find({ email: 'deleted@deleted' });

+ 4 - 3
src/migrations/20180927102719-init-serverurl.js

@@ -1,11 +1,12 @@
 
 
-require('module-alias/register');
 const logger = require('@alias/logger')('growi:migrate:init-serverurl');
 
 const mongoose = require('mongoose');
 const config = require('@root/config/migrate');
 
+const { getModelSafely } = require('@commons/util/mongoose-utils');
+
 /**
  * check all values of the array are equal
  * @see https://stackoverflow.com/a/35568895
@@ -22,7 +23,7 @@ module.exports = {
     logger.info('Apply migration');
     mongoose.connect(config.mongoUri, config.mongodb.options);
 
-    const Config = require('@server/models/config')();
+    const Config = getModelSafely('Config') || require('@server/models/config')();
 
     // find 'app:siteUrl'
     const siteUrlConfig = await Config.findOne({
@@ -81,7 +82,7 @@ module.exports = {
     logger.info('Undo migration');
     mongoose.connect(config.mongoUri, config.mongodb.options);
 
-    const Config = require('@server/models/config')();
+    const Config = getModelSafely('Config') || require('@server/models/config')();
 
     // remote 'app:siteUrl'
     await Config.findOneAndDelete({

+ 6 - 5
src/migrations/20181019114028-abolish-page-group-relation.js

@@ -1,9 +1,10 @@
-require('module-alias/register');
 const logger = require('@alias/logger')('growi:migrate:abolish-page-group-relation');
 
 const mongoose = require('mongoose');
 const config = require('@root/config/migrate');
 
+const { getModelSafely } = require('@commons/util/mongoose-utils');
+
 
 async function isCollectionExists(db, collectionName) {
   const collections = await db.listCollections({ name: collectionName }).toArray();
@@ -37,8 +38,8 @@ module.exports = {
       return;
     }
 
-    const Page = require('@server/models/page')();
-    const UserGroup = require('@server/models/user-group')();
+    const Page = getModelSafely('Page') || require('@server/models/page');
+    const UserGroup = getModelSafely('UserGroup') || require('@server/models/user-group')();
 
     // retrieve all documents from 'pagegrouprelations'
     const relations = await db.collection('pagegrouprelations').find().toArray();
@@ -74,8 +75,8 @@ module.exports = {
     logger.info('Undo migration');
     mongoose.connect(config.mongoUri, config.mongodb.options);
 
-    const Page = require('@server/models/page')();
-    const UserGroup = require('@server/models/user-group')();
+    const Page = getModelSafely('Page') || require('@server/models/page');
+    const UserGroup = getModelSafely('UserGroup') || require('@server/models/user-group')();
 
     // retrieve all Page documents which granted by UserGroup
     const relatedPages = await Page.find({ grant: Page.GRANT_USER_GROUP });

+ 31 - 0
src/migrations/20190618055300-abolish-crowi-classic-auth.js

@@ -0,0 +1,31 @@
+const logger = require('@alias/logger')('growi:migrate:make-email-unique');
+
+const mongoose = require('mongoose');
+const config = require('@root/config/migrate');
+
+const { getModelSafely } = require('@commons/util/mongoose-utils');
+
+
+module.exports = {
+  async up(db, next) {
+    logger.info('Start migration');
+    mongoose.connect(config.mongoUri, config.mongodb.options);
+
+    const Config = getModelSafely('Config') || require('@server/models/config')();
+
+    // enable passport and delete configs for crowi classic auth
+    await Promise.all([
+      Config.findOneAndUpdateByNsAndKey('crowi', 'security:isEnabledPassport', true),
+      Config.deleteOne({ ns: 'crowi', key: 'google:clientId' }),
+      Config.deleteOne({ ns: 'crowi', key: 'google:clientSecret' }),
+    ]);
+
+    logger.info('Migration has successfully terminated');
+    next();
+  },
+
+  down(db, next) {
+    // do not rollback
+    next();
+  },
+};

+ 5 - 10
src/migrations/20190618104011-add-config-app-installed.js

@@ -1,15 +1,10 @@
-require('module-alias/register');
 const logger = require('@alias/logger')('growi:migrate:add-config-app-installed');
 
 const mongoose = require('mongoose');
 const config = require('@root/config/migrate');
 
-function getModel(modelName) {
-  if (mongoose.modelNames().includes(modelName)) {
-    return mongoose.model(modelName);
-  }
-  return null;
-}
+const { getModelSafely } = require('@commons/util/mongoose-utils');
+
 
 /**
  * BEFORE
@@ -25,8 +20,8 @@ module.exports = {
     logger.info('Apply migration');
     mongoose.connect(config.mongoUri, config.mongodb.options);
 
-    const Config = getModel('Config') || require('@server/models/config')();
-    const User = getModel('User') || require('@server/models/user')();
+    const Config = getModelSafely('Config') || require('@server/models/config')();
+    const User = getModelSafely('User') || require('@server/models/user')();
 
     // find 'app:siteUrl'
     const appInstalled = await Config.findOne({
@@ -56,7 +51,7 @@ module.exports = {
     logger.info('Undo migration');
     mongoose.connect(config.mongoUri, config.mongodb.options);
 
-    const Config = getModel('Config') || require('@server/models/config')();
+    const Config = getModelSafely('Config') || require('@server/models/config')();
 
     // remote 'app:siteUrl'
     await Config.findOneAndDelete({

+ 4 - 12
src/server/crowi/express-init.js

@@ -139,11 +139,9 @@ module.exports = function(crowi, app) {
   });
 
   // passport
-  if (getConfig('crowi', 'security:isEnabledPassport')) {
-    debug('initialize Passport');
-    app.use(passport.initialize());
-    app.use(passport.session());
-  }
+  debug('initialize Passport');
+  app.use(passport.initialize());
+  app.use(passport.session());
 
   app.use(flash());
 
@@ -154,13 +152,7 @@ module.exports = function(crowi, app) {
 
   app.use(middlewares.csrfKeyGenerator());
 
-  // switch loginChecker
-  if (getConfig('crowi', 'security:isEnabledPassport')) {
-    app.use(middlewares.loginCheckerForPassport);
-  }
-  else {
-    app.use(middlewares.loginChecker);
-  }
+  app.use(middlewares.loginCheckerForPassport);
 
   app.use(i18nMiddleware.handle(i18next));
 };

+ 0 - 7
src/server/crowi/index.js

@@ -243,8 +243,6 @@ Crowi.prototype.setupSessionConfig = function() {
 // };
 
 Crowi.prototype.setupConfigManager = async function() {
-  this.model('Config', require('../models/config')(this));
-
   const ConfigManager = require('../service/config-manager');
   this.configManager = new ConfigManager(this.model('Config'));
   return this.configManager.loadConfigs();
@@ -300,11 +298,6 @@ Crowi.prototype.getRestQiitaAPIService = function() {
 };
 
 Crowi.prototype.setupPassport = function() {
-  if (!this.configManager.getConfig('crowi', 'security:isEnabledPassport')) {
-    // disabled
-    return;
-  }
-
   debug('Passport is enabled');
 
   // initialize service

+ 0 - 8
src/server/form/admin/securityGoogle.js

@@ -1,8 +0,0 @@
-const form = require('express-form');
-
-const field = form.field;
-
-module.exports = form(
-  field('settingForm[google:clientId]').trim().is(/^[\da-z\-.]+$/),
-  field('settingForm[google:clientSecret]').trim().is(/^[\da-zA-Z\-_]+$/),
-);

+ 0 - 7
src/server/form/admin/securityMechanism.js

@@ -1,7 +0,0 @@
-const form = require('express-form');
-
-const field = form.field;
-
-module.exports = form(
-  field('settingForm[security:isEnabledPassport]').trim().toBooleanStrict(),
-);

+ 0 - 2
src/server/form/index.js

@@ -19,8 +19,6 @@ module.exports = {
     importerQiita: require('./admin/importerQiita'),
     plugin: require('./admin/plugin'),
     securityGeneral: require('./admin/securityGeneral'),
-    securityGoogle: require('./admin/securityGoogle'),
-    securityMechanism: require('./admin/securityMechanism'),
     securityPassportLdap: require('./admin/securityPassportLdap'),
     securityPassportSaml: require('./admin/securityPassportSaml'),
     securityPassportGoogle: require('./admin/securityPassportGoogle'),

+ 0 - 2
src/server/form/register.js

@@ -7,7 +7,5 @@ module.exports = form(
   field('registerForm.name').required(),
   field('registerForm.email').required(),
   field('registerForm.password').required().is(/^[\x20-\x7F]{6,}$/),
-  field('registerForm.googleId'),
-  field('registerForm.googleImage'),
   field('registerForm[app:globalLang]'),
 );

+ 0 - 1
src/server/models/config.js

@@ -61,7 +61,6 @@ module.exports = function(crowi) {
       'security:list-policy:hideRestrictedByOwner' : false,
       'security:list-policy:hideRestrictedByGroup' : false,
 
-      'security:isEnabledPassport' : true,
       'security:passport-ldap:isEnabled' : false,
       'security:passport-ldap:serverUrl' : undefined,
       'security:passport-ldap:isUserBind' : undefined,

+ 1 - 0
src/server/models/index.js

@@ -1,4 +1,5 @@
 module.exports = {
+  Config: require('./Config'),
   Page: require('./page'),
   PageTagRelation: require('./page-tag-relation'),
   User: require('./user'),

+ 5 - 6
src/server/models/user.js

@@ -624,8 +624,8 @@ module.exports = function(crowi) {
 
     const User = this;
     const createdUserList = [];
-
     const mailer = crowi.getMailer();
+
     if (!Array.isArray(emailList)) {
       debug('emailList is not array');
     }
@@ -665,7 +665,7 @@ module.exports = function(crowi) {
           newUser.createdAt = Date.now();
           newUser.status = STATUS_INVITED;
 
-          const globalLang = configManager.getConfig('crowi', 'globalLang');
+          const globalLang = configManager.getConfig('crowi', 'app:globalLang');
           if (globalLang != null) {
             newUser.lang = globalLang;
           }
@@ -698,8 +698,6 @@ module.exports = function(crowi) {
         }
 
         if (toSendEmail) {
-          const appTitle = crowi.appService.getAppTitle();
-
           // TODO: メール送信部分のロジックをサービス化する
           async.each(
             createdUserList,
@@ -708,6 +706,8 @@ module.exports = function(crowi) {
                 return next();
               }
 
+              const appTitle = crowi.appService.getAppTitle();
+
               mailer.send({
                 to: user.email,
                 subject: `Invitation to ${appTitle}`,
@@ -762,8 +762,7 @@ module.exports = function(crowi) {
     }
 
     const configManager = crowi.configManager;
-
-    const globalLang = configManager.getConfig('crowi', 'globalLang');
+    const globalLang = configManager.getConfig('crowi', 'app:globalLang');
     if (globalLang != null) {
       newUser.lang = globalLang;
     }

+ 11 - 13
src/server/routes/admin.js

@@ -14,7 +14,12 @@ module.exports = function(crowi, app) {
   const GlobalNotificationMailSetting = models.GlobalNotificationMailSetting;
   const GlobalNotificationSlackSetting = models.GlobalNotificationSlackSetting; // eslint-disable-line no-unused-vars
 
-  const { configManager, aclService, slackNotificationService } = crowi;
+  const {
+    configManager,
+    aclService,
+    slackNotificationService,
+    customizeService,
+  } = crowi;
 
   const recommendedWhitelist = require('@commons/service/xss/recommended-whitelist');
   const PluginUtils = require('../plugins/plugin-utils');
@@ -1083,23 +1088,16 @@ module.exports = function(crowi, app) {
     return res.json({ status: true });
   };
 
-  actions.api.customizeSetting = function(req, res) {
+  actions.api.customizeSetting = async function(req, res) {
     const form = req.form.settingForm;
 
     if (req.form.isValid) {
       debug('form content', form);
-      return saveSetting(req, res, form);
-    }
-
-    return res.json({ status: false, message: req.form.errors.join('\n') });
-  };
-
-  actions.api.customizeSetting = function(req, res) {
-    const form = req.form.settingForm;
+      await configManager.updateConfigsInTheSameNamespace('crowi', form);
+      customizeService.initCustomCss();
+      customizeService.initCustomTitle();
 
-    if (req.form.isValid) {
-      debug('form content', form);
-      return saveSetting(req, res, form);
+      return res.json({ status: true });
     }
 
     return res.json({ status: false, message: req.form.errors.join('\n') });

+ 12 - 26
src/server/routes/index.js

@@ -22,11 +22,12 @@ module.exports = function(crowi, app) {
   const revision = require('./revision')(crowi, app);
   const search = require('./search')(crowi, app);
   const hackmd = require('./hackmd')(crowi, app);
-  const loginRequired = middlewares.loginRequired;
-  const adminRequired = middlewares.adminRequired;
-  const accessTokenParser = middlewares.accessTokenParser;
-  const csrf = middlewares.csrfVerify;
-  const { configManager } = crowi;
+  const {
+    loginRequired,
+    adminRequired,
+    accessTokenParser,
+    csrfVerify: csrf,
+  } = middlewares;
 
   /* eslint-disable max-len, comma-spacing, no-multi-spaces */
 
@@ -39,21 +40,11 @@ module.exports = function(crowi, app) {
   app.get('/login'                   , middlewares.applicationInstalled    , login.login);
   app.get('/login/invited'           , login.invited);
   app.post('/login/activateInvited'  , form.invited                         , csrf, login.invited);
-
-  // switch POST /login route
-  if (configManager.getConfig('crowi', 'security:isEnabledPassport')) {
-    app.post('/login'                , form.login                           , csrf, loginPassport.loginWithLocal, loginPassport.loginWithLdap, loginPassport.loginFailure);
-    app.post('/_api/login/testLdap'  , loginRequired() , form.login , loginPassport.testLdapCredentials);
-  }
-  else {
-    app.post('/login'                , form.login                           , csrf, login.login);
-  }
+  app.post('/login'                  , form.login                           , csrf, loginPassport.loginWithLocal, loginPassport.loginWithLdap, loginPassport.loginFailure);
+  app.post('/_api/login/testLdap'    , loginRequired() , form.login , loginPassport.testLdapCredentials);
 
   app.post('/register'               , form.register                        , csrf, login.register);
   app.get('/register'                , middlewares.applicationInstalled    , login.register);
-  app.post('/register/google'        , login.registerGoogle);
-  app.get('/google/callback'         , login.googleCallback);
-  app.get('/login/google'            , login.loginGoogle);
   app.get('/logout'                  , logout.logout);
 
   app.get('/admin'                          , loginRequired() , adminRequired , admin.index);
@@ -67,8 +58,6 @@ module.exports = function(crowi, app) {
   // security admin
   app.get('/admin/security'                     , loginRequired() , adminRequired , admin.security.index);
   app.post('/_api/admin/security/general'       , loginRequired() , adminRequired , form.admin.securityGeneral, admin.api.securitySetting);
-  app.post('/_api/admin/security/google'        , loginRequired() , adminRequired , csrf, form.admin.securityGoogle, admin.api.securitySetting);
-  app.post('/_api/admin/security/mechanism'     , loginRequired() , adminRequired , csrf, form.admin.securityMechanism, admin.api.securitySetting);
   app.post('/_api/admin/security/passport-ldap' , loginRequired() , adminRequired , csrf, form.admin.securityPassportLdap, admin.api.securityPassportLdapSetting);
   app.post('/_api/admin/security/passport-saml' , loginRequired() , adminRequired , csrf, form.admin.securityPassportSaml, admin.api.securityPassportSamlSetting);
 
@@ -163,16 +152,13 @@ module.exports = function(crowi, app) {
   app.get('/me/apiToken'              , loginRequired() , me.apiToken);
   app.post('/me'                      , loginRequired() , csrf , form.me.user , me.index);
   // external-accounts
-  if (configManager.getConfig('crowi', 'security:isEnabledPassport')) {
-    app.get('/me/external-accounts'                         , loginRequired() , me.externalAccounts.list);
-    app.post('/me/external-accounts/disassociate'           , loginRequired() , me.externalAccounts.disassociate);
-    app.post('/me/external-accounts/associateLdap'          , loginRequired() , form.login , me.externalAccounts.associateLdap);
-  }
+  app.get('/me/external-accounts'                         , loginRequired() , me.externalAccounts.list);
+  app.post('/me/external-accounts/disassociate'           , loginRequired() , me.externalAccounts.disassociate);
+  app.post('/me/external-accounts/associateLdap'          , loginRequired() , form.login , me.externalAccounts.associateLdap);
+
   app.post('/me/password'             , form.me.password          , loginRequired() , me.password);
   app.post('/me/imagetype'            , form.me.imagetype         , loginRequired() , me.imagetype);
   app.post('/me/apiToken'             , form.me.apiToken          , loginRequired() , me.apiToken);
-  app.post('/me/auth/google'          , loginRequired() , me.authGoogle);
-  app.get('/me/auth/google/callback' , loginRequired() , me.authGoogleCallback);
 
   app.get('/:id([0-9a-z]{24})'       , loginRequired(false) , page.redirector);
   app.get('/_r/:id([0-9a-z]{24})'    , loginRequired(false) , page.redirector); // alias

+ 7 - 118
src/server/routes/login.js

@@ -15,9 +15,6 @@ module.exports = function(crowi, app) {
 
   const actions = {};
 
-  const clearGoogleSession = function(req) {
-    req.session.googleAuthCode = req.session.googleId = req.session.googleEmail = req.session.googleName = req.session.googleImage = null;
-  };
   const loginSuccess = function(req, res, userData) {
     req.user = req.session.user = userData;
 
@@ -32,8 +29,6 @@ module.exports = function(crowi, app) {
       return res.redirect('/me/password');
     }
 
-    clearGoogleSession(req);
-
     const jumpTo = req.session.jumpTo;
     if (jumpTo) {
       req.session.jumpTo = null;
@@ -60,16 +55,6 @@ module.exports = function(crowi, app) {
     return res.redirect('/login');
   };
 
-  actions.googleCallback = function(req, res) {
-    const nextAction = req.session.googleCallbackAction || '/login';
-    debug('googleCallback.nextAction', nextAction);
-    req.session.googleAuthCode = req.query.code || '';
-    debug('google auth code', req.query.code);
-
-
-    return res.redirect(nextAction);
-  };
-
   actions.error = function(req, res) {
     const reason = req.params.reason;
 
@@ -114,43 +99,7 @@ module.exports = function(crowi, app) {
     }
   };
 
-  actions.loginGoogle = function(req, res) {
-    const googleAuth = require('../util/googleAuth')(crowi);
-    const code = req.session.googleAuthCode || null;
-
-    if (!code) {
-      googleAuth.createAuthUrl(req, (err, redirectUrl) => {
-        if (err) {
-          // TODO
-        }
-
-        req.session.googleCallbackAction = '/login/google';
-        return res.redirect(redirectUrl);
-      });
-    }
-    else {
-      googleAuth.handleCallback(req, (err, tokenInfo) => {
-        debug('handleCallback', err, tokenInfo);
-        if (err) {
-          return loginFailure(req, res);
-        }
-
-        const googleId = tokenInfo.user_id;
-        User.findUserByGoogleId(googleId, (err, userData) => {
-          debug('findUserByGoogleId', err, userData);
-          if (!userData) {
-            clearGoogleSession(req);
-            return loginFailure(req, res);
-          }
-          return loginSuccess(req, res, userData);
-        });
-      });
-    }
-  };
-
   actions.register = function(req, res) {
-    const googleAuth = require('../util/googleAuth')(crowi);
-
     // redirect to '/' if both of these are true:
     //  1. user has logged in
     //  2. req.user is not username/email string (which is set by basic-auth-connect)
@@ -170,8 +119,6 @@ module.exports = function(crowi, app) {
       const username = registerForm.username;
       const email = registerForm.email;
       const password = registerForm.password;
-      var googleId = registerForm.googleId || null;
-      var googleImage = registerForm.googleImage || null;
 
       // email と username の unique チェックする
       User.isRegisterable(email, username, (isRegisterable, errOn) => {
@@ -238,81 +185,23 @@ module.exports = function(crowi, app) {
             });
           }
 
-          if (googleId) {
-            userData.updateGoogleId(googleId, (err, userData) => {
-              if (err) { // TODO
-              }
-              return loginSuccess(req, res, userData);
-            });
-          }
-          else {
-            // add a flash message to inform the user that processing was successful -- 2017.09.23 Yuki Takei
-            // cz. loginSuccess method doesn't work on it's own when using passport
-            //      because `req.login()` prepared by passport is not called.
-            req.flash('successMessage', `The user '${userData.username}' is successfully created.`);
 
-            return loginSuccess(req, res, userData);
-          }
+          // add a flash message to inform the user that processing was successful -- 2017.09.23 Yuki Takei
+          // cz. loginSuccess method doesn't work on it's own when using passport
+          //      because `req.login()` prepared by passport is not called.
+          req.flash('successMessage', `The user '${userData.username}' is successfully created.`);
+
+          return loginSuccess(req, res, userData);
         });
       });
     }
     else { // method GET of form is not valid
       debug('session is', req.session);
       const isRegistering = true;
-      // google callback を受ける可能性もある
-      const code = req.session.googleAuthCode || null;
-      var googleId = req.session.googleId || null;
-      let googleEmail = req.session.googleEmail || null;
-      let googleName = req.session.googleName || null;
-      var googleImage = req.session.googleImage || null;
-
-      debug('register. if code', code);
-      // callback 経由で reigster にアクセスしてきた時最初だけこの if に入る
-      // code から email などを取得したらそれを session にいれて code は消去
-      if (code) {
-        googleAuth.handleCallback(req, (err, tokenInfo) => {
-          debug('tokenInfo on register GET', tokenInfo);
-          req.session.googleAuthCode = null;
-
-          if (err) {
-            req.flash('registerWarningMessage', 'Error on connectiong Google');
-            return res.redirect('/login?register=1'); // TODO Handling
-          }
-
-          req.session.googleId = googleId = tokenInfo.user_id;
-          req.session.googleEmail = googleEmail = tokenInfo.email;
-          req.session.googleName = googleName = tokenInfo.name;
-          req.session.googleImage = googleImage = tokenInfo.picture;
-
-          if (!User.isEmailValid(googleEmail)) {
-            req.flash('registerWarningMessage', 'このメールアドレスのGoogleアカウントはコネクトできません。');
-            return res.redirect('/login?register=1');
-          }
-          return res.render('login', {
-            isRegistering, googleId, googleEmail, googleName, googleImage,
-          });
-        });
-      }
-      else {
-        return res.render('login', {
-          isRegistering, googleId, googleEmail, googleName, googleImage,
-        });
-      }
+      return res.render('login', { isRegistering });
     }
   };
 
-  actions.registerGoogle = function(req, res) {
-    const googleAuth = require('../util/googleAuth')(crowi);
-    googleAuth.createAuthUrl(req, (err, redirectUrl) => {
-      if (err) {
-        // TODO
-      }
-
-      req.session.googleCallbackAction = '/register';
-      return res.redirect(redirectUrl);
-    });
-  };
-
   actions.invited = async function(req, res) {
     if (!req.user) {
       return res.redirect('/login');

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

@@ -309,72 +309,5 @@ module.exports = function(crowi, app) {
     });
   };
 
-  actions.authGoogle = function(req, res) {
-    const googleAuth = require('../util/googleAuth')(crowi);
-
-    const userData = req.user;
-
-    const toDisconnect = !!req.body.disconnectGoogle;
-    const toConnect = !!req.body.connectGoogle;
-    if (toDisconnect) {
-      userData.deleteGoogleId((err, userData) => {
-        req.flash('successMessage', 'Disconnected from Google account');
-
-        return res.redirect('/me');
-      });
-    }
-    else if (toConnect) {
-      googleAuth.createAuthUrl(req, (err, redirectUrl) => {
-        if (err) {
-          // TODO
-        }
-
-        req.session.googleCallbackAction = '/me/auth/google/callback';
-        return res.redirect(redirectUrl);
-      });
-    }
-    else {
-      return res.redirect('/me');
-    }
-  };
-
-  actions.authGoogleCallback = function(req, res) {
-    const googleAuth = require('../util/googleAuth')(crowi);
-    const userData = req.user;
-
-    googleAuth.handleCallback(req, (err, tokenInfo) => {
-      if (err) {
-        req.flash('warningMessage.auth.google', err.message); // FIXME: show library error message directly
-        return res.redirect('/me'); // TODO Handling
-      }
-
-      const googleId = tokenInfo.user_id;
-      const googleEmail = tokenInfo.email;
-      if (!User.isEmailValid(googleEmail)) {
-        req.flash('warningMessage.auth.google', 'You can\'t connect with this  Google\'s account');
-        return res.redirect('/me');
-      }
-
-      User.findUserByGoogleId(googleId, (err, googleUser) => {
-        if (!err && googleUser) {
-          req.flash('warningMessage.auth.google', 'This Google\'s account is connected by another user');
-          return res.redirect('/me');
-        }
-
-        userData.updateGoogleId(googleId, (err, userData) => {
-          if (err) {
-            debug('Failed to updateGoogleId', err);
-            req.flash('warningMessage.auth.google', 'Failed to connect Google Account');
-            return res.redirect('/me');
-          }
-
-          // TODO if err
-          req.flash('successMessage', 'Connected with Google');
-          return res.redirect('/me');
-        });
-      });
-    });
-  };
-
   return actions;
 };

+ 0 - 70
src/server/util/googleAuth.js

@@ -1,70 +0,0 @@
-const debug = require('debug')('growi:lib:googleAuth');
-const urljoin = require('url-join');
-const { GoogleApis } = require('googleapis');
-
-/**
- * googleAuth utility
- */
-
-module.exports = function(crowi) {
-  const google = new GoogleApis();
-  const config = crowi.getConfig();
-
-  const lib = {};
-  function createOauth2Client(url) {
-    return new google.auth.OAuth2(
-      config.crowi['google:clientId'],
-      config.crowi['google:clientSecret'],
-      url,
-    );
-  }
-
-  lib.createAuthUrl = function(req, callback) {
-    const callbackUrl = urljoin(crowi.appService.getSiteUrl(), '/google/callback');
-    const oauth2Client = createOauth2Client(callbackUrl);
-    google.options({ auth: oauth2Client });
-
-    const redirectUrl = oauth2Client.generateAuthUrl({
-      access_type: 'offline',
-      scope: ['profile', 'email'],
-    });
-
-    callback(null, redirectUrl);
-  };
-
-  lib.handleCallback = function(req, callback) {
-    const callbackUrl = urljoin(crowi.appService.getSiteUrl(), '/google/callback');
-    const oauth2Client = createOauth2Client(callbackUrl);
-    google.options({ auth: oauth2Client });
-
-    const code = req.session.googleAuthCode || null;
-
-    if (!code) {
-      return callback(new Error('No code exists.'), null);
-    }
-
-    debug('Request googleToken by auth code', code);
-    oauth2Client.getToken(code, (err, tokens) => {
-      debug('Result of google.getToken()', err, tokens);
-      if (err) {
-        return callback(new Error('[googleAuth.handleCallback] Error to get token.'), null);
-      }
-
-      oauth2Client.credentials = tokens;
-
-      const oauth2 = google.oauth2('v2');
-      oauth2.userinfo.get({}, (err, response) => {
-        debug('Response of oauth2.userinfo.get', err, response);
-        if (err) {
-          return callback(new Error('[googleAuth.handleCallback] Error while proceccing userinfo.get.'), null);
-        }
-
-        const data = response.data;
-        data.user_id = data.id; // This is for B.C. (tokeninfo をつかっている前提のコードに対してのもの)
-        return callback(null, data);
-      });
-    });
-  };
-
-  return lib;
-};

+ 0 - 20
src/server/util/middlewares.js

@@ -21,26 +21,6 @@ module.exports = (crowi, app) => {
     };
   };
 
-  middlewares.loginChecker = async function(req, res, next) {
-    const User = crowi.model('User');
-    let user = null;
-
-    try {
-      // session に user object が入ってる
-      if (req.session.user && '_id' in req.session.user) {
-        user = await User.findById(req.session.user._id).populate(User.IMAGE_POPULATION);
-      }
-
-      req.user = user;
-      req.session.user = user;
-      res.locals.user = req.user;
-      next();
-    }
-    catch (err) {
-      next(err);
-    }
-  };
-
   middlewares.loginCheckerForPassport = function(req, res, next) {
     res.locals.user = req.user;
     next();

+ 0 - 1
src/server/util/slack.js

@@ -9,7 +9,6 @@ const urljoin = require('url-join');
 
 module.exports = function(crowi) {
   const config = crowi.getConfig();
-  const Config = crowi.model('Config');
   const Slack = require('slack-node');
   const { configManager } = crowi;
 

+ 4 - 70
src/server/util/swigFunctions.js

@@ -9,6 +9,7 @@ module.exports = function(crowi, app, req, locals) {
     passportService,
     appService,
     fileUploadService,
+    customizeService,
   } = crowi;
   debug('initializing swigFunctions');
 
@@ -64,6 +65,7 @@ module.exports = function(crowi, app, req, locals) {
    */
   locals.appService = appService;
   locals.fileUploadService = fileUploadService;
+  locals.customizeService = customizeService;
 
   locals.noCdn = function() {
     return !!process.env.NO_CDN;
@@ -90,21 +92,12 @@ module.exports = function(crowi, app, req, locals) {
     return cdnResourcesService.getHighlightJsStyleTag(styleName);
   };
 
-  /**
-   * return true if local strategy has been setup successfully
-   *  used whether restarting the server needed
-   */
-  locals.isPassportLocalStrategySetup = function() {
-    return passportService != null && passportService.isLocalStrategySetup;
-  };
-
   /**
    * return true if enabled and strategy has been setup successfully
    */
   locals.isLdapSetup = function() {
     return (
-      configManager.getConfig('crowi', 'security:isEnabledPassport')
-      && configManager.getConfig('crowi', 'security:passport-ldap:isEnabled')
+      configManager.getConfig('crowi', 'security:passport-ldap:isEnabled')
       && passportService.isLdapStrategySetup
     );
   };
@@ -114,35 +107,15 @@ module.exports = function(crowi, app, req, locals) {
    */
   locals.isLdapSetupFailed = function() {
     return (
-      configManager.getConfig('crowi', 'security:isEnabledPassport')
-      && configManager.getConfig('crowi', 'security:passport-ldap:isEnabled')
+      configManager.getConfig('crowi', 'security:passport-ldap:isEnabled')
       && !passportService.isLdapStrategySetup
     );
   };
 
   locals.getSamlMissingMandatoryConfigKeys = function() {
-    // return an empty array if Passport is not enabled
-    // because crowi.passportService is null.
-    if (!configManager.getConfig('crowi', 'security:isEnabledPassport')) {
-      return [];
-    }
-
     return crowi.passportService.getSamlMissingMandatoryConfigKeys();
   };
 
-  locals.googleLoginEnabled = function() {
-    // return false if Passport is enabled
-    // because official crowi mechanism is not used.
-    if (configManager.getConfig('crowi', 'security:isEnabledPassport')) {
-      return false;
-    }
-
-    return (
-      configManager.getConfig('crowi', 'google:clientId')
-      && configManager.getConfig('crowi', 'google:clientSecret')
-    );
-  };
-
   locals.searchConfigured = function() {
     if (crowi.getSearcher()) {
       return true;
@@ -154,45 +127,6 @@ module.exports = function(crowi, app, req, locals) {
     return process.env.HACKMD_URI != null;
   };
 
-  locals.customCss = function() {
-    const customizeService = crowi.customizeService;
-    return customizeService.getCustomCss();
-  };
-
-  locals.customScript = function() {
-    const customizeService = crowi.customizeService;
-    return customizeService.getCustomScript();
-  };
-
-  locals.customHeader = function() {
-    return configManager.getConfig('crowi', 'customize:header') || '';
-  };
-
-  locals.customTitle = function(page) {
-    const customizeService = crowi.customizeService;
-    return customizeService.generateCustomTitle(page);
-  };
-
-  locals.behaviorType = function() {
-    return configManager.getConfig('crowi', 'customize:behavior');
-  };
-
-  locals.layoutType = function() {
-    return configManager.getConfig('crowi', 'customize:layout');
-  };
-
-  locals.highlightJsStyle = function() {
-    return configManager.getConfig('crowi', 'customize:highlightJsStyle');
-  };
-
-  locals.highlightJsStyleBorder = function() {
-    return configManager.getConfig('crowi', 'customize:highlightJsStyleBorder');
-  };
-
-  locals.isEnabledTimeline = function() {
-    return configManager.getConfig('crowi', 'customize:isEnabledTimeline');
-  };
-
   locals.parentPath = function(path) {
     if (path === '/') {
       return path;

+ 3 - 3
src/server/views/admin/app.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('App settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('App settings')) }}{% endblock %}
 
 {% block head_warn_alert_siteurl_undefined %} {# remove including block for './widget/alert_siteurl_undefined.html' #}
 {% endblock %}
@@ -58,8 +58,8 @@
                    id="settingForm[app:confidential]"
                    type="text"
                    name="settingForm[app:confidential]"
-                   value="{{ settingForm['app:confidential'] }}"
-                   placeholder="{{ t('app_setting. ex): internal use only') }}">
+                   value="{{ settingForm['app:confidential'] | default('') }}"
+                   placeholder="{{ t('app_setting. ex&rpar;: internal use only') }}">
             <p class="help-block">{{ t("app_setting.header_content") }}</p>
           </div>
         </div>

+ 7 - 7
src/server/views/admin/customize.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('Customize')) }} {% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('Customize')) }} {% endblock %}
 
 {% block theme_css_block %}
   {% set themeName = getConfig('crowi', 'customize:theme') %}
@@ -307,7 +307,7 @@
             <div class="col-xs-9">
               <select class="form-control selectpicker" name="settingForm[customize:highlightJsStyle]" onChange="selectHighlightJsStyle(event)" {% if noCdn() %}disabled{% endif %}>
                 {% for key in Object.keys(highlightJsCssSelectorOptions) %}
-                  <option value={{key}} {% if key == highlightJsStyle() %} selected {% endif %}>{{highlightJsCssSelectorOptions[key].name}}</option>
+                  <option value={{key}} {% if key == getConfig('crowi', 'customize:highlightJsStyle') %} selected {% endif %}>{{highlightJsCssSelectorOptions[key].name}}</option>
                 {% endfor %}
               </select>
               <p class="help-block text-warning">{{ t('customize_page.nocdn_desc') }}</p>
@@ -331,7 +331,7 @@
           </div>
 
           <div id="highlightJsCssContainer">
-            {{ cdnHighlightJsStyleTag(highlightJsStyle()) }}
+            {{ cdnHighlightJsStyleTag(getConfig('crowi', 'customize:highlightJsStyle')) }}
           </div>
 
           <p class="help-block">
@@ -381,7 +381,7 @@ export  $initHighlight;</code></pre>
 
           <div class="form-group">
             <div class="col-xs-12">
-              <input class="form-control" name="settingForm[customize:title]" value="{{ settingForm['customize:title'] }}"></input>
+              <input class="form-control" name="settingForm[customize:title]" value="{{ settingForm['customize:title'] | default('') }}"></input>
             </div>
           </div>
 
@@ -411,7 +411,7 @@ export  $initHighlight;</code></pre>
         <div class="form-group">
           <div class="col-xs-12">
             <div id="custom-header-editor"></div>
-            <input type="hidden" id="inputCustomHeader" name="settingForm[customize:header]" value="{{ settingForm['customize:header'] }}">
+            <input type="hidden" id="inputCustomHeader" name="settingForm[customize:header]" value="{{ settingForm['customize:header'] | default('') }}">
           </div>
           <div class="col-xs-12">
             <p class="help-block text-right">
@@ -443,7 +443,7 @@ export  $initHighlight;</code></pre>
         <div class="form-group">
           <div class="col-xs-12">
             <div id="custom-css-editor"></div>
-            <input type="hidden" id="inputCustomCss" name="settingForm[customize:css]" value="{{ settingForm['customize:css'] }}">
+            <input type="hidden" id="inputCustomCss" name="settingForm[customize:css]" value="{{ settingForm['customize:css'] | default('') }}">
           </div>
           <div class="col-xs-12">
             <p class="help-block text-right">
@@ -501,7 +501,7 @@ window.addEventListener('load', (event) => {
         <div class="form-group">
           <div class="col-xs-12">
             <div id="custom-script-editor"></div>
-            <input type="hidden" id="inputCustomScript" name="settingForm[customize:script]" value="{{ settingForm['customize:script'] }}">
+            <input type="hidden" id="inputCustomScript" name="settingForm[customize:script]" value="{{ settingForm['customize:script'] | default('') }}">
           </div>
           <div class="col-xs-12">
             <p class="help-block text-right">

+ 1 - 1
src/server/views/admin/external-accounts.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('External Account management')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('External Account management')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 1 - 1
src/server/views/admin/global-notification-detail.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('Notification settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('Notification settings')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 1 - 1
src/server/views/admin/importer.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('Import Data')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('Import Data')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 1 - 1
src/server/views/admin/index.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('admin_top.Management Wiki')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('admin_top.Management Wiki')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 1 - 1
src/server/views/admin/markdown.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('Markdown settings')) }}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('Markdown settings')) }}
  · {{ path }}{% endblock %}
 
 {% block content_header %}

+ 1 - 1
src/server/views/admin/notification.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('Notification settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('Notification settings')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 1 - 1
src/server/views/admin/search.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('Full Text Search management')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('Full Text Search management')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 4 - 141
src/server/views/admin/security.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('Security settings')) }} · {% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('Security settings')) }} · {% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">
@@ -156,139 +156,16 @@
         </div>
        </div>
 
-      <form action="/_api/admin/security/mechanism" method="post" class="form-horizontal mt-5" id="mechanismSetting" role="form">
-        <fieldset>
-          <legend class="alert-anchor">{{ t('Selecting authentication mechanism') }}</legend>
-          <p class="alert alert-info"><b>{{ t("security_setting.note") }}: </b>{{ t("security_setting.require_server_restart_change_auth") }}</p>
-          <div class="form-group">
-            <div class="col-xs-6">
-              <h4>
-                <div class="radio radio-primary">
-                  <input type="radio" id="radioPassportAuthMech" name="settingForm[security:isEnabledPassport]" value="true"
-                      {% if true === settingForm['security:isEnabledPassport'] %}checked="checked"{% endif %}>
-                  <label for="radioPassportAuthMech">
-                    <a href="http://passportjs.org/" target="_blank">
-                      <img src="/images/admin/security/passport-logo.svg" class="passport-logo"> Passport
-                    </a> {{ t("security_setting.auth_mechanism") }} <small class="text-success">({{ t("security_setting.recommended") }})</small>
-                  </label>
-                </div>
-              </h4>
-              <ul>
-                <li>{{ t("security_setting.username_email_password") }}</li>
-                <li>{{ t("security_setting.ldap_auth") }}</li>
-                <li>{{ t("security_setting.saml_auth") }}</li>
-                <li>{{ t("security_setting.google_auth2") }}</li>
-                <li>{{ t("security_setting.github_auth2") }}</li>
-                <li>{{ t("security_setting.twitter_auth2") }}</li>
-                <li class="text-muted">(TBD) <del>{{ t("security_setting.facebook_auth2") }}</del></li>
-              </ul>
-            </div>
-            <div class="col-xs-6">
-              <h4>
-                <div class="radio radio-primary">
-                  <input type="radio" id="radioCrowiAuthMech" name="settingForm[security:isEnabledPassport]" value="false"
-                      {% if !settingForm['security:isEnabledPassport'] %}checked="checked"{% endif %}>
-                  <label for="radioCrowiAuthMech">
-                    Crowi Classic {{ t("security_setting.auth_mechanism") }}
-                  </label>
-                </div>
-              </h4>
-              <ul>
-                <li>{{ t("security_setting.username_email_password") }}</li>
-                <li class="text-muted">
-                  {{ t("security_setting.google_auth2") }}
-                  <ul><li>{{ t("security_setting.google_auth2_by_crowi_desc") }}</li></ul>
-                </li>
-              </ul>
-            </div>
-          </div>
-
-          <div class="form-group">
-            <div class="col-xs-offset-5 col-xs-6">
-              <input type="hidden" name="_csrf" value="{{ csrf() }}">
-              <button type="submit" class="btn btn-primary">{{ t('Update') }}</button>
-            </div>
-          </div>
-        </fieldset>
-      </form>
-
 
       <div class="auth-mechanism-configurations m-t-10">
 
         <legend>{{ t('security_setting.Authentication mechanism settings') }}</legend>
 
-        {% set isOfficialConfigurationVisible = !getConfig('crowi', 'security:isEnabledPassport') %}
-        <div class="official-crowi-auth-settings" {% if !isOfficialConfigurationVisible %}style="display: none;"{% endif %}>
-          {% set isRestartingServerNeeded = isPassportLocalStrategySetup() %}
-          <p class="alert alert-warning"
-              {% if !isRestartingServerNeeded %}style="display: none;"{% endif %}>
-            <b>
-              <i class="icon-exclamation" aria-hidden="true"></i>
-              {{ t("security_setting.require_server_restart") }}
-            </b>
-            {{ t("security_setting.server_on_passport_auth") }}
-          </p>
-
-          <form action="/_api/admin/security/google" method="post" class="form-horizontal" id="googleSetting" role="form"
-              {% if isRestartingServerNeeded %}style="opacity: 0.4;"{% endif %}>
-
-            <fieldset>
-              <h4>{{ t("security_setting.google_setting") }}</h4>
-              <p class="well alert-anchor">
-                {{ t("security_setting.connect_api_manager") }}
-              </p>
-
-              <ol class="help-block">
-                <li>{{ t("security_setting.access_api_manager", "https://console.cloud.google.com/apis/credentials", "API Manager") }}</li>
-                <li>{{ t("security_setting.create_project") }}</li>
-                <li>{{ t("security_setting.create_auth_to_oauth") }}</li>
-                <ol>
-                  <li>{{ t("security_setting.select_webapp") }}</li>
-                  <li>{{ t("security_setting.change_redirect_url") }}</li>
-                </ol>
-              </ol>
-
-              <div class="form-group">
-                <label for="settingForm[google:clientId]" class="col-xs-3 control-label">{{ t("security_setting.clientID") }}</label>
-                <div class="col-xs-6">
-                  <input class="form-control" type="text" name="settingForm[google:clientId]" value="{{ settingForm['google:clientId'] }}">
-                </div>
-              </div>
-
-              <div class="form-group">
-                <label for="settingForm[google:clientSecret]" class="col-xs-3 control-label">{{ t("security_setting.client_secret") }}</label>
-                <div class="col-xs-6">
-                  <input class="form-control" type="text" name="settingForm[google:clientSecret]" value="{{ settingForm['google:clientSecret'] }}">
-                </div>
-              </div>
-
-              <div class="form-group">
-                <div class="col-xs-offset-3 col-xs-6">
-                  <input type="hidden" name="_csrf" value="{{ csrf() }}">
-                  <button type="submit" class="btn btn-primary">{{ t('Update') }}</button>
-                </div>
-              </div>
-
-            </fieldset>
-          </form>
-        </div>
-
         {#
          # passport settings nav
          #}
-        {% set isPassportConfigurationVisible = settingForm['security:isEnabledPassport'] %}
-        <div class="passport-settings" {% if !isPassportConfigurationVisible %}style="display: none;"{% endif %}>
-
-          {% set isRestartingServerNeeded = !isPassportLocalStrategySetup() %}
-          <p class="alert alert-warning"
-              {% if !isRestartingServerNeeded %}style="display: none;"{% endif %}>
-            <b>
-              <i class="icon-exclamation" aria-hidden="true"></i>
-              {{ t("security_setting.require_server_restart") }}
-            </b>
-            {{ t("security_setting.server_on_crowi_auth") }}
-          </p>
-          <ul class="nav nav-tabs" role="tablist" {% if isRestartingServerNeeded %}style="opacity: 0.4;"{% endif %}>
+        <div class="passport-settings">
+          <ul class="nav nav-tabs" role="tablist">
             <li class="active">
               <a href="#passport-ldap" data-toggle="tab" role="tab"><i class="fa fa-sitemap"></i> LDAP</a>
             </li>
@@ -312,7 +189,7 @@
             </li>
           </ul>
 
-          <div class="tab-content p-t-10" {% if isRestartingServerNeeded %}style="opacity: 0.4;"{% endif %}>
+          <div class="tab-content p-t-10">
             <div id="passport-ldap" class="tab-pane active" role="tabpanel" >
               {% include './widget/passport/ldap.html' with { settingForm: settingForm } %}
             </div>
@@ -397,20 +274,6 @@
         return false;
       });
     });
-
-    // switch display according to on / off of radio buttons
-    $('input[name="settingForm[security:isEnabledPassport]"]:radio').change(function() {
-      const isEnabledPassport = ($(this).val() === "true");
-
-      if (isEnabledPassport) {
-        $('.official-crowi-auth-settings').hide(400);
-        $('.passport-settings').show(400);
-      }
-      else {
-        $('.official-crowi-auth-settings').show(400);
-        $('.passport-settings').hide(400);
-      }
-    });
   </script>
 </div>
 {% endblock content_main %}

+ 1 - 1
src/server/views/admin/user-group-detail.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('UserGroup Management') + '/' + userGroup.name) | preventXss }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('UserGroup Management') + '/' + userGroup.name) | preventXss }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 1 - 1
src/server/views/admin/user-groups.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('UserGroup Management')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('UserGroup Management')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 1 - 1
src/server/views/admin/users.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customTitle(t('User_Management')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('User_Management')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 1 - 2
src/server/views/admin/widget/passport/github.html

@@ -1,5 +1,4 @@
-<form action="/_api/admin/security/passport-github" method="post" class="form-horizontal passportStrategy" id="githubSetting" role="form"
-    {% if isRestartingServerNeeded %}style="opacity: 0.4;"{% endif %}>
+<form action="/_api/admin/security/passport-github" method="post" class="form-horizontal passportStrategy" id="githubSetting" role="form">
   <legend class="alert-anchor">{{ t("security_setting.OAuth.GitHub.name") }} {{ t("security_setting.configuration") }}</legend>
 
   {% set nameForIsGitHubEnabled = "settingForm[security:passport-github:isEnabled]" %}

+ 1 - 2
src/server/views/admin/widget/passport/google-oauth.html

@@ -1,5 +1,4 @@
-<form action="/_api/admin/security/passport-google" method="post" class="form-horizontal passportStrategy" id="googleSetting" role="form"
-    {% if isRestartingServerNeeded %}style="opacity: 0.4;"{% endif %}>
+<form action="/_api/admin/security/passport-google" method="post" class="form-horizontal passportStrategy" id="googleSetting" role="form">
   <legend class="alert-anchor">{{ t("security_setting.OAuth.Google.name") }} {{ t("security_setting.configuration") }}</legend>
 
   {% set nameForIsGoogleEnabled = "settingForm[security:passport-google:isEnabled]" %}

+ 1 - 2
src/server/views/admin/widget/passport/oidc.html

@@ -1,5 +1,4 @@
-<form action="/_api/admin/security/passport-oidc" method="post" class="form-horizontal passportStrategy" id="oidcSetting" role="form"
-    {% if isRestartingServerNeeded %}style="opacity: 0.4;"{% endif %}>
+<form action="/_api/admin/security/passport-oidc" method="post" class="form-horizontal passportStrategy" id="oidcSetting" role="form">
   <legend class="alert-anchor">{{ t("security_setting.OAuth.OIDC.name") }} {{ t("security_setting.configuration") }}</legend>
 
   {% set nameForIsOIDCEnabled = "settingForm[security:passport-oidc:isEnabled]" %}

+ 1 - 2
src/server/views/admin/widget/passport/saml.html

@@ -1,5 +1,4 @@
-<form action="/_api/admin/security/passport-saml" method="post" class="form-horizontal passportStrategy" id="samlSetting" role="form"
-    {% if isRestartingServerNeeded %}style="opacity: 0.4;"{% endif %}>
+<form action="/_api/admin/security/passport-saml" method="post" class="form-horizontal passportStrategy" id="samlSetting" role="form">
   <legend class="alert-anchor">{{ t("security_setting.SAML.name") }} {{ t("security_setting.configuration") }}</legend>
 
   {% set nameForIsSamlEnabled = "settingForm[security:passport-saml:isEnabled]" %}

+ 1 - 2
src/server/views/admin/widget/passport/twitter.html

@@ -1,5 +1,4 @@
-<form action="/_api/admin/security/passport-twitter" method="post" class="form-horizontal passportStrategy" id="twitterSetting" role="form"
-    {% if isRestartingServerNeeded %}style="opacity: 0.4;"{% endif %}>
+<form action="/_api/admin/security/passport-twitter" method="post" class="form-horizontal passportStrategy" id="twitterSetting" role="form">
   <legend class="alert-anchor">{{ t("security_setting.OAuth.Twitter.name") }} {{ t("security_setting.configuration") }}</legend>
 
   {% set nameForIsTwitterEnabled = "settingForm[security:passport-twitter:isEnabled]" %}

+ 2 - 2
src/server/views/customlayout-selector/forbidden.html

@@ -1,6 +1,6 @@
-{% if !layoutType() || 'crowi' === layoutType() %}
+{% if !getConfig('crowi', 'customize:layout') || 'crowi' === getConfig('crowi', 'customize:layout') %}
   {% include '../layout-crowi/forbidden.html' %}
-{% elseif !layoutType() || 'kibela' === layoutType()%}
+{% elseif !getConfig('crowi', 'customize:layout') || 'kibela' === getConfig('crowi', 'customize:layout')%}
   {% include '../layout-kibela/forbidden.html' %}
 {% else %}
   {% include '../layout-growi/forbidden.html' %}

+ 2 - 2
src/server/views/customlayout-selector/not_creatable.html

@@ -1,6 +1,6 @@
-{% if !layoutType() || 'crowi' === layoutType() %}
+{% if !getConfig('crowi', 'customize:layout') || 'crowi' === getConfig('crowi', 'customize:layout') %}
   {% include '../layout-crowi/not_creatable.html' %}
-{% elseif !layoutType() || 'kibela' === layoutType()%}
+{% elseif !getConfig('crowi', 'customize:layout') || 'kibela' === getConfig('crowi', 'customize:layout')%}
   {% include '../layout-kibela/not_creatable.html' %}
 {% else %}
   {% include '../layout-growi/not_creatable.html' %}

+ 2 - 2
src/server/views/customlayout-selector/not_found.html

@@ -1,6 +1,6 @@
-{% if !layoutType() || 'crowi' === layoutType() %}
+{% if !getConfig('crowi', 'customize:layout') || 'crowi' === getConfig('crowi', 'customize:layout') %}
   {% include '../layout-crowi/not_found.html' %}
-{% elseif !layoutType() || 'kibela' === layoutType()%}
+{% elseif !getConfig('crowi', 'customize:layout') || 'kibela' === getConfig('crowi', 'customize:layout')%}
   {% include '../layout-kibela/not_found.html' %}
 {% else %}
   {% include '../layout-growi/not_found.html' %}

+ 2 - 2
src/server/views/customlayout-selector/page.html

@@ -1,6 +1,6 @@
-{% if !layoutType() || 'crowi' === layoutType() %}
+{% if !getConfig('crowi', 'customize:layout') || 'crowi' === getConfig('crowi', 'customize:layout') %}
   {% include '../layout-crowi/page.html' %}
-{% elseif !layoutType() || 'kibela' === layoutType()%}
+{% elseif !getConfig('crowi', 'customize:layout') || 'kibela' === getConfig('crowi', 'customize:layout')%}
   {% include '../layout-kibela/page.html' %}
 {% else %}
   {% include '../layout-growi/page.html' %}

+ 2 - 2
src/server/views/customlayout-selector/page_list.html

@@ -1,6 +1,6 @@
-{% if !layoutType() || 'crowi' === layoutType() %}
+{% if !getConfig('crowi', 'customize:layout') || 'crowi' === getConfig('crowi', 'customize:layout') %}
   {% include '../layout-crowi/page_list.html' %}
-{% elseif !layoutType() || 'kibela' === layoutType()%}
+{% elseif !getConfig('crowi', 'customize:layout') || 'kibela' === getConfig('crowi', 'customize:layout')%}
   {% include '../layout-kibela/page_list.html' %}
 {% else %}
   {% include '../layout-growi/page_list.html' %}

+ 2 - 2
src/server/views/customlayout-selector/user_page.html

@@ -1,6 +1,6 @@
-{% if !layoutType() || 'crowi' === layoutType() %}
+{% if !getConfig('crowi', 'customize:layout') || 'crowi' === getConfig('crowi', 'customize:layout') %}
   {% include '../layout-crowi/user_page.html' %}
-{% elseif !layoutType() || 'kibela' === layoutType()%}
+{% elseif !getConfig('crowi', 'customize:layout') || 'kibela' === getConfig('crowi', 'customize:layout')%}
   {% include '../layout-kibela/user_page.html' %}
 {% else %}
   {% include '../layout-growi/user_page.html' %}

+ 3 - 3
src/server/views/installer.html

@@ -4,7 +4,7 @@
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-  <title>{{ customTitle(t('installer.setup')) }}</title>
+  <title>{{ customizeService.generateCustomTitle(t('installer.setup')) }}</title>
   <meta name="description" content="">
   <meta name="author" content="">
 
@@ -69,8 +69,8 @@
 
         <div id='installer-form'
           data-user-name="{{ req.body.registerForm.username }}"
-          data-name="{{ googleName|default(req.body.registerForm.name) }}"
-          data-email="{{ googleEmail|default(req.body.registerForm.email) }}"
+          data-name="{{ req.body.registerForm.name }}"
+          data-email="{{ req.body.registerForm.email }}"
           data-csrf="{{ csrf() }}">
         </div>
 

+ 2 - 2
src/server/views/invited.html

@@ -2,7 +2,7 @@
 
 {% block html_base_css %}invited nologin{% endblock %}
 
-{% block html_title %}{{ customTitle('Registration') }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle('Registration') }}{% endblock %}
 
 
 
@@ -73,7 +73,7 @@
 
         <div class="input-group">
           <span class="input-group-addon"><i class="icon-tag"></i></span>
-          <input type="text" class="form-control" placeholder="{{ t('Name') }}" name="invitedForm[name]" value="{{ googleName|default(req.body.invitedForm.name) }}" required>
+          <input type="text" class="form-control" placeholder="{{ t('Name') }}" name="invitedForm[name]" value="{{ req.body.invitedForm.name }}" required>
         </div>
 
 

+ 1 - 1
src/server/views/layout-crowi/base/layout.html

@@ -1,6 +1,6 @@
 {% extends '../../layout/layout.html' %}
 
-{% block html_title %}{{ customTitle(path) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(path) }}{% endblock %}
 
 {% block html_additional_headers %}
   {% parent %}

+ 1 - 1
src/server/views/layout-growi/page.html

@@ -34,7 +34,7 @@
 
   </div>
 
-  {% if 'growi' === behaviorType() || 'crowi-plus' === behaviorType() %}
+  {% if 'growi' === getConfig('crowi', 'customize:behavior') || 'crowi-plus' === getConfig('crowi', 'customize:behavior') %}
   <div class="row page-list hidden-print m-t-30">
     <div class="col-md-10">
       {% include '../widget/page_list_and_timeline.html' %}

+ 1 - 1
src/server/views/layout-growi/user_page.html

@@ -58,7 +58,7 @@
 
   </div>
 
-  {% if 'growi' === behaviorType() || 'crowi-plus' === behaviorType() %}
+  {% if 'growi' === getConfig('crowi', 'customize:behavior') || 'crowi-plus' === getConfig('crowi', 'customize:behavior') %}
   <div class="row page-list hidden-print m-t-30">
     <div class="col-md-10">
       {% include '../widget/page_list_and_timeline.html' %}

+ 1 - 1
src/server/views/layout-growi/widget/header.html

@@ -41,7 +41,7 @@
       </ul>
       {% endif %}
 
-      {% if not page and not forbidden and ('/' === path or 'crowi' === behaviorType()) and not isUserPageList(path) and !isTrashPage() %}
+      {% if not page and not forbidden and ('/' === path or 'crowi' === getConfig('crowi', 'customize:behavior')) and not isUserPageList(path) and !isTrashPage() %}
         {% if '/' === path.slice(-1) %}
           {% include '../../widget/create_portal.html' %}
         {% endif %}

+ 1 - 1
src/server/views/layout-kibela/page.html

@@ -30,7 +30,7 @@
 
 </div>
 
-  {% if 'growi' === behaviorType() || 'crowi-plus' === behaviorType() %}
+  {% if 'growi' === getConfig('crowi', 'customize:behavior') || 'crowi-plus' === getConfig('crowi', 'customize:behavior') %}
   <div class="row page-list p-t-10 m-t-30 m-b-30 round-corner">
     <div class="col-md-10">
       {% include '../widget/page_list_and_timeline.html' %}

+ 1 - 1
src/server/views/layout-kibela/user_page.html

@@ -51,7 +51,7 @@
 
   </div>
 
-  {% if 'growi' === behaviorType() || 'crowi-plus' === behaviorType() %}
+  {% if 'growi' === getConfig('crowi', 'customize:behavior') || 'crowi-plus' === getConfig('crowi', 'customize:behavior') %}
   <div class="row page-list m-t-30">
     <div class="col-xs-12">
       {% include '../widget/page_list_and_timeline_kibela.html' %}

+ 1 - 1
src/server/views/layout-kibela/widget/header.html

@@ -41,7 +41,7 @@
         </div>
       </li>
     </ul>
-    {% endif %} {% if not page and ('/' === path or 'crowi' === behaviorType()) and not isUserPageList(path) and !isTrashPage()
+    {% endif %} {% if not page and ('/' === path or 'crowi' === getConfig('crowi', 'customize:behavior')) and not isUserPageList(path) and !isTrashPage()
     %} {% if '/' === path.slice(-1) %} {% include '../../widget/create_portal.html' %} {% endif %} {% endif %}
 
   </div>

+ 6 - 6
src/server/views/layout/layout.html

@@ -4,7 +4,7 @@
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-  <title>{% block html_title %}{{ customTitle(path) }}{% endblock %}</title>
+  <title>{% block html_title %}{{ customizeService.generateCustomTitle(path) }}{% endblock %}</title>
   <meta name="description" content="">
   <meta name="author" content="">
 
@@ -12,7 +12,7 @@
 
   <meta name="apple-mobile-web-app-title" content="{{ appService.getAppTitle() }}">
 
-  {{ customHeader() }}
+  {{ getConfig('crowi', 'customize:header') | default('') }}
 
   {% include '../widget/headers/favicon.html' %}
   {% include '../widget/headers/ie11-polyfills.html' %}
@@ -49,12 +49,12 @@
   {% endif %}
 
   {{ cdnStyleTagsByGroup('basis') }}
-  {{ cdnHighlightJsStyleTag(highlightJsStyle()) }}
+  {{ cdnHighlightJsStyleTag(getConfig('crowi', 'customize:highlightJsStyle')) }}
 
   {% block html_additional_headers %}{% endblock %}
 
   <style>
-    {{ customCss() }}
+    {{ customizeService.getCustomCss() }}
   </style>
 </head>
 {% endblock %}
@@ -62,7 +62,7 @@
 {% block html_body %}
 <body
   class="main-container content-wrapper {% block html_base_css %}{% endblock %}
-      {% if !layoutType() || 'crowi' === layoutType() %}crowi{% elseif !layoutType() || 'kibela' === layoutType() %}kibela{% else %}growi{% endif %}"
+      {% if !getConfig('crowi', 'customize:layout') || 'crowi' === getConfig('crowi', 'customize:layout') %}crowi{% elseif !getConfig('crowi', 'customize:layout') || 'kibela' === getConfig('crowi', 'customize:layout') %}kibela{% else %}growi{% endif %}"
   data-me="{{ user._id.toString() }}"
   data-is-admin="{{ user.admin }}"
   data-plugin-enabled="{{ getConfig('crowi', 'plugin:isEnabledPlugins') }}"
@@ -208,7 +208,7 @@
 
 {% block custom_script %}
 <script>
-  {{ customScript() }}
+  {{ customizeService.getCustomScript() }}
 </script>
 {% endblock %}
 

+ 16 - 49
src/server/views/login.html

@@ -2,7 +2,7 @@
 
 {% block html_base_css %}login-page nologin{% endblock %}
 
-{% block html_title %}{{ customTitle(t('Sign in')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('Sign in')) }}{% endblock %}
 
 
 
@@ -100,7 +100,7 @@
       </div>
     </div>
 
-    <div class="login-dialog p-b-10 col-sm-offset-4 col-sm-4 flipper {% if req.query.register or req.body.registerForm or isRegistering or googleId %}to-flip{% endif %}" id="login-dialog">
+    <div class="login-dialog p-b-10 col-sm-offset-4 col-sm-4 flipper {% if req.query.register or req.body.registerForm or isRegistering %}to-flip{% endif %}" id="login-dialog">
 
       <div class="front">
         <form role="form" action="/login" method="post">
@@ -130,35 +130,19 @@
           </div>
         </form>
 
-        {% if googleLoginEnabled() %}
-        <hr>
-
-        <div class="input-group m-t-15 m-b-10 mx-auto">
-          <form role="form" action="/login/google" method="get">
-            <input type="hidden" name="_csrf" value="{{ csrf() }}">
-            <button type="submit" class="fcbtn btn btn-danger btn-1b btn-login-oauth" id="google">
-              <span class="btn-label"><i class="icon-social-google"></i></span>
-              {{ t('Sign in') }}
-            </button>
-            <div class="small text-right">by Google Account</div>
-          </form>
-        </div>
-        {% endif %}
         {% if (
-          getConfig('crowi', 'security:isEnabledPassport') && (
-            getConfig('crowi', 'security:passport-google:isEnabled') ||
-            getConfig('crowi', 'security:passport-github:isEnabled') ||
-            getConfig('crowi', 'security:passport-facebook:isEnabled') ||
-            getConfig('crowi', 'security:passport-twitter:isEnabled')||
-            getConfig('crowi', 'security:passport-oidc:isEnabled') ||
-            getConfig('crowi', 'security:passport-saml:isEnabled')
-          )
+          getConfig('crowi', 'security:passport-google:isEnabled') ||
+          getConfig('crowi', 'security:passport-github:isEnabled') ||
+          getConfig('crowi', 'security:passport-facebook:isEnabled') ||
+          getConfig('crowi', 'security:passport-twitter:isEnabled')||
+          getConfig('crowi', 'security:passport-oidc:isEnabled') ||
+          getConfig('crowi', 'security:passport-saml:isEnabled')
         ) %}
         <hr class="mb-1">
         <div class="collapse collapse-oauth collapse-anchor">
           <div class="spacer"></div>
           <div class="d-flex flex-row justify-content-between flex-wrap">
-            {% if getConfig('crowi', 'security:isEnabledPassport') && getConfig('crowi', 'security:passport-google:isEnabled') %}
+            {% if getConfig('crowi', 'security:passport-google:isEnabled') %}
             <form role="form" action="/passport/google" class="d-inline-flex flex-column">
               <button type="submit" class="fcbtn btn btn-1b btn-login-oauth d-flex" id="google">
                 <span class="btn-label"><i class="fa fa-google"></i></span>
@@ -167,7 +151,7 @@
               <div class="small text-right">by Google Account</div>
             </form>
             {% endif %}
-            {% if getConfig('crowi', 'security:isEnabledPassport') && getConfig('crowi', 'security:passport-github:isEnabled') %}
+            {% if getConfig('crowi', 'security:passport-github:isEnabled') %}
             <form role="form" action="/passport/github" class="d-inline-flex flex-column">
               <input type="hidden" name="_csrf" value="{{ csrf() }}">
               <button type="submit" class="fcbtn btn btn-1b btn-login-oauth d-inline-flex" id="github">
@@ -177,7 +161,7 @@
               <div class="small text-right">by GitHub Account</div>
             </form>
             {% endif %}
-            {% if getConfig('crowi', 'security:isEnabledPassport') && getConfig('crowi', 'security:passport-facebook:isEnabled') %}
+            {% if getConfig('crowi', 'security:passport-facebook:isEnabled') %}
             <form role="form" action="/passport/facebook" class="d-inline-flex flex-column">
               <input type="hidden" name="_csrf" value="{{ csrf() }}">
               <button type="submit" class="fcbtn btn btn-1b btn-login-oauth d-inline-flex" id="facebook">
@@ -187,7 +171,7 @@
               <div class="small text-right">by Facebook Account</div>
             </form>
             {% endif %}
-            {% if getConfig('crowi', 'security:isEnabledPassport') && getConfig('crowi', 'security:passport-twitter:isEnabled') %}
+            {% if getConfig('crowi', 'security:passport-twitter:isEnabled') %}
             <form role="form" action="/passport/twitter" class="d-inline-flex flex-column">
               <input type="hidden" name="_csrf" value="{{ csrf() }}">
               <button type="submit" class="fcbtn btn btn-1b btn-login-oauth d-inline-flex" id="twitter">
@@ -197,7 +181,7 @@
               <div class="small text-right">by Twitter Account</div>
             </form>
             {% endif %}
-            {% if getConfig('crowi', 'security:isEnabledPassport') && getConfig('crowi', 'security:passport-oidc:isEnabled') %}
+            {% if getConfig('crowi', 'security:passport-oidc:isEnabled') %}
             <form role="form" action="/passport/oidc" class="d-inline-flex flex-column">
               <input type="hidden" name="_csrf" value="{{ csrf() }}">
               <button type="submit" class="fcbtn btn btn-1b btn-login-oauth d-inline-flex" id="oidc">
@@ -207,7 +191,7 @@
               <div class="small text-right">{{ getConfig('crowi', 'security:passport-oidc:providerName') || "OpenID Connect" }}</div>
             </form>
             {% endif %}
-            {% if getConfig('crowi', 'security:isEnabledPassport') && getConfig('crowi', 'security:passport-saml:isEnabled') %}
+            {% if getConfig('crowi', 'security:passport-saml:isEnabled') %}
             <form role="form" action="/passport/saml" class="d-inline-flex flex-column">
               <input type="hidden" name="_csrf" value="{{ csrf() }}">
               <button type="submit" class="fcbtn btn btn-1b btn-login-oauth d-inline-flex" id="saml">
@@ -265,21 +249,7 @@
         </p>
         {% endif %}
 
-        {% if googleId %}
-        <div class="google-info alert alert-info">
-          {% if googleImage %}
-          <p class="text-center">
-            <img src="{{ googleImage }}" class="img-circle img-circle-lg">
-          </p>
-          {% endif %}
-          <code>{{ googleEmail }}</code> {{ t('page_register with this Google Account') }}<br>
-          {{ t('page_register.notice.google_account_continue') }}
-        </div>
-        {% endif %}
-
         <form role="form" method="post" action="/register" id="register-form">
-          <input type="hidden" class="form-control" name="registerForm[googleId]" value="{{ googleId|default(req.body.registerForm.googleId) }}">
-
           <div class="input-group" id="input-group-username">
             <span class="input-group-addon"><i class="icon-user"></i></span>
             <input type="text" class="form-control" placeholder="{{ t('User ID') }}" name="registerForm[username]" value="{{ req.body.registerForm.username }}" required>
@@ -290,12 +260,12 @@
 
           <div class="input-group">
             <span class="input-group-addon"><i class="icon-tag"></i></span>
-            <input type="text" class="form-control" placeholder="{{ t('Name') }}" name="registerForm[name]" value="{{ googleName|default(req.body.registerForm.name) }}" required>
+            <input type="text" class="form-control" placeholder="{{ t('Name') }}" name="registerForm[name]" value="{{ req.body.registerForm.name }}" required>
           </div>
 
           <div class="input-group">
             <span class="input-group-addon"><i class="icon-envelope"></i></span>
-            <input type="email" class="form-control" placeholder="{{ t('Email') }}" name="registerForm[email]" value="{{ googleEmail|default(req.body.registerForm.email) }}" required>
+            <input type="email" class="form-control" placeholder="{{ t('Email') }}" name="registerForm[email]" value="{{ req.body.registerForm.email }}" required>
           </div>
           {% if config.crowi['security:registrationWhiteList'] && config.crowi['security:registrationWhiteList'].length %}
           <p class="help-block">
@@ -313,9 +283,6 @@
             <input type="password" class="form-control" placeholder="{{ t('Password') }}" name="registerForm[password]" required>
           </div>
 
-          {% if googleImage %}
-            <input type="hidden" name="registerForm[googleImage]" value="{{ googleImage }}">
-          {% endif  %}
           <input type="hidden" name="_csrf" value="{{ csrf() }}">
 
           <div class="input-group m-t-30 m-b-20 d-flex justify-content-center">

+ 1 - 1
src/server/views/login/error.html

@@ -2,7 +2,7 @@
 
 {% block html_base_css %}error nologin{% endblock %}
 
-{% block html_title %}{{ customTitle('セットアップ') }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle('セットアップ') }}{% endblock %}
 
 
 

+ 1 - 3
src/server/views/me/api_token.html

@@ -1,7 +1,7 @@
 {% extends '../layout-growi/base/layout.html' %}
 
 
-{% block html_title %}{{ customTitle(t('API Settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('API Settings')) }}{% endblock %}
 
 
 {% block content_header %}
@@ -17,9 +17,7 @@
 
   <ul class="nav nav-tabs">
     <li><a href="/me"><i class="icon-user"></i> {{ t('User Information') }}</a></li>
-    {% if getConfig('crowi', 'security:isEnabledPassport') %}
     <li><a href="/me/external-accounts"><i class="icon-share-alt"></i> {{ t('External Accounts') }}</a></li>
-    {% endif %}
     <li><a href="/me/password"><i class="icon-lock"></i> {{ t('Password Settings') }}</a></li>
     <li class="active"><a href="/me/apiToken"><i class="icon-paper-plane"></i> {{ t('API Settings') }}</a></li>
   </ul>

+ 1 - 1
src/server/views/me/external-accounts.html

@@ -1,6 +1,6 @@
 {% extends '../layout-growi/base/layout.html' %}
 
-{% block html_title %}{{ customTitle(t('user_management.external_account')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('user_management.external_account')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">

+ 1 - 52
src/server/views/me/index.html

@@ -1,6 +1,6 @@
 {% extends '../layout-growi/base/layout.html' %}
 
-{% block html_title %}{{ customTitle(t('User Settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('User Settings')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">
@@ -15,9 +15,7 @@
 
   <ul class="nav nav-tabs">
     <li class="active"><a href="/me"><i class="icon-user"></i> {{ t('User Information') }}</a></li>
-    {% if getConfig('crowi', 'security:isEnabledPassport') %}
     <li><a href="/me/external-accounts"><i class="icon-share-alt"></i> {{ t('External Accounts') }}</a></li>
-    {% endif %}
     <li><a href="/me/password"><i class="icon-lock"></i> {{ t('Password Settings') }}</a></li>
     <li><a href="/me/apiToken"><i class="icon-paper-plane"></i> {{ t('API Settings') }}</a></li>
   </ul>
@@ -263,55 +261,6 @@
     });
   </script>
 
-  {% if googleLoginEnabled() %}
-  <div class="form-box">
-    <legend>{{ t('Google Setting') }}</legend>
-    <form action="/me/auth/google" method="post" class="form-horizontal col-sm-12" role="form">
-      <fieldset>
-        {% set wmessage = req.flash('warningMessage.auth.google') %}
-        {% if wmessage.length %}
-        <div class="alert alert-danger">
-          {{ wmessage }}
-        </div>
-        {% endif %}
-
-        <div class="form-group">
-        {% if user.googleId %}
-        <div>
-          <p>
-            <input type="submit" name="disconnectGoogle" class="btn btn-default" value="{{ t('Disconnect') }}">
-          </p>
-          <p class="help-block">
-            {{ t('page_me.form_help.google_disconnect1') }}<br>
-            {{ t('page_me.form_help.google_disconnect2') }}
-          </p>
-        </div>
-        {% else %}
-        <div>
-          <div class="text-center">
-            <input type="submit" name="connectGoogle" class="btn btn-google" value="Googleコネクト">
-          </div>
-          <p class="help-block">
-            {{ t('page_me.form_help.google_connect1') }}<br>
-          </p>
-          {% if config.crowi['security:registrationWhiteList'] && config.crowi['security:registrationWhiteList'].length %}
-          <p class="help-block">
-            {{ t('page_register.form_help.email') }}<br>
-            {{ t('page_me.form_help.google_connect2') }}
-          </p>
-          <ul>
-            {% for em in config.crowi['security:registrationWhiteList'] %}
-            <li><code>{{ em }}</code></li>
-            {% endfor %}
-          </ul>
-          {% endif %}
-        </div>
-        {% endif %}
-      </fieldset>
-    </form>
-  </div>
-  {% endif %}
-
   </div> {# end of .tab-contents #}
 
   {#

+ 1 - 3
src/server/views/me/password.html

@@ -1,6 +1,6 @@
 {% extends '../layout-growi/base/layout.html' %}
 
-{% block html_title %}{{ customTitle(t('Password Settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitle(t('Password Settings')) }}{% endblock %}
 
 {% block content_header %}
 <div class="header-wrap">
@@ -15,9 +15,7 @@
 
   <ul class="nav nav-tabs">
     <li><a href="/me"><i class="icon-user"></i> {{ t('User Information') }}</a></li>
-    {% if getConfig('crowi', 'security:isEnabledPassport') %}
     <li><a href="/me/external-accounts"><i class="icon-share-alt"></i> {{ t('External Accounts') }}</a></li>
-    {% endif %}
     <li class="active"><a href="/me/password"><i class="icon-lock"></i> {{ t('Password Settings') }}</a></li>
     <li><a href="/me/apiToken"><i class="icon-paper-plane"></i> {{ t('API Settings') }}</a></li>
   </ul>

+ 3 - 3
src/server/views/page_presentation.html

@@ -6,7 +6,7 @@
     <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
 
-    {{ customHeader() }}
+    {{ getConfig('crowi', 'customize:header') | default('') }}
 
     <!-- polyfills for IE11 -->
     <script>
@@ -32,10 +32,10 @@
     <title>{{ path|path2name }} | {{ path }}</title>
 
     {{ cdnStyleTagsByGroup('basis') }}
-    {{ cdnHighlightJsStyleTag(highlightJsStyle()) }}
+    {{ cdnHighlightJsStyleTag(getConfig('crowi', 'customize:highlightJsStyle')) }}
 
     <style>
-      {{ customCss() }}
+      {{ customizeService.getCustomCss() }}
     </style>
   </head>
   <body>

+ 0 - 7
src/server/views/widget/alert_breaking_changes.html

@@ -1,12 +1,5 @@
 {# Added in v3.4.6 }
 
-{% if getConfig('crowi', 'security:isEnabledPassport') !== true %}
-<div class="myadmin-alert alert alert-warning mb-0">
-  <i class="icon-exclamation"></i>
-  {{ t("breaking_changes.v346_passport_is_not_enabled", '<a href="/admin/security">' + t('Security settings') + '<i class="icon-login"></i></a>') }}
-</div>
-{% endif %}
-
 {% if getConfig('crowi', 'security:basicName') || getConfig('crowi', 'security:basicSecret') %}
 <div class="myadmin-alert alert alert-warning mb-0">
   <i class="icon-exclamation"></i>

+ 2 - 2
src/server/views/widget/page_content.html

@@ -21,7 +21,7 @@
 
   {% include 'page_alerts.html' %}
 
-  {% if !layoutType() || 'kibela' === layoutType() %}
+  {% if !getConfig('crowi', 'customize:layout') || 'kibela' === getConfig('crowi', 'customize:layout') %}
     {% include 'page_tabs_kibela.html' %}
   {% else %}
     {% include 'page_tabs.html' %}
@@ -40,7 +40,7 @@
         </div>
         <div id="page" class="m-t-15"></div>
       </div>
-    {% elseif 'crowi' === behaviorType() %}
+    {% elseif 'crowi' === getConfig('crowi', 'customize:behavior') %}
       <div class="tab-pane active" id="cancel-creating-portal">
       </div>
     {% endif %}

+ 2 - 2
src/server/views/widget/page_list_and_timeline.html

@@ -1,7 +1,7 @@
 <div class="page-list-container">
   <ul class="nav nav-tabs">
       <li class="active"><a href="#view-list" data-toggle="tab">{{ t('List View') }}</a></li>
-      {% if isEnabledTimeline() %}
+      {% if getConfig('crowi', 'customize:isEnabledTimeline') %}
       <li><a href="#view-timeline" data-toggle="tab">{{ t('Timeline View') }}</a></li>
       {% endif %}
   </ul>
@@ -23,7 +23,7 @@
     </div>
 
     {# timeline view #}
-    {% if isEnabledTimeline() %}
+    {% if getConfig('crowi', 'customize:isEnabledTimeline') %}
     <div class="tab-pane m-t-30" id="view-timeline" data-shown=0>
       {% for page in pages %}
       <div class="timeline-body" id="id-{{ page.id }}" data-page-id="{{ page.id }}" data-page-path="{{ page.path }}" data-revision="{{ page.revision.toString() }}">

+ 2 - 2
src/server/views/widget/page_list_and_timeline_kibela.html

@@ -1,7 +1,7 @@
 <div class="page-list-container">
   <ul class="nav nav-tabs customtab">
       <li class="active"><a href="#view-list" data-toggle="tab">{{ t('List View') }}</a></li>
-      {% if isEnabledTimeline() %}
+      {% if getConfig('crowi', 'customize:isEnabledTimeline') %}
       <li><a href="#view-timeline" data-toggle="tab">{{ t('Timeline View') }}</a></li>
       {% endif %}
   </ul>
@@ -23,7 +23,7 @@
     </div>
 
     {# timeline view #}
-    {% if isEnabledTimeline() %}
+    {% if getConfig('crowi', 'customize:isEnabledTimeline') %}
     <div class="tab-pane m-t-30" id="view-timeline" data-shown=0>
       {% for page in pages %}
       <div class="timeline-body" id="id-{{ page.id }}" data-page-id="{{ page.id }}" data-page-path="{{ page.path }}" data-revision="{{ page.revision._id }}">

+ 6 - 151
yarn.lock

@@ -644,13 +644,6 @@ abbrev@1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
 
-abort-controller@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
-  integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
-  dependencies:
-    event-target-shim "^5.0.0"
-
 accepts@1.3.3:
   version "1.3.3"
   resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
@@ -710,12 +703,6 @@ after@0.8.2:
   version "0.8.2"
   resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
 
-agent-base@^4.1.0:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
-  dependencies:
-    es6-promisify "^5.0.0"
-
 agentkeepalive@^3.4.1:
   version "3.4.1"
   resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.4.1.tgz#aa95aebc3a749bca5ed53e3880a09f5235b48f0c"
@@ -951,11 +938,6 @@ arrify@^1.0.0, arrify@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
 
-arrify@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
-  integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
-
 asap@^2.0.0, asap@~2.0.3:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
@@ -1797,10 +1779,6 @@ base64-js@^1.0.2:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886"
 
-base64-js@^1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
-
 base64id@1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
@@ -1878,10 +1856,6 @@ bignumber.js@^4.0.4:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.1.0.tgz#db6f14067c140bd46624815a7916c92d9b6c24b1"
 
-bignumber.js@^7.0.0:
-  version "7.2.1"
-  resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-7.2.1.tgz#80c048759d826800807c4bfd521e50edbba57a5f"
-
 binary-extensions@^1.0.0:
   version "1.11.0"
   resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
@@ -3951,21 +3925,11 @@ es6-object-assign@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c"
 
-es6-promise@^4.0.3:
-  version "4.2.5"
-  resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
-
 es6-promise@^4.2.6:
   version "4.2.6"
   resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f"
   integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==
 
-es6-promisify@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
-  dependencies:
-    es6-promise "^4.0.3"
-
 esa-nodejs@^0.0.7:
   version "0.0.7"
   resolved "https://registry.yarnpkg.com/esa-nodejs/-/esa-nodejs-0.0.7.tgz#c4749412605ad430d5da17aa4928291927561b42"
@@ -4193,10 +4157,6 @@ event-stream@^3.3.2, event-stream@~3.3.0:
     stream-combiner "~0.0.4"
     through "~2.3.1"
 
-event-target-shim@^5.0.0:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
-
 eventemitter3@1.x.x:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508"
@@ -4438,7 +4398,7 @@ extend@^3.0.0, extend@~3.0.1:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
 
-extend@^3.0.2, extend@~3.0.2:
+extend@~3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
 
@@ -4497,10 +4457,6 @@ fast-levenshtein@~2.0.4:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
 
-fast-text-encoding@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz#3e5ce8293409cfaa7177a71b9ca84e1b1e6f25ef"
-
 fastparse@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
@@ -4895,30 +4851,12 @@ gauge@~2.7.3:
     strip-ansi "^3.0.1"
     wide-align "^1.1.0"
 
-gaxios@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-2.0.1.tgz#2ca1c9eb64c525d852048721316c138dddf40708"
-  integrity sha512-c1NXovTxkgRJTIgB2FrFmOFg4YIV6N/bAa4f/FZ4jIw13Ql9ya/82x69CswvotJhbV3DiGnlTZwoq2NVXk2Irg==
-  dependencies:
-    abort-controller "^3.0.0"
-    extend "^3.0.2"
-    https-proxy-agent "^2.2.1"
-    node-fetch "^2.3.0"
-
 gaze@^1.0.0:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
   dependencies:
     globule "^1.0.0"
 
-gcp-metadata@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-2.0.0.tgz#afd6092bd68e64c508e1687dfb829f5800eaa12e"
-  integrity sha512-BN6KUUWo6WLkDRst+Y7bqpXq1PYMrKUecNLRdZESp7oYtMjWcZdAM0UYvcip8wb0GXNO/j8Z8HTccK4iYtMvyQ==
-  dependencies:
-    gaxios "^2.0.0"
-    json-bigint "^0.3.0"
-
 get-caller-file@^1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
@@ -5092,21 +5030,6 @@ gonzales-pe@^4.0.3:
   dependencies:
     minimist "1.1.x"
 
-google-auth-library@^4.0.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-4.2.0.tgz#fe1144ff07bea2852f3669b759f774fcc5171d02"
-  integrity sha512-AtIzv/MZpo8BQvt1J+ObetUVFQBAae2I3u6Wy4XqePYShHnYiRdXqWr2WWBkIllOGbWEwsq4PUfvafgw76XGLQ==
-  dependencies:
-    arrify "^2.0.0"
-    base64-js "^1.3.0"
-    fast-text-encoding "^1.0.0"
-    gaxios "^2.0.0"
-    gcp-metadata "^2.0.0"
-    gtoken "^3.0.0"
-    jws "^3.1.5"
-    lru-cache "^5.0.0"
-    semver "^6.0.0"
-
 google-auth-library@~0.10.0:
   version "0.10.0"
   resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e"
@@ -5127,25 +5050,6 @@ google-p12-pem@^0.1.0:
   dependencies:
     node-forge "^0.7.1"
 
-google-p12-pem@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-2.0.0.tgz#78f57cfeee46bd676e4a556009432712b687bad6"
-  integrity sha512-n8eGSKzWOb9/EmSBIh81sPvsQM939QlpHMXahTZDzuRIpCu09x3Oaqz+mXGjL4TeCvSbcnOC0YZRvjkJ9s9lnA==
-  dependencies:
-    node-forge "^0.8.0"
-
-googleapis-common@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/googleapis-common/-/googleapis-common-2.0.0.tgz#66683d7036503fbd3ac7d2cb154efe1d767c928d"
-  integrity sha512-RyUkadTbrTWOCMnKYVYg1pxeH6oFKDr8WHOesbjsgPY1tS10q8Wdmf3VUKL3MMqNEM5ue2IxdfM2FzpYUGHaxA==
-  dependencies:
-    gaxios "^2.0.0"
-    google-auth-library "^4.0.0"
-    pify "^4.0.0"
-    qs "^6.5.2"
-    url-template "^2.0.8"
-    uuid "^3.2.1"
-
 googleapis@^16.0.0:
   version "16.1.0"
   resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-16.1.0.tgz#0f19f2d70572d918881a0f626e3b1a2fa8629576"
@@ -5154,14 +5058,6 @@ googleapis@^16.0.0:
     google-auth-library "~0.10.0"
     string-template "~1.0.0"
 
-googleapis@^40.0.0:
-  version "40.0.0"
-  resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-40.0.0.tgz#c2b16f660fb7a8dcada97e9862b73955ba83865e"
-  integrity sha512-G4iUF6V141mbgbXmbXQDYP0pOYJAONvA8m+RzYfuVBcwfKm7Pn6Aes9LT0a6ddmW9CmydHmHdOgKZuWwkXueXg==
-  dependencies:
-    google-auth-library "^4.0.0"
-    googleapis-common "^2.0.0"
-
 got@^6.7.1:
   version "6.7.1"
   resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
@@ -5228,17 +5124,6 @@ gtoken@^1.2.1:
     mime "^1.4.1"
     request "^2.72.0"
 
-gtoken@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-3.0.0.tgz#7d37245b5109442d8ec28075d5de15505c7462ad"
-  integrity sha512-IY9HVi78D4ykVHn+ThI7rlcpdFtKyo9e9YLim9S9T3rp6fEnfeTexcrqzSpExVshPofsdauLKIa8dEnzX7ZLfQ==
-  dependencies:
-    gaxios "^2.0.0"
-    google-p12-pem "^2.0.0"
-    jws "^3.1.5"
-    mime "^2.2.0"
-    pify "^4.0.0"
-
 gud@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
@@ -5572,13 +5457,6 @@ https-browserify@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
 
-https-proxy-agent@^2.2.1:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
-  dependencies:
-    agent-base "^4.1.0"
-    debug "^3.1.0"
-
 humanize-ms@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
@@ -6776,12 +6654,6 @@ jsesc@~0.5.0:
   version "0.5.0"
   resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
 
-json-bigint@^0.3.0:
-  version "0.3.0"
-  resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-0.3.0.tgz#0ccd912c4b8270d05f056fbd13814b53d3825b1e"
-  dependencies:
-    bignumber.js "^7.0.0"
-
 json-buffer@3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
@@ -6907,7 +6779,7 @@ jwa@^1.1.5:
     ecdsa-sig-formatter "1.0.10"
     safe-buffer "^5.0.1"
 
-jws@^3.0.0, jws@^3.1.5:
+jws@^3.0.0:
   version "3.1.5"
   resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.5.tgz#80d12d05b293d1e841e7cb8b4e69e561adcf834f"
   dependencies:
@@ -7296,7 +7168,7 @@ lru-cache@^4.0.1, lru-cache@^4.0.2:
     pseudomap "^1.0.2"
     yallist "^2.1.2"
 
-lru-cache@^5.0.0, lru-cache@^5.1.1:
+lru-cache@^5.1.1:
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
   dependencies:
@@ -7655,10 +7527,6 @@ mime@^1.4.1:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
 
-mime@^2.2.0:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369"
-
 mimic-fn@^1.0.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
@@ -8052,11 +7920,6 @@ node-fetch@^1.0.1:
     encoding "^0.1.11"
     is-stream "^1.0.1"
 
-node-fetch@^2.3.0:
-  version "2.6.0"
-  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
-  integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
-
 node-forge@^0.7.0:
   version "0.7.6"
   resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac"
@@ -8065,7 +7928,7 @@ node-forge@^0.7.1:
   version "0.7.1"
   resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300"
 
-node-forge@^0.8.0, node-forge@^0.8.1:
+node-forge@^0.8.1:
   version "0.8.4"
   resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.4.tgz#d6738662b661be19e2711ef01aa3b18212f13030"
   integrity sha512-UOfdpxivIYY4g5tqp5FNRNgROVNxRACUxxJREntJLFaJr1E0UEqFtUIk0F/jYx/E+Y6sVXd0KDi/m5My0yGCVw==
@@ -9009,7 +8872,7 @@ pify@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
 
-pify@^4.0.0, pify@^4.0.1:
+pify@^4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
 
@@ -9690,7 +9553,7 @@ qs@6.5.1, qs@~6.5.1:
   version "6.5.1"
   resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
 
-qs@^6.5.2, qs@~6.5.2:
+qs@~6.5.2:
   version "6.5.2"
   resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
 
@@ -12234,10 +12097,6 @@ url-parse-lax@^3.0.0:
   dependencies:
     prepend-http "^2.0.0"
 
-url-template@^2.0.8:
-  version "2.0.8"
-  resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21"
-
 url-to-options@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
@@ -12310,10 +12169,6 @@ uuid@^3.0.1, uuid@^3.3.2:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
 
-uuid@^3.2.1:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
-
 uws@~0.14.4:
   version "0.14.5"
   resolved "https://registry.yarnpkg.com/uws/-/uws-0.14.5.tgz#67aaf33c46b2a587a5f6666d00f7691328f149dc"