UNPKG

generator-razor

Version:

Yeoman generator for razor TYPO3 distribution

577 lines (520 loc) 15.5 kB
'use strict' const Generator = require('yeoman-generator') const chalk = require('chalk') const yosay = require('yosay') const link = require('fs-symlink') const mysql = require('mysql') const fs = require('fs-extra') const pathExists = require('path-exists') const request = require('request') const argon2 = require('argon2') const copydir = require('copy-dir') const crypto = require('crypto') const remote = require('yeoman-remote') let rzr module.exports = class extends Generator { prompting () { const t = this const done = this.async() this.log(yosay( 'Welcome to the official TYPO3 ' + chalk.red('razor') + ' generator!' )) this._getSrc(this, 'https://get.typo3.org/json', (response) => { const prompts = [{ type: 'input', name: 'ProjectName', message: 'Choose your project name', default: 'Project' }, { type: 'input', name: 'SrcPath', message: 'What is the path to the TYPO3 source files?', default: '../typo3_src', store: true }, { type: 'list', name: 'Version', message: 'Choose your TYPO3 version', choices: response, store: true }, { type: 'input', name: 'DbUsername', message: 'Database username?', default: 'root', store: true }, { type: 'input', name: 'DbPassword', message: 'Database password?', default: 'root', store: true }, { type: 'input', name: 'DbHostname', message: 'Database hostname?', default: 'localhost', store: true }, { type: 'list', name: 'DbSocket', message: 'Database socket path?', choices: [{ name: 'None', value: '' }, { name: 'MAMP', value: '/Applications/MAMP/tmp/mysql/mysql.sock' }], store: true }, { type: 'input', name: 'DbNew', message: 'New database name? A new database, username and password will be created.', default: 'newproject' }, { type: 'input', name: 'User', message: 'TYPO3 admin username?', default: 'admin', store: true }, { type: 'input', name: 'Pass', message: 'TYPO3 install tool & admin user password?', default: 'joh316' }, { type: 'input', name: 'AdminEmail', message: 'TYPO3 admin email?', default: 'john@doe.com', store: true }, { type: 'list', name: 'Transport', message: 'How to send emails?', choices: [{ name: 'smtp', value: 'smtp' }, { name: 'sendmail', value: 'sendmail' }], store: true }, { when: answers => answers.Transport === 'smtp', type: 'input', name: 'SmtpServer', message: 'SMTP server?', default: 'localhost:25', store: true }, { when: answers => answers.Transport === 'smtp', type: 'list', name: 'Encrypt', message: 'SMTP encrypt?', default: true, choices: [{ name: 'true (TYPO3 >= 10 - if port 465 or other)', value: true }, { name: 'false (TYPO3 >= 10 - if port 587)', value: false }, { name: 'ssl (TYPO3 9.5.x)', value: 'ssl' }, { name: 'tls (TYPO3 9.5.x)', value: 'tls' }], store: true }, { when: answers => answers.Transport === 'smtp', type: 'input', name: 'SmtpUser', message: 'SMTP username?', default: '', store: true }, { when: answers => answers.Transport === 'smtp', type: 'input', name: 'SmtpPass', message: 'SMTP password?', default: '', store: true }, { when: answers => answers.Transport === 'smtp', type: 'input', name: 'SmtpEmail', message: 'Sender email?', default: '', store: true }, { when: answers => answers.Transport === 'smtp', type: 'input', name: 'SmtpName', message: 'Sender name?', default: '', store: true }, { type: 'list', name: 'English', message: 'Activate English language in TYPO3?', choices: [{ name: 'No', value: false }, { name: 'Yes', value: true }], store: true }, { type: 'list', name: 'EnglishDefault', message: 'Set English as default language?', choices: [{ name: 'No', value: false }, { name: 'Yes', value: true }], store: true }, { type: 'input', name: 'Author', message: 'Author name', default: 'John Doe', store: true }, { type: 'input', name: 'Email', message: 'Author eMail', default: 'john@doe.com', store: true }, { type: 'input', name: 'Website', message: 'Author website', default: 'www.johndoe.com', store: true }, { type: 'list', name: 'Copyright', message: 'Add copyright?', choices: [{ name: 'No', value: false }, { name: 'Gandayo', value: true }], store: true }, { type: 'list', name: 'Htaccess', message: 'Add .htaccess-dev file for development?', choices: [{ name: 'Yes', value: true }, { name: 'No', value: false }], store: true }, { type: 'list', name: 'FontAwesome', message: 'FontAwesome Pro?', choices: [{ name: 'Yes', value: true }, { name: 'No', value: false }], store: true }, { type: 'list', name: 'Search', message: 'Activate search?', choices: [{ name: 'No', value: false }, { name: 'Yes', value: true }] }, { type: 'list', name: 'SSL', message: 'Activate SSL/https for dev?', choices: [{ name: 'Yes', value: true }, { name: 'No', value: false }], store: true }, { type: 'list', name: 'Cols', message: 'Bootstrap columns?', choices: [{ name: '24', value: 24 }, { name: '12', value: 12 }], store: true }] return t.prompt(prompts).then(answers => { t.props = answers done() }) }) } writing () { const t = this rzr = this.props const path = rzr.SrcPath + '/typo3_src-' + rzr.Version // Version let version = '124' if (rzr.Version.indexOf('13.4') !== -1) { version = '134' } else if (rzr.Version.indexOf('14.3') !== -1) { version = '143' } this._createSymlinks(this, path, () => { copydir(t.templatePath(version), t.destinationPath('./'), () => { t._localconf(t) t._localSettings(t) t._createDb((response) => { t._processSqlFile(t, response, () => { t._setRazorConfig() }) }) }) }) } install () { rzr = this.props // Branch let branch = 'razor12-dev' if (rzr.Version.indexOf('13.4') !== -1) { branch = 'razor13-dev' } else if (rzr.Version.indexOf('14.3') !== -1) { branch = 'razor14-dev' } // yarn settings const yarnSettings = { dev: true, 'no-lockfile': true, 'modules-folder': 'typo3conf/ext/' } // Install this.yarnInstall([ 'ssh://git@github.com/rafu1987/razor.git#' + branch ], yarnSettings) } end () { // Delete package.json and .yarn-integrity files when finished fs.unlink('package.json', () => {}) fs.unlink('typo3conf/ext/.yarn-integrity', () => {}) // Copy razor extensions after install to typo3conf/ext/, starting with TYPO3 >= 12.4.x if (rzr.Version.indexOf('12.4') !== -1 || rzr.Version.indexOf('13.4') !== -1 || rzr.Version.indexOf('14.3') !== -1) { fs.copy('typo3conf/ext/razor/Initialisation/Extensions', 'typo3conf/ext') } } _getSrc (t, url, callback) { // Get TYPO3 source from JSON request({ url: url, json: true }, (error, response, body) => { if (!error && response.statusCode === 200) { const releases12 = body['12']['releases'] const releases13 = body['13']['releases'] const releases14 = body['14']['releases'] const releasesObj = t._mergeOptions(releases14, releases13, releases12) const keys = Object.keys(releasesObj) const len = keys.length const arr = [] // Filter out only 12.4.x 13.4.x, 14.3.x for (let i = 0; i < len; i++) { if (keys[i].indexOf('12.4.') !== -1 || keys[i].indexOf('13.4.') !== -1 || keys[i].indexOf('14.3.') !== -1) { arr.push({ name: keys[i], value: keys[i] }) } } return callback(arr) } }) } _mergeOptions (obj1, obj2, obj3) { const obj4 = {} for (let attrname in obj1) { obj4[attrname] = obj1[attrname] } for (let attrname in obj2) { obj4[attrname] = obj2[attrname] } for (let attrname in obj3) { obj4[attrname] = obj3[attrname] } return obj4 } _createSymlinks (t, path, callback) { // Check if TYPO3 source is available if (pathExists.sync(path) === false) { remote.extract('https://get.typo3.org/' + rzr.Version, rzr.SrcPath, () => {}) } // Symlinks link(path, 'typo3_src') link('typo3_src/typo3', 'typo3') link('typo3_src/index.php', 'index.php') return callback() } _localconf (t) { fs.readFile('typo3conf/system/settings.php', 'utf8', (err, content) => { let newContent = t._substituteMarker(content, '###DBNEW###', rzr.DbNew.toLowerCase(), true) newContent = t._substituteMarker(newContent, '###HOST###', rzr.DbHostname, true) newContent = t._substituteMarker(newContent, '###PROJECTNAME###', rzr.ProjectName, true) const encryptionKey = crypto.randomBytes((96 + 1) / 2).toString('hex') newContent = t._substituteMarker(newContent, '###ENCRYPTION_KEY###', encryptionKey, true) const hash = argon2.hash(rzr.Pass) hash.then(function (res) { newContent = t._substituteMarker(newContent, '###PASS###', res, true) t._localconfWrite(newContent) }) if (err) { console.error('error setting settings.php') } }) } _localconfWrite (content) { fs.writeFile('typo3conf/system/settings.php', content, 'utf8', () => {}) } _localSettings (t) { if (rzr.Transport === 'smtp') { let encryptVariable = '###SMTP_ENCRYPT###' if (rzr.Encrypt === true || rzr.Encrypt === false) { encryptVariable = "'###SMTP_ENCRYPT###'" } fs.readFile('typo3conf/system/local.php', 'utf8', (err, content) => { let newContent = t._substituteMarker(content, '###TRANSPORT###', rzr.Transport, true) newContent = t._substituteMarker(newContent, encryptVariable, rzr.Encrypt, true) newContent = t._substituteMarker(newContent, '###SMTP_PASS###', rzr.SmtpPass, true) newContent = t._substituteMarker(newContent, '###SMTP_SERVER###', rzr.SmtpServer, true) newContent = t._substituteMarker(newContent, '###SMTP_USER###', rzr.SmtpUser, true) newContent = t._substituteMarker(newContent, '###SMTP_EMAIL###', rzr.SmtpEmail, true) newContent = t._substituteMarker(newContent, '###SMTP_NAME###', rzr.SmtpName, true) fs.writeFile('typo3conf/system/local.php', newContent, 'utf8', () => {}) if (err) { console.error('error setting local settings') } }) } else { fs.unlink('typo3conf/system/local.php', () => {}) } } _createDb (callback) { const charset = 'utf8mb4' const collate = 'utf8mb4_unicode_ci' // Connect to database const connection = mysql.createConnection({ host: rzr.DbHostname, user: rzr.DbUsername, password: rzr.DbPassword, socketPath: rzr.DbSocket, multipleStatements: true }) connection.connect((err) => { if (err) { console.error('error connecting') } }) const dbNew = rzr.DbNew.toLowerCase() // Create database table and user connection.query('CREATE DATABASE `' + dbNew + '` CHARACTER SET ' + charset + ' COLLATE ' + collate + ';') connection.query('CREATE USER "' + dbNew + '"@"%" IDENTIFIED BY "' + dbNew + '";') connection.query('GRANT ALL PRIVILEGES ON `' + dbNew + '`.* TO "' + dbNew + '"@"%";') // Connect to new db connection.query('USE `' + dbNew + '`;') return callback(connection) } _processSqlFile (t, connection, callback) { // Read sql file fs.readFile('./db.sql', 'utf8', (err, data) => { if (err) { console.error(err) } let result = t._substituteMarker(data, '###ADMIN###', rzr.User, false) const hash = argon2.hash(rzr.Pass) hash.then(function (res) { result = t._substituteMarker(result, '###PASS###', res, false) t._sqlWrite(t, result, connection, callback) }) }) } _sqlWrite (t, result, connection, callback) { // Write file fs.writeFile('db.sql', result, 'utf8', (err) => { if (err) { console.error(err) } // Read file again with changes fs.readFile('./db.sql', 'utf8', (err, data) => { // Import sql file connection.query(data, () => { connection.end() // Delete db.sql file after import fs.unlink('db.sql', () => {}) return callback() }) if (err) { console.error(err) } }) }) } _substituteMarker (content, marker, newContent, toString) { const regEx = new RegExp(marker, 'g') if (toString) { return content.toString().replace(regEx, newContent) } else { return content.replace(regEx, newContent) } } _setRazorConfig () { const obj = { siteName: rzr.ProjectName, user: rzr.User, adminEmail: rzr.AdminEmail, english: rzr.English, englishDefault: rzr.EnglishDefault, author: rzr.Author, email: rzr.Email, website: rzr.Website, copyright: rzr.Copyright, fontawesome: rzr.FontAwesome, cols: rzr.Cols, htaccess: rzr.Htaccess, smtpemail: rzr.SmtpEmail, search: rzr.Search, ssl: rzr.SSL } // Rename or delete? if (rzr.Htaccess) { if (rzr.SSL) { fs.rename('_.htaccess-dev-ssl', '.htaccess-dev', () => {}) fs.unlink('_.htaccess-dev', () => {}) } else { fs.rename('_.htaccess-dev', '.htaccess-dev', () => {}) fs.unlink('_.htaccess-dev-ssl', () => {}) } } else { fs.unlink('_.htaccess-dev', () => {}) fs.unlink('_.htaccess-dev-ssl', () => {}) } fs.writeFile('razor.json', JSON.stringify(obj, null, 2), (err) => { if (err) { return console.error(err) } }) } }