diff --git a/config/mail.js b/config/mail.js index 1e02f0cda..c0dfefec9 100755 --- a/config/mail.js +++ b/config/mail.js @@ -55,7 +55,7 @@ let mailConf = { }, expediteur: 'NoReply ', administrateur: 'Responsable Newmips ', - host: 'https://'+process.env.HOSTNAME+'.newmips.studio' + host: 'https://'+process.env.SUB_DOMAIN+'.newmips.studio' }, cloud: { transport: { @@ -69,7 +69,7 @@ let mailConf = { }, expediteur: 'NoReply ', administrateur: 'Responsable Newmips ', - host: 'https://'+process.env.HOSTNAME+'.newmips.studio' + host: 'https://'+process.env.SUB_DOMAIN+'.newmips.studio' } } diff --git a/locales/en-EN.json b/locales/en-EN.json index f494d1c89..f0bfa74a6 100755 --- a/locales/en-EN.json +++ b/locales/en-EN.json @@ -13,7 +13,8 @@ "success": "Update completed. You could now log in with your username and password", "hasAlreadyPassword": "Can not update. This user already has a password.", "userNotExist": "Error, this user doesn't exist.", - "passwordNotMatch": "Sorry, passwords do not match. Password must contain at least 8 characters." + "passwordNotMatch": "Sorry, passwords do not match. Password must contain at least 8 characters.", + "userNotActivate": "Your account is not activated, please do the first login procedure." }, "authentication": "Connection", "login": "Login", @@ -110,7 +111,8 @@ "modal_title": "How to clone this application ?", "text1": "In order to clone your application just execute this command:", "text2": "Your Gitlab login is:", - "text3": "and your password is the one you use on your generator account" + "text3": "and your password is the one of your generator account or your Gitlab account if you have changed it on gitlab", + "text4": "(If you have forgotten your password you can do a password change procedure on the generator, it will also change the password of your gitlab account)" }, "no_project_1": "No application found.", "no_project_2": "You can generate one directly from home or with a script." diff --git a/locales/fr-FR.json b/locales/fr-FR.json index 837970af9..fc05e13f3 100644 --- a/locales/fr-FR.json +++ b/locales/fr-FR.json @@ -13,7 +13,8 @@ "success": "Mise à jour effectuée. Vous pouvez désormais vous connecter avec votre identifiant et votre nouveau mot de passe.", "hasAlreadyPassword": "Mise à jour impossible. Cet utilisateur possède déjà un mot de passe.", "userNotExist": "Erreur, cet utilisateur n'existe pas.", - "passwordNotMatch": "Désolé, les mots de passe ne correspondent pas. Le mot de passe doit faire minimum 8 caractères." + "passwordNotMatch": "Désolé, les mots de passe ne correspondent pas. Le mot de passe doit faire minimum 8 caractères.", + "userNotActivate": "Votre compte n'est pas activé, merci de faire la procédure de première connexion." }, "authentication": "Connexion", "login": "Login", @@ -109,7 +110,8 @@ "modal_title": "Comment cloner cette application ?", "text1": "Afin de pouvoir cloner votre application il suffit d'executer cette commande :", "text2": "Votre identifiant Gitlab est :", - "text3": "et votre mot de passe est celui de votre compte générateur" + "text3": "et votre mot de passe est celui de votre compte générateur ou de votre compte Gitlab si vous l'avez changé sur gitlab", + "text4": "(Si vous avez oublié votre mot de passe vous pouvez faire une procédure de changement de mot de passe sur le générateur, cela changera aussi celui de votre compte gitlab)" }, "no_project_1": "Aucune application générée.", "no_project_2": "Vous pouvez créer une application directement depuis l'accueil ou à l'aide d'un script." @@ -237,7 +239,7 @@ "textthree": "simplement revenir en arrière.", "404": "Le lien que vous avez suivi peut être incorrect ou la page peut avoir été supprimée.", "valueTooLong": "Désolé, la valeur renseignée dépasse la longueur maximum autorisée (<30) après génération (%s).", - "cannotFindInstruction": "Désolé, je ne comprend pas ce que vous me demandez.", + "cannotFindInstruction": "Désolé, je ne comprends pas ce que vous me demandez.", "missingParametersInstruction": "Ils manque des paramètres à votre instruction. Consultez la documentation" }, "back":{ diff --git a/models/index.js b/models/index.js index 3a1f09567..3f5624c40 100755 --- a/models/index.js +++ b/models/index.js @@ -1,13 +1,13 @@ 'use strict'; -var fs = require('fs'); -var path = require('path'); -var Sequelize = require('sequelize'); -var basename = path.basename(module.filename); -var env = require('../config/global'); -var dbConfig = require('../config/database'); -var moment_timezone = require('moment-timezone'); -var db = {}; +const fs = require('fs'); +const path = require('path'); +const Sequelize = require('sequelize'); +const env = require('../config/global'); +const dbConfig = require('../config/database'); + +let basename = path.basename(module.filename); +let db = {}; const Op = Sequelize.Op; const operatorsAliases = { @@ -47,7 +47,7 @@ const operatorsAliases = { $col: Op.col }; -var sequelize = new Sequelize(dbConfig.database, dbConfig.user, dbConfig.password, { +const sequelize = new Sequelize(dbConfig.database, dbConfig.user, dbConfig.password, { host: dbConfig.host, logging: false, port: dbConfig.port, @@ -60,14 +60,13 @@ var sequelize = new Sequelize(dbConfig.database, dbConfig.user, dbConfig.passwor }, charset: 'utf8', collate: 'utf8_general_ci', - timezone: moment_timezone.tz.guess(), operatorsAliases }) fs.readdirSync(__dirname).filter(function(file) { return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); }).forEach(function(file) { - var model = sequelize['import'](path.join(__dirname, file)); + let model = sequelize['import'](path.join(__dirname, file)); db[model.name] = model; }) diff --git a/package.json b/package.json index 7924a9158..6f7abfa24 100644 --- a/package.json +++ b/package.json @@ -42,11 +42,10 @@ "math": "0.0.3", "mocha": "^5.2.0", "moment": "^2.22.1", - "moment-timezone": "^0.5.17", "morgan": "^1.9.0", "multer": "^1.3.0", "mysql": "^2.15.0", - "mysql2": "^1.5.3", + "mysql2": "^1.7.0", "nodemailer": "^4.6.5", "npm": "^6.4.0", "passport": "^0.4.0", diff --git a/public/js/Newmips/instructionsScriptStatus.js b/public/js/Newmips/instructionsScriptStatus.js index dede83579..b499622f8 100755 --- a/public/js/Newmips/instructionsScriptStatus.js +++ b/public/js/Newmips/instructionsScriptStatus.js @@ -10,6 +10,12 @@ function fetchStatus() { success: function(data) { try { + // Skip current update status due to internal serveur error + if(data.skip){ + setTimeout(fetchStatus, 50); + return; + } + $("#instructionCount").text('Instructions : ' + data.doneInstruction + ' / ' + data.totalInstruction); var percent = (Number(data.doneInstruction) * 100 / Number(data.totalInstruction)).toFixed(0); @@ -22,18 +28,21 @@ function fetchStatus() { else $("#answers").html("" + data.text[0].message + "

" + $("#answers").html()); } + if (!data.over) setTimeout(fetchStatus, 50); else { if (percent >= 100) { window.location.href = "/application/preview?id_application="+data.id_application+"&timeout=50000"; - /*$("#goTo").attr('href', $("#goTo").attr('href')+data.id_application);*/ $("#goTo").show(); $("#scriptSubmit").prop('disabled', false); $("#goTo").prop('disabled', false); $("#progressbarcontent").hide(); } else { - $("#scriptSubmit").prop('disabled', false); + // Wait 2 sec before let user click again on button + setTimeout(function(){ + $("#scriptSubmit").prop('disabled', false); + }, 2000); $("#progressbarcontent").hide(); } } diff --git a/routes/application.js b/routes/application.js index 6a9badbab..e87e5539c 100755 --- a/routes/application.js +++ b/routes/application.js @@ -16,6 +16,10 @@ var fs = require('fs-extra'); var parser = require('../services/bot.js'); var globalConf = require('../config/global.js'); var gitlabConf = require('../config/gitlab.js'); + +// Gitlab API +const gitlab = require('../services/gitlab_api'); + var helpers = require('../utils/helpers'); var attrHelper = require('../utils/attr_helper'); var gitHelper = require('../utils/git_helper'); @@ -669,32 +673,35 @@ router.post('/set_logo', block_access.hasAccessApplication, function (req, res) // List all applications router.get('/list', block_access.isLoggedIn, function(req, res) { - var data = {}; - - models.Project.findAll({ - include: [{ - model: models.Application, - required: true, + (async () => { + let projects = await models.Project.findAll({ include: [{ - model: models.User, - as: "users", - where: { - id: req.session.passport.user.id - }, - required: true - }] - }], - order: [ - [models.Application, 'id', 'DESC'] - ] - }).then(function(projects) { - - let data = {}; + model: models.Application, + required: true, + include: [{ + model: models.User, + as: "users", + where: { + id: req.session.passport.user.id + }, + required: true + }] + }], + order: [ + [models.Application, 'id', 'DESC'] + ] + }); let iframe_status_url; let host = globalConf.host; let port; let appName; + let data = {}; + + // Get user project for clone url generation + let gitlabProjects = []; + if(gitlabConf.doGit) + gitlabProjects = await gitlab.getAllProjects(req.session.gitlab.user.id); for (var i = 0; i < projects.length; i++) { for (var j = 0; j < projects[i].Applications.length; j++) { @@ -710,20 +717,26 @@ router.get('/list', block_access.isLoggedIn, function(req, res) { } if(gitlabConf.doGit){ - projects[i].dataValues.Applications[j].dataValues.repo_url = gitlabConf.protocol + "://" + gitlabConf.url + "/" + req.session.gitlab.user.username + "/" + globalConf.host.replace(/\./g, "-") + "-" + appName + ".git" - data.gitlabUser = req.session.gitlab.user; + let project = gitlabProjects.filter(x => x.name == globalConf.host + "-" + appName)[0]; + if(project) { + // projects[i].dataValues.Applications[j].dataValues.repo_url = gitlabConf.protocol + "://" + gitlabConf.url + "/" + req.session.gitlab.user.username + "/" + globalConf.host.replace(/\./g, "-") + "-" + appName + ".git" + projects[i].dataValues.Applications[j].dataValues.repo_url = project.http_url_to_repo; + data.gitlabUser = req.session.gitlab.user; + } } - projects[i].dataValues.Applications[j].dataValues.url = iframe_status_url; } } - data.projects = projects; + + data.projects = projects + return data; + })().then(data => { res.render('front/application', data); - }).catch(function(err) { + }).catch(err => { console.error(err); data.code = 500; res.render('common/error', data); - }); + }) }); router.post('/execute', block_access.isLoggedIn, function(req, res) { diff --git a/routes/instruction_script.js b/routes/instruction_script.js index 1af32662f..286dadbb3 100755 --- a/routes/instruction_script.js +++ b/routes/instruction_script.js @@ -16,8 +16,11 @@ const parser = require('../services/bot.js'); const structure_application = require('../structure/structure_application'); -let scriptProcessing = false; -let scriptData = []; +let scriptProcessing = { + timeout: moment(), + state: false +}; +let scriptData = {}; let message = ""; function execute(req, instruction) { @@ -302,11 +305,7 @@ router.post('/execute', block_access.isLoggedIn, multer({ dest: './upload/' }).single('instructions'), function(req, res) { - // Reset idxAtMandatoryInstructionStart to handle multiple scripts execution - idxAtMandatoryInstructionStart = -1; - var userId = req.session.passport.user.id; - // Init scriptData object for user. (session simulation) scriptData[userId] = { over: false, @@ -321,7 +320,8 @@ router.post('/execute', block_access.isLoggedIn, multer({ id_data_entity: -1 } }; - if(scriptProcessing){ + + if(scriptProcessing.state && moment().diff(scriptProcessing.timeout, 'seconds') < 100){ let __ = require("../services/language")(req.session.lang_user).__; scriptData[userId].answers = [{ message: __('instructionScript.alreadyProcessing') @@ -330,14 +330,19 @@ router.post('/execute', block_access.isLoggedIn, multer({ scriptData[userId].overDueToProcessing = true; return res.end(); } - scriptProcessing = true; + + // Reset idxAtMandatoryInstructionStart to handle multiple scripts execution + idxAtMandatoryInstructionStart = -1; + + scriptProcessing.state = true; + scriptProcessing.timeout = moment(); // Get file extension - var extensionFile = req.file.originalname.split("."); + let extensionFile = req.file.originalname.split("."); extensionFile = extensionFile[extensionFile.length -1]; // Read file to determine encoding - var fileContent = fs.readFileSync(req.file.path); - var encoding = require('jschardet').detect(fileContent); + let fileContent = fs.readFileSync(req.file.path); + let encoding = require('jschardet').detect(fileContent); // If extension or encoding is not supported, send error if ((extensionFile != 'txt' && extensionFile != 'nps') || (encoding.encoding.toLowerCase() != 'utf-8' && encoding.encoding.toLowerCase() != 'windows-1252' && encoding.encoding.toLowerCase() != 'ascii')) { scriptData[userId].answers.push({ @@ -350,18 +355,18 @@ router.post('/execute', block_access.isLoggedIn, multer({ } // Open file descriptor - var rl = readline.createInterface({ + let rl = readline.createInterface({ input: fs.createReadStream(req.file.path) }); // Read file line by line, check for empty line, line comment, scope comment - var fileLines = [], + let fileLines = [], commenting = false, invalidScript = false; /* If one of theses value is to 2 after readings all lines then there is an error, line to 1 are set because they are mandatory lines added by the generator */ - var exception = { + let exception = { createNewProject : { value: 0, errorMessage: "You can't create or select more than one project in the same script." @@ -401,7 +406,7 @@ router.post('/execute', block_access.isLoggedIn, multer({ }; rl.on('line', function(sourceLine) { - var line = sourceLine; + let line = sourceLine; // Empty line || One line comment scope if (line.trim() == '' || ((line.indexOf('/*') != -1 && line.indexOf('*/') != -1) || line.indexOf('//*') != -1)) @@ -421,9 +426,7 @@ router.post('/execute', block_access.isLoggedIn, multer({ if (positionComment != -1){ line = line.substring(0, line.indexOf('//')); } - console.log(line); var parserResult = parser.parse(line); - console.log(parserResult); // Get the wanted function given by the bot to do some checks var designerFunction = parserResult.function; var designerValue = null; @@ -568,10 +571,9 @@ router.post('/execute', block_access.isLoggedIn, multer({ /* Execute when it's not a file upload but a file written in textarea */ router.post('/execute_alt', block_access.isLoggedIn, function(req, res) { - // Reset idxAtMandatoryInstructionStart to handle multiple scripts execution - idxAtMandatoryInstructionStart = -1; - var userId = req.session.passport.user.id; + let userId = req.session.passport.user.id; + let __ = require("../services/language")(req.session.lang_user).__; // Init scriptData object for user. (session simulation) scriptData[userId] = { @@ -587,8 +589,9 @@ router.post('/execute_alt', block_access.isLoggedIn, function(req, res) { id_data_entity: -1 } }; - if(scriptProcessing){ - let __ = require("../services/language")(req.session.lang_user).__; + + // Processing already occured less than the last 100 seconds + if(scriptProcessing.state && moment().diff(scriptProcessing.timeout, 'seconds') < 100){ scriptData[userId].answers = [{ message: __('instructionScript.alreadyProcessing') }]; @@ -596,16 +599,22 @@ router.post('/execute_alt', block_access.isLoggedIn, function(req, res) { scriptData[userId].overDueToProcessing = true; return res.end(); } - scriptProcessing = true; - var tmpFilename = moment().format('YY-MM-DD-HH_mm_ss')+"_custom_script.txt"; - var tmpPath = __dirname+'/../upload/'+tmpFilename; + // Reset idxAtMandatoryInstructionStart to handle multiple scripts execution + idxAtMandatoryInstructionStart = -1; + + scriptProcessing.state = true; + scriptProcessing.timeout = moment(); + + let tmpFilename = moment().format('YY-MM-DD-HH_mm_ss')+"_custom_script.txt"; + let tmpPath = __dirname+'/../upload/'+tmpFilename; // Load template script and unzip master file if application is created using template let templateEntry = req.body.template_entry; let template = {}; fs.openSync(tmpPath, 'w'); + if(templateEntry){ let templateLang; switch(req.session.lang_user.toLowerCase()) { @@ -620,23 +629,30 @@ router.post('/execute_alt', block_access.isLoggedIn, function(req, res) { break; } - var files = fs.readdirSync(__dirname + "/../templates/"+templateEntry); - let found = false; - for (var i = 0; i < files.length; i++) { - var filename = path.join(__dirname + "/../templates/"+templateEntry, files[i]); - if (filename.indexOf("_"+templateLang+"_") != -1 && filename.indexOf(".nps") != -1) { - fs.writeFileSync(tmpPath, fs.readFileSync(filename)); - found = true; - break; - }; - }; - if(!found){ - req.session.toastr = [{ - message: "template.no_script", - level: "error" - }] - return res.redirect("/templates"); + let files = fs.readdirSync(__dirname + "/../templates/"+templateEntry); + let filename = false; + + for (let i = 0; i < files.length; i++) { + if (files[i].indexOf(".nps") != -1) { + if(!filename) + filename = path.join(__dirname + "/../templates/"+templateEntry, files[i]); + else if(files[i].indexOf("_"+templateLang+"_") != -1) + filename = path.join(__dirname + "/../templates/"+templateEntry, files[i]); + } + } + + if(!filename){ + scriptData[userId].answers = [{ + message: __('template.no_script') + }]; + scriptData[userId].over = true; + scriptProcessing.state = false; + return res.end(); } + + // Write template script in the tmpPath + fs.writeFileSync(tmpPath, fs.readFileSync(filename)); + } else { fs.writeFileSync(tmpPath, req.body.text); } @@ -837,6 +853,7 @@ router.post('/execute_alt', block_access.isLoggedIn, function(req, res) { //var process_server = process_manager.process_server; var process_server_per_app = process_manager.process_server_per_app; + if (process_server_per_app[idApplication] != null && typeof process_server_per_app[idApplication] !== "undefined") { process_manager.killChildProcess(process_server_per_app[idApplication].pid, function(err) { if(err) @@ -874,29 +891,35 @@ router.post('/execute_alt', block_access.isLoggedIn, function(req, res) { }); // Script execution status -router.get('/status', function(req, res) { - var userId = req.session.passport.user.id; - var stats = { - totalInstruction: scriptData[userId].totalInstruction, - doneInstruction: scriptData[userId].doneInstruction, - over: scriptData[userId].over, - text: scriptData[userId].answers - }; - scriptData[userId].answers = []; - - // Script over, remove data from array - if (stats.over) { - stats.id_application = scriptData[userId].ids.id_application; - req.session.id_application = scriptData[userId].ids.id_application; - req.session.id_project = scriptData[userId].ids.id_project; - req.session.id_data_entity = scriptData[userId].ids.id_data_entity; - req.session.id_module = scriptData[userId].ids.id_module; - if(typeof scriptData[userId].overDueToProcessing === 'undefined') - scriptProcessing = false; - scriptData.splice(scriptData.indexOf(userId), 1); - } +router.get('/status', (req, res) => { + try { + let userId = req.session.passport.user.id; + let stats = { + totalInstruction: scriptData[userId].totalInstruction, + doneInstruction: scriptData[userId].doneInstruction, + over: scriptData[userId].over, + text: scriptData[userId].answers + }; + scriptData[userId].answers = []; + + // Script over, remove data from array + if (stats.over) { + stats.id_application = scriptData[userId].ids.id_application; + req.session.id_application = scriptData[userId].ids.id_application; + req.session.id_project = scriptData[userId].ids.id_project; + req.session.id_data_entity = scriptData[userId].ids.id_data_entity; + req.session.id_module = scriptData[userId].ids.id_module; + if(typeof scriptData[userId].overDueToProcessing === 'undefined') + scriptProcessing.state = false; + delete scriptData[userId]; + } - res.send(stats).end(); + res.send(stats).end(); + } catch(err) { + res.send({ + skip: true + }).end(); + } }); module.exports = router; \ No newline at end of file diff --git a/routes/routes.js b/routes/routes.js index 3e0783885..fc78da93c 100755 --- a/routes/routes.js +++ b/routes/routes.js @@ -65,10 +65,29 @@ router.post('/login', auth.isLoggedIn, function(req, res) { // Get gitlab instance if(gitlabConf.doGit){ gitlab.getUser(email_user).then(gitlabUser => { - req.session.gitlab = { - user: gitlabUser - }; - res.redirect('/default/home'); + + if (gitlabUser){ + req.session.gitlab = { + user: gitlabUser + }; + return res.redirect('/default/home'); + } + + // Generate gitlab user if not found + let usernameGitlab = email_user.replace(/\@/g, "").replace(/\./g, "").trim(); + gitlabUser = gitlab.createUser({ + email: email_user, + password: req.body.password_user, + username: usernameGitlab, + name: usernameGitlab, + admin: false, + skip_confirmation: true + }).then(gitlabUser => { + req.session.gitlab = { + user: gitlabUser + }; + res.redirect('/default/home'); + }) }).catch(err => { console.error(err); req.session.toastr = [{ @@ -126,17 +145,15 @@ router.post('/first_connection', block_access.loginAccess, function(req, res, do if(gitlabConf.doGit){ let gitlabUser = await gitlab.getUser(email_user); - if (!gitlabUser) { + if (!gitlabUser) gitlabUser = await gitlab.createUser({ email: email_user, password: req.body.password_user2, username: usernameGitlab, - name: email_user, - website_url: globalConf.host, + name: usernameGitlab, admin: false, - confirm: false + skip_confirmation: true }) - } req.session.gitlab = { user: gitlabUser @@ -183,7 +200,7 @@ router.post('/reset_password', block_access.loginAccess, function(req, res) { login: req.body.login.toLowerCase(), email: req.body.mail } - }).then(function(user){ + }).then(user => { if(!user){ req.session.toastr = [{ message: "login.first_connection.userNotExist", @@ -192,8 +209,16 @@ router.post('/reset_password', block_access.loginAccess, function(req, res) { return res.render('login/reset_password'); } + if(!user.password && !user.enabled){ + req.session.toastr = [{ + message: "login.first_connection.userNotActivate", + level: "error" + }]; + return res.redirect('/first_connection'); + } + // Create unique token and insert into user - var token = crypto.randomBytes(64).toString('hex'); + let token = crypto.randomBytes(64).toString('hex'); models.User.update({ token_password_reset: token @@ -286,77 +311,94 @@ router.post('/reset_password_form', block_access.loginAccess, function(req, res) let login_user = req.body.login_user.toLowerCase(); let email_user = req.body.email_user; - models.User.findOne({ - where: { - login: login_user, - email: email_user, - $or: [{password: ""}, {password: null}] + (async () => { + let user = await models.User.findOne({ + where: { + login: login_user, + email: email_user, + $or: [{password: ""}, {password: null}] + } + }); + + if(req.body.password_user != req.body.password_user2 || req.body.password_user.length < 8) { + throw { + message: "login.first_connection.passwordNotMatch", + redirect: '/reset_password_form/'+user.token_password_reset + } } - }).then(function(user){ - if(req.body.password_user == req.body.password_user2 && req.body.password_user.length >= 8){ - let password = bcrypt.hashSync(req.body.password_user2, null, null); - if(user){ - if(user.password == "" || user.password == null){ - models.User.update({ - password: password, - token_password_reset: null - }, { - where: { - id: user.id - } - }).then(function(){ - // Autologin after first connection form done - models.User.findOne({ - where: { - id: user.id - } - }).then(function(connectedUser){ - req.login(connectedUser, function(err) { - if (err) { - console.error(err); - req.session.toastr = [{ - message: err.message, - level: "error" - }]; - res.redirect('/login'); - } else{ - req.session.toastr = [{ - message: "login.passwordReset", - level: "success" - }]; - res.redirect('/default/home'); - } - }); - }); - }); - } else{ - req.session.toastr = [{ - message: "login.first_connection.hasAlreadyPassword", - level: "error" - }]; - res.redirect('/login'); - } - } else{ + + let password = bcrypt.hashSync(req.body.password_user2, null, null); + + if(!user){ + throw { + message: "login.first_connection.userNotExist", + redirect: '/login' + } + } + + if(user.password && user.password != ''){ + throw { + message: "login.first_connection.hasAlreadyPassword", + redirect: '/login' + } + } + + await models.User.update({ + password: password, + token_password_reset: null + }, { + where: { + id: user.id + } + }); + + // Update Gitlab password + if(gitlabConf.doGit){ + let gitlabUser = await gitlab.getUser(email_user); + + if(!gitlabUser) + console.warn('Cannot update gitlab user password, user not found.'); + else { + await gitlab.updateUser(gitlabUser, { + password: req.body.password_user2, + skip_reconfirmation: true + }); + } + } + + // Autologin after first connection form done + let connectedUser = await models.User.findOne({ + where: { + id: user.id + } + }); + + return connectedUser; + + })().then(connectedUser => { + req.login(connectedUser, err => { + if (err) { + console.error(err); req.session.toastr = [{ - message: "login.first_connection.userNotExist", + message: err.message, level: "error" }]; res.redirect('/login'); + } else { + req.session.toastr = [{ + message: "login.passwordReset", + level: "success" + }]; + res.redirect('/default/home'); } - } else{ - req.session.toastr = [{ - message: "login.first_connection.passwordNotMatch", - level: "error" - }]; - res.redirect('/reset_password_form/'+user.token_password_reset); - } - }).catch(function(err){ + }); + }).catch(err => { req.session.toastr = [{ message: err.message, level: "error" }]; - res.redirect('/login'); - }); + res.redirect(err.redirect ? err.redirect : '/login'); + }) }); // Logout diff --git a/routes/users.js b/routes/users.js index 9831ae9f9..c8d7425eb 100755 --- a/routes/users.js +++ b/routes/users.js @@ -1,9 +1,14 @@ -var express = require('express'); -var router = express.Router(); -var block_access = require('../utils/block_access'); -var models = require('../models/'); -var fs = require('fs-extra'); -var moment = require("moment"); +const express = require('express'); +const router = express.Router(); +const block_access = require('../utils/block_access'); +const models = require('../models/'); +const fs = require('fs-extra'); +const moment = require("moment"); + +// Gitlab API +const gitlab = require('../services/gitlab_api'); +const gitlabConf = require('../config/gitlab.js'); +const globalConf = require('../config/global.js'); router.get('/', block_access.isAdmin, (req, res) => { data = {}; @@ -108,7 +113,7 @@ router.post('/update', block_access.isAdmin, (req, res) => { where: { id: req.body.id } - }).then(() => { + }).then(_ => { req.session.toastr = [{ message: "action.success.update", level: "success" @@ -129,7 +134,7 @@ router.post('/delete', block_access.isAdmin, (req, res) => { where: { id: req.body.id } - }).then(() => { + }).then(_ => { req.session.toastr = [{ message: 'action.success.destroy', level: "success" @@ -139,58 +144,81 @@ router.post('/delete', block_access.isAdmin, (req, res) => { }) router.post('/assign', block_access.isAdmin, (req, res) => { - var app = req.body.app; - var userId = req.body.id_user; - models.User.findById(userId).then(user => { - if (!user) { - data.code = 404; - console.log("User not found"); - return res.render('common/error', data); + (async () => { + let appID = req.body.app; + let userID = req.body.id_user; + let user = await models.User.findByPk(userID); + + if (!user) + throw new Error("User not found"); + + await user.addApplication(appID); + + // Add user to gitlab project too + if(gitlabConf.doGit){ + if(!Array.isArray(appID)) + appID = [appID]; + + let gitlabUser = await gitlab.getUser(user.email); + + for (let i = 0; i < appID.length; i++) { + let application = await models.Application.findByPk(appID[i]); + let projectName = globalConf.host + "-" + application.codeName.substring(2); + let gitlabProject = await gitlab.getProject(projectName); + await gitlab.addUserToProject(gitlabUser.id, gitlabProject.id); + } } - user.addApplication(app).then(() => { - res.redirect('/users/show/'+userId+"#applications"); - }).catch((err) => { - data.code = 500; - console.error(err); - return res.render('common/error', data); - }) - }).catch((err) => { - data.code = 500; + return userID; + })().then(userID => { + res.redirect('/users/show/'+userID+"#applications"); + }).catch(err => { console.error(err); - return res.render('common/error', data); + return res.render('common/error', { + code: 500 + }); }) }) router.post('/remove_access', block_access.isAdmin, (req, res) => { - let appId = req.body.id_app; - let userId = req.body.id_user; - let data = {}; - models.User.findById(userId).then(user => { - if (!user) { - data.code = 404; - console.log("User not found"); - return res.render('common/error', data); - } - // Get all associations - user.getApplications().then(applications => { - // Remove entity from association array - for (var i = 0; i < applications.length; i++) - if (applications[i].id == appId) { - applications.splice(i, 1); - break; - } + (async () => { + let appID = req.body.id_app; + let userID = req.body.id_user; + let user = await models.User.findByPk(userID); - // Set back associations without removed entity - user.setApplications(applications).then(() => { - res.redirect('/users/show/'+userId+"#applications"); - }) - }) - }).catch((err) => { - data.code = 500; + let data = {}; + if (!user) + throw new Error('404 - User not found'); + + let applications = await user.getApplications(); + + // Remove entity from association array + for (var i = 0; i < applications.length; i++) + if (applications[i].id == appID) { + applications.splice(i, 1); + break; + } + + await user.setApplications(applications); + + // Remove gitlab access + if(gitlabConf.doGit){ + let application = await models.Application.findByPk(appID); + let projectName = globalConf.host + "-" + application.codeName.substring(2); + let gitlabProject = await gitlab.getProject(projectName); + let gitlabUser = await gitlab.getUser(user.email); + await gitlab.removeUserFromProject(gitlabUser.id, gitlabProject.id); + } + + return user.id; + })().then(userID => { + res.redirect('/users/show/'+userID+"#applications"); + }).catch(err => { console.error(err); - return res.render('common/error', data); + return res.render('common/error', { + code: 500 + }); }) }) diff --git a/server.js b/server.js index 0b2305661..c99d4e4b5 100755 --- a/server.js +++ b/server.js @@ -80,11 +80,11 @@ app.use(morgan('dev', { if(globalConf.env != "develop"){ require('console-stamp')(console, { formatter: function() { - return moment().format('YYYY-MM-DD HH:mm:ss-SSS'); + return moment().format('MM-DD HH:mm:ss'); }, - label: true, - datePrefix: "[", - dateSuffix: "]-- " + label: false, + datePrefix: "", + dateSuffix: "" }); } diff --git a/services/bot.js b/services/bot.js index d7d8161f9..8998683a6 100644 --- a/services/bot.js +++ b/services/bot.js @@ -1,6 +1,6 @@ function checkAndCreateAttr(instructionsFunction, options, valueToCheck) { - var attr = { + let attr = { function: instructionsFunction, options: options }; @@ -21,33 +21,33 @@ function checkAndCreateAttr(instructionsFunction, options, valueToCheck) { // ******* BASIC Actions ******* // exports.showSession = function (result) { - var attr = {}; + let attr = {}; attr.function = "showSession"; return attr; }; exports.help = function (result) { - var attr = {}; + let attr = {}; attr.function = "help"; return attr; }; exports.deploy = function (result) { - var attr = {}; + let attr = {}; attr.function = "deploy"; return attr; }; exports.restart = function (result) { - var attr = {}; + let attr = {}; attr.function = "restart"; return attr; }; exports.installNodePackage = function (result) { - var attr = { + let attr = { specificModule: null }; @@ -60,25 +60,25 @@ exports.installNodePackage = function (result) { }; exports.gitPush = function (result) { - var attr = {}; + let attr = {}; attr.function = "gitPush"; return attr; }; exports.gitPull = function (result) { - var attr = {}; + let attr = {}; attr.function = "gitPull"; return attr; }; exports.gitCommit = function (result) { - var attr = {}; + let attr = {}; attr.function = "gitCommit"; return attr; }; exports.gitStatus = function (result) { - var attr = {}; + let attr = {}; attr.function = "gitStatus"; return attr; }; @@ -86,12 +86,12 @@ exports.gitStatus = function (result) { // ******* SELECT Actions ******* // exports.selectProject = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { "value": value }; - var attr = { + let attr = { function: "selectProject", options: options }; @@ -100,12 +100,12 @@ exports.selectProject = function (result) { exports.selectApplication = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value }; - var attr = { + let attr = { function: "selectApplication", options: options }; @@ -114,12 +114,12 @@ exports.selectApplication = function (result) { exports.selectModule = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value }; - var attr = { + let attr = { function: "selectModule", options: options }; @@ -128,12 +128,12 @@ exports.selectModule = function (result) { exports.selectEntity = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value.trim() }; - var attr = { + let attr = { function: "selectEntity", options: options }; @@ -144,14 +144,14 @@ exports.selectEntity = function (result) { exports.setFieldAttribute = function (result) { // Set entity name as the first option in options array - var options = { + let options = { value: result[1], word: result[2], attributeValue: result[3], processValue: true }; - var attr = { + let attr = { function: "setFieldAttribute", options: options }; @@ -161,13 +161,13 @@ exports.setFieldAttribute = function (result) { exports.setFieldKnownAttribute = function (result) { // Set entity name as the first option in options array - var options = { + let options = { value: result[1], word: result[2], processValue: true }; - var attr = { + let attr = { function: "setFieldKnownAttribute", options: options }; @@ -178,13 +178,13 @@ exports.setFieldKnownAttribute = function (result) { exports.setColumnVisibility = function (result) { // Set entity name as the first option in options array - var options = { + let options = { value: result[1], word: result[2], processValue: true }; - var attr = { + let attr = { function: "setColumnVisibility", options: options }; @@ -194,13 +194,13 @@ exports.setColumnVisibility = function (result) { exports.setColumnHidden = function (result) { // Set entity name as the first option in options array - var options = { + let options = { value: result[1], word: "hidden", processValue: true }; - var attr = { + let attr = { function: "setColumnVisibility", options: options }; @@ -210,13 +210,13 @@ exports.setColumnHidden = function (result) { exports.setColumnVisible = function (result) { // Set entity name as the first option in options array - var options = { + let options = { value: result[1], word: "visible", processValue: true }; - var attr = { + let attr = { function: "setColumnVisibility", options: options }; @@ -226,8 +226,8 @@ exports.setColumnVisible = function (result) { // ******* CREATE Actions ******* // exports.createNewProject = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -237,8 +237,8 @@ exports.createNewProject = function (result) { exports.createNewApplication = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -248,8 +248,8 @@ exports.createNewApplication = function (result) { exports.createNewModule = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -259,8 +259,8 @@ exports.createNewModule = function (result) { exports.createNewEntity = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -271,14 +271,14 @@ exports.createNewEntity = function (result) { exports.createNewDataField = function (result) { // Field name has not been defined - var value = result[1]; - var defaultValue = null; + let value = result[1]; + let defaultValue = null; // Default value ? if (typeof result[2] !== "undefined") defaultValue = result[2]; - var options = { + let options = { value: value, defaultValue: defaultValue, processValue: true @@ -289,9 +289,9 @@ exports.createNewDataField = function (result) { exports.createNewDataFieldWithType = function (result) { - var value = result[1]; - var type = result[2].toLowerCase().trim(); - var defaultValue = null; + let value = result[1]; + let type = result[2].toLowerCase().trim(); + let defaultValue = null; // Default value ? if (typeof result[3] !== "undefined") @@ -302,7 +302,7 @@ exports.createNewDataFieldWithType = function (result) { // defaultValue = result[3]; // Preparing Options - var options = { + let options = { value: value, type: type, defaultValue: defaultValue, @@ -314,15 +314,15 @@ exports.createNewDataFieldWithType = function (result) { exports.createNewDataFieldWithTypeEnum = function (result) { - var value = result[1]; - var allValues = result[2]; - var defaultValue = null; + let value = result[1]; + let allValues = result[2]; + let defaultValue = null; // Default value ? if (typeof result[3] !== "undefined") defaultValue = result[3]; - var options = { + let options = { value: value, type: "enum", allValues: allValues, @@ -335,15 +335,15 @@ exports.createNewDataFieldWithTypeEnum = function (result) { exports.createNewDataFieldWithTypeRadio = function (result) { - var value = result[1]; - var allValues = result[2]; - var defaultValue = null; + let value = result[1]; + let allValues = result[2]; + let defaultValue = null; // Default value ? if (typeof result[3] !== "undefined") defaultValue = result[3]; - var options = { + let options = { value: value, type: "radio", allValues: allValues, @@ -357,14 +357,14 @@ exports.createNewDataFieldWithTypeRadio = function (result) { // ******* DELETE Actions ******* // exports.deleteProject = function (result) { - var value = result[1]; + let value = result[1]; - var options = { + let options = { value: value, processValue: true }; - var attr = { + let attr = { function: "deleteProject", options: options }; @@ -373,14 +373,14 @@ exports.deleteProject = function (result) { exports.deleteApplication = function (result) { - var value = result[1]; + let value = result[1]; - var options = { + let options = { value: value, processValue: true }; - var attr = { + let attr = { function: "deleteApplication", options: options }; @@ -389,14 +389,14 @@ exports.deleteApplication = function (result) { exports.deleteModule = function (result) { - var value = result[1]; + let value = result[1]; - var options = { + let options = { value: value, processValue: true }; - var attr = { + let attr = { function: "deleteModule", options: options }; @@ -405,14 +405,14 @@ exports.deleteModule = function (result) { exports.deleteDataEntity = function (result) { - var value = result[1]; + let value = result[1]; - var options = { + let options = { value: value, processValue: true }; - var attr = { + let attr = { function: "deleteDataEntity", options: options }; @@ -421,14 +421,14 @@ exports.deleteDataEntity = function (result) { exports.deleteDataField = function (result) { - var value = result[1]; + let value = result[1]; - var options = { + let options = { value: value, processValue: true }; - var attr = { + let attr = { function: "deleteDataField", options: options }; @@ -437,14 +437,14 @@ exports.deleteDataField = function (result) { exports.deleteTab = function (result) { - var value = result[1]; + let value = result[1]; - var options = { + let options = { value: value, processValue: true }; - var attr = { + let attr = { function: "deleteTab", options: options }; @@ -454,7 +454,7 @@ exports.deleteTab = function (result) { // ******* LIST Actions ******* // exports.listProject = function (result) { - var attr = { + let attr = { function: "listProject" }; return attr; @@ -462,7 +462,7 @@ exports.listProject = function (result) { exports.listApplication = function (result) { - var attr = { + let attr = { function: "listApplication" }; return attr; @@ -470,7 +470,7 @@ exports.listApplication = function (result) { exports.listModule = function (result) { - var attr = { + let attr = { function: "listModule" }; return attr; @@ -478,7 +478,7 @@ exports.listModule = function (result) { exports.listDataEntity = function (result) { - var attr = { + let attr = { function: "listDataEntity" }; return attr; @@ -486,7 +486,7 @@ exports.listDataEntity = function (result) { exports.listDataField = function (result) { - var attr = { + let attr = { function: "listDataField" }; return attr; @@ -498,10 +498,10 @@ exports.listDataField = function (result) { // Tabs in show exports.relationshipHasOne = function (result) { - var source = result[1]; - var target = result[2]; + let source = result[1]; + let target = result[2]; - var options = { + let options = { target: target, source: source, foreignKey: "id_" + target.toLowerCase(), @@ -514,11 +514,11 @@ exports.relationshipHasOne = function (result) { exports.relationshipHasOneWithName = function (result) { - var source = result[1]; - var target = result[2]; - var as = result[3]; + let source = result[1]; + let target = result[2]; + let as = result[3]; - var options = { + let options = { target: target, source: source, foreignKey: "id_" + target.toLowerCase() + "_" + as.toLowerCase(), @@ -533,10 +533,10 @@ exports.relationshipHasOneWithName = function (result) { // --------- Field in create / update / show --------- exports.createFieldRelatedTo = function (result) { - var as = result[1]; - var target = result[2]; + let as = result[1]; + let target = result[2]; - var options = { + let options = { target: target, foreignKey: "id_" + target.toLowerCase() + "_" + as.toLowerCase(), as: as, @@ -548,11 +548,11 @@ exports.createFieldRelatedTo = function (result) { exports.createFieldRelatedToUsing = function (result) { - var as = result[1]; - var target = result[2]; - var usingField = result[3]; + let as = result[1]; + let target = result[2]; + let usingField = result[3]; - var options = { + let options = { target: target, foreignKey: "id_" + target.toLowerCase() + "_" + as.toLowerCase(), as: as, @@ -565,11 +565,11 @@ exports.createFieldRelatedToUsing = function (result) { exports.createFieldRelatedToMultiple = function (result) { - var as = result[1]; - var target = result[2]; + let as = result[1]; + let target = result[2]; // Preparing Options - var options = { + let options = { target: target, as: as, processValue: true @@ -580,11 +580,11 @@ exports.createFieldRelatedToMultiple = function (result) { exports.createFieldRelatedToMultipleUsing = function (result) { - var as = result[1]; - var target = result[2]; - var usingField = result[3]; + let as = result[1]; + let target = result[2]; + let usingField = result[3]; - var options = { + let options = { target: target, as: as, usingField: usingField, @@ -596,11 +596,11 @@ exports.createFieldRelatedToMultipleUsing = function (result) { exports.createFieldRelatedToMultipleCheckbox = function (result) { - var as = result[1]; - var target = result[2]; + let as = result[1]; + let target = result[2]; // Preparing Options - var options = { + let options = { target: target, isCheckbox: true, as: as, @@ -612,11 +612,11 @@ exports.createFieldRelatedToMultipleCheckbox = function (result) { exports.createFieldRelatedToMultipleCheckboxUsing = function (result) { - var as = result[1]; - var target = result[2]; - var usingField = result[3]; + let as = result[1]; + let target = result[2]; + let usingField = result[3]; - var options = { + let options = { target: target, as: as, usingField: usingField, @@ -631,10 +631,10 @@ exports.createFieldRelatedToMultipleCheckboxUsing = function (result) { // Tabs in show exports.relationshipHasMany = function (result) { - var source = result[1]; - var target = result[2]; + let source = result[1]; + let target = result[2]; - var options = { + let options = { target: target, source: source, foreignKey: "id_" + source.toLowerCase(), @@ -647,11 +647,11 @@ exports.relationshipHasMany = function (result) { exports.relationshipHasManyWithName = function (result) { - var source = result[1]; - var target = result[2]; - var as = result[3]; + let source = result[1]; + let target = result[2]; + let as = result[3]; - var options = { + let options = { target: target, source: source, foreignKey: "id_" + source.toLowerCase() + "_" + as.toLowerCase(), @@ -663,16 +663,16 @@ exports.relationshipHasManyWithName = function (result) { }; exports.relationshipHasManyPreset = function (result) { - var source = result[1]; - var target = result[2]; - var as = target; - var foreignKey = "id_" + source.toLowerCase(); + let source = result[1]; + let target = result[2]; + let as = target; + let foreignKey = "id_" + source.toLowerCase(); if (typeof result[3] !== "undefined") as = result[3]; foreignKey = "id_" + source.toLowerCase() + "_" + as.toLowerCase() - var options = { + let options = { target: target, source: source, foreignKey: foreignKey, @@ -684,17 +684,17 @@ exports.relationshipHasManyPreset = function (result) { }; exports.relationshipHasManyPresetUsing = function (result) { - var source = result[1]; - var target = result[2]; - var usingField = result[3]; - var as = target; - var foreignKey = "id_" + source.toLowerCase(); + let source = result[1]; + let target = result[2]; + let usingField = result[3]; + let as = target; + let foreignKey = "id_" + source.toLowerCase(); if (typeof result[4] !== "undefined") as = result[4]; foreignKey = "id_" + source.toLowerCase() + "_" + as.toLowerCase() - var options = { + let options = { target: target, source: source, foreignKey: foreignKey, @@ -710,7 +710,7 @@ exports.relationshipHasManyPresetUsing = function (result) { /* STATUS */ exports.createNewComponentStatus = function (result) { - var defaultValue = result[0].indexOf("component") != -1 ? "Status" : "Statut"; + let defaultValue = result[0].indexOf("component") != -1 ? "Status" : "Statut"; return { function: "createNewComponentStatus", options: {value: defaultValue, processValue: true} @@ -718,8 +718,8 @@ exports.createNewComponentStatus = function (result) { } exports.createNewComponentStatusWithName = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -729,9 +729,9 @@ exports.createNewComponentStatusWithName = function (result) { exports.deleteComponentStatus = function (result) { - var options = {}; + let options = {}; - var attr = { + let attr = { function: "deleteComponentStatus", options: options }; @@ -739,8 +739,8 @@ exports.deleteComponentStatus = function (result) { }; exports.deleteComponentStatusWithName = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -751,9 +751,9 @@ exports.deleteComponentStatusWithName = function (result) { /* LOCAL FILE STORAGE */ exports.createNewComponentLocalFileStorage = function (result) { - var options = {}; + let options = {}; - var attr = { + let attr = { function: "createNewComponentLocalFileStorage", options: options }; @@ -762,8 +762,8 @@ exports.createNewComponentLocalFileStorage = function (result) { exports.createNewComponentLocalFileStorageWithName = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -774,9 +774,9 @@ exports.createNewComponentLocalFileStorageWithName = function (result) { /* CONTACT FORM */ exports.createNewComponentContactForm = function (result) { - var options = {}; + let options = {}; - var attr = { + let attr = { function: "createNewComponentContactForm", options: options }; @@ -785,8 +785,8 @@ exports.createNewComponentContactForm = function (result) { exports.createNewComponentContactFormWithName = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -796,9 +796,9 @@ exports.createNewComponentContactFormWithName = function (result) { exports.deleteComponentContactForm = function (result) { - var options = {}; + let options = {}; - var attr = { + let attr = { function: "deleteComponentContactForm", options: options }; @@ -806,8 +806,8 @@ exports.deleteComponentContactForm = function (result) { }; exports.deleteComponentContactFormWithName = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -818,9 +818,9 @@ exports.deleteComponentContactFormWithName = function (result) { /* AGENDA */ exports.createNewComponentAgenda = function (result) { - var options = {}; + let options = {}; - var attr = { + let attr = { function: "createNewComponentAgenda", options: options }; @@ -829,8 +829,8 @@ exports.createNewComponentAgenda = function (result) { exports.createNewComponentAgendaWithName = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -840,9 +840,9 @@ exports.createNewComponentAgendaWithName = function (result) { exports.deleteAgenda = function (result) { - var options = {}; + let options = {}; - var attr = { + let attr = { function: "deleteAgenda", options: options }; @@ -851,8 +851,8 @@ exports.deleteAgenda = function (result) { exports.deleteAgendaWithName = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value, processValue: true }; @@ -873,7 +873,7 @@ exports.createNewComponentCra = function (result) { * @returns {function name and user instruction} */ exports.createNewComponentAddress = function (result) { - var options = { + let options = { componentName: "Address", instruction: result[0] }; @@ -886,7 +886,7 @@ exports.createNewComponentAddress = function (result) { * @returns {function name and user instruction} */ exports.createNewComponentAddressWithName = function (result) { - var options = { + let options = { componentName: result[1], instruction: result[0] }; @@ -907,9 +907,9 @@ exports.deleteComponentAddress = function (result) { /* PRINT */ exports.createNewComponentPrint = function (result) { - var options = {}; + let options = {}; - var attr = { + let attr = { function: "createNewComponentPrint", options: options }; @@ -918,14 +918,14 @@ exports.createNewComponentPrint = function (result) { exports.createNewComponentPrintWithName = function (result) { - var value = result[1]; + let value = result[1]; - var options = { + let options = { value: value, processValue: true }; - var attr = { + let attr = { function: "createNewComponentPrint", options: options }; @@ -934,9 +934,9 @@ exports.createNewComponentPrintWithName = function (result) { exports.deleteComponentPrint = function (result) { - var options = {}; + let options = {}; - var attr = { + let attr = { function: "deleteComponentPrint", options: options }; @@ -945,14 +945,14 @@ exports.deleteComponentPrint = function (result) { exports.deleteComponentPrintWithName = function (result) { - var value = result[1]; + let value = result[1]; - var options = { + let options = { value: value, processValue: true }; - var attr = { + let attr = { function: "deleteComponentPrint", options: options }; @@ -970,7 +970,7 @@ exports.createComponentDocumentTemplate = function (result) { }; exports.createComponentDocumentTemplateWithName = function (result) { - var options={ + let options={ instruction:result[0], componentName:result[1] }; @@ -995,12 +995,12 @@ exports.createComponentChat = function (result) { // ******* INTERFACE Actions ******* // exports.setLogo = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value }; - var attr = { + let attr = { function: "setLogo", options: options }; @@ -1008,19 +1008,19 @@ exports.setLogo = function (result) { }; exports.removeLogo = function (result) { - var attr = {}; + let attr = {}; attr.function = "removeLogo"; return attr; }; exports.setLayout = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value }; - var attr = { + let attr = { function: "setLayout", options: options }; @@ -1029,7 +1029,7 @@ exports.setLayout = function (result) { exports.listLayout = function (result) { - var attr = { + let attr = { function: "listLayout" }; return attr; @@ -1037,12 +1037,12 @@ exports.listLayout = function (result) { exports.setTheme = function (result) { - var value = result[1]; - var options = { + let value = result[1]; + let options = { value: value }; - var attr = { + let attr = { function: "setTheme", options: options }; @@ -1051,7 +1051,7 @@ exports.setTheme = function (result) { exports.listTheme = function (result) { - var attr = { + let attr = { function: "listTheme" }; return attr; @@ -1062,7 +1062,7 @@ exports.listIcon = function (result) { } exports.setIcon = function (result) { - var attr = { + let attr = { function: "setIcon", iconValue: result[1] }; @@ -1070,7 +1070,7 @@ exports.setIcon = function (result) { } exports.setIconToEntity = function (result) { - var attr = { + let attr = { function: "setIconToEntity", iconValue: result[1], entityTarget: result[2] @@ -1100,7 +1100,7 @@ function getRightWidgetType(originalType) { } function buildAttrForPiechart(result) { - var attr = { + let attr = { function: 'createWidgetPiechart', widgetType: 'piechart', widgetInputType: 'Piechart' @@ -1118,21 +1118,21 @@ function buildAttrForPiechart(result) { } exports.createWidgetPiechart = function (result) { - var attr = buildAttrForPiechart(result); + let attr = buildAttrForPiechart(result); attr.legend = true; return attr; } exports.createWidgetPiechartWithoutLegend = function (result) { - var attr = buildAttrForPiechart(result); + let attr = buildAttrForPiechart(result); attr.legend = false; return attr; } exports.createWidgetLastRecordsWithLimit = function (result) { - var attr = { + let attr = { function: 'createWidgetLastRecords', widgetType: 'lastrecords', widgetInputType: 'last records' @@ -1150,14 +1150,14 @@ exports.createWidgetLastRecordsWithLimit = function (result) { } // Remove unwanted spaces from columns - for (var i = 0; i < attr.columns.length; i++) + for (let i = 0; i < attr.columns.length; i++) attr.columns[i] = attr.columns[i].trim(); return attr; } exports.createWidgetLastRecords = function (result) { - var attr = { + let attr = { function: 'createWidgetLastRecords', widgetType: 'lastrecords', widgetInputType: 'last records', @@ -1174,15 +1174,15 @@ exports.createWidgetLastRecords = function (result) { } // Remove unwanted spaces from columns - for (var i = 0; i < attr.columns.length; i++) + for (let i = 0; i < attr.columns.length; i++) attr.columns[i] = attr.columns[i].trim(); return attr; } exports.createWidgetOnEntity = function (result) { - var originalType = result[1]; - var finalType = getRightWidgetType(originalType); + let originalType = result[1]; + let finalType = getRightWidgetType(originalType); if (finalType == -1) return {error: 'error.missingParametersInstruction'}; @@ -1196,8 +1196,8 @@ exports.createWidgetOnEntity = function (result) { } exports.createWidget = function (result) { - var originalType = result[1]; - var finalType = getRightWidgetType(originalType); + let originalType = result[1]; + let finalType = getRightWidgetType(originalType); if (finalType == -1) return {error: 'error.missingParametersInstruction'}; @@ -1246,7 +1246,7 @@ exports.apero = function (result) { } } -var training = { +let training = { "apero": [ "Apéro !" ], @@ -2755,16 +2755,16 @@ var training = { // ******* Parse ******* exports.parse = function (instruction) { - var instructionResult = { + let instructionResult = { instructionLength: 0 }; - for (var action in training) { - for (var i = 0; i < training[action].length; i++) { - var regStr = training[action][i]; - var regExp = new RegExp(regStr, "ig"); + for (let action in training) { + for (let i = 0; i < training[action].length; i++) { + let regStr = training[action][i]; + let regExp = new RegExp(regStr, "ig"); - var result = regExp.exec(instruction); + let result = regExp.exec(instruction); if (result !== null) { /* Get the most complicated instruction found */ if (instructionResult.instructionLength < regStr.length) { @@ -2777,7 +2777,7 @@ exports.parse = function (instruction) { } } } - var attr = {}; + let attr = {}; if (typeof instructionResult.action !== "undefined") { attr = this[instructionResult.action](instructionResult.result); attr.instruction = instruction; @@ -2791,52 +2791,52 @@ exports.parse = function (instruction) { // ******* Completion ******* exports.complete = function (instruction) { - var answers = []; - var p = 0; + let answers = []; + let p = 0; // Check all training key phrases - for (var action in training) { + for (let action in training) { // Check each blocks - for (var i = 0; i < training[action].length; i++) { + for (let i = 0; i < training[action].length; i++) { // Template to compare to - var template = training[action][i].split(" "); + let template = training[action][i].split(" "); // Split current key phrase and instructions into arrays to loop - var instr = instruction.trim().split(" "); + let instr = instruction.trim().split(" "); - var k = 0; // index in template - var m = 0; // index in instruction + let k = 0; // index in template + let m = 0; // index in instruction - var l = instr.length; - var n = template.length; + let l = instr.length; + let n = template.length; - var answer = " "; - var valid = true; - var variable = false; + let answer = " "; + let valid = true; + let letiable = false; while ((m < l) && (k < n) && (valid)) { // Check if words are the same, goto next word if (template[k] == "(.*)" || template[k] == instr[m]) { - variable = false; + letiable = false; k++; } else { // Check if beginning of word are the same - var sublen = instr[m].length; + let sublen = instr[m].length; if (template[k].substring(0, sublen) == instr[m]) { // Do not increment k, we are still on keyword - variable = false; + letiable = false; } else { - // If we parse the variable value + // If we parse the letiable value if (template[k] == "(.*)") { // Check next word if (template[k + 1]) { k++; - variable = true; + letiable = true; } } else { - // If we are not parsing a variable, it means template is not appropriate => Exit - if (!variable) + // If we are not parsing a letiable, it means template is not appropriate => Exit + if (!letiable) valid = false; } } @@ -2847,8 +2847,8 @@ exports.complete = function (instruction) { // Instruction has respected template, so send next keyword if any if ((valid) && (m == l)) { - var found = false; - var firstLoop = true; + let found = false; + let firstLoop = true; while ((k < n) && !found) { // Return next keyword @@ -2857,12 +2857,12 @@ exports.complete = function (instruction) { else { if (template[k - 1] == "type") answer = answer + "[type] "; - // Return [variable] to explain this is something dynamic + // Return [letiable] to explain this is something dynamic else - answer = answer + "[variable] "; + answer = answer + "[letiable] "; - // If first loop on variable, we need to display possible end of instruction - // Else, it means we have keyword at the beginning of suggestion, so we cut on variable step + // If first loop on letiable, we need to display possible end of instruction + // Else, it means we have keyword at the beginning of suggestion, so we cut on letiable step if (!firstLoop) found = true; } @@ -2908,7 +2908,7 @@ exports.complete = function (instruction) { } // Filter array of results (remove double values) - var i, j, len = answers.length, + let i, j, len = answers.length, out = [], obj = {}; for (i = 0; i < len; i++) diff --git a/services/cloud_manager.js b/services/cloud_manager.js index 6db85faa0..1a13f468f 100644 --- a/services/cloud_manager.js +++ b/services/cloud_manager.js @@ -51,7 +51,7 @@ exports.deploy = (attr, callback) => { return callback(err); gitHelper.gitTag(appID, applicationConf.version, applicationPath).then(_ => { - gitHelper.gitPush(attr, (err, infoGit)=> { + gitHelper.gitPush(attr, (err, infoGit) => { if(err) return callback(err, null); @@ -59,19 +59,30 @@ exports.deploy = (attr, callback) => { let nameRepo = globalConfig.host + '-' + appName; let subdomain = globalConfig.sub_domain + '-' + appName + '-' + globalConfig.dns_cloud.replace('.', '-'); - portainerDeploy(nameRepo, subdomain, appID, appName, attr.gitlabUser).then(data => { - return callback(null, { - message: "botresponse.deployment", - messageParams: [data.url, data.url] - }); - }).catch(err => { - if(typeof err.message !== "undefined") - console.error(err.message); - else - console.error(err); + gitHelper.gitRemotes(attr, (err, remotes) => { - return callback(err); - }); + // Gitlab url handling + let gitlabUrl = ""; + if(remotes.length > 0 && remotes[0].refs && remotes[0].refs.fetch) + gitlabUrl = remotes[0].refs.fetch; // Getting actuel .git fetch remote + else + gitlabUrl = gitlabConfig.sshUrl + ":" + attr.gitlabUser.username + "/" + repoName + ".git"; // Generating manually the remote, can generate clone error if the connected user is note the owning user of the gitlab repo + + console.log('Cloning in cloud: ' + gitlabUrl); + portainerDeploy(nameRepo, subdomain, appID, appName, gitlabUrl).then(data => { + return callback(null, { + message: "botresponse.deployment", + messageParams: [data.url, data.url] + }); + }).catch(err => { + if(typeof err.message !== "undefined") + console.error(err.message); + else + console.error(err); + + return callback(err); + }); + }) }); }).catch(function(e) { console.log(e); @@ -80,9 +91,8 @@ exports.deploy = (attr, callback) => { }); } -async function portainerDeploy(repoName, subdomain, appID, appName, gitlabUser){ +async function portainerDeploy(repoName, subdomain, appID, appName, gitlabUrl){ // Preparing all needed values - let gitlabUrl = gitlabConfig.sshUrl + ":" + gitlabUser.username + "/" + repoName + ".git"; let stackName = globalConfig.sub_domain + "-" + appName + "-" + globalConfig.dns_cloud.replace(".", "-"); let cloudUrl = globalConfig.sub_domain + "-" + appName + "." + globalConfig.dns_cloud; diff --git a/services/designer.js b/services/designer.js index 395635b5a..bddcbd7a3 100755 --- a/services/designer.js +++ b/services/designer.js @@ -1,4 +1,4 @@ -// Database Generator +// Newmips Database const db_project = require("../database/project"); const db_application = require("../database/application"); const db_module = require("../database/module"); @@ -9,27 +9,28 @@ const database = require("../database/database"); // Session const session = require("./session"); -const cloud_manager = require('../services/cloud_manager'); -// Bot -var bot = require('../services/bot.js'); +// Bot grammar +let bot = require('../services/bot.js'); -// Structure -var structure_application = require("../structure/structure_application"); -var structure_module = require("../structure/structure_module"); -var structure_data_entity = require("../structure/structure_data_entity"); -var structure_data_field = require("../structure/structure_data_field"); -var structure_component = require("../structure/structure_component"); -var structure_ui = require("../structure/structure_ui"); +// Structure files +let structure_application = require("../structure/structure_application"); +let structure_module = require("../structure/structure_module"); +let structure_data_entity = require("../structure/structure_data_entity"); +let structure_data_field = require("../structure/structure_data_field"); +let structure_component = require("../structure/structure_component"); +let structure_ui = require("../structure/structure_ui"); -// Other -var helpers = require("../utils/helpers"); -var attrHelper = require("../utils/attr_helper"); -var gitHelper = require("../utils/git_helper"); -var translateHelper = require("../utils/translate"); +// Utils +let helpers = require("../utils/helpers"); +let attrHelper = require("../utils/attr_helper"); +let gitHelper = require("../utils/git_helper"); +let translateHelper = require("../utils/translate"); +// Others const fs = require('fs-extra'); const sequelize = require('../models/').sequelize; +const cloud_manager = require('../services/cloud_manager'); /* --------------------------------------------------------------- */ /* -------------------------- General ---------------------------- */ @@ -283,6 +284,7 @@ function deleteApplication(attr, callback) { let err = new Error("You do not have access to this application, you cannot delete it.") return callback(err, null); } + structure_application.deleteApplication(id_application, function (err, infoStructure) { if (err) return callback(err, null); @@ -310,6 +312,7 @@ function deleteApplication(attr, callback) { var request = ""; if(sequelize.options.dialect == "mysql") request += "SET FOREIGN_KEY_CHECKS=0;"; + for (var i = 0; i < results.length; i++) { for (var prop in results[i]) { // Postgres additionnal check @@ -323,8 +326,10 @@ function deleteApplication(attr, callback) { } } } + if(sequelize.options.dialect == "mysql") request += "SET FOREIGN_KEY_CHECKS=1;"; + sequelize.query(request).then(function () { callback(null, infoDB); }).catch(function(err){ @@ -1001,27 +1006,30 @@ exports.setFieldKnownAttribute = function (attr, callback) { }) } else if (uniqueAttribute.indexOf(wordParam) != -1) { - var sourceEntity = attr.id_application + "_" + attr.name_data_entity; - var constraintName = attr.id_application + "_" + attr.name_data_entity + "_" + attr.options.value + "_unique"; + let sourceEntity = attr.id_application + "_" + attr.name_data_entity; + let constraintName = sourceEntity + "_" + attr.options.value + "_unique"; - var possibilityUnique = ["unique"]; - var possibilityNotUnique = ["not-unique", "non-unique"]; + let possibilityUnique = ["unique"]; + let possibilityNotUnique = ["not-unique", "non-unique"]; - var attribute = attr.options.word.toLowerCase(); - var request = ""; + let attribute = attr.options.word.toLowerCase(); + let request = ""; + + // Get application database, it won't be newmips if seperate DB + let appDBConf = require(__dirname+'/../workspace/' + attr.id_application + '/config/database.js'); // Add or remove the unique constraint ? if(sequelize.options.dialect == "mysql"){ if (possibilityUnique.indexOf(attribute) != -1) { - request = "ALTER TABLE `" + sourceEntity + "` ADD CONSTRAINT " + constraintName + " UNIQUE (`" + attr.options.value + "`);"; + request = "ALTER TABLE `" + appDBConf.database + "`.`" + sourceEntity + "` ADD CONSTRAINT " + constraintName + " UNIQUE (`" + attr.options.value + "`);"; } else if (possibilityNotUnique.indexOf(attribute) != -1) { - request = "ALTER TABLE `" + sourceEntity + "` DROP INDEX `" + constraintName + "`;"; + request = "ALTER TABLE `" + appDBConf.database + "`.`" + sourceEntity + "` DROP INDEX `" + constraintName + "`;"; } } else if (sequelize.options.dialect == "postgres"){ if (possibilityUnique.indexOf(attribute) != -1) { - request = "ALTER TABLE \"" + sourceEntity + "\" ADD CONSTRAINT \"" + constraintName + "\" UNIQUE (" + attr.options.value + ");"; + request = "ALTER TABLE \"" + appDBConf.database + "\".\"" + sourceEntity + "\" ADD CONSTRAINT \"" + constraintName + "\" UNIQUE (" + attr.options.value + ");"; } else if (possibilityNotUnique.indexOf(attribute) != -1) { - request = "ALTER TABLE \"" + sourceEntity + "\" DROP INDEX \"" + constraintName + "\";"; + request = "ALTER TABLE \"" + appDBConf.database + "\".\"" + sourceEntity + "\" DROP INDEX \"" + constraintName + "\";"; } } @@ -1194,6 +1202,11 @@ exports.createNewHasOne = function (attr, callback) { return callback(err, null); } } + } else if(attr.options.as == optionsSourceObject[i].as){ + let err = new Error(); + err.message = "database.field.error.alreadyExist"; + err.messageParams = [attr.options.showAs]; + return callback(err, null); } } @@ -1358,6 +1371,44 @@ function belongsToMany(attr, optionObj, setupFunction, exportsContext) { id_data_entity: attr.id_data_entity }; + // { function: 'createNewHasManyPreset', + // options: + // { target: 'e_user', + // source: 'e_projet', + // foreignKey: 'fk_id_projet_participant_using_login', + // as: 'r_participant_using_login', + // processValue: true, + // showTarget: 'User', + // urlTarget: 'user', + // showSource: 'Projet', + // urlSource: 'projet', + // showForeignKey: 'id_projet_participant using login', + // showAs: 'Participant using Login', + // urlAs: 'participant_using_login', + // through: '11_e_projet_e_user' }, + // instruction: 'entity Projet has many existing User called Participant using Login', + // id_project: 11, + // id_application: 11, + // id_module: 30, + // id_data_entity: 147, + // googleTranslate: false, + // lang_user: 'fr-FR', + // currentUser: + // { id: 1, + // email: 'admin@admin.fr', + // enabled: true, + // first_name: 'admin', + // last_name: 'NEWMIPS', + // login: 'admin', + // password: '$2a$10$h2kI8qTdNqlh64FeqzRGjOVzhRGr60xf5b/JCL/R.y4747uvSwj1u', + // phone: null, + // token_password_reset: null, + // version: 1, + // id_role: 1 }, + // gitlabUser: null, + // targetType: 'auto_generate' } + + if (attr.targetType == "hasMany") { structure_data_field.setupHasManyTab(reversedAttr, function () { resolve(); @@ -1422,6 +1473,11 @@ exports.createNewHasMany = function (attr, callback) { return callback(err, null); } } + } else if(attr.options.as == optionsSourceObject[i].as){ + let err = new Error(); + err.message = "database.field.error.alreadyExist"; + err.messageParams = [attr.options.showAs]; + return callback(err, null); } } @@ -1510,7 +1566,9 @@ exports.createNewHasMany = function (attr, callback) { for (var i = 0; i < optionsObject.length; i++) { if (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].target.toLowerCase() != attr.options.target.toLowerCase() - && optionsObject[i].relation != "belongsTo") { + && optionsObject[i].relation != "belongsTo" + && optionsObject[i].structureType != "auto_generate") { + doingBelongsToMany = true; /* Then lets create the belongs to many association */ belongsToMany(attr, optionsObject[i], "setupHasManyTab", exportsContext).then(function () { @@ -1643,11 +1701,11 @@ exports.createNewHasManyPreset = function (attr, callback) { return callback(err, null); let sourceOptionsPath = __dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.source.toLowerCase() + '.json'; - var optionsSourceFile = helpers.readFileSyncWithCatch(sourceOptionsPath); - var optionsSourceObject = JSON.parse(optionsSourceFile); - var toSync = true; + let optionsSourceFile = helpers.readFileSyncWithCatch(sourceOptionsPath); + let optionsSourceObject = JSON.parse(optionsSourceFile); + let toSync = true; let saveFile = false; - // Vérification si une relation existe déjà de la source VERS la target + // Vérification si une relation existe déjà avec cet alias for (var i = 0; i < optionsSourceObject.length; i++) { if (optionsSourceObject[i].target.toLowerCase() == attr.options.target.toLowerCase()) { // If alias already used @@ -1661,12 +1719,17 @@ exports.createNewHasManyPreset = function (attr, callback) { return callback(err, null); } } + } else if(attr.options.as == optionsSourceObject[i].as){ + let err = new Error(); + err.message = "database.field.error.alreadyExist"; + err.messageParams = [attr.options.showAs]; + return callback(err, null); } } attr.options.through = attr.id_application + "_" + idEntitySource + "_" + entityTarget.id + "_" + attr.options.as.substring(2); if (attr.options.through.length > 55) { - var err = new Error(); + let err = new Error(); err.message = "error.valueTooLong"; err.messageParams = [attr.options.through]; return callback(err, null); @@ -1676,33 +1739,39 @@ exports.createNewHasManyPreset = function (attr, callback) { if(saveFile) fs.writeFileSync(sourceOptionsPath, JSON.stringify(optionsSourceObject, null, 4), "utf8") + let optionsFile = helpers.readFileSyncWithCatch(__dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.target.toLowerCase() + '.json'); + let targetOptions = JSON.parse(optionsFile); + let cptExistingHasMany = 0; - var optionsFile = helpers.readFileSyncWithCatch(__dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.target.toLowerCase() + '.json'); - var optionsObject = JSON.parse(optionsFile); - var cptExistingHasMany = 0; + // Preparing variable + let source = attr.options.source.toLowerCase(); + let target = attr.options.target.toLowerCase(); // Check if there is no or just one belongsToMany to do - for (var i = 0; i < optionsObject.length; i++) { - if (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation != "belongsTo") { + for (let i = 0; i < targetOptions.length; i++) + if (targetOptions[i].target.toLowerCase() == source && targetOptions[i].relation != "belongsTo") cptExistingHasMany++; - } - } /* If there are multiple has many association from target to source we can't handle on which one we gonna link the belongsToMany association */ if (cptExistingHasMany > 1) { - var err = new Error("structure.association.error.tooMuchHasMany"); + let err = new Error("structure.association.error.tooMuchHasMany"); return callback(err, null); } - var doingBelongsToMany = false; - + let doingBelongsToMany = false, targetObjTarget; // Vérification si une relation existe déjà de la target VERS la source - for (var i = 0; i < optionsObject.length; i++) { - if (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation != "belongsTo") { + for (let i = 0; i < targetOptions.length; i++) { + targetObjTarget = targetOptions[i].target.toLowerCase(); + + if (targetObjTarget == source + && targetObjTarget != target + && targetOptions[i].relation != "belongsTo" + && targetOptions[i].structureType != "auto_generate") { + doingBelongsToMany = true; /* Then lets create the belongs to many association */ - belongsToMany(attr, optionsObject[i], "setupHasManyPresetTab", exportsContext).then(function () { - var info = {}; + belongsToMany(attr, targetOptions[i], "setupHasManyPresetTab", exportsContext).then(function () { + let info = {}; info.insertId = attr.id_data_entity; info.message = "structure.association.hasManyExisting.success"; info.messageParams = [attr.options.showTarget, attr.options.showSource]; @@ -1711,9 +1780,9 @@ exports.createNewHasManyPreset = function (attr, callback) { console.error(err); return callback(err, null); }); - } else if (attr.options.source.toLowerCase() != attr.options.target.toLowerCase() - && (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation == "belongsTo") - && (optionsObject[i].foreignKey == attr.options.foreignKey)) { + } else if (source != target + && (targetObjTarget == source && targetOptions[i].relation == "belongsTo") + && targetOptions[i].foreignKey == attr.options.foreignKey) { // We avoid the toSync to append because the already existing has one relation has already created the foreign key in BDD toSync = false; } @@ -1758,295 +1827,319 @@ exports.createNewHasManyPreset = function (attr, callback) { // Create a field in create/show/update related to target entity exports.createNewFieldRelatedTo = function (attr, callback) { - // Instruction is add field _FOREIGNKEY_ related to _TARGET_ -> We don't know the source entity name - db_entity.getDataEntityById(attr.id_data_entity, function (err, source_entity) { - if (err && typeof attr.options.source === "undefined") + // Check if a field with this name already exist + db_field.getFieldByCodeName({ + codeName: 'f_' + attr.options.urlAs, + idEntity: attr.id_data_entity + }, (err, field) => { + if(field){ + var err = new Error(); + err.message = "database.field.error.alreadyExist"; + err.messageParams = [attr.options.showAs]; return callback(err, null); - // With preset instruction with already know the source of the related to - // "entity (.*) has one preset (.*) called (.*) using (.*)" - if (typeof attr.options.source === "undefined") { - attr.options.source = source_entity.codeName; - attr.options.showSource = source_entity.name; - attr.options.urlSource = attrHelper.removePrefix(source_entity.codeName, "entity"); } - // Vérifie que la target existe bien avant de creer la source et la clé étrangère (foreign key) - db_entity.selectEntityTarget(attr, function (err, dataEntity) { - // If target entity doesn't exists, send error - if (err) + // Instruction is add field _FOREIGNKEY_ related to _TARGET_ -> We don't know the source entity name + db_entity.getDataEntityById(attr.id_data_entity, function (err, source_entity) { + if (err && typeof attr.options.source === "undefined") return callback(err, null); - var allUsingExist = true; - // If a using field or fields has been asked, we have to check if those fields exist in the entity - if (typeof attr.options.usingField !== "undefined") { - var attributesPath = __dirname + '/../workspace/' + attr.id_application + '/models/attributes/' + attr.options.target.toLowerCase() - delete require.cache[require.resolve(attributesPath)]; - var attributeTarget = require(attributesPath); - for (var i = 0; i < attr.options.usingField.length; i++) { - if (typeof attributeTarget[attr.options.usingField[i]] === "undefined") { - allUsingExist = false; - var missingField = attr.options.showUsingField[i]; - } else { - attr.options.usingField[i] = { - value: attr.options.usingField[i], - type: attributeTarget[attr.options.usingField[i]].newmipsType + // With preset instruction with already know the source of the related to + // "entity (.*) has one preset (.*) called (.*) using (.*)" + if (typeof attr.options.source === "undefined") { + attr.options.source = source_entity.codeName; + attr.options.showSource = source_entity.name; + attr.options.urlSource = attrHelper.removePrefix(source_entity.codeName, "entity"); + } + // Vérifie que la target existe bien avant de creer la source et la clé étrangère (foreign key) + db_entity.selectEntityTarget(attr, function (err, dataEntity) { + // If target entity doesn't exists, send error + if (err) + return callback(err, null); + var allUsingExist = true; + // If a using field or fields has been asked, we have to check if those fields exist in the entity + if (typeof attr.options.usingField !== "undefined") { + var attributesPath = __dirname + '/../workspace/' + attr.id_application + '/models/attributes/' + attr.options.target.toLowerCase() + delete require.cache[require.resolve(attributesPath)]; + var attributeTarget = require(attributesPath); + for (var i = 0; i < attr.options.usingField.length; i++) { + if (typeof attributeTarget[attr.options.usingField[i]] === "undefined") { + allUsingExist = false; + var missingField = attr.options.showUsingField[i]; + } else { + attr.options.usingField[i] = { + value: attr.options.usingField[i], + type: attributeTarget[attr.options.usingField[i]].newmipsType + } } } } - } - // If a asked using field doesn't exist in the target entity we send an error - if (!allUsingExist) { - var err = new Error("structure.association.relatedTo.missingField"); - err.messageParams = [missingField, attr.options.showTarget]; - return callback(err, null); - } - // Check if an association already exists from source to target - let sourceOptionsPath = __dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.source.toLowerCase() + '.json'; - let optionsSourceObject = JSON.parse(helpers.readFileSyncWithCatch(sourceOptionsPath)); - let toSync = true; - let constraints = true; - let saveFile = false; - // Check if an association already exists with the same alias - for (var i = 0; i < optionsSourceObject.length; i++) { - if (optionsSourceObject[i].target.toLowerCase() == attr.options.target.toLowerCase()) { - // If alias already used - if (attr.options.as == optionsSourceObject[i].as){ - if(optionsSourceObject[i].structureType == "auto_generate") { - // Remove auto generate key by the generator - optionsSourceObject.splice(i, 1); - saveFile = true; - } else - return callback(new Error("structure.association.error.alreadySameAlias"), null); - } - } else if(attr.options.as == optionsSourceObject[i].as){ - let err = new Error(); - err.message = "database.field.error.alreadyExist"; - err.messageParams = [attr.options.showAs]; + // If a asked using field doesn't exist in the target entity we send an error + if (!allUsingExist) { + var err = new Error("structure.association.relatedTo.missingField"); + err.messageParams = [missingField, attr.options.showTarget]; return callback(err, null); } - } - - // Changes to be saved, remove auto_generate key - if(saveFile) - fs.writeFileSync(sourceOptionsPath, JSON.stringify(optionsSourceObject, null, 4), "utf8"); - - // Check if an association already exists from target to source - var optionsFile = helpers.readFileSyncWithCatch(__dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.target.toLowerCase() + '.json'); - var optionsObject = JSON.parse(optionsFile); - for (var i = 0; i < optionsObject.length; i++) { - if (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation != "hasMany" && optionsObject[i].relation != "belongsToMany") { - constraints = false; - } else if (attr.options.source.toLowerCase() != attr.options.target.toLowerCase() - && (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation == "hasMany") - && (optionsObject[i].foreignKey == attr.options.foreignKey)) { - // We avoid the toSync to append because the already existing has many relation has already created the foreign key in BDD - toSync = false; + // Check if an association already exists from source to target + let sourceOptionsPath = __dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.source.toLowerCase() + '.json'; + let optionsSourceObject = JSON.parse(helpers.readFileSyncWithCatch(sourceOptionsPath)); + let toSync = true; + let constraints = true; + let saveFile = false; + // Check if an association already exists with the same alias + for (var i = 0; i < optionsSourceObject.length; i++) { + if (optionsSourceObject[i].target.toLowerCase() == attr.options.target.toLowerCase()) { + // If alias already used + if (attr.options.as == optionsSourceObject[i].as){ + if(optionsSourceObject[i].structureType == "auto_generate") { + // Remove auto generate key by the generator + optionsSourceObject.splice(i, 1); + saveFile = true; + } else + return callback(new Error("structure.association.error.alreadySameAlias"), null); + } + } else if(attr.options.as == optionsSourceObject[i].as){ + let err = new Error(); + err.message = "database.field.error.alreadyExist"; + err.messageParams = [attr.options.showAs]; + return callback(err, null); + } } - } - // Add foreign key to newmips's DB - db_field.createNewForeignKey(attr, function (err, created_foreignKey) { - if (err) - return callback(err, null); - // Créer le lien belongsTo en la source et la target dans models/options/source.json - var associationOption = { - idApp: attr.id_application, - source: attr.options.source, - target: attr.options.target, - foreignKey: attr.options.foreignKey, - as: attr.options.as, - showAs: attr.options.showAs, - relation: "belongsTo", - through: null, - toSync: true, - type: "relatedTo", - constraints: constraints - }; - if (typeof attr.options.usingField !== "undefined") { - associationOption.usingField = attr.options.usingField; + + // Changes to be saved, remove auto_generate key + if(saveFile) + fs.writeFileSync(sourceOptionsPath, JSON.stringify(optionsSourceObject, null, 4), "utf8"); + + // Check if an association already exists from target to source + var optionsFile = helpers.readFileSyncWithCatch(__dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.target.toLowerCase() + '.json'); + var optionsObject = JSON.parse(optionsFile); + for (var i = 0; i < optionsObject.length; i++) { + if (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation != "hasMany" && optionsObject[i].relation != "belongsToMany") { + constraints = false; + } else if (attr.options.source.toLowerCase() != attr.options.target.toLowerCase() + && (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation == "hasMany") + && (optionsObject[i].foreignKey == attr.options.foreignKey)) { + // We avoid the toSync to append because the already existing has many relation has already created the foreign key in BDD + toSync = false; + } } + // Add foreign key to newmips's DB + db_field.createNewForeignKey(attr, function (err, created_foreignKey) { + if (err) + return callback(err, null); + // Créer le lien belongsTo en la source et la target dans models/options/source.json + var associationOption = { + idApp: attr.id_application, + source: attr.options.source, + target: attr.options.target, + foreignKey: attr.options.foreignKey, + as: attr.options.as, + showAs: attr.options.showAs, + relation: "belongsTo", + through: null, + toSync: true, + type: "relatedTo", + constraints: constraints + }; + if (typeof attr.options.usingField !== "undefined") { + associationOption.usingField = attr.options.usingField; + } - var reversedOption = { - idApp: attr.id_application, - source: attr.options.target, - target: attr.options.source, - foreignKey: attr.options.foreignKey, - as: "r_"+attr.options.source.substring(2), - relation: "hasMany", - type: "auto_generate", - constraints: constraints - }; - structure_data_entity.setupAssociation(associationOption, function () { - structure_data_entity.setupAssociation(reversedOption, function () { - // Ajouter le field d'assocation dans create_fields/update_fields. Ajout d'un tab dans le show - structure_data_field.setupRelatedToField(attr, function (err, data) { - if (err){return callback(err, null);} - // Stay on the source entity in session - var info = {}; - info.insertId = attr.id_data_entity; - info.message = "structure.association.relatedTo.success"; - info.messageParams = [attr.options.showAs, attr.options.showTarget, attr.options.showAs, attr.options.showAs, attr.options.showAs]; - callback(null, info); + var reversedOption = { + idApp: attr.id_application, + source: attr.options.target, + target: attr.options.source, + foreignKey: attr.options.foreignKey, + as: "r_"+attr.options.source.substring(2), + relation: "hasMany", + type: "auto_generate", + constraints: constraints + }; + structure_data_entity.setupAssociation(associationOption, function () { + structure_data_entity.setupAssociation(reversedOption, function () { + // Ajouter le field d'assocation dans create_fields/update_fields. Ajout d'un tab dans le show + structure_data_field.setupRelatedToField(attr, function (err, data) { + if (err){return callback(err, null);} + // Stay on the source entity in session + var info = {}; + info.insertId = attr.id_data_entity; + info.message = "structure.association.relatedTo.success"; + info.messageParams = [attr.options.showAs, attr.options.showTarget, attr.options.showAs, attr.options.showAs, attr.options.showAs]; + callback(null, info); + }) }) }) }) }) - }) - }) + }); + }); } // Select multiple in create/show/update related to target entity exports.createNewFieldRelatedToMultiple = function (attr, callback) { var exportsContext = this; - // Instruction is add field _FOREIGNKEY_ related to multiple _TARGET_ -> We don't know the source entity name so we have to find it - db_entity.getDataEntityById(attr.id_data_entity, function (err, source_entity) { - if (err && typeof attr.options.source === "undefined") + // Check if a field with this name already exist + db_field.getFieldByCodeName({ + codeName: 'f_' + attr.options.urlAs, + idEntity: attr.id_data_entity + }, (err, field) => { + if(field){ + var err = new Error(); + err.message = "database.field.error.alreadyExist"; + err.messageParams = [attr.options.showAs]; return callback(err, null); - - // With preset instruction with already know the source of the related to - // "entity (.*) has one preset (.*) called (.*) using (.*)" - if (typeof attr.options.source === "undefined") { - attr.options.source = source_entity.codeName; - attr.options.showSource = source_entity.name; - attr.options.urlSource = attrHelper.removePrefix(source_entity.codeName, "entity"); } + // Instruction is add field _FOREIGNKEY_ related to multiple _TARGET_ -> We don't know the source entity name so we have to find it + db_entity.getDataEntityById(attr.id_data_entity, (err, source_entity) => { + if (err && typeof attr.options.source === "undefined") + return callback(err, null); - // Now we know the source entity, so we can generate the foreign key - attr.options.foreignKey = "fk_id_" + attr.options.source + "_" + attr.options.as.toLowerCase().substring(2); + // With preset instruction with already know the source of the related to + // "entity (.*) has one preset (.*) called (.*) using (.*)" + if (typeof attr.options.source === "undefined") { + attr.options.source = source_entity.codeName; + attr.options.showSource = source_entity.name; + attr.options.urlSource = attrHelper.removePrefix(source_entity.codeName, "entity"); + } - // Vérifie que la target existe bien avant de creer la source et la clé étrangère (foreign key) - db_entity.selectEntityTarget(attr, (err, entityTarget) => { - // If target entity doesn't exists, send error - if (err) - return callback(err, null); + // Now we know the source entity, so we can generate the foreign key + attr.options.foreignKey = "fk_id_" + attr.options.source + "_" + attr.options.as.toLowerCase().substring(2); - var allUsingExist = true; - - // If a using field or fields has been asked, we have to check if those fields exist in the entity - if (typeof attr.options.usingField !== "undefined") { - var attributesPath = __dirname + '/../workspace/' + attr.id_application + '/models/attributes/' + attr.options.target.toLowerCase() - delete require.cache[require.resolve(attributesPath)]; - var attributeTarget = require(attributesPath); - for (var i = 0; i < attr.options.usingField.length; i++) { - if (typeof attributeTarget[attr.options.usingField[i]] === "undefined") { - allUsingExist = false; - var missingField = attr.options.showUsingField[i]; - } else { - attr.options.usingField[i] = { - value: attr.options.usingField[i], - type: attributeTarget[attr.options.usingField[i]].newmipsType + // Vérifie que la target existe bien avant de creer la source et la clé étrangère (foreign key) + db_entity.selectEntityTarget(attr, (err, entityTarget) => { + // If target entity doesn't exists, send error + if (err) + return callback(err, null); + + var allUsingExist = true; + + // If a using field or fields has been asked, we have to check if those fields exist in the entity + if (typeof attr.options.usingField !== "undefined") { + var attributesPath = __dirname + '/../workspace/' + attr.id_application + '/models/attributes/' + attr.options.target.toLowerCase() + delete require.cache[require.resolve(attributesPath)]; + var attributeTarget = require(attributesPath); + for (var i = 0; i < attr.options.usingField.length; i++) { + if (typeof attributeTarget[attr.options.usingField[i]] === "undefined") { + allUsingExist = false; + var missingField = attr.options.showUsingField[i]; + } else { + attr.options.usingField[i] = { + value: attr.options.usingField[i], + type: attributeTarget[attr.options.usingField[i]].newmipsType + } } } } - } - // If a asked using field doesn't exist in the target entity we send an error - if (!allUsingExist) { - var err = new Error("structure.association.relatedTo.missingField"); - err.messageParams = [missingField, attr.options.showTarget]; - return callback(err, null); - } + // If a asked using field doesn't exist in the target entity we send an error + if (!allUsingExist) { + var err = new Error("structure.association.relatedTo.missingField"); + err.messageParams = [missingField, attr.options.showTarget]; + return callback(err, null); + } - // Check if an association already exists from source to target - var optionsSourceFile = helpers.readFileSyncWithCatch(__dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.source.toLowerCase() + '.json'); - var optionsSourceObject = JSON.parse(optionsSourceFile); + // Check if an association already exists from source to target + var optionsSourceFile = helpers.readFileSyncWithCatch(__dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.source.toLowerCase() + '.json'); + var optionsSourceObject = JSON.parse(optionsSourceFile); - var toSync = true; - var relation = "belongsToMany"; + var toSync = true; + var relation = "belongsToMany"; - // Check already exisiting association from source to target entity - for (var i = 0; i < optionsSourceObject.length; i++) { - if (optionsSourceObject[i].target.toLowerCase() == attr.options.target.toLowerCase()) { - if (attr.options.as == optionsSourceObject[i].as) { + // Check already exisiting association from source to target entity + for (var i = 0; i < optionsSourceObject.length; i++) { + if (optionsSourceObject[i].target.toLowerCase() == attr.options.target.toLowerCase()) { + if (attr.options.as == optionsSourceObject[i].as) { + var err = new Error("structure.association.error.alreadySameAlias"); + return callback(err, null); + } + } else if (optionsSourceObject[i].relation == "belongsToMany" && (attr.options.as == optionsSourceObject[i].as)) { var err = new Error("structure.association.error.alreadySameAlias"); return callback(err, null); + } else if(attr.options.as == optionsSourceObject[i].as){ + let err = new Error(); + err.message = "database.field.error.alreadyExist"; + err.messageParams = [attr.options.showAs]; + return callback(err, null); } - } else if (optionsSourceObject[i].relation == "belongsToMany" && (attr.options.as == optionsSourceObject[i].as)) { - var err = new Error("structure.association.error.alreadySameAlias"); - return callback(err, null); - } else if(attr.options.as == optionsSourceObject[i].as){ - let err = new Error(); - err.message = "database.field.error.alreadyExist"; - err.messageParams = [attr.options.showAs]; - return callback(err, null); } - } - var info = {}; - attr.options.through = attr.id_application + "_" + source_entity.id + "_" + entityTarget.id + "_" + attr.options.as.substring(2); - if (attr.options.through.length > 55) { - var err = new Error("error.valueTooLong"); - err.messageParams = [attr.options.through]; - return callback(err, null); - } + var info = {}; + attr.options.through = attr.id_application + "_" + source_entity.id + "_" + entityTarget.id + "_" + attr.options.as.substring(2); + if (attr.options.through.length > 55) { + var err = new Error("error.valueTooLong"); + err.messageParams = [attr.options.through]; + return callback(err, null); + } - // Check if an association already exists from target to source - var optionsFile = helpers.readFileSyncWithCatch(__dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.target.toLowerCase() + '.json'); - var optionsObject = JSON.parse(optionsFile); + // Check if an association already exists from target to source + var optionsFile = helpers.readFileSyncWithCatch(__dirname+'/../workspace/' + attr.id_application + '/models/options/' + attr.options.target.toLowerCase() + '.json'); + var optionsObject = JSON.parse(optionsFile); - for (var i = 0; i < optionsObject.length; i++) { - if (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation != "belongsTo") { - attr.options.through = attr.id_application + "_" + entityTarget.id + "_" + source_entity.id + "_" + attr.options.as.substring(2); - if (attr.options.through.length > 55) { - var err = new Error("error.valueTooLong"); - err.messageParams = [attr.options.through]; - return callback(err, null); - } - } else if (attr.options.source.toLowerCase() != attr.options.target.toLowerCase() - && (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation == "belongsTo")) { - - // Temporary solution ! TODO: Mispy should ask if we want to link the already existing 1,1 with this new 1,n - if ((attr.options.target.substring(2) == attr.options.as.substring(2)) - && (optionsObject[i].target.substring(2) == optionsObject[i].as.substring(2))) { - //&& (optionsObject[i].foreignKey == attr.options.foreignKey) - // If alias both side are the same that their own target then it trigger the 1,1 / 1,n generation - attr.options.foreignKey = optionsObject[i].foreignKey; - // We avoid the toSync to append because the already existing has one relation has already created the foreign key in BDD - toSync = false; - // If it's already define that target entity belongsTo source entity, then we create a simple hasMany instead of a belongsToMany - relation = "hasMany"; - attr.options.through = null; + for (var i = 0; i < optionsObject.length; i++) { + if (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation != "belongsTo") { + attr.options.through = attr.id_application + "_" + entityTarget.id + "_" + source_entity.id + "_" + attr.options.as.substring(2); + if (attr.options.through.length > 55) { + var err = new Error("error.valueTooLong"); + err.messageParams = [attr.options.through]; + return callback(err, null); + } + } else if (attr.options.source.toLowerCase() != attr.options.target.toLowerCase() + && (optionsObject[i].target.toLowerCase() == attr.options.source.toLowerCase() && optionsObject[i].relation == "belongsTo")) { + + // Temporary solution ! TODO: Mispy should ask if we want to link the already existing 1,1 with this new 1,n + if ((attr.options.target.substring(2) == attr.options.as.substring(2)) + && (optionsObject[i].target.substring(2) == optionsObject[i].as.substring(2))) { + //&& (optionsObject[i].foreignKey == attr.options.foreignKey) + // If alias both side are the same that their own target then it trigger the 1,1 / 1,n generation + attr.options.foreignKey = optionsObject[i].foreignKey; + // We avoid the toSync to append because the already existing has one relation has already created the foreign key in BDD + toSync = false; + // If it's already define that target entity belongsTo source entity, then we create a simple hasMany instead of a belongsToMany + relation = "hasMany"; + attr.options.through = null; + } } } - } - // If there is a circular has many we have to convert it to a belongsToMany assocation, so we stop the code here. - // If not we continue doing a simple related to multiple association. - var reversedAttr = { - options: { - showForeignKey: attr.options.showAs, - foreignKey: attr.options.foreignKey, - source: attr.options.source, - }, - id_data_entity: attr.id_data_entity, - id_application: attr.id_application - }; - - db_field.createNewForeignKey(reversedAttr, (err, created_foreignKey) => { - if (err){return callback(err, null);} - // Create the belongsToMany link between source and target - var associationOption = { - idApp: attr.id_application, - source: attr.options.source, - target: attr.options.target, - foreignKey: attr.options.foreignKey, - as: attr.options.as, - showAs: attr.options.showAs, - relation: relation, - through: attr.options.through, - toSync: toSync, - type: attr.options.isCheckbox ? "relatedToMultipleCheckbox" : "relatedToMultiple" + // If there is a circular has many we have to convert it to a belongsToMany assocation, so we stop the code here. + // If not we continue doing a simple related to multiple association. + var reversedAttr = { + options: { + showForeignKey: attr.options.showAs, + foreignKey: attr.options.foreignKey, + source: attr.options.source, + }, + id_data_entity: attr.id_data_entity, + id_application: attr.id_application }; - if (typeof attr.options.usingField !== "undefined") - associationOption.usingField = attr.options.usingField; - if (typeof attr.options.isCheckbox !== "undefined" && attr.options.isCheckbox) { - // If it's a checkbox presentation style, we need to load association directly in the route, not in ajax - associationOption.loadOnStart = true; - } - structure_data_entity.setupAssociation(associationOption, () => { - // Ajouter le field d'assocation dans create_fields/update_fields. Ajout d'un tab dans le show - structure_data_field.setupRelatedToMultipleField(attr, () => { - var info = {}; - info.message = "structure.association.relatedToMultiple.success"; - info.messageParams = [attr.options.showAs, attr.options.showTarget, attr.options.showSource, attr.options.showAs, attr.options.showAs]; - callback(null, info); + + db_field.createNewForeignKey(reversedAttr, (err, created_foreignKey) => { + if (err){return callback(err, null);} + // Create the belongsToMany link between source and target + var associationOption = { + idApp: attr.id_application, + source: attr.options.source, + target: attr.options.target, + foreignKey: attr.options.foreignKey, + as: attr.options.as, + showAs: attr.options.showAs, + relation: relation, + through: attr.options.through, + toSync: toSync, + type: attr.options.isCheckbox ? "relatedToMultipleCheckbox" : "relatedToMultiple" + }; + if (typeof attr.options.usingField !== "undefined") + associationOption.usingField = attr.options.usingField; + if (typeof attr.options.isCheckbox !== "undefined" && attr.options.isCheckbox) { + // If it's a checkbox presentation style, we need to load association directly in the route, not in ajax + associationOption.loadOnStart = true; + } + structure_data_entity.setupAssociation(associationOption, () => { + // Ajouter le field d'assocation dans create_fields/update_fields. Ajout d'un tab dans le show + structure_data_field.setupRelatedToMultipleField(attr, () => { + var info = {}; + info.message = "structure.association.relatedToMultiple.success"; + info.messageParams = [attr.options.showAs, attr.options.showTarget, attr.options.showSource, attr.options.showAs, attr.options.showAs]; + callback(null, info); + }); }); }); }); @@ -2479,7 +2572,7 @@ exports.createNewComponentAgenda = function (attr, callback) { exports.deleteAgenda = function (attr, callback) { - var exportsContext = this; + let exportsContext = this; /* If there is no defined name for the module */ if (typeof attr.options.value === "undefined") { @@ -2489,48 +2582,47 @@ exports.deleteAgenda = function (attr, callback) { } // Check if component with this name is in this module - db_component.getComponentByCodeNameInModule(attr.id_module, attr.options.value, attr.options.showValue, function (err, component) { + db_component.getComponentByCodeNameInModule(attr.id_module, attr.options.value, attr.options.showValue, (err, component) => { if (!component) { - var err = new Error("database.component.notFound.notFoundInModule"); + let err = new Error("database.component.notFound.notFoundInModule"); err.messageParams = [attr.options.showValue, attr.id_module]; return callback(err, null); - } else { + } - var showValueEvent = attr.options.showValue + " Event"; - var showValueCategory = attr.options.showValue + " Category"; + let showValueEvent = attr.options.showValue + " Event"; + let showValueCategory = attr.options.showValue + " Category"; - var instructions = [ - "delete entity " + showValueCategory, - "delete entity " + showValueEvent, - ]; + let instructions = [ + "delete entity " + showValueCategory, + "delete entity " + showValueEvent, + ]; - // Start doing necessary instruction for component creation - exportsContext.recursiveInstructionExecute(attr, instructions, 0, function (err) { + // Start doing necessary instruction for component creation + exportsContext.recursiveInstructionExecute(attr, instructions, 0, err => { + if (err) + return callback(err, null); + + // Create the component in newmips database + db_component.deleteComponentOnModule(attr.options.value, attr.id_module, (err, info) => { if (err) return callback(err, null); - // Create the component in newmips database - db_component.deleteComponentOnModule(attr.options.value, attr.id_module, function (err, info) { + db_module.getModuleById(attr.id_module, (err, module) => { if (err) return callback(err, null); - db_module.getModuleById(attr.id_module, function (err, module) { + attr.options.moduleName = module.codeName; + structure_component.deleteAgenda(attr, err => { if (err) return callback(err, null); - attr.options.moduleName = module.codeName; - structure_component.deleteAgenda(attr, function (err) { - if (err) - return callback(err, null); - var info = { - message: "database.component.delete.success" - }; - callback(null, info); + callback(null, { + message: "database.component.delete.success" }); }); }); }); - } + }); }); } diff --git a/services/gitlab_api.js b/services/gitlab_api.js index 3a4471a46..98ef47ec1 100644 --- a/services/gitlab_api.js +++ b/services/gitlab_api.js @@ -52,6 +52,29 @@ exports.createUser = async (infos) => { } } +exports.updateUser = async (user, obj) => { + let options = { + uri: gitlabURL + "/users/"+user.id, + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'Private-Token': token + }, + qs: obj, + json: true // Automatically stringifies the body to JSON + }; + + console.log("GITLAB CALL => updateUser"); + + try { + let user = await request(options); + return user.length == 0 ? false : user[0]; + } catch(err){ + console.error(err); + throw new Error("An error occured while getting gitlab user."); + } +} + exports.createProjectForUser = async (infos) => { let options = { uri: gitlabURL + "/projects/user/"+infos.user_id, @@ -96,6 +119,30 @@ exports.addMemberToProject = async (infos) => { } } +exports.getAllProjects = async () => { + let options = { + uri: gitlabURL + "/projects", + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Private-Token': token + }, + qs: { + search: globalConf.host // Reduce search on current generator repository + }, + json: true // Automatically stringifies the body to JSON + }; + + console.log("GITLAB CALL => getAllProjects"); + + try { + return await request(options); + } catch(err){ + console.error(err); + throw new Error("An error occured while getting gitlab project."); + } +} + exports.getProject = async (projectName) => { let options = { uri: gitlabURL + "/projects", @@ -104,6 +151,9 @@ exports.getProject = async (projectName) => { 'Content-Type': 'application/json', 'Private-Token': token }, + qs: { + search: globalConf.host // Reduce search on current generator repository + }, json: true // Automatically stringifies the body to JSON }; @@ -119,6 +169,74 @@ exports.getProject = async (projectName) => { } } +exports.getProjectForUser = async (userID) => { + let options = { + uri: gitlabURL + "/users/"+userID+"/projects", + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Private-Token': token + }, + json: true // Automatically stringifies the body to JSON + }; + + console.log("GITLAB CALL => getProjectsForUser"); + + try { + return await request(options); + } catch(err){ + console.error(err); + throw new Error("An error occured while getting gitlab project."); + } +} + +exports.addUserToProject = async (userID, projectID) => { + let options = { + uri: gitlabURL + "/projects/"+projectID+"/members", + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Private-Token': token + }, + qs: { + user_id: userID, + access_level: 30 + }, + json: true // Automatically stringifies the body to JSON + }; + + console.log("GITLAB CALL => addUserToProject"); + + try { + return await request(options); + } catch(err) { + console.warn("An error occured while adding user to gitlab project."); + console.error(err.message); + // throw new Error("An error occured while adding user to gitlab project."); + } +} + +exports.removeUserFromProject = async (userID, projectID) => { + let options = { + uri: gitlabURL + "/projects/"+projectID+"/members/"+userID, + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + 'Private-Token': token + }, + json: true // Automatically stringifies the body to JSON + }; + + console.log("GITLAB CALL => removeUserFromProject"); + + try { + return await request(options); + } catch(err){ + console.warn("An error occured while remove user from gitlab project.") + console.error(err.message); + } +} + exports.deleteProject = async (projectID) => { let options = { uri: gitlabURL + "/projects/"+projectID, diff --git a/structure/pieces/administration/routes/e_user.js b/structure/pieces/administration/routes/e_user.js index 91d3c4f0a..6b75e80ef 100644 --- a/structure/pieces/administration/routes/e_user.js +++ b/structure/pieces/administration/routes/e_user.js @@ -725,9 +725,10 @@ router.get('/settings', block_access.isLoggedIn, function(req, res) { router.post('/settings', block_access.isLoggedIn, function(req, res) { - let updateObject = { - f_email: req.body.f_email - }; + let updateObject = {}; + + if(req.body.f_email && req.body.f_email != '') + updateObject.f_email = req.body.f_email models.E_user.findById(req.session.passport.user.id).then(user => { let newPassword = new Promise((resolve, reject) => { diff --git a/structure/pieces/component/agenda/routes/route_agenda.js b/structure/pieces/component/agenda/routes/route_agenda.js index f8359dc70..fcd3fac1d 100644 --- a/structure/pieces/component/agenda/routes/route_agenda.js +++ b/structure/pieces/component/agenda/routes/route_agenda.js @@ -1,20 +1,12 @@ -var express = require('express'); -var router = express.Router(); -var block_access = require('../utils/block_access'); - -// Sequelize -var models = require('../models/'); - -var model_builder = require('../utils/model_builder'); -var moment = require("moment"); - -var attributes = require('../models/attributes/e_URL_ROUTE_event'); -var options = require('../models/options/e_URL_ROUTE_event'); -var model_builder = require('../utils/model_builder'); -var entity_helper = require('../utils/entity_helper'); - -// Winston logger -var logger = require('../utils/logger'); +const express = require('express'); +const router = express.Router(); +const block_access = require('../utils/block_access'); +const models = require('../models/'); +const model_builder = require('../utils/model_builder'); +const moment = require("moment"); +const attributes = require('../models/attributes/e_URL_ROUTE_event'); +const options = require('../models/options/e_URL_ROUTE_event'); +const entity_helper = require('../utils/entity_helper'); router.get('/', block_access.isLoggedIn, function(req, res) { var data = {}; @@ -145,16 +137,17 @@ router.post('/update_event', block_access.actionAccessMiddleware("URL_ROUTE_even }); }); -router.post('/update_event_drop', block_access.actionAccessMiddleware("URL_ROUTE_event", 'update'), function(req, res) { +router.post('/update_event_drop', block_access.actionAccessMiddleware("agenda_event", 'update'), function(req, res) { - var updateObj = { + let updateObj = { f_start_date: req.body.start, - f_end_date: req.body.end + f_end_date: req.body.end, + f_all_day: typeof req.body.allDay === 'boolean' ? req.body.allDay : false }; - models.CODE_NAME_EVENT_MODEL.findById(req.body.eventId).then(function(currentEvent){ + models.E_agenda_event.findById(req.body.eventId).then(function(currentEvent){ currentEvent.update(updateObj, {where: {id: req.body.eventId}}).then(function(updateEvent){ - var users = []; + let users = []; if(req.body.idUsers != null){ users = req.body.idUsers; } else if (req.body.idUser != null){ diff --git a/structure/structure_application.js b/structure/structure_application.js index 90605c4b1..f8d7ec7f2 100755 --- a/structure/structure_application.js +++ b/structure/structure_application.js @@ -101,20 +101,22 @@ exports.setupApplication = function(attr, callback) { "CREATE USER IF NOT EXISTS 'workspace_" + appID + "'@'127.0.0.1' IDENTIFIED BY 'workspace_" + appID + "';", "CREATE USER IF NOT EXISTS 'workspace_" + appID + "'@'%' IDENTIFIED BY 'workspace_" + appID + "';", "GRANT ALL PRIVILEGES ON workspace_" + appID + ".* TO 'workspace_" + appID + "'@'127.0.0.1';", - "GRANT ALL PRIVILEGES ON workspace_" + appID + ".* TO 'workspace_" + appID + "'@'%';" + "GRANT ALL PRIVILEGES ON workspace_" + appID + ".* TO 'workspace_" + appID + "'@'%';", + "GRANT ALL PRIVILEGES ON workspace_" + appID + ".* TO '" + dbConf.user + "'@'127.0.0.1';", + "GRANT ALL PRIVILEGES ON workspace_" + appID + ".* TO '" + dbConf.user + "'@'%';" ]; let conn = await mysql.createConnection({ - host: globalConf.env == "cloud"||"docker" ? process.env.DATABASE_IP : dbConf.host, - user: globalConf.env == "cloud"||"docker" ? "root" : dbConf.user, - password: globalConf.env == "cloud"||"docker" ? "P@ssw0rd+" : dbConf.password + host: globalConf.env == "cloud" || globalConf.env == "docker" ? process.env.DATABASE_IP : dbConf.host, + user: globalConf.env == "cloud" || globalConf.env == "docker" ? "root" : dbConf.user, + password: globalConf.env == "cloud" || globalConf.env == "docker" ? "P@ssw0rd+" : dbConf.password }); - for (var i = 0; i < db_requests.length; i++) { + for (var i = 0; i < db_requests.length; i++) await conn.query(db_requests[i]); - } conn.end(); + return; } workspace_db().then(_ => { @@ -625,9 +627,9 @@ exports.deleteApplication = function(appID, callback) { if(globalConf.separate_workspace_db){ (async () => { let conn = await mysql.createConnection({ - host: globalConf.env == "cloud"||"docker" ? process.env.DATABASE_IP : dbConf.host, - user: globalConf.env == "cloud"||"docker" ? "root" : dbConf.user, - password: globalConf.env == "cloud"||"docker" ? "P@ssw0rd+" : dbConf.password + host: globalConf.env == "cloud" || globalConf.env == "docker" ? process.env.DATABASE_IP : dbConf.host, + user: globalConf.env == "cloud" || globalConf.env == "docker" ? "root" : dbConf.user, + password: globalConf.env == "cloud" || globalConf.env == "docker" ? "P@ssw0rd+" : dbConf.password }); await conn.query("DROP DATABASE IF EXISTS workspace_"+appID+";"); conn.end(); diff --git a/structure/structure_component.js b/structure/structure_component.js index d3ccbbfed..235a1a37c 100755 --- a/structure/structure_component.js +++ b/structure/structure_component.js @@ -1,9 +1,9 @@ -var fs = require("fs-extra"); -var domHelper = require('../utils/jsDomHelper'); -var translateHelper = require("../utils/translate"); -var helpers = require("../utils/helpers"); -var printHelper = require("../utils/print_helper"); -var moment = require("moment"); +const fs = require("fs-extra"); +const domHelper = require('../utils/jsDomHelper'); +const translateHelper = require("../utils/translate"); +const helpers = require("../utils/helpers"); +const printHelper = require("../utils/print_helper"); +const moment = require("moment"); function setupComponentModel(idApplication, folderComponent, componentName, filename, callback) { // CREATE MODEL FILE @@ -699,36 +699,38 @@ exports.newAgenda = function (attr, callback) { }); } -exports.deleteAgenda = function (attr, callback) { +exports.deleteAgenda = (attr, callback) => { - var idApplication = attr.id_application; - var urlComponent = attr.options.urlValue.toLowerCase(); + let appID = attr.id_application; + let urlComponent = attr.options.urlValue.toLowerCase(); - var baseFolder = __dirname + '/../workspace/' + idApplication; - var layoutFileName = baseFolder + '/views/layout_' + attr.options.moduleName.toLowerCase() + '.dust'; + let baseFolder = __dirname + '/../workspace/' + appID; + let layoutFileName = baseFolder + '/views/layout_' + attr.options.moduleName.toLowerCase() + '.dust'; + + // Remove agenda controller + fs.unlinkSync(baseFolder + '/routes/' + attr.options.value + '.js'); // Delete views folder helpers.rmdirSyncRecursive(baseFolder + '/views/' + attr.options.value); - domHelper.read(layoutFileName).then(function ($) { - + domHelper.read(layoutFileName).then($ => { $("#" + urlComponent + "_menu_item").remove(); // Write back to file - domHelper.write(layoutFileName, $).then(function () { + domHelper.write(layoutFileName, $).then(_ => { // Clean empty and useless dust helper created by removing
  • - var layoutContent = fs.readFileSync(layoutFileName, 'utf8'); + let layoutContent = fs.readFileSync(layoutFileName, 'utf8'); // Remove empty dust helper layoutContent = layoutContent.replace(/{#entityAccess entity=".+"}\W*{\/entityAccess}/g, ""); - var writeStream = fs.createWriteStream(layoutFileName); + let writeStream = fs.createWriteStream(layoutFileName); writeStream.write(layoutContent); writeStream.end(); - writeStream.on('finish', function () { + writeStream.on('finish', _ => { callback(); }); }); - }).catch(function (err) { + }).catch(err => { callback(err, null); }); } diff --git a/structure/structure_data_entity.js b/structure/structure_data_entity.js index 820e0b3e7..1c3dea2df 100644 --- a/structure/structure_data_entity.js +++ b/structure/structure_data_entity.js @@ -358,9 +358,9 @@ exports.deleteDataEntity = function (id_application, name_module, name_data_enti fs.unlinkSync(baseFolder + '/models/attributes/' + name_data_entity + '.json'); // Remove relationships in options.json files - var optionFiles = fs.readdirSync(baseFolder + '/models/options/'); + var optionFiles = fs.readdirSync(baseFolder + '/models/options/').filter(x => x.indexOf('.json') != -1); for (var file in optionFiles) { - var options = require(baseFolder + '/models/options/' + optionFiles[file]); + var options = JSON.parse(fs.readFileSync(baseFolder + '/models/options/' + optionFiles[file])); var optionsCpy = []; for (var i = 0; i < options.length; i++) if (options[i].target != name_data_entity) diff --git a/structure/structure_data_field.js b/structure/structure_data_field.js index ef256406e..33b0c3d67 100755 --- a/structure/structure_data_field.js +++ b/structure/structure_data_field.js @@ -968,6 +968,8 @@ exports.setRequiredAttribute = function (attr, callback) { var length = ""; if (attr.sqlDataType == "varchar") length = "(" + attr.sqlDataTypeLength + ")"; + + // Set required if (set) { switch (attributesObj[attr.options.value].type) { case "STRING": @@ -1002,6 +1004,7 @@ exports.setRequiredAttribute = function (attr, callback) { toSync.queries.push("ALTER TABLE `" + tableName + "` ALTER `" + attr.options.value + "` SET DEFAULT '" + defaultValue + "';"); } } else { + // Set optional attributesObj[attr.options.value].defaultValue = null; // TODO postgres if (attr.sqlDataType && attr.dialect == "mysql") { diff --git a/structure/template/config/database.js b/structure/template/config/database.js index 3666a1e0f..7cf9bc80e 100755 --- a/structure/template/config/database.js +++ b/structure/template/config/database.js @@ -1,6 +1,6 @@ -var globalConf = require('./global'); +const globalConf = require('./global'); -var databaseConf = { +let databaseConf = { develop: { host: '127.0.0.1', port: '3306', //mysql: 3306 - postgres: 5432 diff --git a/structure/template/models/index.js b/structure/template/models/index.js index 26848dc2a..740c9adb9 100755 --- a/structure/template/models/index.js +++ b/structure/template/models/index.js @@ -7,7 +7,6 @@ var basename = path.basename(module.filename); var dbConfig = require('../config/database'); var globalConf = require('../config/global'); var moment = require('moment'); -var moment_timezone = require('moment-timezone'); var db = {}; const Op = Sequelize.Op; @@ -70,7 +69,6 @@ if (dbConfig.dialect == 'sqlite'){ }, charset: 'utf8', collate: 'utf8_general_ci', - timezone: moment_timezone.tz.guess(), operatorsAliases } } diff --git a/structure/template/package.json b/structure/template/package.json index 31f16ba04..570597bc6 100755 --- a/structure/template/package.json +++ b/structure/template/package.json @@ -32,11 +32,10 @@ "jszip": "2.6.1", "mime-types": "^2.1.17", "moment": "^2.22.1", - "moment-timezone": "^0.5.6", "morgan": "^1.9.0", "multer": "^1.2.0", "mysql": "^2.15.0", - "mysql2": "^1.5.3", + "mysql2": "^1.7.0", "nodemailer": "^4.6.5", "ovh": "^2.0.1", "passport": "^0.4.0", diff --git a/structure/template/public/js/Newmips/component/agenda.js b/structure/template/public/js/Newmips/component/agenda.js index aa1a35690..9d0240cef 100644 --- a/structure/template/public/js/Newmips/component/agenda.js +++ b/structure/template/public/js/Newmips/component/agenda.js @@ -134,6 +134,7 @@ $(document).ready(function() { eventId: event.eventId, start: startDate, end: endDate, + allDay: event.allDay, idUser: event.resourceId || null, idUsers: event.resourceIds || null }; diff --git a/structure/template/server.js b/structure/template/server.js index 9996655f7..70944db66 100755 --- a/structure/template/server.js +++ b/structure/template/server.js @@ -70,11 +70,11 @@ app.use(morgan('dev', { require('console-stamp')(console, { formatter: function() { - return moment().format('YYYY-MM-DD HH:mm:ss-SSS'); + return moment().format('MM-DD HH:mm:ss'); }, - label: true, - datePrefix: "[", - dateSuffix: "]-- " + label: false, + datePrefix: "", + dateSuffix: "" }); // Overide console.warn & console.error to file+line diff --git a/structure/template/utils/model_builder.js b/structure/template/utils/model_builder.js index 956948112..86003b768 100755 --- a/structure/template/utils/model_builder.js +++ b/structure/template/utils/model_builder.js @@ -107,8 +107,8 @@ exports.formatSearch = function (column, searchValue, type) { } break; case 'currency': - formatedSearch = models.Sequelize.where(models.Sequelize.col(column), { - like: `${searchValue}%` + formatedSearch = require('../models').Sequelize.where(require('../models').Sequelize.col(column), { + $like: searchValue + '%' }); break; default: diff --git a/structure/template/views/main_layout.dust b/structure/template/views/main_layout.dust index 8c499d129..dfa854539 100755 --- a/structure/template/views/main_layout.dust +++ b/structure/template/views/main_layout.dust @@ -148,8 +148,8 @@
  • {! Menu Body !}
  • - - + +
  • {! Menu Footer !}