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

Merge branch 'reactify-admin/security' into call-api-local-security-setting

# Conflicts:
#	src/server/routes/apiv3/security-setting.js
WESEEK Kaito 6 лет назад
Родитель
Сommit
1e7d9fd24f

+ 46 - 0
.github/workflows/build-rc.yml

@@ -0,0 +1,46 @@
+name: Release Docker Images for RC
+
+on:
+  push:
+    branches:
+      - rc/*
+
+jobs:
+
+  build-rc:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v1
+
+    - name: Set up Docker Buildx
+      uses: crazy-max/ghaction-docker-buildx@v1.0.4
+
+    - name: Login to docker.io registry
+      run: |
+        echo ${{ secrets. DOCKER_REGISTRY_PASSWORD }} | docker login --username wsmoogle --password-stdin
+
+    - name: Build Docker Image
+      run: |
+        CACHE_REF=weseek/growi-cache:3
+        docker buildx build \
+          --tag growi \
+          --platform linux/amd64 \
+          --load \
+          --cache-from=type=registry,ref=$CACHE_REF \
+          --cache-to=type=registry,ref=$CACHE_REF,mode=max \
+          --file ./docker/Dockerfile .
+
+    - name: Get SemVer
+      run: |
+        semver=`npm run version --silent`
+        echo ::set-env name=SEMVER::$semver
+
+    - name: Docker Tags by SemVer
+      uses: weseek/ghaction-docker-tags-by-semver@v1.0.3
+      with:
+        source: growi
+        target: weseek/growi
+        semver: ${{ env.SEMVER }}
+        publish: true

+ 74 - 0
.github/workflows/build.yml

@@ -0,0 +1,74 @@
+name: Release Docker Images
+
+on:
+  push:
+    tags:
+      - v3.*
+
+jobs:
+
+  build:
+
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        flavor: [default, nocdn]
+
+    steps:
+    - uses: actions/checkout@v1
+
+    - name: Determine suffix
+      run: |
+        [[ ${{ matrix.flavor }} = "nocdn" ]] && suffix="-nocdn" || suffix=""
+        echo ::set-env name=SUFFIX::$suffix
+
+    - name: Set up Docker Buildx
+      uses: crazy-max/ghaction-docker-buildx@v1.0.4
+
+    - name: Login to docker.io registry
+      run: |
+        echo ${{ secrets. DOCKER_REGISTRY_PASSWORD }} | docker login --username wsmoogle --password-stdin
+
+    - name: Build Docker Image
+      run: |
+        CACHE_REF=weseek/growi-cache:3${{ env.SUFFIX }}
+        docker buildx build \
+          --tag growi \
+          --build-arg flavor=${{ matrix.flavor }} \
+          --platform linux/amd64 \
+          --load \
+          --cache-from=type=registry,ref=$CACHE_REF \
+          --cache-to=type=registry,ref=$CACHE_REF,mode=max \
+          --file ./docker/Dockerfile .
+
+    - name: Get SemVer
+      run: |
+        semver=`npm run version --silent`
+        echo ::set-env name=SEMVER::$semver
+
+    - name: Docker Tags by SemVer
+      uses: weseek/ghaction-docker-tags-by-semver@v1.0.5
+      with:
+        source: growi
+        target: weseek/growi
+        semver: ${{ env.SEMVER }}
+        suffix: ${{ env.SUFFIX }}
+        additional-tags: 'latest'
+        publish: true
+
+  publish-desc:
+
+    runs-on: ubuntu-latest
+    needs: build
+
+    steps:
+    - uses: actions/checkout@v1
+
+    - name: Update Docker Hub Description
+      uses: peter-evans/dockerhub-description@v2.1.0
+      env:
+        DOCKERHUB_USERNAME: wsmoogle
+        DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
+        DOCKERHUB_REPOSITORY: weseek/growi
+        README_FILEPATH: ./docker/README.md

+ 164 - 0
.github/workflows/ci.yml

@@ -0,0 +1,164 @@
+name: Node CI
+
+on: [push]
+
+jobs:
+
+  resolve-dependencies:
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        node-version: [10.x, 12.x]
+
+    steps:
+    - uses: actions/checkout@v1
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+    - name: Cache/Restore node_modules
+      id: cache
+      uses: actions/cache@v1
+      with:
+        path: node_modules
+        key: ${{ runner.OS }}-node_modules-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
+    - name: Install dependencies
+      if: steps.cache.outputs.cache-hit != 'true'
+      run: |
+        yarn
+    - name: Install plugins
+      if: steps.cache.outputs.cache-hit != 'true'
+      run: |
+        yarn add growi-plugin-lsx growi-plugin-pukiwiki-like-linker growi-plugin-attachment-refs
+        yarn add -D react-images react-motion
+    - name: Print dependencies
+      run: |
+        echo -n "node " && node -v
+        echo -n "npm " && npm -v
+        yarn list --depth=0
+
+
+  test:
+    runs-on: ubuntu-latest
+    needs: resolve-dependencies
+
+    strategy:
+      matrix:
+        node-version: [10.x, 12.x]
+
+    steps:
+    - uses: actions/checkout@v1
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+    - name: Cache/Restore node_modules
+      uses: actions/cache@v1
+      with:
+        path: node_modules
+        key: ${{ runner.OS }}-node_modules-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
+    - name: yarn lint
+      run: |
+        yarn lint
+    - name: Launch MongoDB
+      uses: wbari/start-mongoDB@v0.2
+      with:
+        mongoDBVersion: 3.6
+    - name: yarn test
+      run: |
+        yarn test
+      env:
+        MONGO_URI: mongodb://localhost:27017/growi_test
+
+    - name: Slack Notification
+      uses: homoluctus/slatify@master
+      if: failure()
+      with:
+        type: ${{ job.status }}
+        job_name: '*test (${{ matrix.node-version }})*'
+        channel: '#ci'
+        url: ${{ secrets.SLACK_WEBHOOK_URL }}
+
+  build-dev:
+    runs-on: ubuntu-latest
+    needs: resolve-dependencies
+
+    strategy:
+      matrix:
+        node-version: [10.x, 12.x]
+
+    steps:
+    - uses: actions/checkout@v1
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+    - name: Cache/Restore node_modules
+      uses: actions/cache@v1
+      with:
+        path: node_modules
+        key: ${{ runner.OS }}-node_modules-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
+    - name: yarn build:dev
+      run: |
+        yarn build:dev
+
+    - name: Slack Notification
+      uses: homoluctus/slatify@master
+      if: failure()
+      with:
+        type: ${{ job.status }}
+        job_name: '*build-dev (${{ matrix.node-version }})*'
+        channel: '#ci'
+        url: ${{ secrets.SLACK_WEBHOOK_URL }}
+
+
+  build-prod:
+    runs-on: ubuntu-latest
+    needs: resolve-dependencies
+
+    strategy:
+      matrix:
+        node-version: [10.x, 12.x]
+
+    steps:
+    - uses: actions/checkout@v1
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+    - name: Cache/Restore node_modules
+      uses: actions/cache@v1
+      with:
+        path: node_modules
+        key: ${{ runner.OS }}-node_modules-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
+    - name: Launch MongoDB
+      uses: wbari/start-mongoDB@v0.2
+      with:
+        mongoDBVersion: 3.6
+    - name: yarn build:prod:analyze
+      run: |
+        yarn build:prod:analyze
+    - name: Shrink dependencies for production
+      run: |
+        yarn install --production
+    - name: yarn server:prod:ci
+      run: |
+        yarn server:prod:ci
+      env:
+        MONGO_URI: mongodb://localhost:27017/growi
+
+    - name: Upload reports
+      uses: actions/upload-artifact@v1
+      if: success()
+      with:
+        name: report
+        path: report
+    - name: Slack Notification
+      uses: homoluctus/slatify@master
+      if: failure()
+      with:
+        type: ${{ job.status }}
+        job_name: '*build-prod (${{ matrix.node-version }})*'
+        channel: '#ci'
+        url: ${{ secrets.SLACK_WEBHOOK_URL }}

+ 0 - 30
.github/workflows/main.yml

@@ -1,30 +0,0 @@
-name: CI
-
-on:
-  push:
-    branches:
-      - support/github-actions
-
-jobs:
-  build:
-
-    runs-on: ubuntu-latest
-
-    steps:
-    - uses: actions/checkout@v1
-
-    - name: Bump version
-      run: sh ./bin/github-actions/bump-version.sh
-
-    - name: Set up Docker Buildx
-      uses: crazy-max/ghaction-docker-buildx@v1.0.4
-      with:
-        # Buildx version. Example: v0.3.0
-        version: # optional, default is latest
-
-    - name: Build Docker Image
-      run: |
-        docker buildx build \
-          --platform linux/amd64 \
-          --output "type=image,push=false" \
-          --file ./docker/Dockerfile .

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

@@ -0,0 +1,37 @@
+name: GitHub Release
+
+on:
+  push:
+    branches:
+      - release
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v1
+      with:
+        fetch-depth: 1
+
+    - name: Init Git
+      run: |
+        git config --local user.name "GitHub Action"
+        git config --local user.email "info@weseek.co.jp"
+
+    - name: Bump version
+      run: |
+        npm version patch
+        sh ./bin/github-actions/bump-version.sh
+
+    - name: Commit
+      run: |
+        git commit -am "Release $RELEASE_VERSION"
+
+    - name: Push tag
+      uses: ad-m/github-push-action@master
+      with:
+        branch: null
+        github_token: ${{ secrets. GITHUB_TOKEN }}
+

+ 0 - 95
.github/workflows/test.yml

@@ -1,95 +0,0 @@
-name: Node CI
-
-# on: [push]
-on:
-  push:
-    branches:
-      - support/github-actions
-
-jobs:
-
-  resolve-dependencies:
-    runs-on: ubuntu-latest
-
-    strategy:
-      matrix:
-        node-version: [10.x, 12.x]
-
-    steps:
-    - uses: actions/checkout@v1
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v1
-      with:
-        node-version: ${{ matrix.node-version }}
-    - name: install dependencies
-      run: |
-        yarn
-    - name: install plugins
-      run: |
-        yarn add growi-plugin-lsx growi-plugin-pukiwiki-like-linker growi-plugin-attachment-refs
-        yarn add -D react-images react-motion
-    - name: print dependencies
-      run: |
-        echo -n "node " && node -v
-        echo -n "npm " && npm -v
-        yarn list --depth=0
-
-
-  lint:
-    runs-on: ubuntu-latest
-    needs: resolve-dependencies
-
-    steps:
-    - uses: actions/checkout@v1
-    - name: yarn lint
-      run: |
-        yarn lint
-
-
-  test:
-    runs-on: ubuntu-latest
-    needs: resolve-dependencies
-
-    steps:
-    - name: Launch MongoDB
-      uses: wbari/start-mongoDB@v0.2
-      with:
-        mongoDBVersion: 3.6
-
-    - name: yarn test
-      run: |
-        yarn test
-      env:
-        MONGO_URI: mongodb://localhost:27017/growi_test
-
-
-  build-dev:
-    runs-on: ubuntu-latest
-    needs: resolve-dependencies
-
-    steps:
-    - name: yarn build:dev
-      run: |
-        yarn build:dev
-
-
-  build-prod:
-    runs-on: ubuntu-latest
-    needs: resolve-dependencies
-
-    steps:
-    - name: Launch MongoDB
-      uses: wbari/start-mongoDB@v0.2
-      with:
-        mongoDBVersion: 3.6
-    - name: yarn build:prod:analyze
-      run: |
-        yarn build:prod:analyze
-    - name: shrink dependencies for production
-      run: |
-        yarn install --production
-    - name: yarn server:prod:ci
-      run: |
-        yarn server:prod:ci
-      env:
-        MONGO_URI: mongodb://localhost:27017/growi

+ 4 - 0
CHANGES.md

@@ -20,6 +20,10 @@ Upgrading Guide: https://docs.growi.org/en/admin-guide/upgrading/36x.html
 * Support: Upgrade libs
     * growi-commons
 
+## 3.5.24
+
+* Fix: Plugins are not working on Heroku
+
 ## 3.5.23
 
 * Fix: Global Notification failed to send e-mail

+ 1 - 1
README.md

@@ -19,7 +19,7 @@
 GROWI 
 ===========
 
-[![wercker status](https://app.wercker.com/status/595b761d0e26796ddb304679f7bf27de/s/master "wercker status")](https://app.wercker.com/project/byKey/595b761d0e26796ddb304679f7bf27de)
+[![Actions Status](https://github.com/weseek/growi/workflows/Node%20CI/badge.svg)](https://github.com/weseek/growi/actions)
 [![dependencies status](https://david-dm.org/weseek/growi.svg)](https://david-dm.org/weseek/growi)
 [![devDependencies Status](https://david-dm.org/weseek/growi/dev-status.svg)](https://david-dm.org/weseek/growi?type=dev)
 [![docker pulls](https://img.shields.io/docker/pulls/weseek/growi.svg)](https://hub.docker.com/r/weseek/growi/)

+ 1 - 1
bin/heroku/install-packages.sh

@@ -1,3 +1,3 @@
 #!/bin/sh
 
-yarn add -D $ADDITIONAL_PACKAGES
+yarn add $ADDITIONAL_PACKAGES

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

@@ -557,7 +557,8 @@
         "register_2": "Create Project if no projects exist",
         "register_3": "Create Credentials → OAuth client ID → Select \"Web application\"",
         "register_4": "Register your OAuth App with one of Authorized redirect URIs as <code>{{url}}</code>",
-        "register_5": "Copy and paste your ClientID and Client Secret above"
+        "register_5": "Copy and paste your ClientID and Client Secret above",
+        "updated_google": "Succeeded to update Google OAuth setting"
       },
       "Facebook": {
         "name": "Facebook OAuth"
@@ -569,14 +570,16 @@
         "register_2": "Sign in Twitter",
         "register_3": "Create Credentials &rightarrow; OAuth client ID &rightarrow; Select \"Web application\"",
         "register_4": "Register your OAuth App with one of Authorized redirect URIs as <code>{{url}}</code>",
-        "register_5": "Copy and paste your ClientID and Client Secret above"
+        "register_5": "Copy and paste your ClientID and Client Secret above",
+        "updated_twitter": "Succeeded to update Twitter OAuth setting"
       },
       "GitHub": {
         "enable_github":"enable GitHub OAuth",
         "name": "GitHub OAuth",
         "register_1": "Access {{link}}",
         "register_2": "Register your OAuth App with \"Authorization callback URL\" as <code>{{url}}</code>",
-        "register_3": "Copy and paste your ClientID and Client Secret above"
+        "register_3": "Copy and paste your ClientID and Client Secret above",
+        "updated_github": "Succeeded to update GitHub OAuth setting"
       },
       "OIDC": {
         "name": "OpenID Connect",

+ 6 - 3
resource/locales/ja/translation.json

@@ -552,7 +552,8 @@
         "register_2": "プロジェクトがない場合はプロジェクトを作成",
         "register_3": "認証情報を作成 &rightarrow; OAuthクライアントID &rightarrow; ウェブアプリケーションを選択",
         "register_4": "承認済みのリダイレクトURIを<code>{{url}}</code>としてGrowiを登録",
-        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力"
+        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力",
+        "updated_google": "Google OAuth を更新しました"
       },
       "Facebook": {
         "name": "Facebook OAuth"
@@ -564,14 +565,16 @@
         "register_2": "Twitterにサインイン",
         "register_3": "Create New Appをクリック &rightarrow; Application Detailsの各項目を入力",
         "register_4": "Create your Twitter Applicationで作成",
-        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力"
+        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力",
+        "updated_twitter": "Twitter OAuth を更新しました"
       },
       "GitHub": {
         "enable_github":"GitHub OAuth を有効にする",
         "name": "GitHub OAuth",
         "register_1": "{{link}} へアクセス",
         "register_2": "\"Authorization callback URL\"を<code>{{url}}</code>としてGrowiを登録",
-        "register_3": "上記フォームにクライアントIDとクライアントシークレットを入力"
+        "register_3": "上記フォームにクライアントIDとクライアントシークレットを入力",
+        "updated_github": "GitHub OAuth を更新しました"
       },
       "OIDC": {
         "name": "OpenID Connect",

+ 54 - 2
src/client/js/components/Admin/Security/GithubSecuritySetting.jsx

@@ -2,15 +2,55 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
+import loggerFactory from '@alias/logger';
 
 import { createSubscribedElement } from '../../UnstatedUtils';
+import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 import AppContainer from '../../../services/AppContainer';
 import AdminGeneralSecurityContainer from '../../../services/AdminGeneralSecurityContainer';
 import AdminGithubSecurityContainer from '../../../services/AdminGithubSecurityConatainer';
 
+const logger = loggerFactory('growi:security:AdminGitHubSecurityContainer');
+
 class GithubSecurityManagement extends React.Component {
 
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      retrieveError: null,
+    };
+
+    this.onClickSubmit = this.onClickSubmit.bind(this);
+  }
+
+  async componentDidMount() {
+    const { adminGithubSecurityContainer } = this.props;
+
+    try {
+      await adminGithubSecurityContainer.retrieveSecurityData();
+    }
+    catch (err) {
+      toastError(err);
+      this.setState({ retrieveError: err });
+      logger.error(err);
+    }
+  }
+
+  async onClickSubmit() {
+    const { t, adminGithubSecurityContainer } = this.props;
+
+    try {
+      await adminGithubSecurityContainer.updateGitHubSetting();
+      toastSuccess(t('security_setting.OAuth.GitHub.updated_github'));
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+    }
+  }
+
   render() {
     const { t, adminGeneralSecurityContainer, adminGithubSecurityContainer } = this.props;
     return (
@@ -21,6 +61,12 @@ class GithubSecurityManagement extends React.Component {
           { t('security_setting.OAuth.GitHub.name') } { t('security_setting.configuration') }
         </h2>
 
+        {this.state.retrieveError != null && (
+        <div className="alert alert-danger">
+          <p>{t('Error occurred')} : {this.state.err}</p>
+        </div>
+        )}
+
         <div className="row mb-5">
           <strong className="col-xs-3 text-right">{ t('security_setting.OAuth.GitHub.name') }</strong>
           <div className="col-xs-6 text-left">
@@ -44,7 +90,7 @@ class GithubSecurityManagement extends React.Component {
             <input
               className="form-control"
               type="text"
-              value={adminGithubSecurityContainer.state.callbackUrl}
+              value={adminGithubSecurityContainer.state.appSiteUrl}
               readOnly
             />
             <p className="help-block small">{ t('security_setting.desc_of_callback_URL', { AuthName: 'OAuth' }) }</p>
@@ -87,7 +133,7 @@ class GithubSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="githubClientSecret"
-                  value={adminGithubSecurityContainer.state.githubClientSecret}
+                  defaultValue={adminGithubSecurityContainer.state.githubClientSecret}
                   onChange={e => adminGithubSecurityContainer.changeGithubClientSecret(e.target.value)}
                 />
                 <p className="help-block">
@@ -119,6 +165,12 @@ class GithubSecurityManagement extends React.Component {
           </React.Fragment>
         )}
 
+        <div className="row my-3">
+          <div className="col-xs-offset-3 col-xs-5">
+            <div className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</div>
+          </div>
+        </div>
+
         <hr />
 
         <div style={{ minHeight: '300px' }}>

+ 54 - 2
src/client/js/components/Admin/Security/GoogleSecuritySetting.jsx

@@ -2,15 +2,55 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
+import loggerFactory from '@alias/logger';
 
 import { createSubscribedElement } from '../../UnstatedUtils';
+import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 import AppContainer from '../../../services/AppContainer';
 import AdminGeneralSecurityContainer from '../../../services/AdminGeneralSecurityContainer';
 import AdminGoogleSecurityContainer from '../../../services/AdminGoogleSecurityContainer';
 
+const logger = loggerFactory('growi:security:AdminGoogleSecurityContainer');
+
 class GoogleSecurityManagement extends React.Component {
 
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      retrieveError: null,
+    };
+
+    this.onClickSubmit = this.onClickSubmit.bind(this);
+  }
+
+  async componentDidMount() {
+    const { adminGoogleSecurityContainer } = this.props;
+
+    try {
+      await adminGoogleSecurityContainer.retrieveSecurityData();
+    }
+    catch (err) {
+      toastError(err);
+      this.setState({ retrieveError: err });
+      logger.error(err);
+    }
+  }
+
+  async onClickSubmit() {
+    const { t, adminGoogleSecurityContainer } = this.props;
+
+    try {
+      await adminGoogleSecurityContainer.updateGoogleSetting();
+      toastSuccess(t('security_setting.OAuth.Google.updated_google'));
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+    }
+  }
+
   render() {
     const { t, adminGeneralSecurityContainer, adminGoogleSecurityContainer } = this.props;
     return (
@@ -21,6 +61,12 @@ class GoogleSecurityManagement extends React.Component {
           { t('security_setting.OAuth.Google.name') } { t('security_setting.configuration') }
         </h2>
 
+        {this.state.retrieveError != null && (
+        <div className="alert alert-danger">
+          <p>{t('Error occurred')} : {this.state.err}</p>
+        </div>
+        )}
+
         <div className="row mb-5">
           <strong className="col-xs-3 text-right">{ t('security_setting.OAuth.Google.name') }</strong>
           <div className="col-xs-6 text-left">
@@ -71,7 +117,7 @@ class GoogleSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="googleClientId"
-                  value={adminGoogleSecurityContainer.state.googleClientId}
+                  defaultValue={adminGoogleSecurityContainer.state.googleClientId}
                   onChange={e => adminGoogleSecurityContainer.changeGoogleClientId(e.target.value)}
                 />
                 <p className="help-block">
@@ -87,7 +133,7 @@ class GoogleSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="googleClientSecret"
-                  value={adminGoogleSecurityContainer.state.googleClientSecret}
+                  defaultValue={adminGoogleSecurityContainer.state.googleClientSecret}
                   onChange={e => adminGoogleSecurityContainer.changeGoogleClientSecret(e.target.value)}
                 />
                 <p className="help-block">
@@ -119,6 +165,12 @@ class GoogleSecurityManagement extends React.Component {
           </React.Fragment>
         )}
 
+        <div className="row my-3">
+          <div className="col-xs-offset-3 col-xs-5">
+            <button type="button" className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</button>
+          </div>
+        </div>
+
         <hr />
 
         <div style={{ minHeight: '300px' }}>

+ 55 - 3
src/client/js/components/Admin/Security/TwitterSecuritySetting.jsx

@@ -2,15 +2,55 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
+import loggerFactory from '@alias/logger';
 
 import { createSubscribedElement } from '../../UnstatedUtils';
+import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 import AppContainer from '../../../services/AppContainer';
 import AdminGeneralSecurityContainer from '../../../services/AdminGeneralSecurityContainer';
 import AdminTwitterSecurityContainer from '../../../services/AdminTwitterSecurityContainer';
 
+const logger = loggerFactory('growi:security:AdminTwitterSecurityContainer');
+
 class TwitterSecurityManagement extends React.Component {
 
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      retrieveError: null,
+    };
+
+    this.onClickSubmit = this.onClickSubmit.bind(this);
+  }
+
+  async componentDidMount() {
+    const { adminTwitterSecurityContainer } = this.props;
+
+    try {
+      await adminTwitterSecurityContainer.retrieveSecurityData();
+    }
+    catch (err) {
+      toastError(err);
+      this.setState({ retrieveError: err });
+      logger.error(err);
+    }
+  }
+
+  async onClickSubmit() {
+    const { t, adminTwitterSecurityContainer } = this.props;
+
+    try {
+      await adminTwitterSecurityContainer.updateTwitterSetting();
+      toastSuccess(t('security_setting.OAuth.Twitter.updated_twitter'));
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+    }
+  }
+
   render() {
     const { t, adminGeneralSecurityContainer, adminTwitterSecurityContainer } = this.props;
     return (
@@ -21,6 +61,12 @@ class TwitterSecurityManagement extends React.Component {
           { t('security_setting.OAuth.Twitter.name') } { t('security_setting.configuration') }
         </h2>
 
+        {this.state.retrieveError != null && (
+        <div className="alert alert-danger">
+          <p>{t('Error occurred')} : {this.state.err}</p>
+        </div>
+        )}
+
         <div className="row mb-5">
           <strong className="col-xs-3 text-right">{ t('security_setting.OAuth.Twitter.name') }</strong>
           <div className="col-xs-6 text-left">
@@ -71,8 +117,8 @@ class TwitterSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="TwitterConsumerId"
-                  value={adminTwitterSecurityContainer.state.TwitterConsumerId}
-                  onChange={e => adminTwitterSecurityContainer.changeTwitterConsumerId(e.target.value)}
+                  defaultValue={adminTwitterSecurityContainer.state.twitterConsumerKey}
+                  onChange={e => adminTwitterSecurityContainer.changeTwitterConsumerKey(e.target.value)}
                 />
                 <p className="help-block">
                   <small dangerouslySetInnerHTML={{ __html: t('security_setting.Use env var if empty', { env: 'OAUTH_TWITTER_CONSUMER_KEY' }) }} />
@@ -87,7 +133,7 @@ class TwitterSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="TwitterConsumerSecret"
-                  value={adminTwitterSecurityContainer.state.TwitterConsumerSecret}
+                  defaultValue={adminTwitterSecurityContainer.state.twitterConsumerSecret}
                   onChange={e => adminTwitterSecurityContainer.changeTwitterConsumerSecret(e.target.value)}
                 />
                 <p className="help-block">
@@ -119,6 +165,12 @@ class TwitterSecurityManagement extends React.Component {
           </React.Fragment>
         )}
 
+        <div className="row my-3">
+          <div className="col-xs-offset-3 col-xs-5">
+            <button type="button" className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</button>
+          </div>
+        </div>
+
         <hr />
 
         <div style={{ minHeight: '300px' }}>

+ 1 - 1
src/client/js/services/AdminGeneralSecurityContainer.js

@@ -24,7 +24,7 @@ export default class AdminGeneralSecurityContainer extends Container {
       isHideRestrictedByOwner: true,
       isHideRestrictedByGroup: true,
       useOnlyEnvVarsForSomeOptions: true,
-      appSiteUrl: '',
+      appSiteUrl: appContainer.config.crowi.url || '',
       isLocalEnabled: true,
       registrationMode: 'open',
       registrationWhiteList: '',

+ 34 - 6
src/client/js/services/AdminGithubSecurityConatainer.js

@@ -1,6 +1,9 @@
 import { Container } from 'unstated';
 
 import loggerFactory from '@alias/logger';
+import { pathUtils } from 'growi-commons';
+
+import urljoin from 'url-join';
 
 // eslint-disable-next-line no-unused-vars
 const logger = loggerFactory('growi:security:AdminGithubSecurityContainer');
@@ -17,19 +20,25 @@ export default class AdminGithubSecurityContainer extends Container {
     this.appContainer = appContainer;
 
     this.state = {
-      // TODO GW-583 set value
-      appSiteUrl: '',
+      appSiteUrl: urljoin(pathUtils.removeTrailingSlash(appContainer.config.crowi.url), '/passport/github/callback'),
       githubClientId: '',
       githubClientSecret: '',
       isSameUsernameTreatedAsIdenticalUser: true,
     };
 
-    this.init();
-
   }
 
-  init() {
-    // TODO GW-583 fetch config value with api
+  /**
+   * retrieve security data
+   */
+  async retrieveSecurityData() {
+    const response = await this.appContainer.apiv3.get('/security-setting/');
+    const { githubOAuth } = response.data.securityParams;
+    this.setState({
+      githubClientId: githubOAuth.githubClientId || '',
+      githubClientSecret: githubOAuth.githubClientSecret || '',
+      isSameUsernameTreatedAsIdenticalUser: githubOAuth.isSameUsernameTreatedAsIdenticalUser || false,
+    });
   }
 
   /**
@@ -60,4 +69,23 @@ export default class AdminGithubSecurityContainer extends Container {
     this.setState({ isSameUsernameTreatedAsIdenticalUser: !this.state.isSameUsernameTreatedAsIdenticalUser });
   }
 
+  /**
+   * Update githubSetting
+   */
+  async updateGitHubSetting() {
+
+    const response = await this.appContainer.apiv3.put('/security-setting/github-oauth', {
+      githubClientId: this.state.githubClientId,
+      githubClientSecret: this.state.githubClientSecret,
+      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
+    });
+
+    this.setState({
+      githubClientId: this.state.githubClientId,
+      githubClientSecret: this.state.githubClientSecret,
+      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
+    });
+    return response;
+  }
+
 }

+ 37 - 6
src/client/js/services/AdminGoogleSecurityContainer.js

@@ -1,6 +1,9 @@
 import { Container } from 'unstated';
 
 import loggerFactory from '@alias/logger';
+import { pathUtils } from 'growi-commons';
+
+import urljoin from 'url-join';
 
 // eslint-disable-next-line no-unused-vars
 const logger = loggerFactory('growi:security:AdminGoogleSecurityContainer');
@@ -17,19 +20,26 @@ export default class AdminGoogleSecurityContainer extends Container {
     this.appContainer = appContainer;
 
     this.state = {
-      // TODO GW-583 set value
-      appSiteUrl: '',
+      callbackUrl: urljoin(pathUtils.removeTrailingSlash(appContainer.config.crowi.url), '/passport/google/callback'),
       googleClientId: '',
       googleClientSecret: '',
-      isSameUsernameTreatedAsIdenticalUser: true,
+      isSameUsernameTreatedAsIdenticalUser: false,
     };
 
-    this.init();
 
   }
 
-  init() {
-    // TODO GW-583 fetch config value with api
+  /**
+   * retrieve security data
+   */
+  async retrieveSecurityData() {
+    const response = await this.appContainer.apiv3.get('/security-setting/');
+    const { googleOAuth } = response.data.securityParams;
+    this.setState({
+      googleClientId: googleOAuth.googleClientId || '',
+      googleClientSecret: googleOAuth.googleClientSecret || '',
+      isSameUsernameTreatedAsIdenticalUser: googleOAuth.isSameUsernameTreatedAsIdenticalUser || false,
+    });
   }
 
   /**
@@ -60,4 +70,25 @@ export default class AdminGoogleSecurityContainer extends Container {
     this.setState({ isSameUsernameTreatedAsIdenticalUser: !this.state.isSameUsernameTreatedAsIdenticalUser });
   }
 
+  /**
+   * Update googleSetting
+   */
+  async updateGoogleSetting() {
+
+    const response = await this.appContainer.apiv3.put('/security-setting/google-oauth', {
+      googleClientId: this.state.googleClientId,
+      googleClientSecret: this.state.googleClientSecret,
+      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
+    });
+
+    const { securitySettingParams } = response.data;
+
+    this.setState({
+      googleClientId: securitySettingParams.googleClientId,
+      googleClientSecret: securitySettingParams.googleClientSecret,
+      isSameUsernameTreatedAsIdenticalUser: securitySettingParams.isSameUsernameTreatedAsIdenticalUser,
+    });
+    return response;
+  }
+
 }

+ 42 - 14
src/client/js/services/AdminTwitterSecurityContainer.js

@@ -1,6 +1,9 @@
 import { Container } from 'unstated';
 
 import loggerFactory from '@alias/logger';
+import { pathUtils } from 'growi-commons';
+
+import urljoin from 'url-join';
 
 // eslint-disable-next-line no-unused-vars
 const logger = loggerFactory('growi:security:AdminTwitterSecurityContainer');
@@ -17,19 +20,25 @@ export default class AdminTwitterSecurityContainer extends Container {
     this.appContainer = appContainer;
 
     this.state = {
-      // TODO GW-583 set value
-      appSiteUrl: '',
-      TwitterConsumerId: '',
-      TwitterConsumerSecret: '',
-      isSameUsernameTreatedAsIdenticalUser: true,
+      callbackUrl: urljoin(pathUtils.removeTrailingSlash(appContainer.config.crowi.url), '/passport/twitter/callback'),
+      twitterConsumerKey: '',
+      twitterConsumerSecret: '',
+      isSameUsernameTreatedAsIdenticalUser: false,
     };
 
-    this.init();
-
   }
 
-  init() {
-    // TODO GW-583 fetch config value with api
+  /**
+   * retrieve security data
+   */
+  async retrieveSecurityData() {
+    const response = await this.appContainer.apiv3.get('/security-setting/');
+    const { twitterOAuth } = response.data.securityParams;
+    this.setState({
+      twitterConsumerKey: twitterOAuth.twitterConsumerKey || '',
+      twitterConsumerSecret: twitterOAuth.twitterConsumerSecret || '',
+      isSameUsernameTreatedAsIdenticalUser: twitterOAuth.isSameUsernameTreatedAsIdenticalUser || false,
+    });
   }
 
   /**
@@ -40,17 +49,17 @@ export default class AdminTwitterSecurityContainer extends Container {
   }
 
   /**
-   * Change TwitterConsumerId
+   * Change twitterConsumerKey
    */
-  changeTwitterConsumerId(value) {
-    this.setState({ TwitterConsumerId: value });
+  changeTwitterConsumerKey(value) {
+    this.setState({ twitterConsumerKey: value });
   }
 
   /**
-   * Change TwitterConsumerSecret
+   * Change twitterConsumerSecret
    */
   changeTwitterConsumerSecret(value) {
-    this.setState({ TwitterConsumerSecret: value });
+    this.setState({ twitterConsumerSecret: value });
   }
 
   /**
@@ -60,4 +69,23 @@ export default class AdminTwitterSecurityContainer extends Container {
     this.setState({ isSameUsernameTreatedAsIdenticalUser: !this.state.isSameUsernameTreatedAsIdenticalUser });
   }
 
+  /**
+   * Update twitterSetting
+   */
+  async updateTwitterSetting() {
+
+    const response = await this.appContainer.apiv3.put('/security-setting/twitter-oauth', {
+      twitterConsumerKey: this.state.twitterConsumerKey,
+      twitterConsumerSecret: this.state.twitterConsumerSecret,
+      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
+    });
+
+    this.setState({
+      twitterConsumerKey: this.state.twitterConsumerKey,
+      twitterConsumerSecret: this.state.twitterConsumerSecret,
+      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
+    });
+    return response;
+  }
+
 }

+ 197 - 35
src/server/routes/apiv3/security-setting.js

@@ -19,10 +19,20 @@ const validator = {
     body('hideRestrictedByOwner').isBoolean(),
     body('hideRestrictedByGroup').isBoolean(),
   ],
-  localSetting: [
-    body('isLocalEnabled').isBoolean(),
-    body('registrationMode').isString(),
-    body('registrationWhiteList').toArray(),
+  googleOAuth: [
+    body('googleClientId').isString(),
+    body('googleClientSecret').isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
+  ],
+  githubOAuth: [
+    body('githubClientId').isString(),
+    body('githubClientSecret').isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
+  ],
+  twitterOAuth: [
+    body('twitterConsumerKey').isString(),
+    body('twitterConsumerSecret').isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
   ],
 };
 
@@ -63,34 +73,47 @@ const validator = {
  *                  hideRestrictedByGroup:
  *                    type: boolean
  *                    description: enable hide by group
- *          LocalSetting:
- *            type: object
- *              LocalEnabledParams:
- *                type: object
- *                properties:
- *                  isLocalEnabled:
- *                    type: boolean
- *                    description: enable local
- *              ModeParams:
- *                type: object
- *                properties:
- *                  registrationMode:
- *                    type:string
- *                    description: type of registrationMode
- *              WhiteListParams:
- *                type: object
- *                properties:
- *                  registrationWhiteList:
- *                    type:string
- *                    description: type of registrationwhiteList
+ *          GitHubOAuthSetting:
+ *            type:object
+ *              githubClientId:
+ *                type: string
+ *                description: key of comsumer
+ *              githubClientSecret:
+ *                type: string
+ *                description: password of comsumer
+ *              isSameUsernameTreatedAsIdenticalUser
+ *                type: boolean
+ *                description: local account automatically linked the email matched
+ *          GoogleOAuthSetting:
+ *            type:object
+ *              googleClientId:
+ *                type: string
+ *                description: key of comsumer
+ *              googleClientSecret:
+ *                type: string
+ *                description: password of comsumer
+ *              isSameUsernameTreatedAsIdenticalUser
+ *                type: boolean
+ *                description: local account automatically linked the email matched
+ *          TwitterOAuthSetting:
+ *            type:object
+ *              twitterConsumerKey:
+ *                type: string
+ *                description: key of comsumer
+ *              twitterConsumerSecret:
+ *                type: string
+ *                description: password of comsumer
+ *              isSameUsernameTreatedAsIdenticalUser
+ *                type: boolean
+ *                description: local account automatically linked the email matched
  */
-
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
   const adminRequired = require('../../middleware/admin-required')(crowi);
   const csrf = require('../../middleware/csrf')(crowi);
 
   const { ApiV3FormValidator } = crowi.middlewares;
+
   /**
    * @swagger
    *
@@ -109,17 +132,27 @@ module.exports = (crowi) => {
    *                      $ref: '#/components/schemas/SecurityParams'
    */
   router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
+
     const securityParams = {
-      localSetting: {
-        LocalEnabledParams: {
-          isLocalEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-local:isEnabled') || false,
-        },
-        ModeParams: {
-          registrationMode: await crowi.configManager.getConfig('crowi', 'security:registrationMode') || '',
-        },
-        WhiteListParams: {
-          registrationWhiteList: await crowi.configManager.getConfig('crowi', 'security:registrationWhiteList') || '',
-        },
+      generalAuth: {
+        isGoogleOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-google:isEnabled'),
+        isGithubOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-github:isEnabled'),
+        isTwitterOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:isEnabled'),
+      },
+      googleOAuth: {
+        googleClientId: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientId'),
+        googleClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientSecret'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-google:isSameUsernameTreatedAsIdenticalUser'),
+      },
+      githubOAuth: {
+        githubClientId: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientId'),
+        githubClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientSecret'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-github:isSameUsernameTreatedAsIdenticalUser'),
+      },
+      twitterOAuth: {
+        twitterConsumerKey: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerKey'),
+        twitterConsumerSecret: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerSecret'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:isSameUsernameTreatedAsIdenticalUser'),
       },
     };
 
@@ -243,5 +276,134 @@ module.exports = (crowi) => {
     }
   });
 
+   *    /security-setting/google-oauth:
+   *      put:
+   *        tags: [SecuritySetting]
+   *        description: Update google OAuth
+   *        requestBody:
+   *          required: true
+   *          content:
+   *            application/json:
+   *              schema:
+   *                $ref: '#/components/schemas/SecurityParams/GoogleOAuthSetting'
+   *        responses:
+   *          200:
+   *            description: Succeeded to google OAuth
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  $ref: '#/components/schemas/SecurityParams/GoogleOAuthSetting'
+   */
+  router.put('/google-oauth', loginRequiredStrictly, adminRequired, csrf, validator.googleOAuth, ApiV3FormValidator, async(req, res) => {
+    const requestParams = {
+      'security:passport-google:clientId': req.body.googleClientId,
+      'security:passport-google:clientSecret': req.body.googleClientSecret,
+      'security:passport-google:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
+    };
+
+    try {
+      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      const securitySettingParams = {
+        googleClientId: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientId'),
+        googleClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientSecret'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-google:isSameUsernameTreatedAsIdenticalUser'),
+      };
+      return res.apiv3({ securitySettingParams });
+    }
+    catch (err) {
+      const msg = 'Error occurred in updating googleOAuth';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'update-googleOAuth-failed'));
+    }
+  });
+
+  /**
+   * @swagger
+   *
+   *    /security-setting/github-oauth:
+   *      put:
+   *        tags: [SecuritySetting]
+   *        description: Update github OAuth
+   *        requestBody:
+   *          required: true
+   *          content:
+   *            application/json:
+   *              schema:
+   *                $ref: '#/components/schemas/SecurityParams/GitHubOAuthSetting'
+   *        responses:
+   *          200:
+   *            description: Succeeded to github OAuth
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  $ref: '#/components/schemas/SecurityParams/GitHubOAuthSetting'
+   */
+  router.put('/github-oauth', loginRequiredStrictly, adminRequired, csrf, validator.githubOAuth, ApiV3FormValidator, async(req, res) => {
+    const requestParams = {
+      'security:passport-github:clientId': req.body.githubClientId,
+      'security:passport-github:clientSecret': req.body.githubClientSecret,
+      'security:passport-github:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
+    };
+
+    try {
+      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      const securitySettingParams = {
+        githubClientId: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientId'),
+        githubClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientSecret'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-github:isSameUsernameTreatedAsIdenticalUser'),
+      };
+      return res.apiv3({ securitySettingParams });
+    }
+    catch (err) {
+      const msg = 'Error occurred in updating githubOAuth';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'update-githubOAuth-failed'));
+    }
+  });
+
+  /**
+   * @swagger
+   *
+   *    /security-setting/twitter-oauth:
+   *      put:
+   *        tags: [SecuritySetting]
+   *        description: Update twitter OAuth
+   *        requestBody:
+   *          required: true
+   *          content:
+   *            application/json:
+   *              schema:
+   *                $ref: '#/components/schemas/SecurityParams/TwitterOAuthSetting'
+   *        responses:
+   *          200:
+   *            description: Succeeded to update twitter OAuth
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  $ref: '#/components/schemas/SecurityParams/TwitterOAuthSetting'
+   */
+  router.put('/twitter-oauth', loginRequiredStrictly, adminRequired, csrf, validator.twitterOAuth, ApiV3FormValidator, async(req, res) => {
+    const requestParams = {
+      'security:passport-twitter:consumerKey': req.body.twitterConsumerKey,
+      'security:passport-twitter:consumerSecret': req.body.twitterConsumerSecret,
+      'security:passport-twitter:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
+    };
+
+    try {
+      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      const securitySettingParams = {
+        twitterConsumerId: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerKey'),
+        twitterConsumerSecret: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerSecret'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:isSameUsernameTreatedAsIdenticalUser'),
+      };
+      return res.apiv3({ securitySettingParams });
+    }
+    catch (err) {
+      const msg = 'Error occurred in updating twitterOAuth';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'update-twitterOAuth-failed'));
+    }
+  });
+
   return router;
 };

+ 2 - 2
src/server/service/search-delegator/elasticsearch.js

@@ -91,8 +91,8 @@ class ElasticsearchDelegator {
       host = `${url.protocol}//${url.host}`;
       indexName = url.pathname.substring(1); // omit heading slash
 
-      if (url.auth != null) {
-        httpAuth = url.auth;
+      if (url.username != null && url.password != null) {
+        httpAuth = `${url.username}:${url.password}`;
       }
     }
 

+ 3 - 172
wercker.yml

@@ -1,187 +1,18 @@
 box: node:12-slim
 
-services:
-  - mongo:3.6
-
-
 test:
   steps:
     - script:
-      name: set yarn cache-folder
-      code: yarn config set cache-folder $WERCKER_CACHE_DIR/yarn
-
-    - script:
-      name: install dependencies
-      code: |
-        yarn
-
-    - script:
-      name: install plugins
-      code: |
-        yarn add growi-plugin-lsx growi-plugin-pukiwiki-like-linker growi-plugin-attachment-refs
-        yarn add -D react-images react-motion
-
-    - script:
-      name: print dependencies
-      code: |
-        echo -n "node " && node -v
-        echo -n "npm " && npm -v
-        yarn list --depth=0
-
-    - script:
-      name: yarn lint
-      code: |
-        yarn lint
-
-    - script:
-      name: yarn test
-      code: |
-        export MONGO_URI=mongodb://$MONGO_PORT_27017_TCP_ADDR/growi_test
-        echo "export MONGO_URI=$MONGO_URI"
-        yarn test
-
-  after-steps:
-    - slack-notifier:
-      url: $SLACK_WEBHOOK_URL
-      channel: ci
-      username: wercker
-      notify_on: "failed"
+      code: echo "CI processes are migrated to GitHub Actions"
 
 
 build-prod:
   steps:
     - script:
-      name: set yarn cache-folder
-      code: yarn config set cache-folder $WERCKER_CACHE_DIR/yarn
-
-    - script:
-      name: yarn build:prod:analyze
-      code: |
-        yarn build:prod:analyze
-
-    - script:
-      name: shrink dependencies for production
-      code: |
-        yarn install --production
-
-    - script:
-      name: yarn server:prod:ci
-      code: |
-        export MONGO_URI=mongodb://$MONGO_PORT_27017_TCP_ADDR/growi
-        echo "export MONGO_URI=$MONGO_URI"
-        yarn server:prod:ci
-
-  after-steps:
-    - script:
-      name: copy report to artifacts
-      code: |
-        cp -r report $WERCKER_REPORT_ARTIFACTS_DIR
-
-    - slack-notifier:
-      url: $SLACK_WEBHOOK_URL
-      channel: ci
-      username: wercker
-      notify_on: "failed"
+      code: echo "CI processes are migrated to GitHub Actions"
 
 
 build-dev:
   steps:
     - script:
-      name: set yarn cache-folder
-      code: yarn config set cache-folder $WERCKER_CACHE_DIR/yarn
-
-    - script:
-      name: yarn build:dev
-      code: |
-        yarn build:dev
-
-  after-steps:
-    - slack-notifier:
-      url: $SLACK_WEBHOOK_URL
-      channel: ci
-      username: wercker
-      notify_on: "failed"
-
-
-release: # would be run on release branch
-  steps:
-    - install-packages:
-      packages: jq
-
-    - script:
-      name: bump version
-      code: |
-        sh ./bin/wercker/init-git.sh
-        # git reset
-        git reset --hard
-        # npm version to bump version
-        npm version patch
-
-    - script:
-      name: get RELEASE_VERSION
-      code: |
-        export RELEASE_VERSION=`npm run version --silent`
-        echo "export RELEASE_VERSION=$RELEASE_VERSION"
-
-    - script:
-      name: commit and push
-      code: |
-        TMP_RELEASE_BRANCH=tmp/release-$RELEASE_VERSION
-        git checkout -B $TMP_RELEASE_BRANCH
-        git push -u origin HEAD:$TMP_RELEASE_BRANCH
-        export RELEASE_GIT_COMMIT=`git rev-parse HEAD`
-
-    - github-create-release:
-      token: $GITHUB_TOKEN
-      tag: v$RELEASE_VERSION
-      target-commitish: $RELEASE_GIT_COMMIT
-
-    - script:
-      name: remove temporary release branch
-      code: |
-        git push --delete origin $TMP_RELEASE_BRANCH
-
-    - script:
-      name: trigger growi-docker release pipeline
-      code: GROWI_DOCKER_PIPELINE_ID=$GROWI_DOCKER_PIPELINE_ID_CDN sh ./bin/wercker/trigger-growi-docker.sh
-
-    - script:
-      name: trigger growi-docker release-nocdn pipeline
-      code: GROWI_DOCKER_PIPELINE_ID=$GROWI_DOCKER_PIPELINE_ID_NOCDN sh ./bin/wercker/trigger-growi-docker.sh
-
-    - script:
-      name: trigger growi-docs deploy pipeline
-      code: sh ./bin/wercker/trigger-growi-docs.sh
-
-  after-steps:
-    - slack-notifier:
-      url: $SLACK_WEBHOOK_URL
-      channel: ci
-      username: wercker
-      notify_on: "failed"
-
-
-release-rc: # would be run on rc/* branches
-  steps:
-    - install-packages:
-      packages: jq
-
-    - script:
-      name: get RELEASE_VERSION
-      code: |
-        export RELEASE_VERSION=`npm run version --silent`
-        export RELEASE_GIT_COMMIT=$WERCKER_GIT_COMMIT
-        echo "export RELEASE_VERSION=$RELEASE_VERSION"
-        echo "export RELEASE_GIT_COMMIT=$RELEASE_GIT_COMMIT"
-
-    - script:
-      name: trigger growi-docker release-rc pipeline
-      code: sh ./bin/wercker/trigger-growi-docker.sh
-
-  after-steps:
-    - slack-notifier:
-      url: $SLACK_WEBHOOK_URL
-      channel: ci
-      username: wercker
-      notify_on: "failed"
-
+      code: echo "CI processes are migrated to GitHub Actions"