Yuki Takei 4 лет назад
Родитель
Сommit
f74a43ac76

+ 2 - 0
packages/app/src/interfaces/user.ts

@@ -1,6 +1,8 @@
 export type IUser = {
   name: string;
   username: string;
+  email: string;
+  password: string;
   imageUrlCached: string;
   admin: boolean;
 }

+ 13 - 60
packages/app/src/server/routes/installer.js

@@ -1,59 +1,13 @@
 import loggerFactory from '~/utils/logger';
 
-module.exports = function(crowi) {
-  const logger = loggerFactory('growi:routes:installer');
-  const path = require('path');
-  const fs = require('graceful-fs');
+import { InstallerService, FailedToCreateAdminUserError } from '../service/installer';
 
-  const models = crowi.models;
-  const { appService } = crowi;
+const logger = loggerFactory('growi:routes:installer');
 
-  const User = models.User;
-  const Page = models.Page;
+module.exports = function(crowi) {
 
   const actions = {};
 
-  async function initSearchIndex() {
-    const { searchService } = crowi;
-    if (!searchService.isReachable) {
-      return;
-    }
-
-    await searchService.rebuildIndex();
-  }
-
-  async function createPage(filePath, pagePath, owner, lang) {
-    try {
-      const markdown = fs.readFileSync(filePath);
-      return Page.create(pagePath, markdown, owner, {});
-    }
-    catch (err) {
-      logger.error(`Failed to create ${pagePath}`, err);
-    }
-  }
-
-  async function createInitialPages(owner, lang) {
-    const promises = [];
-
-    // create portal page for '/'
-    promises.push(createPage(path.join(crowi.localeDir, lang, 'welcome.md'), '/', owner, lang));
-
-    // create /Sandbox/*
-    promises.push(createPage(path.join(crowi.localeDir, lang, 'sandbox.md'), '/Sandbox', owner, lang));
-    promises.push(createPage(path.join(crowi.localeDir, lang, 'sandbox-bootstrap4.md'), '/Sandbox/Bootstrap4', owner, lang));
-    promises.push(createPage(path.join(crowi.localeDir, lang, 'sandbox-diagrams.md'), '/Sandbox/Diagrams', owner, lang));
-    promises.push(createPage(path.join(crowi.localeDir, lang, 'sandbox-math.md'), '/Sandbox/Math', owner, lang));
-
-    await Promise.all(promises);
-
-    try {
-      await initSearchIndex();
-    }
-    catch (err) {
-      logger.error('Failed to build Elasticsearch Indices', err);
-    }
-  }
-
   actions.index = function(req, res) {
     return res.render('installer');
   };
@@ -71,24 +25,23 @@ module.exports = function(crowi) {
     const password = registerForm.password;
     const language = registerForm['app:globalLang'] || 'en_US';
 
-    await appService.initDB(language);
+    const installerService = new InstallerService(crowi);
 
-    // create first admin user
-    // TODO: with transaction
     let adminUser;
     try {
-      adminUser = await User.createUser(name, username, email, password, language);
-      await adminUser.asyncMakeAdmin();
+      adminUser = await installerService.install({
+        name,
+        username,
+        email,
+        password,
+      }, language);
     }
     catch (err) {
-      req.form.errors.push(req.t('message.failed_to_create_admin_user', { errMessage: err.message }));
+      if (err instanceof FailedToCreateAdminUserError) {
+        req.form.errors.push(req.t('message.failed_to_create_admin_user', { errMessage: err.message }));
+      }
       return res.render('installer');
     }
-    // create initial pages
-    await createInitialPages(adminUser, language);
-
-    appService.setupAfterInstall();
-    appService.publishPostInstallationMessage();
 
     // login with passport
     req.logIn(adminUser, (err) => {

+ 109 - 0
packages/app/src/server/service/installer.ts

@@ -0,0 +1,109 @@
+import mongoose from 'mongoose';
+import fs from 'graceful-fs';
+import path from 'path';
+import ExtensibleCustomError from 'extensible-custom-error';
+
+import { IPage } from '~/interfaces/page';
+import { IUser } from '~/interfaces/user';
+import loggerFactory from '~/utils/logger';
+
+import AppService from './app';
+import SearchService from './search';
+
+const logger = loggerFactory('growi:service:installer');
+
+export class FailedToCreateAdminUserError extends ExtensibleCustomError {
+}
+
+export class InstallerService {
+
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  crowi: any;
+
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
+  constructor(crowi: any) {
+    this.crowi = crowi;
+  }
+
+  private async initSearchIndex() {
+    const searchService: SearchService = this.crowi.searchService;
+    if (!searchService.isReachable) {
+      return;
+    }
+
+    await searchService.rebuildIndex();
+  }
+
+  private async createPage(filePath, pagePath, owner): Promise<IPage|undefined> {
+
+    // TODO typescriptize models/user.js and remove eslint-disable-next-line
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    const Page = mongoose.model('Page') as any;
+
+    try {
+      const markdown = fs.readFileSync(filePath);
+      return Page.create(pagePath, markdown, owner, {}) as IPage;
+    }
+    catch (err) {
+      logger.error(`Failed to create ${pagePath}`, err);
+    }
+  }
+
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  private async createInitialPages(owner, lang): Promise<any> {
+    const { localeDir } = this.crowi;
+
+    const promises: Promise<IPage|undefined>[] = [];
+
+    // create portal page for '/'
+    promises.push(this.createPage(path.join(localeDir, lang, 'welcome.md'), '/', owner));
+
+    // create /Sandbox/*
+    promises.push(this.createPage(path.join(localeDir, lang, 'sandbox.md'), '/Sandbox', owner));
+    promises.push(this.createPage(path.join(localeDir, lang, 'sandbox-bootstrap4.md'), '/Sandbox/Bootstrap4', owner));
+    promises.push(this.createPage(path.join(localeDir, lang, 'sandbox-diagrams.md'), '/Sandbox/Diagrams', owner));
+    promises.push(this.createPage(path.join(localeDir, lang, 'sandbox-math.md'), '/Sandbox/Math', owner));
+
+    await Promise.all(promises);
+
+    try {
+      await this.initSearchIndex();
+    }
+    catch (err) {
+      logger.error('Failed to build Elasticsearch Indices', err);
+    }
+  }
+
+  async install(firstAdminUserToSave: IUser, language: string): Promise<IUser> {
+    const appService: AppService = this.crowi.appService;
+
+    await appService.initDB(language);
+
+    // TODO typescriptize models/user.js and remove eslint-disable-next-line
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    const User = mongoose.model('User') as any;
+
+    // create first admin user
+    // TODO: with transaction
+    let adminUser;
+    try {
+      const {
+        name, username, email, password,
+      } = firstAdminUserToSave;
+      adminUser = await User.createUser(name, username, email, password, language);
+      await adminUser.asyncMakeAdmin();
+    }
+    catch (err) {
+      throw new FailedToCreateAdminUserError(err);
+    }
+
+    // create initial pages
+    await this.createInitialPages(adminUser, language);
+
+    appService.setupAfterInstall();
+    appService.publishPostInstallationMessage();
+
+    return adminUser;
+  }
+
+}