Settings = new Mongo.Collection('settings'); Settings.attachSchema( new SimpleSchema({ disableRegistration: { type: Boolean, }, 'mailServer.username': { type: String, optional: true, }, 'mailServer.password': { type: String, optional: true, }, 'mailServer.host': { type: String, optional: true, }, 'mailServer.port': { type: String, optional: true, }, 'mailServer.enableTLS': { type: Boolean, optional: true, }, 'mailServer.from': { type: String, optional: true, }, productName: { type: String, optional: true, }, displayAuthenticationMethod: { type: Boolean, optional: true, }, defaultAuthenticationMethod: { type: String, optional: false, }, hideLogo: { type: Boolean, optional: true, }, createdAt: { type: Date, denyUpdate: true, // eslint-disable-next-line consistent-return autoValue() { if (this.isInsert) { return new Date(); } else if (this.isUpsert) { return { $setOnInsert: new Date() }; } else { this.unset(); } }, }, modifiedAt: { type: Date, // eslint-disable-next-line consistent-return autoValue() { if (this.isInsert || this.isUpsert || this.isUpdate) { return new Date(); } else { this.unset(); } }, }, }), ); Settings.helpers({ mailUrl() { if (!this.mailServer.host) { return null; } const protocol = this.mailServer.enableTLS ? 'smtps://' : 'smtp://'; if (!this.mailServer.username && !this.mailServer.password) { return `${protocol}${this.mailServer.host}:${this.mailServer.port}/`; } return `${protocol}${this.mailServer.username}:${encodeURIComponent( this.mailServer.password, )}@${this.mailServer.host}:${this.mailServer.port}/`; }, }); Settings.allow({ update(userId) { const user = Users.findOne(userId); return user && user.isAdmin; }, }); if (Meteor.isServer) { Meteor.startup(() => { Settings._collection._ensureIndex({ modifiedAt: -1 }); const setting = Settings.findOne({}); if (!setting) { const now = new Date(); const domain = process.env.ROOT_URL.match( /\/\/(?:www\.)?(.*)?(?:\/)?/, )[1]; const from = `Boards Support `; const defaultSetting = { disableRegistration: false, mailServer: { username: '', password: '', host: '', port: '', enableTLS: false, from, }, createdAt: now, modifiedAt: now, displayAuthenticationMethod: true, defaultAuthenticationMethod: 'password', }; Settings.insert(defaultSetting); } const newSetting = Settings.findOne(); if (!process.env.MAIL_URL && newSetting.mailUrl()) process.env.MAIL_URL = newSetting.mailUrl(); Accounts.emailTemplates.from = process.env.MAIL_FROM ? process.env.MAIL_FROM : newSetting.mailServer.from; }); Settings.after.update((userId, doc, fieldNames) => { // assign new values to mail-from & MAIL_URL in environment if (_.contains(fieldNames, 'mailServer') && doc.mailServer.host) { const protocol = doc.mailServer.enableTLS ? 'smtps://' : 'smtp://'; if (!doc.mailServer.username && !doc.mailServer.password) { process.env.MAIL_URL = `${protocol}${doc.mailServer.host}:${doc.mailServer.port}/`; } else { process.env.MAIL_URL = `${protocol}${ doc.mailServer.username }:${encodeURIComponent(doc.mailServer.password)}@${ doc.mailServer.host }:${doc.mailServer.port}/`; } Accounts.emailTemplates.from = doc.mailServer.from; } }); function getRandomNum(min, max) { const range = max - min; const rand = Math.random(); return min + Math.round(rand * range); } function getEnvVar(name) { const value = process.env[name]; if (value) { return value; } throw new Meteor.Error([ 'var-not-exist', `The environment variable ${name} does not exist`, ]); } function sendInvitationEmail(_id) { const icode = InvitationCodes.findOne(_id); const author = Users.findOne(Meteor.userId()); try { const params = { email: icode.email, inviter: Users.findOne(icode.authorId).username, user: icode.email.split('@')[0], icode: icode.code, url: FlowRouter.url('sign-up'), }; const lang = author.getLanguage(); Email.send({ to: icode.email, from: Accounts.emailTemplates.from, subject: TAPi18n.__('email-invite-register-subject', params, lang), text: TAPi18n.__('email-invite-register-text', params, lang), }); } catch (e) { InvitationCodes.remove(_id); throw new Meteor.Error('email-fail', e.message); } } function isLdapEnabled() { return process.env.LDAP_ENABLE === 'true'; } function isOauth2Enabled() { return process.env.OAUTH2_ENABLED === 'true'; } function isCasEnabled() { return process.env.CAS_ENABLED === 'true'; } function isApiEnabled() { return process.env.WITH_API === 'true'; } Meteor.methods({ sendInvitation(emails, boards) { check(emails, [String]); check(boards, [String]); const user = Users.findOne(Meteor.userId()); if (!user.isAdmin) { throw new Meteor.Error('not-allowed'); } emails.forEach(email => { if (email && SimpleSchema.RegEx.Email.test(email)) { // Checks if the email is already link to an account. const userExist = Users.findOne({ email }); if (userExist) { throw new Meteor.Error( 'user-exist', `The user with the email ${email} has already an account.`, ); } // Checks if the email is already link to an invitation. const invitation = InvitationCodes.findOne({ email }); if (invitation) { InvitationCodes.update(invitation, { $set: { boardsToBeInvited: boards }, }); sendInvitationEmail(invitation._id); } else { const code = getRandomNum(100000, 999999); InvitationCodes.insert( { code, email, boardsToBeInvited: boards, createdAt: new Date(), authorId: Meteor.userId(), }, function(err, _id) { if (!err && _id) { sendInvitationEmail(_id); } else { throw new Meteor.Error( 'invitation-generated-fail', err.message, ); } }, ); } } }); }, sendSMTPTestEmail() { if (!Meteor.userId()) { throw new Meteor.Error('invalid-user'); } const user = Meteor.user(); if (!user.emails || !user.emails[0] || !user.emails[0].address) { throw new Meteor.Error('email-invalid'); } this.unblock(); const lang = user.getLanguage(); try { Email.send({ to: user.emails[0].address, from: Accounts.emailTemplates.from, subject: TAPi18n.__('email-smtp-test-subject', { lng: lang }), text: TAPi18n.__('email-smtp-test-text', { lng: lang }), }); } catch ({ message }) { throw new Meteor.Error( 'email-fail', `${TAPi18n.__('email-fail-text', { lng: lang })}: ${message}`, message, ); } return { message: 'email-sent', email: user.emails[0].address, }; }, getCustomUI() { const setting = Settings.findOne({}); if (!setting.productName) { return { productName: '', }; } else { return { productName: `${setting.productName}`, }; } }, getMatomoConf() { return { address: getEnvVar('MATOMO_ADDRESS'), siteId: getEnvVar('MATOMO_SITE_ID'), doNotTrack: process.env.MATOMO_DO_NOT_TRACK || false, withUserName: process.env.MATOMO_WITH_USERNAME || false, }; }, _isLdapEnabled() { return isLdapEnabled(); }, _isOauth2Enabled() { return isOauth2Enabled(); }, _isCasEnabled() { return isCasEnabled(); }, _isApiEnabled() { return isApiEnabled(); }, // Gets all connection methods to use it in the Template getAuthenticationsEnabled() { return { ldap: isLdapEnabled(), oauth2: isOauth2Enabled(), cas: isCasEnabled(), }; }, getDefaultAuthenticationMethod() { return process.env.DEFAULT_AUTHENTICATION_METHOD; }, isPasswordLoginDisabled() { return process.env.PASSWORD_LOGIN_ENABLED === 'false'; }, }); } export default Settings;