Browse Source

Merge pull request #2566 from weseek/imprv/reload-with-message-after-install

Imprv/reload with message after install
Yuki Takei 5 years ago
parent
commit
dace661f41

+ 13 - 13
src/client/js/components/InstallerForm.jsx

@@ -15,24 +15,24 @@ class InstallerForm extends React.Component {
       isValidUserName: true,
       selectedLang: {},
     };
-    this.checkUserName = this.checkUserName.bind(this);
+    // this.checkUserName = this.checkUserName.bind(this);
   }
 
   componentWillMount() {
     this.changeLanguage(localeMetadatas[0]);
   }
 
-  checkUserName(event) {
-    const axios = require('axios').create({
-      headers: {
-        'Content-Type': 'application/json',
-        'X-Requested-With': 'XMLHttpRequest',
-      },
-      responseType: 'json',
-    });
-    axios.get('/_api/check_username', { params: { username: event.target.value } })
-      .then((res) => { return this.setState({ isValidUserName: res.data.valid }) });
-  }
+  // checkUserName(event) {
+  //   const axios = require('axios').create({
+  //     headers: {
+  //       'Content-Type': 'application/json',
+  //       'X-Requested-With': 'XMLHttpRequest',
+  //     },
+  //     responseType: 'json',
+  //   });
+  //   axios.get('/_api/check_username', { params: { username: event.target.value } })
+  //     .then((res) => { return this.setState({ isValidUserName: res.data.valid }) });
+  // }
 
   changeLanguage(meta) {
     i18next.changeLanguage(meta.id);
@@ -94,7 +94,7 @@ class InstallerForm extends React.Component {
                 placeholder={this.props.t('User ID')}
                 name="registerForm[username]"
                 defaultValue={this.props.userName}
-                onBlur={this.checkUserName}
+                // onBlur={this.checkUserName} // need not to check username before installation -- 2020.07.24 Yuki Takei
                 required
               />
             </div>

+ 24 - 9
src/server/crowi/index.js

@@ -35,6 +35,8 @@ function Crowi(rootdir) {
   this.tmpDir = path.join(this.rootDir, 'tmp') + sep;
   this.cacheDir = path.join(this.tmpDir, 'cache');
 
+  this.express = null;
+
   this.config = {};
   this.configManager = null;
   this.mailService = null;
@@ -378,7 +380,9 @@ Crowi.prototype.start = async function() {
   }
 
   await this.init();
-  const express = await this.buildServer();
+  await this.buildServer();
+
+  const { express } = this;
 
   // setup plugins
   this.pluginService = new PluginService(this, express);
@@ -401,14 +405,14 @@ Crowi.prototype.start = async function() {
   this.io = io;
 
   // setup Express Routes
-  this.setupRoutesAtLast(express);
+  this.setupRoutesAtLast();
 
   return serverListening;
 };
 
-Crowi.prototype.buildServer = function() {
-  const express = require('express')();
+Crowi.prototype.buildServer = async function() {
   const env = this.node_env;
+  const express = require('express')();
 
   require('./express-init')(this, express);
 
@@ -427,15 +431,20 @@ Crowi.prototype.buildServer = function() {
     express.use(morgan('dev'));
   }
 
-  return Promise.resolve(express);
+  this.express = express;
 };
 
 /**
  * setup Express Routes
  * !! this must be at last because it includes '/*' route !!
  */
-Crowi.prototype.setupRoutesAtLast = function(app) {
-  require('../routes')(this, app);
+Crowi.prototype.setupRoutesAtLast = function() {
+  require('../routes')(this, this.express);
+};
+
+Crowi.prototype.setupAfterInstall = function() {
+  this.pluginService.autoDetectAndLoadPlugins();
+  this.setupRoutesAtLast();
 };
 
 /**
@@ -496,7 +505,7 @@ Crowi.prototype.setUpAcl = async function() {
 Crowi.prototype.setUpCustomize = async function() {
   const CustomizeService = require('../service/customize');
   if (this.customizeService == null) {
-    this.customizeService = new CustomizeService(this.configManager, this.appService, this.xssService, this.configPubsub);
+    this.customizeService = new CustomizeService(this);
     this.customizeService.initCustomCss();
     this.customizeService.initCustomTitle();
 
@@ -513,7 +522,13 @@ Crowi.prototype.setUpCustomize = async function() {
 Crowi.prototype.setUpApp = async function() {
   const AppService = require('../service/app');
   if (this.appService == null) {
-    this.appService = new AppService(this.configManager);
+    this.appService = new AppService(this);
+
+    // add as a message handler
+    const isInstalled = this.configManager.getConfig('crowi', 'app:installed');
+    if (this.configPubsub != null && !isInstalled) {
+      this.configPubsub.addMessageHandler(this.appService);
+    }
   }
 };
 

+ 1 - 1
src/server/models/vo/config-pubsub-message.js

@@ -1,6 +1,6 @@
 class ConfigPubsubMessage {
 
-  constructor(eventName, body) {
+  constructor(eventName, body = {}) {
     this.eventName = eventName;
     for (const [key, value] of Object.entries(body)) {
       this[key] = value;

+ 1 - 1
src/server/routes/index.js

@@ -20,7 +20,6 @@ module.exports = function(crowi, app) {
   const logout = require('./logout')(crowi, app);
   const me = require('./me')(crowi, app);
   const admin = require('./admin')(crowi, app);
-  const installer = require('./installer')(crowi, app);
   const user = require('./user')(crowi, app);
   const attachment = require('./attachment')(crowi, app);
   const comment = require('./comment')(crowi, app);
@@ -41,6 +40,7 @@ module.exports = function(crowi, app) {
 
   // installer
   if (!isInstalled) {
+    const installer = require('./installer')(crowi);
     app.get('/installer'               , applicationNotInstalled , installer.index);
     app.post('/installer'              , applicationNotInstalled , form.register , csrf, installer.install);
     return;

+ 4 - 5
src/server/routes/installer.js

@@ -1,4 +1,4 @@
-module.exports = function(crowi, app) {
+module.exports = function(crowi) {
   const logger = require('@alias/logger')('growi:routes:installer');
   const path = require('path');
   const fs = require('graceful-fs');
@@ -84,10 +84,9 @@ module.exports = function(crowi, app) {
     }
     // create initial pages
     await createInitialPages(adminUser, language);
-    // init plugins
-    crowi.pluginService.autoDetectAndLoadPlugins();
-    // setup routes
-    crowi.setupRoutesAtLast(app);
+
+    crowi.setupAfterInstall();
+    appService.publishPostInstallationMessage();
 
     // login with passport
     req.logIn(adminUser, (err) => {

+ 64 - 4
src/server/service/app.js

@@ -1,13 +1,73 @@
 const logger = require('@alias/logger')('growi:service:AppService'); // eslint-disable-line no-unused-vars
 const { pathUtils } = require('growi-commons');
 
+
+const ConfigPubsubMessage = require('../models/vo/config-pubsub-message');
+const ConfigPubsubMessageHandlable = require('./config-pubsub/handlable');
+
 /**
  * the service class of AppService
  */
-class AppService {
+class AppService extends ConfigPubsubMessageHandlable {
+
+  constructor(crowi) {
+    super();
+
+    this.crowi = crowi;
+    this.configManager = crowi.configManager;
+    this.configPubsub = crowi.configPubsub;
+  }
+
+  /**
+   * @inheritdoc
+   */
+  shouldHandleConfigPubsubMessage(configPubsubMessage) {
+    const { eventName } = configPubsubMessage;
+    if (eventName !== 'systemInstalled') {
+      return false;
+    }
+
+    const isInstalled = this.crowi.configManager.getConfig('crowi', 'app:installed');
+
+    return !isInstalled;
+  }
+
+  /**
+   * @inheritdoc
+   */
+  async handleConfigPubsubMessage(configPubsubMessage) {
+    logger.info('Invoke post installation process by pubsub notification');
+
+    const { crowi, configManager, configPubsub } = this;
+
+    // load config and setup
+    await configManager.loadConfigs();
+
+    const isInstalled = this.crowi.configManager.getConfig('crowi', 'app:installed');
+    if (isInstalled) {
+      crowi.setupAfterInstall();
+
+      // remove message handler
+      configPubsub.removeMessageHandler(this);
+    }
+  }
+
+  async publishPostInstallationMessage() {
+    const { configPubsub } = this;
+
+    if (configPubsub != null) {
+      const configPubsubMessage = new ConfigPubsubMessage('systemInstalled');
+
+      try {
+        await configPubsub.publish(configPubsubMessage);
+      }
+      catch (e) {
+        logger.error('Failed to publish post installation message with configPubsub: ', e.message);
+      }
+    }
 
-  constructor(configManager) {
-    this.configManager = configManager;
+    // remove message handler
+    configPubsub.removeMessageHandler(this);
   }
 
   getAppTitle() {
@@ -49,7 +109,7 @@ class AppService {
   async initDB(globalLang) {
     const initialConfig = this.configManager.configModel.getConfigsObjectForInstalling();
     initialConfig['app:globalLang'] = globalLang;
-    await this.configManager.updateConfigsInTheSameNamespace('crowi', initialConfig);
+    await this.configManager.updateConfigsInTheSameNamespace('crowi', initialConfig, true);
   }
 
   async isDBInitialized() {

+ 16 - 0
src/server/service/config-pubsub/base.js

@@ -39,6 +39,22 @@ class ConfigPubsubDelegator {
       logger.debug('Unsupported instance: ', handlable);
       return;
     }
+
+    this.handlableList.push(handlable);
+  }
+
+  /**
+   * Remove message handler
+   * @param {ConfigPubsubMessageHandlable} handlable
+   */
+  removeMessageHandler(handlable) {
+    if (!(handlable instanceof ConfigPubsubMessageHandlable)) {
+      logger.warn('Unsupported instance');
+      logger.debug('Unsupported instance: ', handlable);
+      return;
+    }
+
+    this.handlableList = this.handlableList.filter(h => h !== handlable);
   }
 
 }

+ 15 - 6
src/server/service/config-pubsub/nchan.js

@@ -49,15 +49,15 @@ class NchanDelegator extends ConfigPubsubDelegator {
       }
     }
 
+    if (this.client != null && this.shouldResubscribe()) {
+      logger.info('The connection to config pubsub server is offline. Try to reconnect...');
+    }
+
     // init client
     if (this.client == null) {
       this.initClient();
     }
 
-    if (this.shouldResubscribe()) {
-      logger.info('The connection to config pubsub server is offline. Try to reconnect...');
-    }
-
     // connect
     this.isConnecting = true;
     const url = this.constructUrl(this.subscribePath).toString();
@@ -81,9 +81,18 @@ class NchanDelegator extends ConfigPubsubDelegator {
    */
   addMessageHandler(handlable) {
     super.addMessageHandler(handlable);
+    this.registerMessageHandlerToConnection(handlable);
+  }
 
-    this.handlableList.push(handlable);
+  /**
+   * @inheritdoc
+   */
+  removeMessageHandler(handlable) {
+    super.removeMessageHandler(handlable);
+    this.subscribe(true);
+  }
 
+  registerMessageHandlerToConnection(handlable) {
     if (this.connection != null) {
       this.connection.on('message', (messageObj) => {
         this.handleMessage(messageObj, handlable);
@@ -122,7 +131,7 @@ class NchanDelegator extends ConfigPubsubDelegator {
       });
 
       // register all message handlers
-      this.handlableList.forEach(handler => this.addMessageHandler(handler));
+      this.handlableList.forEach(handler => this.registerMessageHandlerToConnection(handler));
     });
 
     this.client = client;

+ 7 - 6
src/server/service/customize.js

@@ -12,12 +12,13 @@ const ConfigPubsubMessageHandlable = require('./config-pubsub/handlable');
  */
 class CustomizeService extends ConfigPubsubMessageHandlable {
 
-  constructor(configManager, appService, xssService) {
+  constructor(crowi) {
     super();
 
-    this.configManager = configManager;
-    this.appService = appService;
-    this.xssService = xssService;
+    this.configManager = crowi.configManager;
+    this.configPubsub = crowi.configPubsub;
+    this.appService = crowi.appService;
+    this.xssService = crowi.xssService;
 
     this.lastLoadedAt = null;
   }
@@ -38,7 +39,7 @@ class CustomizeService extends ConfigPubsubMessageHandlable {
    * @inheritdoc
    */
   async handleConfigPubsubMessage(configPubsubMessage) {
-    const { configManager } = this.appService;
+    const { configManager } = this;
 
     logger.info('Reset customized value by pubsub notification');
     await configManager.loadConfigs();
@@ -47,7 +48,7 @@ class CustomizeService extends ConfigPubsubMessageHandlable {
   }
 
   async publishUpdatedMessage() {
-    const { configPubsub } = this.appService;
+    const { configPubsub } = this;
 
     if (configPubsub != null) {
       const configPubsubMessage = new ConfigPubsubMessage('customizeServiceUpdated', { updatedAt: new Date() });