diff --git a/src/betagouv.ts b/src/betagouv.ts index a5e136ba5..24ed08527 100644 --- a/src/betagouv.ts +++ b/src/betagouv.ts @@ -21,13 +21,13 @@ export interface OvhRedirection { } export enum EMAIL_PLAN_TYPE { - EMAIL_PLAN_PRO='EMAIL_PLAN_PRO', - EMAIL_PLAN_EXCHANGE='EMAIL_PLAN_EXCHANGE', - EMAIL_PLAN_BASIC='EMAIL_PLAN_BASIC' + EMAIL_PLAN_PRO = 'EMAIL_PLAN_PRO', + EMAIL_PLAN_EXCHANGE = 'EMAIL_PLAN_EXCHANGE', + EMAIL_PLAN_BASIC = 'EMAIL_PLAN_BASIC', } export interface OvhMailingList { - id: string + id: string; } export interface OvhResponder { @@ -46,6 +46,14 @@ export interface OvhExchangeCreationData { company?: string; } +export interface OvhProCreationData { + firstName?: string; + lastName?: string; + displayName?: string; + initial?: string; + company?: string; +} + const betaGouv = { sendInfoToChat: async ( text: string, @@ -53,13 +61,16 @@ const betaGouv = { username: string = null, hookURL: string = null ) => { - const params: any = { text, channel: channel === 'general' ? 'town-square' : channel }; + const params: any = { + text, + channel: channel === 'general' ? 'town-square' : channel, + }; if (!hookURL) { hookURL = config.CHAT_WEBHOOK_URL_SECRETARIAT; if (channel === 'general') { hookURL = config.CHAT_WEBHOOK_URL_GENERAL; - } else if(channel === 'dinum') { - hookURL = config.CHAT_WEBHOOK_URL_DINUM + } else if (channel === 'dinum') { + hookURL = config.CHAT_WEBHOOK_URL_DINUM; } else if (channel && channel !== 'secretariat') { hookURL = config.CHAT_WEBHOOK_URL_GENERAL; } @@ -100,7 +111,7 @@ const betaGouv = { ) .catch((err) => { throw new Error(`Error to get users infos in ${config.domain}: ${err}`); - }) + }); }, incubators: async (): Promise => { return axios @@ -108,7 +119,7 @@ const betaGouv = { .then((response) => response.data) .catch((err) => { throw new Error(`Error to get incubators infos : ${err}`); - }) + }); }, sponsors: async (): Promise => { return axios @@ -116,21 +127,23 @@ const betaGouv = { .then((response) => response.data) .catch((err) => { throw new Error(`Error to get incubators infos : ${err}`); - }) - }, - getJobs: async(): Promise => { - return await axios.get(config.JOBS_API) - .then(res => res.data) - .catch((err) => { - throw new Error(`Error to get jobs infos : ${err}`); - }) - }, - getJobsWTTJ: async(): Promise => { - return await axios.get(config.JOBS_WTTJ_API) - .then(res => res.data.jobs) - .catch((err) => { - throw new Error(`Error to get jobs infos : ${err}`); - }) + }); + }, + getJobs: async (): Promise => { + return await axios + .get(config.JOBS_API) + .then((res) => res.data) + .catch((err) => { + throw new Error(`Error to get jobs infos : ${err}`); + }); + }, + getJobsWTTJ: async (): Promise => { + return await axios + .get(config.JOBS_WTTJ_API) + .then((res) => res.data.jobs) + .catch((err) => { + throw new Error(`Error to get jobs infos : ${err}`); + }); }, userInfosById: async (id: string): Promise => { const users = await betaGouv.usersInfos(); @@ -139,14 +152,18 @@ const betaGouv = { startupInfos: async (): Promise => { return axios .get(config.startupsDetailsAPI) - .then((response) => Object.keys(response.data).map(key => response.data[key])) + .then((response) => + Object.keys(response.data).map((key) => response.data[key]) + ) .catch((err) => { - throw new Error(`Error to get startups infos in ${config.domain}: ${err}`); - }) + throw new Error( + `Error to get startups infos in ${config.domain}: ${err}` + ); + }); }, startupInfosById: async (id: string): Promise => { const startups = await betaGouv.startupInfos(); - return startups.find(startup => startup.id === id); + return startups.find((startup) => startup.id === id); }, startupsInfos: async () => axios @@ -160,121 +177,145 @@ const betaGouv = { }; const betaOVH = { - emailInfos: async (id: string) : Promise<{ - email: string, - emailPlan: EMAIL_PLAN_TYPE, - isPro?: boolean, - isExchange?: boolean + emailInfos: async ( + id: string + ): Promise<{ + email: string; + emailPlan: EMAIL_PLAN_TYPE; + isPro?: boolean; + isExchange?: boolean; }> => { const errorHandler = (err) => { if (err.error === 404) return null; throw err; - } - const promises = [] + }; + const promises = []; const url = `/email/domain/${config.domain}/account/${id}`; - promises.push(ovh.requestPromised('GET', url, {}).then(data => ({ - ...data, - emailPlan: EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC, - })).catch(errorHandler)) + promises.push( + ovh + .requestPromised('GET', url, {}) + .then((data) => ({ + ...data, + emailPlan: EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC, + })) + .catch(errorHandler) + ); if (config.OVH_EMAIL_PRO_NAME) { const urlPro = `/email/pro/${config.OVH_EMAIL_PRO_NAME}/account/${id}@${config.domain}`; promises.push( - ovh.requestPromised('GET', urlPro, {}).then(data => ({ - ...data, - emailPlan: EMAIL_PLAN_TYPE.EMAIL_PLAN_PRO, - isPro: true, - email: data.primaryEmailAddress })).catch(errorHandler) - ) + ovh + .requestPromised('GET', urlPro, {}) + .then((data) => ({ + ...data, + emailPlan: EMAIL_PLAN_TYPE.EMAIL_PLAN_PRO, + isPro: true, + email: data.primaryEmailAddress, + })) + .catch(errorHandler) + ); } if (config.OVH_EMAIL_EXCHANGE_NAME) { - const urlExchange = `/email/exchange/${config.OVH_EMAIL_EXCHANGE_NAME}/service/${config.OVH_EMAIL_EXCHANGE_NAME}/account/${id}@${config.domain}` + const urlExchange = `/email/exchange/${config.OVH_EMAIL_EXCHANGE_NAME}/service/${config.OVH_EMAIL_EXCHANGE_NAME}/account/${id}@${config.domain}`; promises.push( - ovh.requestPromised('GET', urlExchange, {}).then(data => ({ - ...data, - emailPlan: EMAIL_PLAN_TYPE.EMAIL_PLAN_EXCHANGE, - isExchange: true, - email: data.primaryEmailAddress })).catch(errorHandler) - ) + ovh + .requestPromised('GET', urlExchange, {}) + .then((data) => ({ + ...data, + emailPlan: EMAIL_PLAN_TYPE.EMAIL_PLAN_EXCHANGE, + isExchange: true, + email: data.primaryEmailAddress, + })) + .catch(errorHandler) + ); } try { return await Promise.all(promises).then((data) => { - const emailInfos = data.filter(d => d)[0] - return emailInfos ? emailInfos : null + const emailInfos = data.filter((d) => d)[0]; + return emailInfos ? emailInfos : null; }); } catch (err) { if (err.error === 404) return null; throw new Error(`OVH Error GET on ${url} : ${JSON.stringify(err)}`); } }, - getAllEmailInfos: async () : Promise => { + getAllEmailInfos: async (): Promise => { // https://eu.api.ovh.com/console/#/email/domain/%7Bdomain%7D/account#GET // result is an array of the users ids : ['firstname1.lastname1', 'firstname2.lastname2', ...] - const promises = [] + const promises = []; const url = `/email/domain/${config.domain}/account/`; - promises.push(ovh.requestPromised('GET', url, {})) + promises.push(ovh.requestPromised('GET', url, {})); if (config.OVH_EMAIL_PRO_NAME) { const urlPro = `/email/pro/${config.OVH_EMAIL_PRO_NAME}/account`; promises.push( - ovh.requestPromised('GET', urlPro, {}).then(data => data.map(d => d.split('@')[0])).catch(e => []) - ) + ovh + .requestPromised('GET', urlPro, {}) + .then((data) => data.map((d) => d.split('@')[0])) + .catch((e) => []) + ); } if (config.OVH_EMAIL_EXCHANGE_NAME) { - const urlExchange = `/email/exchange/${config.OVH_EMAIL_EXCHANGE_NAME}/service/${config.OVH_EMAIL_EXCHANGE_NAME}/account` + const urlExchange = `/email/exchange/${config.OVH_EMAIL_EXCHANGE_NAME}/service/${config.OVH_EMAIL_EXCHANGE_NAME}/account`; promises.push( - ovh.requestPromised('GET', urlExchange, { primaryEmailAddress: `%@${config.domain}` }) - .then(data => data.map(d => d.split('@')[0])) - .catch(e => []) - ) + ovh + .requestPromised('GET', urlExchange, { + primaryEmailAddress: `%@${config.domain}`, + }) + .then((data) => data.map((d) => d.split('@')[0])) + .catch((e) => []) + ); } try { return await Promise.all(promises).then((data) => { - return data.flat(1) + return data.flat(1); }); } catch (err) { - console.error(`OVH Error GET on ${url} : ${JSON.stringify(err)}`) + console.error(`OVH Error GET on ${url} : ${JSON.stringify(err)}`); throw new Error(`OVH Error GET on ${url} : ${JSON.stringify(err)}`); } }, - migrateEmailAccount: async({ + migrateEmailAccount: async ({ userId, destinationServiceName, destinationEmailAddress, - password + password, }: { - userId: string, - destinationServiceName: string, - destinationEmailAddress: string, //configure.me adress - password: string - }) : Promise => { - const url = `/email/domain/${config.domain}/account/${userId}/migrate/${destinationServiceName}/destinationEmailAddress/${destinationEmailAddress}/migrate` + userId: string; + destinationServiceName: string; + destinationEmailAddress: string; //configure.me adress + password: string; + }): Promise => { + const url = `/email/domain/${config.domain}/account/${userId}/migrate/${destinationServiceName}/destinationEmailAddress/${destinationEmailAddress}/migrate`; try { return ovh.requestPromised('POST', url, { - password - }) - } catch(err) { - console.error(`OVH Error POST on ${url} : ${JSON.stringify(err)}`) + password, + }); + } catch (err) { + console.error(`OVH Error POST on ${url} : ${JSON.stringify(err)}`); throw new Error(`OVH Error POST on ${url} : ${JSON.stringify(err)}`); } }, - getAvailableProEmailInfos: async () : Promise => { + getAvailableProEmailInfos: async (): Promise => { if (!config.OVH_EMAIL_PRO_NAME) { - return [] + return []; } const urlPro = `/email/pro/${config.OVH_EMAIL_PRO_NAME}/account`; /* TODO - * use /email/domain/{domain}/account/{accountName}/migrate/{destinationServiceName}/destinationEmailAddress instead - * get available email instead of all emails - */ + * use /email/domain/{domain}/account/{accountName}/migrate/{destinationServiceName}/destinationEmailAddress instead + * get available email instead of all emails + */ try { - console.log(`GET OVH pro emails infos : ${urlPro}`) - return ovh.requestPromised('GET', urlPro, {}).then( - data => data.filter(email => email.includes('@configureme.me'))) - } catch(err) { - console.error(`OVH Error GET on ${urlPro} : ${JSON.stringify(err)}`) + console.log(`GET OVH pro emails infos : ${urlPro}`); + return ovh + .requestPromised('GET', urlPro, {}) + .then((data) => + data.filter((email) => email.includes('@configureme.me')) + ); + } catch (err) { + console.error(`OVH Error GET on ${urlPro} : ${JSON.stringify(err)}`); throw new Error(`OVH Error GET on ${urlPro} : ${JSON.stringify(err)}`); } }, - getAllMailingList: async() => { + getAllMailingList: async () => { const url = `/email/domain/${config.domain}/mailingList/`; try { return await ovh.requestPromised('GET', url, {}); @@ -283,8 +324,8 @@ const betaOVH = { throw new Error(`OVH Error GET on ${url} : ${JSON.stringify(err)}`); } }, - createMailingList: async(mailingListName: string) => { - const url = `/email/domain/${config.domain}/mailingList` + createMailingList: async (mailingListName: string) => { + const url = `/email/domain/${config.domain}/mailingList`; try { return await ovh.requestPromised('POST', url, { language: 'fr', @@ -292,16 +333,21 @@ const betaOVH = { options: { moderatorMessage: false, subscribeByModerator: false, - usersPostOnly: false + usersPostOnly: false, }, ownerEmail: 'espace-membre@beta.gouv.fr', }); } catch (err) { if (err.error === 404) return null; - throw new Error(`OVH Error createMailingList on ${url} : ${JSON.stringify(err)}`); + throw new Error( + `OVH Error createMailingList on ${url} : ${JSON.stringify(err)}` + ); } }, - unsubscribeFromMailingList: async(mailingListName: string, email: string) => { + unsubscribeFromMailingList: async ( + mailingListName: string, + email: string + ) => { const url = `/email/domain/${config.domain}/mailingList/${mailingListName}/subscriber/${email}`; try { return await ovh.requestPromised('DELETE', url); @@ -310,11 +356,14 @@ const betaOVH = { throw new Error(`OVH Error DELETE on ${url} : ${JSON.stringify(err)}`); } }, - subscribeToMailingList: async (mailingListName: string, email: string): Promise => { + subscribeToMailingList: async ( + mailingListName: string, + email: string + ): Promise => { const url = `/email/domain/${config.domain}/mailingList/${mailingListName}/subscriber`; try { return await ovh.requestPromised('POST', url, { - email + email, }); } catch (err) { throw new Error(`OVH Error subscribe on ${url} : ${JSON.stringify(err)}`); @@ -323,9 +372,7 @@ const betaOVH = { // get active users with email registered on ovh getActiveUsers: async () => { const users = await betaGouv.usersInfos(); - const activeUsers = users.filter( - (user) => !checkUserIsExpired(user) - ); + const activeUsers = users.filter((user) => !checkUserIsExpired(user)); return activeUsers; }, getActiveRegisteredOVHUsers: async () => { @@ -336,7 +383,7 @@ const betaOVH = { ); return activeUsers; }, - getResponder: async (id):Promise => { + getResponder: async (id): Promise => { const url = `/email/domain/${config.domain}/responder/${id}`; try { @@ -349,13 +396,13 @@ const betaOVH = { setResponder: async (id, { content, from, to }) => { const url = `/email/domain/${config.domain}/responder`; try { - const params : OvhResponder = { + const params: OvhResponder = { account: id, content, from, to, - copy: true - } + copy: true, + }; return await ovh.requestPromised('POST', url, params); } catch (err) { throw new Error(`OVH Error POST on ${url} : ${JSON.stringify(err)}`); @@ -364,7 +411,7 @@ const betaOVH = { updateResponder: async (id, { content, from, to }) => { const url = `/email/domain/${config.domain}/responder/${id}`; try { - return await ovh.requestPromised('PUT', url, { + return await ovh.requestPromised('PUT', url, { content, from, to, @@ -373,7 +420,7 @@ const betaOVH = { throw new Error(`OVH Error PUT on ${url} : ${JSON.stringify(err)}`); } }, - deleteResponder: async(id) => { + deleteResponder: async (id) => { const url = `/email/domain/${config.domain}/responder/${id}`; try { return await ovh.requestPromised('DELETE', url); @@ -390,7 +437,9 @@ const betaOVH = { password, }); } catch (err) { - throw new Error(`OVH Error POST on ${url}, account ${id}: ${JSON.stringify(err)}`); + throw new Error( + `OVH Error POST on ${url}, account ${id}: ${JSON.stringify(err)}` + ); } }, deleteEmail: async (id) => { @@ -474,7 +523,9 @@ const betaOVH = { throw new Error(`OVH Error on ${url} : ${JSON.stringify(err)}`); } }, - getMailingListSubscribers: async (mailingListName: string): Promise => { + getMailingListSubscribers: async ( + mailingListName: string + ): Promise => { const url = `/email/domain/${config.domain}/mailingList/${mailingListName}/subscriber`; try { @@ -496,9 +547,9 @@ const betaOVH = { changePassword: async (id, password, plan) => { let url = `/email/domain/${config.domain}/account/${id}/changePassword`; if (plan === EMAIL_PLAN_TYPE.EMAIL_PLAN_PRO) { - url = `/email/pro/${config.OVH_EMAIL_PRO_NAME}/account/${id}@${config.domain}/changePassword` + url = `/email/pro/${config.OVH_EMAIL_PRO_NAME}/account/${id}@${config.domain}/changePassword`; } else if (plan === EMAIL_PLAN_TYPE.EMAIL_PLAN_EXCHANGE) { - url = `/email/exchange/${config.OVH_EMAIL_EXCHANGE_NAME}/service/${config.OVH_EMAIL_EXCHANGE_NAME}/account/${id}@${config.domain}/changePassword` + url = `/email/exchange/${config.OVH_EMAIL_EXCHANGE_NAME}/service/${config.OVH_EMAIL_EXCHANGE_NAME}/account/${id}@${config.domain}/changePassword`; } try { await ovh.requestPromised('POST', url, { password }); @@ -506,19 +557,56 @@ const betaOVH = { throw new Error(`OVH Error on ${url} : ${JSON.stringify(err)}`); } }, + createEmailPro: async (id: string, creationData: OvhProCreationData) => { + const primaryEmailAddress = `${id}@${config.domain}`; + const getAccountsUrl = `/email/pro/${config.OVH_EMAIL_PRO_NAME}/service/${config.OVH_EMAIL_PRO_NAME}/account`; + let availableAccounts; + try { + availableAccounts = await ovh.requestPromised('GET', getAccountsUrl, { + primaryEmailAddress: '%@configureme.me', + }); + } catch (err) { + throw new Error( + `OVH Error on ${getAccountsUrl} : ${JSON.stringify(err)}` + ); + } + if (availableAccounts.length === 0) { + throw new Error('No Ovh Pro account available'); + } + + const accountToBeAssigned = _.sample(availableAccounts); + + console.log( + `Assigning Ovh Pro account ${accountToBeAssigned} to ${primaryEmailAddress}` + ); + + const assignAccountUrl = `/email/pro/${config.OVH_EMAIL_PRO_NAME}/service/${config.OVH_EMAIL_PRO_NAME}/account/${accountToBeAssigned}`; - createEmailForExchange: async (id: string, creationData: OvhExchangeCreationData) => { + try { + const result = await ovh.requestPromised('PUT', assignAccountUrl, { + ...creationData, + login: id, + domain: config.domain, + }); + console.log(`Account ${primaryEmailAddress} assigned`); + return result; + } catch (err) { + throw new Error( + `OVH Error on ${assignAccountUrl} : ${JSON.stringify(err)}` + ); + } + }, + createEmailForExchange: async ( + id: string, + creationData: OvhExchangeCreationData + ) => { const primaryEmailAddress = `${id}@${config.domain}`; const getAccountsUrl = `/email/exchange/${config.OVH_EMAIL_EXCHANGE_NAME}/service/${config.OVH_EMAIL_EXCHANGE_NAME}/account`; let availableAccounts; try { - availableAccounts = await ovh.requestPromised( - 'GET', - getAccountsUrl, - { - primaryEmailAddress: '%@configureme.me', - } - ); + availableAccounts = await ovh.requestPromised('GET', getAccountsUrl, { + primaryEmailAddress: '%@configureme.me', + }); } catch (err) { throw new Error( `OVH Error on ${getAccountsUrl} : ${JSON.stringify(err)}` @@ -530,16 +618,18 @@ const betaOVH = { const accountToBeAssigned = _.sample(availableAccounts); - console.log(`Assigning Exchange account ${accountToBeAssigned} to ${primaryEmailAddress}`); + console.log( + `Assigning Exchange account ${accountToBeAssigned} to ${primaryEmailAddress}` + ); const assignAccountUrl = `/email/exchange/${config.OVH_EMAIL_EXCHANGE_NAME}/service/${config.OVH_EMAIL_EXCHANGE_NAME}/account/${accountToBeAssigned}`; try { - const result = await ovh.requestPromised( - 'PUT', - assignAccountUrl, - { ...creationData, login: id, domain: config.domain } - ); + const result = await ovh.requestPromised('PUT', assignAccountUrl, { + ...creationData, + login: id, + domain: config.domain, + }); console.log(`Account ${primaryEmailAddress} assigned`); return result; } catch (err) { @@ -557,9 +647,7 @@ const betaOVH = { ); return result; } catch (err) { - throw new Error( - `OVH Error: ${JSON.stringify(err)}` - ); + throw new Error(`OVH Error: ${JSON.stringify(err)}`); } }, }; diff --git a/src/config/index.ts b/src/config/index.ts index 5b309a7c9..f3176abbd 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,3 +1,4 @@ +import { EMAIL_PLAN_TYPE } from '@/betagouv'; import { MemberType } from '@/models/dbUser'; import { config } from 'dotenv'; @@ -8,26 +9,28 @@ const isSecure = (process.env.SECURE || 'true') === 'true'; const userStatusOptions = [ { name: 'Indépendant', key: 'independent' }, { - name: - 'Agent Public (fonctionnaire ou sous contrat stage, alternance, CDD ou CDI avec une structure publique)', + name: 'Agent Public (fonctionnaire ou sous contrat stage, alternance, CDD ou CDI avec une structure publique)', key: 'admin', }, { name: 'Société de service', key: 'service' }, ]; const memberTypeOptions = [ - { name: `Membre d'une startup ou d'un incubateur`, key: MemberType.BETA}, - { name: 'Attributaire', key: MemberType.ATTRIBUTAIRE}, - { name: `Membre d'un autre service DINUM (etalab, ...)`, key: MemberType.DINUM}, - { name: `Autre`, key: MemberType.OTHER} -] + { name: `Membre d'une startup ou d'un incubateur`, key: MemberType.BETA }, + { name: 'Attributaire', key: MemberType.ATTRIBUTAIRE }, + { + name: `Membre d'un autre service DINUM (etalab, ...)`, + key: MemberType.DINUM, + }, + { name: `Autre`, key: MemberType.OTHER }, +]; const userBadgeOptions = [{ name: 'Ségur (Paris)', key: 'segur' }]; const CRON_TASK_ENV_VAR = { AIRTABLE_API_KEY: process.env.AIRTABLE_API_KEY, - AIRTABLE_FORMATION_BASE_ID: process.env.AIRTABLE_FORMATION_BASE_ID -} + AIRTABLE_FORMATION_BASE_ID: process.env.AIRTABLE_FORMATION_BASE_ID, +}; export default { ...CRON_TASK_ENV_VAR, @@ -45,8 +48,11 @@ export default { CHATWOOT_BADGE_ID: process.env.CHATWOOT_BADGE_ID, domain: process.env.SECRETARIAT_DOMAIN || 'beta.gouv.fr', DS_TOKEN: process.env.DS_TOKEN, - DS_DEMARCHE_NUMBER: process.env.DS_DEMARCHE_NUMBER ? parseInt(process.env.DS_DEMARCHE_NUMBER) : null, + DS_DEMARCHE_NUMBER: process.env.DS_DEMARCHE_NUMBER + ? parseInt(process.env.DS_DEMARCHE_NUMBER) + : null, DS_DEMARCHE_ID: process.env.DS_DEMARCHE_ID, + EMAIL_DEFAULT_PLAN: EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC, newsletterTemplateId: process.env.NEWSLETTER_TEMPLATE_ID, newsletterSentDay: process.env.NEWSLETTER_SENT_DAY || 'THURSDAY', padURL: process.env.PAD_URL || 'https://pad.incubateur.net', @@ -64,20 +70,25 @@ export default { newsletterHashSecret: process.env.NEWSLETTER_HASH_SECRET, newsletterSendTime: process.env.NEWSLETTER_SEND_TIME, NEWSLETTER_BOT_ICON_URL: process.env.NEWSLETTER_BOT_ICON_URL, - mattermostURL: process.env.MATTERMOST_URL || 'https://mattermost.incubateur.net', + mattermostURL: + process.env.MATTERMOST_URL || 'https://mattermost.incubateur.net', senderEmail: process.env.MAIL_SENDER || 'espace-membre@incubateur.net', CHAT_WEBHOOK_URL_SECRETARIAT: process.env.CHAT_WEBHOOK_URL_SECRETARIAT, CHAT_WEBHOOK_URL_GENERAL: process.env.CHAT_WEBHOOK_URL_GENERAL, CHAT_WEBHOOK_URL_DINUM: process.env.CHAT_WEBHOOK_URL_DINUM, CHAT_WEBHOOK_URL_GIP: process.env.CHAT_WEBHOOK_URL_GIP, - SPONSOR_API: process.env.SPONSOR_API || 'https://beta.gouv.fr/api/v2.5/sponsors.json', + SPONSOR_API: + process.env.SPONSOR_API || 'https://beta.gouv.fr/api/v2.5/sponsors.json', usersAPI: process.env.USERS_API || 'https://beta.gouv.fr/api/v2.3/authors.json', - incubatorAPI: process.env.INCUBATOR_API || 'https://beta.gouv.fr/api/v2.5/incubators.json', + incubatorAPI: + process.env.INCUBATOR_API || + 'https://beta.gouv.fr/api/v2.5/incubators.json', startupsAPI: process.env.STARTUPS_API || 'https://beta.gouv.fr/api/v2.5/startups.json', startupsDetailsAPI: - process.env.STARTUPS_DETAILS_API || 'https://beta.gouv.fr/api/v2.3/startups_details.json', + process.env.STARTUPS_DETAILS_API || + 'https://beta.gouv.fr/api/v2.3/startups_details.json', githubToken: process.env.GITHUB_TOKEN, githubOrganizationName: process.env.GITHUB_ORGANIZATION_NAME || 'betagouv', githubOrgAdminToken: process.env.GITHUB_ORG_ADMIN_TOKEN, @@ -89,27 +100,41 @@ export default { process.env.VISIT_MAIL_RECIPIENT || 'espace-membre@incubateur.net', visitSenderEmail: process.env.VISIT_MAIL_SENDER || 'secretariat@beta.gouv.fr', sentryDNS: process.env.SENTRY_DNS || false, - ESPACE_MEMBRE_ADMIN: process.env.ESPACE_MEMBRE_ADMIN ? process.env.ESPACE_MEMBRE_ADMIN.split(','):[], - MAILING_LIST_NEWSLETTER: process.env.MAILING_LIST_NEWSLETTER ? parseInt(process.env.MAILING_LIST_NEWSLETTER) : null, - MAILING_LIST_ONBOARDING: process.env.MAILING_LIST_ONBOARDING ? parseInt(process.env.MAILING_LIST_ONBOARDING) : null, - MAILING_LIST_REMINDER: process.env.MAILING_LIST_REMINDER ? parseInt(process.env.MAILING_LIST_REMINDER) : null, + ESPACE_MEMBRE_ADMIN: process.env.ESPACE_MEMBRE_ADMIN + ? process.env.ESPACE_MEMBRE_ADMIN.split(',') + : [], + MAILING_LIST_NEWSLETTER: process.env.MAILING_LIST_NEWSLETTER + ? parseInt(process.env.MAILING_LIST_NEWSLETTER) + : null, + MAILING_LIST_ONBOARDING: process.env.MAILING_LIST_ONBOARDING + ? parseInt(process.env.MAILING_LIST_ONBOARDING) + : null, + MAILING_LIST_REMINDER: process.env.MAILING_LIST_REMINDER + ? parseInt(process.env.MAILING_LIST_REMINDER) + : null, MARRAINAGE_GROUP_LIMIT: parseInt(process.env.MARRAINAGE_GROUP_LIMIT) || 5, - MARRAINAGE_GROUP_WEEK_LIMIT: parseInt(process.env.MARRAINAGE_GROUP_WEEK_LIMIT) || 2, + MARRAINAGE_GROUP_WEEK_LIMIT: + parseInt(process.env.MARRAINAGE_GROUP_WEEK_LIMIT) || 2, mattermostBotToken: process.env.MATTERMOST_BOT_TOKEN, mattermostTeamId: process.env.MATTERMOST_TEAM_ID || 'testteam', mattermostAlumniTeamId: process.env.MATTERMOST_ALUMNI_TEAM_ID || 'testalumniteam', mattermostInvitationLink: process.env.MATTERMOST_INVITATION_LINK || '', MATTERMOST_INVITE_ID: process.env.MATTERMOST_INVITE_ID, - MATTERMOST_ALLOWED_DOMAINS: process.env.MATTERMOST_ALLOWED_DOMAINS || 'beta.gouv.fr', + MATTERMOST_ALLOWED_DOMAINS: + process.env.MATTERMOST_ALLOWED_DOMAINS || 'beta.gouv.fr', MATTERMOST_PARTNERS_AUTHORS_URL: process.env.MATTERMOST_PARTNERS_AUTHORS_URL, - MATTERMOST_PARTNERS_AUTHORS_URLS: process.env.MATTERMOST_PARTNERS_AUTHORS_URLS ? JSON.parse(process.env.MATTERMOST_PARTNERS_AUTHORS_URLS) : [], - MATTERMOST_EMAIL_REGEX_EXCEPTION: process.env.MATTERMOST_EMAIL_REGEX_EXCEPTION, + MATTERMOST_PARTNERS_AUTHORS_URLS: process.env.MATTERMOST_PARTNERS_AUTHORS_URLS + ? JSON.parse(process.env.MATTERMOST_PARTNERS_AUTHORS_URLS) + : [], + MATTERMOST_EMAIL_REGEX_EXCEPTION: + process.env.MATTERMOST_EMAIL_REGEX_EXCEPTION, OVH_EMAIL_PRO_NAME: process.env.OVH_EMAIL_PRO_NAME, OVH_EMAIL_EXCHANGE_NAME: process.env.OVH_EMAIL_EXCHANGE_NAME, investigationReportsIframeURL: process.env.INVESTIGATION_REPORTS_IFRAME_URL || '', - incubateurMailingListName: process.env.INCUBATEUR_MAILING_LIST_NAME || 'incubateur', + incubateurMailingListName: + process.env.INCUBATEUR_MAILING_LIST_NAME || 'incubateur', JOBS_API: process.env.JOBS_API || 'https://beta.gouv.fr/api/v2.5/jobs.json', JOBS_WTTJ_API: process.env.JOBS_WTTJ_API, leavesEmail: process.env.LEAVES_EMAIL || 'depart@beta.gouv.fr', @@ -119,38 +144,61 @@ export default { process.env.FEATURE_REACTIVE_MATTERMOST_USERS === 'true', featureAddGithubUserToOrganization: process.env.FEATURE_ADD_GITHUB_USER_TO_ORGANIZATION === 'true', - featureAddUserToCommunityTeam: process.env.FEATURE_ADD_USER_TO_COMMUNITY_ON_MATTERMOST === 'true', - featureCreateUserOnMattermost: process.env.FEATURE_CREATE_USER_ON_MATTERMOST === 'true', + featureAddUserToCommunityTeam: + process.env.FEATURE_ADD_USER_TO_COMMUNITY_ON_MATTERMOST === 'true', + featureCreateUserOnMattermost: + process.env.FEATURE_CREATE_USER_ON_MATTERMOST === 'true', featureRemoveGithubUserFromOrganization: process.env.FEATURE_REMOVE_GITHUB_USER_FROM_ORGANIZATION === 'true', featureOnUserContractEnd: process.env.FEATURE_ON_USER_CONTRACT_END === 'true', featureAddExpiredUsersToAlumniOnMattermost: process.env.FEATURE_ADD_EXPIRED_USERS_TO_ALUMNI_ON_MATTERMOST === 'true', - featureRemoveExpiredUsersFromCommunityOnMattermost: process.env.FEATURE_REMOVED_EXPIRED_USERS_FROM_COMMUNITY_ON_MATTERMOST === 'true', + featureRemoveExpiredUsersFromCommunityOnMattermost: + process.env.FEATURE_REMOVED_EXPIRED_USERS_FROM_COMMUNITY_ON_MATTERMOST === + 'true', featureSendJ1Email: process.env.FEATURE_SEND_J1_EMAIL === 'true', featureSendJ30Email: process.env.FEATURE_SEND_J30_EMAIL === 'true', - featureDeleteOVHEmailAccounts: process.env.FEATURE_DELETE_OVH_EMAIL_ACCOUNTS === 'true', - featureDeleteSecondaryEmail: process.env.FEATURE_DELETE_SECONDARY_EMAIL === 'true', + featureDeleteOVHEmailAccounts: + process.env.FEATURE_DELETE_OVH_EMAIL_ACCOUNTS === 'true', + featureDeleteSecondaryEmail: + process.env.FEATURE_DELETE_SECONDARY_EMAIL === 'true', featureDeleteRedirectionsAfterQuitting: process.env.FEATURE_DELETE_REDIRECTIONS_AFTER_QUITTING === 'true', - featureRemoveEmailsFromMailingList: process.env.FEATURE_REMOVE_EMAILS_FROM_MAILING_LIST === 'true', - featureRemindUserWithPendingPullRequestOnAuthorFile: process.env.FEATURE_REMIND_USER_WITH_PENDING_PULL_REQUEST_ON_AUTHOR_FILE === 'true', + featureRemoveEmailsFromMailingList: + process.env.FEATURE_REMOVE_EMAILS_FROM_MAILING_LIST === 'true', + featureRemindUserWithPendingPullRequestOnAuthorFile: + process.env.FEATURE_REMIND_USER_WITH_PENDING_PULL_REQUEST_ON_AUTHOR_FILE === + 'true', featureSetEmailExpired: process.env.FEATURE_SET_EMAIL_EXPIRED === 'true', - featureSubscribeToIncubateurMailingList: process.env.FEATURE_SUBSCRIBE_TO_INCUBATEUR_MAILING_LIST === 'true', - featureUnsubscribeFromIncubateurMailingList: process.env.FEATURE_UNSUBSCRIBE_FROM_INCUBATEUR_MAILING_LIST === 'true', - featureSendMessageToActiveUsersWithoutSecondaryEmail: process.env.FEATURE_SEND_MESSAGE_TO_ACTIVE_USERS_WITHOUT_SECONDARY_EMAIL === 'true', + featureSubscribeToIncubateurMailingList: + process.env.FEATURE_SUBSCRIBE_TO_INCUBATEUR_MAILING_LIST === 'true', + featureUnsubscribeFromIncubateurMailingList: + process.env.FEATURE_UNSUBSCRIBE_FROM_INCUBATEUR_MAILING_LIST === 'true', + featureSendMessageToActiveUsersWithoutSecondaryEmail: + process.env.FEATURE_SEND_MESSAGE_TO_ACTIVE_USERS_WITHOUT_SECONDARY_EMAIL === + 'true', FEATURE_CREATE_MARRAINAGE: process.env.FEATURE_CREATE_MARRAINAGE === 'true', - FEATURE_MATTERMOST_REMOVE_USERS: process.env.FEATURE_MATTERMOST_REMOVE_USERS === 'true', - FEATURE_SYNC_BETAGOUV_USER_API: process.env.FEATURE_SYNC_BETAGOUV_USER_API === 'true', - FEATURE_PUBLISH_JOBS_TO_MATTERMOST: process.env.FEATURE_PUBLISH_JOBS_TO_MATTERMOST === 'true', - FEATURE_PUBLISH_WTTJ_JOBS_TO_MATTERMOST: process.env.FEATURE_PUBLISH_WTTJ_JOBS_TO_MATTERMOST === 'true', + FEATURE_MATTERMOST_REMOVE_USERS: + process.env.FEATURE_MATTERMOST_REMOVE_USERS === 'true', + FEATURE_SYNC_BETAGOUV_USER_API: + process.env.FEATURE_SYNC_BETAGOUV_USER_API === 'true', + FEATURE_PUBLISH_JOBS_TO_MATTERMOST: + process.env.FEATURE_PUBLISH_JOBS_TO_MATTERMOST === 'true', + FEATURE_PUBLISH_WTTJ_JOBS_TO_MATTERMOST: + process.env.FEATURE_PUBLISH_WTTJ_JOBS_TO_MATTERMOST === 'true', // If both emails of the users are already in sib update will not work - FEATURE_SIB_USE_UPDATE_CONTACT_EMAIL: process.env.FEATURE_SIB_USE_UPDATE_CONTACT_EMAIL === 'true', - FEATURE_SEND_EMAIL_TO_STARTUP_TO_UPDATE_PHASE: process.env.FEATURE_SEND_EMAIL_TO_STARTUP_TO_UPDATE_PHASE === 'true', - FEATURE_SEND_MESSAGE_TO_TEAM_FOR_JOB_OPENED_FOR_A_LONG_TIME: process.env.FEATURE_SEND_MESSAGE_TO_TEAM_FOR_JOB_OPENED_FOR_A_LONG_TIME === 'true', + FEATURE_SIB_USE_UPDATE_CONTACT_EMAIL: + process.env.FEATURE_SIB_USE_UPDATE_CONTACT_EMAIL === 'true', + FEATURE_SEND_EMAIL_TO_STARTUP_TO_UPDATE_PHASE: + process.env.FEATURE_SEND_EMAIL_TO_STARTUP_TO_UPDATE_PHASE === 'true', + FEATURE_SEND_MESSAGE_TO_TEAM_FOR_JOB_OPENED_FOR_A_LONG_TIME: + process.env.FEATURE_SEND_MESSAGE_TO_TEAM_FOR_JOB_OPENED_FOR_A_LONG_TIME === + 'true', FEATURE_USE_NEW_MARRAINAGE: process.env.FEATURE_USE_NEW_MARRAINAGE === 'true', FEATURE_NEWSLETTER: process.env.FEATURE_NEWSLETTER === 'true', - MARRAINAGE_ONBOARDER_LIST: process.env.MARRAINAGE_ONBOARDER_LIST ? process.env.MARRAINAGE_ONBOARDER_LIST.split(',') : undefined, + MARRAINAGE_ONBOARDER_LIST: process.env.MARRAINAGE_ONBOARDER_LIST + ? process.env.MARRAINAGE_ONBOARDER_LIST.split(',') + : undefined, SIB_WEBHOOK_ID: process.env.SIB_WEBHOOK_ID, tchap_api: process.env.TCHAP_API, HASH_SALT: process.env.HASH_SALT, diff --git a/src/controllers/usersController/createEmailForUser.ts b/src/controllers/usersController/createEmailForUser.ts index 4aacfd3de..855464007 100644 --- a/src/controllers/usersController/createEmailForUser.ts +++ b/src/controllers/usersController/createEmailForUser.ts @@ -1,165 +1,211 @@ -import crypto from "crypto" -import config from "@config"; -import BetaGouv, { EMAIL_PLAN_TYPE, OvhExchangeCreationData } from "@/betagouv"; -import * as utils from "@controllers/utils"; -import knex from "@/db/index"; -import { MemberWithPermission } from "@models/member"; -import { DBUser, EmailStatusCode } from "@/models/dbUser/dbUser"; -import { addEvent, EventCode } from "@/lib/events"; -import { _ } from "lodash"; - -const INCUBATORS_USING_EXCHANGE = [ 'gip-inclusion' ]; - -export async function createEmailAndUpdateSecondaryEmail({username, email} : {username:string, email:string}, currentUser: string) { - const isCurrentUser = currentUser === username; - const [user, dbUser]: [MemberWithPermission, DBUser] = await Promise.all([ - utils.userInfos(username, isCurrentUser), - knex('users').where({ username }).first() - ]); - if (!user.userInfos) { - throw new Error( - `Le membre ${username} n'a pas de fiche sur Github : vous ne pouvez pas créer son compte email.`, - ); - } - - if (user.isExpired) { - throw new Error( - `Le compte du membre ${username} est expiré.`, - ); - } +import crypto from 'crypto'; +import config from '@config'; +import BetaGouv, { + EMAIL_PLAN_TYPE, + OvhExchangeCreationData, + OvhProCreationData, +} from '@/betagouv'; +import * as utils from '@controllers/utils'; +import knex from '@/db/index'; +import { MemberWithPermission } from '@models/member'; +import { DBUser, EmailStatusCode } from '@/models/dbUser/dbUser'; +import { addEvent, EventCode } from '@/lib/events'; +import { _ } from 'lodash'; + +const INCUBATORS_USING_EXCHANGE = ['gip-inclusion']; + +export async function createEmailAndUpdateSecondaryEmail( + { username, email }: { username: string; email: string }, + currentUser: string +) { + const isCurrentUser = currentUser === username; + const [user, dbUser]: [MemberWithPermission, DBUser] = await Promise.all([ + utils.userInfos(username, isCurrentUser), + knex('users').where({ username }).first(), + ]); + if (!user.userInfos) { + throw new Error( + `Le membre ${username} n'a pas de fiche sur Github : vous ne pouvez pas créer son compte email.` + ); + } - if (!user.canCreateEmail) { - throw new Error('Vous n\'avez pas le droit de créer le compte email du membre.'); - } + if (user.isExpired) { + throw new Error(`Le compte du membre ${username} est expiré.`); + } - if (!isCurrentUser) { - const loggedUserInfo = await BetaGouv.userInfosById(currentUser); - if (utils.checkUserIsExpired(loggedUserInfo)) { - throw new Error('Vous ne pouvez pas créer le compte email car votre compte a une date de fin expiré sur Github.'); - } + if (!user.canCreateEmail) { + throw new Error( + "Vous n'avez pas le droit de créer le compte email du membre." + ); + } + + if (!isCurrentUser) { + const loggedUserInfo = await BetaGouv.userInfosById(currentUser); + if (utils.checkUserIsExpired(loggedUserInfo)) { + throw new Error( + 'Vous ne pouvez pas créer le compte email car votre compte a une date de fin expiré sur Github.' + ); } - let emailIsRecreated = false - if (dbUser) { - if (dbUser.email_is_redirection) { - throw new Error( - `Le membre ${username} ne peut pas avoir d'email beta.gouv.fr, iel utilise une adresse de redirection.`, - ); - } - emailIsRecreated = dbUser.primary_email_status === EmailStatusCode.EMAIL_DELETED - await updateSecondaryEmail(username, email) - } else { - await knex('users').insert({ - username, - primary_email_status: EmailStatusCode.EMAIL_UNSET, - secondary_email: email - }) + } + let emailIsRecreated = false; + if (dbUser) { + if (dbUser.email_is_redirection) { + throw new Error( + `Le membre ${username} ne peut pas avoir d'email beta.gouv.fr, iel utilise une adresse de redirection.` + ); } - await createEmail(username, currentUser, emailIsRecreated); + emailIsRecreated = + dbUser.primary_email_status === EmailStatusCode.EMAIL_DELETED; + await updateSecondaryEmail(username, email); + } else { + await knex('users').insert({ + username, + primary_email_status: EmailStatusCode.EMAIL_UNSET, + secondary_email: email, + }); + } + await createEmail(username, currentUser, emailIsRecreated); } export async function createEmailForUser(req, res) { - const username = req.sanitize(req.params.username); - const email = req.sanitize(req.body.to_email); - - try { - await createEmailAndUpdateSecondaryEmail({username, email}, req.auth.id) - req.flash('message', 'Le compte email a bien été créé.'); - res.redirect(`/community/${username}`); - } catch (err) { - console.error(err); - - req.flash('error', err.message); - res.redirect('/community'); - } + const username = req.sanitize(req.params.username); + const email = req.sanitize(req.body.to_email); + + try { + await createEmailAndUpdateSecondaryEmail({ username, email }, req.auth.id); + req.flash('message', 'Le compte email a bien été créé.'); + res.redirect(`/community/${username}`); + } catch (err) { + console.error(err); + + req.flash('error', err.message); + res.redirect('/community'); + } } -async function getEmailCreationParams(username: string): - Promise< - { planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_EXCHANGE, creationData: OvhExchangeCreationData } - | { planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC, password: string } - > { - const [ usersInfos, startupsInfos ] = await Promise.all([ - BetaGouv.usersInfos(), - BetaGouv.startupsInfos() - ]); - - const userInfo = _.find(usersInfos, { id: username }); - - const needsExchange = _.some(userInfo?.startups, (id) => { - const startup = _.find(startupsInfos, { id }); - const incubator = startup?.relationships?.incubator?.data?.id; - return _.includes(INCUBATORS_USING_EXCHANGE, incubator); - }); - - if (needsExchange) { - const displayName = userInfo?.fullname ?? ''; - const [ firstName, ...lastNames ] = displayName.split(' '); - const lastName = lastNames.join(' '); - - return { - planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_EXCHANGE, - creationData: { - displayName, - firstName, - lastName - } - } - } else { - const password = crypto.randomBytes(16) - .toString('base64') - .slice(0, -2); - - return { - planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC, - password - }; +async function getEmailCreationParams(username: string): Promise< + | { + planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_EXCHANGE; + creationData: OvhExchangeCreationData; + } + | { planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC; password: string } + | { + planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_PRO; + creationData: OvhProCreationData; } +> { + const [usersInfos, startupsInfos] = await Promise.all([ + BetaGouv.usersInfos(), + BetaGouv.startupsInfos(), + ]); + + const userInfo = _.find(usersInfos, { id: username }); + + const needsExchange = _.some(userInfo?.startups, (id) => { + const startup = _.find(startupsInfos, { id }); + const incubator = startup?.relationships?.incubator?.data?.id; + return _.includes(INCUBATORS_USING_EXCHANGE, incubator); + }); + + if (needsExchange) { + const displayName = userInfo?.fullname ?? ''; + const [firstName, ...lastNames] = displayName.split(' '); + const lastName = lastNames.join(' '); + + return { + planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_EXCHANGE, + creationData: { + displayName, + firstName, + lastName, + }, + }; + } else if (config.EMAIL_DEFAULT_PLAN === EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC) { + const password = crypto.randomBytes(16).toString('base64').slice(0, -2); + + return { + planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC, + password, + }; + } else { + const displayName = userInfo?.fullname ?? ''; + const [firstName, ...lastNames] = displayName.split(' '); + const lastName = lastNames.join(' '); + + return { + planType: EMAIL_PLAN_TYPE.EMAIL_PLAN_PRO, + creationData: { + displayName, + firstName, + lastName, + }, + }; + } } -export async function createEmail(username: string, creator: string, emailIsRecreated: boolean=false) { - const email = utils.buildBetaEmail(username); +export async function createEmail( + username: string, + creator: string, + emailIsRecreated: boolean = false +) { + const email = utils.buildBetaEmail(username); - const secretariatUrl = `${config.protocol}://${config.host}`; + const secretariatUrl = `${config.protocol}://${config.host}`; - const message = `À la demande de ${creator} sur <${secretariatUrl}>, je lance la création d'un compte mail pour ${username}`; + const message = `À la demande de ${creator} sur <${secretariatUrl}>, je lance la création d'un compte mail pour ${username}`; - await BetaGouv.sendInfoToChat(message); + await BetaGouv.sendInfoToChat(message); - const emailCreationParams = await getEmailCreationParams(username); + const emailCreationParams = await getEmailCreationParams(username); - switch (emailCreationParams.planType) { - case EMAIL_PLAN_TYPE.EMAIL_PLAN_EXCHANGE: - await BetaGouv.createEmailForExchange(username, emailCreationParams.creationData); - break; - case EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC: - await BetaGouv.createEmail(username, emailCreationParams.password); - break; - } - - await knex('users').where({ + switch (emailCreationParams.planType) { + case EMAIL_PLAN_TYPE.EMAIL_PLAN_EXCHANGE: + await BetaGouv.createEmailForExchange( username, - }).update({ - primary_email: email, - primary_email_status: emailIsRecreated ? EmailStatusCode.EMAIL_RECREATION_PENDING : EmailStatusCode.EMAIL_CREATION_PENDING, - primary_email_status_updated_at: new Date() + emailCreationParams.creationData + ); + break; + case EMAIL_PLAN_TYPE.EMAIL_PLAN_BASIC: + await BetaGouv.createEmail(username, emailCreationParams.password); + break; + case EMAIL_PLAN_TYPE.EMAIL_PLAN_PRO: + await BetaGouv.createEmailPro(username, emailCreationParams.creationData); + break; + } + + await knex('users') + .where({ + username, }) + .update({ + primary_email: email, + primary_email_status: emailIsRecreated + ? EmailStatusCode.EMAIL_RECREATION_PENDING + : EmailStatusCode.EMAIL_CREATION_PENDING, + primary_email_status_updated_at: new Date(), + }); - addEvent(emailIsRecreated ? EventCode.MEMBER_EMAIL_RECREATED : EventCode.MEMBER_EMAIL_CREATED, { - created_by_username: creator, - action_on_username: username, - action_metadata: { - value: email - } - }) - console.log( - `Création de compte by=${creator}&email=${email}`, - ); + addEvent( + emailIsRecreated + ? EventCode.MEMBER_EMAIL_RECREATED + : EventCode.MEMBER_EMAIL_CREATED, + { + created_by_username: creator, + action_on_username: username, + action_metadata: { + value: email, + }, + } + ); + console.log(`Création de compte by=${creator}&email=${email}`); } export async function updateSecondaryEmail(username, secondary_email) { - return knex('users').where({ - username - }).update({ - secondary_email + return knex('users') + .where({ + username, }) + .update({ + secondary_email, + }); } diff --git a/tests/test-user.ts b/tests/test-user.ts index 28d57b8d4..950cf1aad 100644 --- a/tests/test-user.ts +++ b/tests/test-user.ts @@ -2,19 +2,25 @@ import chai from 'chai'; import chaiHttp from 'chai-http'; import nock from 'nock'; import sinon from 'sinon'; -import Betagouv from '@/betagouv'; +import Betagouv, { EMAIL_PLAN_TYPE } from '@/betagouv'; import config from '@config'; import * as controllerUtils from '@controllers/utils'; import * as mattermost from '@/lib/mattermost'; import knex from '@/db'; import app from '@/index'; -import { createEmailAddresses, createRedirectionEmailAdresses, subscribeEmailAddresses, unsubscribeEmailAddresses } from '@/schedulers/emailScheduler'; +import { + createEmailAddresses, + createRedirectionEmailAdresses, + subscribeEmailAddresses, + unsubscribeEmailAddresses, +} from '@/schedulers/emailScheduler'; import { createEmail } from '@controllers/usersController'; import testUsers from './users.json'; import utils from './utils'; -import { EmailStatusCode } from '@/models/dbUser/dbUser' +import { EmailStatusCode } from '@/models/dbUser/dbUser'; import * as session from '@/helpers/session'; import betagouv from '@/betagouv'; +import { Member } from '@/models/member'; chai.use(chaiHttp); @@ -38,41 +44,43 @@ describe('User', () => { }); }); describe('POST /users/:username/email authenticated', () => { - let getToken - let sendEmailStub; + let getToken; + let sendEmailStub; beforeEach((done) => { sendEmailStub = sinon .stub(controllerUtils, 'sendMail') - .returns(Promise.resolve(true)) - getToken = sinon.stub(session, 'getToken') - getToken.returns(utils.getJWT('membre.actif')) - done() + .returns(Promise.resolve(true)); + getToken = sinon.stub(session, 'getToken'); + getToken.returns(utils.getJWT('membre.actif')); + done(); }); afterEach((done) => { - sendEmailStub.restore() - getToken.restore() - done() + sendEmailStub.restore(); + getToken.restore(); + done(); }); it('should ask OVH to create an email', async () => { const ovhEmailCreation = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/account/) .reply(200); - await knex('users').where({ username: 'membre.nouveau'}).update({ - primary_email: null - }) - await chai - .request(app) - .post('/users/membre.nouveau/email') - .type('form') - .send({ - to_email: 'test@example.com', - }) - - const res = await knex('users').where({ username: 'membre.nouveau'}).first() - res.primary_email.should.equal(`membre.nouveau@${config.domain}`) - ovhEmailCreation.isDone().should.be.true; + await knex('users').where({ username: 'membre.nouveau' }).update({ + primary_email: null, + }); + await chai + .request(app) + .post('/users/membre.nouveau/email') + .type('form') + .send({ + to_email: 'test@example.com', + }); + + const res = await knex('users') + .where({ username: 'membre.nouveau' }) + .first(); + res.primary_email.should.equal(`membre.nouveau@${config.domain}`); + ovhEmailCreation.isDone().should.be.true; }); it('should not allow email creation from delegate if email already exists', (done) => { @@ -151,7 +159,7 @@ describe('User', () => { const ovhEmailCreation = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/account/) .reply(200); - getToken.returns(utils.getJWT('membre.expire')) + getToken.returns(utils.getJWT('membre.expire')); chai .request(app) @@ -170,40 +178,43 @@ describe('User', () => { const ovhEmailCreation = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/account/) .reply(200); - await knex('users').where({ username: 'membre.actif'}).update({ - primary_email: null - }) - getToken.returns(utils.getJWT('julien.dauphant')) + await knex('users').where({ username: 'membre.actif' }).update({ + primary_email: null, + }); + getToken.returns(utils.getJWT('julien.dauphant')); await chai .request(app) .post('/users/membre.actif/email') .type('form') .send({ to_email: 'test@example.com', - }) - ovhEmailCreation.isDone().should.be.true; - const user = await knex('users').where({ username: 'membre.actif' }).first() - user.secondary_email.should.equal('test@example.com') + }); + ovhEmailCreation.isDone().should.be.true; + const user = await knex('users') + .where({ username: 'membre.actif' }) + .first(); + user.secondary_email.should.equal('test@example.com'); }); it('should create email and insert user in database if user on github', async () => { const ovhEmailCreation = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/account/) .reply(200); - await knex('users').where({ username: 'membre.actif'}).delete() - getToken.returns(utils.getJWT('julien.dauphant')) + await knex('users').where({ username: 'membre.actif' }).delete(); + getToken.returns(utils.getJWT('julien.dauphant')); await chai .request(app) .post('/users/membre.actif/email') .type('form') .send({ to_email: 'test@example.com', - }) - ovhEmailCreation.isDone().should.be.true; - const user = await knex('users').where({ username: 'membre.actif' }).first() - user.secondary_email.should.equal('test@example.com') + }); + ovhEmailCreation.isDone().should.be.true; + const user = await knex('users') + .where({ username: 'membre.actif' }) + .first(); + user.secondary_email.should.equal('test@example.com'); }); - }); describe('POST /api/users/:username/create-email unauthenticated', () => { @@ -222,40 +233,42 @@ describe('User', () => { }); }); describe('POST /api/users/:username/create-email authenticated', () => { - let getToken + let getToken; let sendEmailStub; beforeEach((done) => { - getToken = sinon.stub(session, 'getToken') - getToken.returns(utils.getJWT('membre.actif')) + getToken = sinon.stub(session, 'getToken'); + getToken.returns(utils.getJWT('membre.actif')); sendEmailStub = sinon .stub(controllerUtils, 'sendMail') - .returns(Promise.resolve(true)) - done() + .returns(Promise.resolve(true)); + done(); }); afterEach((done) => { - sendEmailStub.restore() - getToken.restore() - done() + sendEmailStub.restore(); + getToken.restore(); + done(); }); it('should ask OVH to create an email', async () => { const ovhEmailCreation = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/account/) .reply(200); - await knex('users').where({ username: 'membre.nouveau'}).update({ - primary_email: null - }) - await chai - .request(app) - .post('/api/users/membre.nouveau/create-email') - .send({ - to_email: 'test@example.com', - }) - - const res = await knex('users').where({ username: 'membre.nouveau'}).first() - res.primary_email.should.equal(`membre.nouveau@${config.domain}`) - ovhEmailCreation.isDone().should.be.true; + await knex('users').where({ username: 'membre.nouveau' }).update({ + primary_email: null, + }); + await chai + .request(app) + .post('/api/users/membre.nouveau/create-email') + .send({ + to_email: 'test@example.com', + }); + + const res = await knex('users') + .where({ username: 'membre.nouveau' }) + .first(); + res.primary_email.should.equal(`membre.nouveau@${config.domain}`); + ovhEmailCreation.isDone().should.be.true; }); }); @@ -266,31 +279,37 @@ describe('User', () => { beforeEach((done) => { sendEmailStub = sinon .stub(controllerUtils, 'sendMail') - .returns(Promise.resolve(true)) - mattermostSearchUserStub = sinon.stub(mattermost, 'searchUsers').returns(Promise.resolve([{ - email: 'adresse.email@beta.gouv.fr' - }])) - mattermostGetUserStub = sinon.stub(mattermost, 'getUserByEmail').returns(Promise.resolve({ - email: 'adresse.email@beta.gouv.fr' - } as mattermost.MattermostUser)) - done() + .returns(Promise.resolve(true)); + mattermostSearchUserStub = sinon.stub(mattermost, 'searchUsers').returns( + Promise.resolve([ + { + email: 'adresse.email@beta.gouv.fr', + }, + ]) + ); + mattermostGetUserStub = sinon.stub(mattermost, 'getUserByEmail').returns( + Promise.resolve({ + email: 'adresse.email@beta.gouv.fr', + } as mattermost.MattermostUser) + ); + done(); }); afterEach((done) => { - sendEmailStub.restore() - mattermostGetUserStub.restore() - mattermostSearchUserStub.restore() - done() + sendEmailStub.restore(); + mattermostGetUserStub.restore(); + mattermostSearchUserStub.restore(); + done(); }); it('should get user public info', async () => { - const res = await chai - .request(app) - .get('/api/public/users/membre.nouveau') - res.should.have.status(200); - res.body.username.should.equal('membre.nouveau') - mattermostSearchUserStub.calledOnce.should.be.true - mattermostGetUserStub.calledOnce.should.be.true + const res = await chai + .request(app) + .get('/api/public/users/membre.nouveau'); + res.should.have.status(200); + res.body.username.should.equal('membre.nouveau'); + mattermostSearchUserStub.calledOnce.should.be.true; + mattermostGetUserStub.calledOnce.should.be.true; }); }); @@ -311,16 +330,16 @@ describe('User', () => { }); describe('POST /users/:username/redirections authenticated', () => { - let getToken + let getToken; beforeEach(() => { - getToken = sinon.stub(session, 'getToken') - getToken.returns(utils.getJWT('membre.actif')) - }) + getToken = sinon.stub(session, 'getToken'); + getToken.returns(utils.getJWT('membre.actif')); + }); afterEach(() => { - getToken.restore() - }) + getToken.restore(); + }); it('should ask OVH to create a redirection', (done) => { const ovhRedirectionCreation = nock(/.*ovh.com/) @@ -362,7 +381,7 @@ describe('User', () => { const ovhRedirectionCreation = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/redirection/) .reply(200); - getToken.returns(utils.getJWT('membre.expire')) + getToken.returns(utils.getJWT('membre.expire')); chai .request(app) .post('/users/membre.expire/redirections') @@ -390,16 +409,16 @@ describe('User', () => { }); describe('POST /users/:username/redirections/:email/delete authenticated', () => { - let getToken + let getToken; beforeEach(() => { - getToken = sinon.stub(session, 'getToken') - getToken.returns(utils.getJWT('membre.actif')) - }) + getToken = sinon.stub(session, 'getToken'); + getToken.returns(utils.getJWT('membre.actif')); + }); afterEach(() => { - getToken.restore() - }) + getToken.restore(); + }); it('should ask OVH to delete a redirection', (done) => { const ovhRedirectionDeletion = nock(/.*ovh.com/) @@ -433,7 +452,7 @@ describe('User', () => { const ovhRedirectionDeletion = nock(/.*ovh.com/) .delete(/^.*email\/domain\/.*\/redirection\/.*/) .reply(200); - getToken.returns(utils.getJWT('membre.expire')) + getToken.returns(utils.getJWT('membre.expire')); chai .request(app) @@ -479,16 +498,16 @@ describe('User', () => { }); describe('POST /users/:username/password authenticated', () => { - let getToken + let getToken; beforeEach(() => { - getToken = sinon.stub(session, 'getToken') - getToken.returns(utils.getJWT('membre.actif')) - }) + getToken = sinon.stub(session, 'getToken'); + getToken.returns(utils.getJWT('membre.actif')); + }); afterEach(() => { - getToken.restore() - }) + getToken.restore(); + }); it('should redirect to user page', (done) => { chai @@ -513,31 +532,31 @@ describe('User', () => { utils.mockSlackSecretariat(); utils.mockOvhTime(); utils.mockOvhRedirections(); - const username = 'membre.nouveau' + const username = 'membre.nouveau'; await knex('users') .where({ username }) - .update({ primary_email_status: EmailStatusCode.EMAIL_ACTIVE }) + .update({ primary_email_status: EmailStatusCode.EMAIL_ACTIVE }); nock(/.*ovh.com/) .get(/^.*email\/domain\/.*\/account\/.*/) .reply(200, { accountName: username, email: 'membre.nouveau@example.com', - }).persist(); + }) + .persist(); ovhPasswordNock = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/account\/.*\/changePassword/) .reply(200); - getToken.returns(utils.getJWT(`${username}`)) + getToken.returns(utils.getJWT(`${username}`)); await chai .request(app) .post(`/users/${username}/password`) .type('form') .send({ new_password: 'Test_Password_1234', - }) + }); ovhPasswordNock.isDone().should.be.true; - const user = await knex('users').where({ username }).first() - + const user = await knex('users').where({ username }).first(); }); it('should perform a password change and pass status to active if status was suspended', async () => { utils.cleanMocks(); @@ -547,31 +566,32 @@ describe('User', () => { utils.mockSlackSecretariat(); utils.mockOvhTime(); utils.mockOvhRedirections(); - const username = 'membre.nouveau' + const username = 'membre.nouveau'; await knex('users') .where({ username }) - .update({ primary_email_status: EmailStatusCode.EMAIL_SUSPENDED }) + .update({ primary_email_status: EmailStatusCode.EMAIL_SUSPENDED }); nock(/.*ovh.com/) .get(/^.*email\/domain\/.*\/account\/.*/) .reply(200, { accountName: username, email: 'membre.nouveau@example.com', - }).persist(); + }) + .persist(); ovhPasswordNock = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/account\/.*\/changePassword/) .reply(200); - getToken.returns(utils.getJWT(`${username}`)) + getToken.returns(utils.getJWT(`${username}`)); await chai - .request(app) - .post(`/users/${username}/password`) - .type('form') - .send({ - new_password: 'Test_Password_1234', - }) + .request(app) + .post(`/users/${username}/password`) + .type('form') + .send({ + new_password: 'Test_Password_1234', + }); ovhPasswordNock.isDone().should.be.true; - const user = await knex('users').where({ username }).first() - user.primary_email_status.should.be.equal(EmailStatusCode.EMAIL_ACTIVE) + const user = await knex('users').where({ username }).first(); + user.primary_email_status.should.be.equal(EmailStatusCode.EMAIL_ACTIVE); }); it('should not allow a password change from delegate', (done) => { @@ -595,7 +615,7 @@ describe('User', () => { ovhPasswordNock = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/account\/.*\/changePassword/) .reply(200); - getToken.returns(utils.getJWT('membre.expire')) + getToken.returns(utils.getJWT('membre.expire')); chai .request(app) @@ -658,35 +678,38 @@ describe('User', () => { }); describe('POST /user/:username/email/delete', () => { - let getToken + let getToken; beforeEach(() => { - getToken = sinon.stub(session, 'getToken') - getToken.returns(utils.getJWT('membre.actif')) - }) + getToken = sinon.stub(session, 'getToken'); + getToken.returns(utils.getJWT('membre.actif')); + }); afterEach(() => { - getToken.restore() - }) - it('should keep the user in database secretariat', async() => { + getToken.restore(); + }); + it('should keep the user in database secretariat', async () => { const addRedirection = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/redirection/) .reply(200); - const dbRes = await knex('users').select().where({ username: 'membre.actif' }) + const dbRes = await knex('users') + .select() + .where({ username: 'membre.actif' }); dbRes.length.should.equal(1); - await chai - .request(app) - .post('/users/membre.actif/email/delete') - const dbNewRes = await knex('users').where({ username: 'membre.actif' }) + await chai.request(app).post('/users/membre.actif/email/delete'); + const dbNewRes = await knex('users').where({ username: 'membre.actif' }); dbNewRes.length.should.equal(1); addRedirection.isDone().should.be.true; }); it('should ask OVH to redirect to the departs email', (done) => { const expectedRedirectionBody = (body) => { - return body.from === `membre.actif@${config.domain}` && body.to === config.leavesEmail; - } + return ( + body.from === `membre.actif@${config.domain}` && + body.to === config.leavesEmail + ); + }; const ovhRedirectionDepartureEmail = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/redirection/, expectedRedirectionBody) @@ -703,18 +726,18 @@ describe('User', () => { }); describe('POST /users/:username/secondary_email', () => { - let getToken + let getToken; beforeEach((done) => { - getToken = sinon.stub(session, 'getToken') - getToken.returns(utils.getJWT('membre.nouveau')) - done() - }) + getToken = sinon.stub(session, 'getToken'); + getToken.returns(utils.getJWT('membre.nouveau')); + done(); + }); afterEach((done) => { - getToken.restore() - done() - }) + getToken.restore(); + done(); + }); it('should return 200 to add secondary email', async () => { const username = 'membre.nouveau'; const secondaryEmail = 'membre.nouveau.perso@example.com'; @@ -725,7 +748,7 @@ describe('User', () => { .send({ username, secondaryEmail, - }) + }); res.should.have.status(200); }); @@ -736,21 +759,23 @@ describe('User', () => { await knex('users') .select() .where({ username: 'membre.nouveau' }) - .first() + .first(); await chai - .request(app) - .post(`/users/${username}/secondary_email`) - .type('form') - .send({ - username, - secondaryEmail, - }) - const dbNewRes = await knex('users').select().where({ username: 'membre.nouveau' }) + .request(app) + .post(`/users/${username}/secondary_email`) + .type('form') + .send({ + username, + secondaryEmail, + }); + const dbNewRes = await knex('users') + .select() + .where({ username: 'membre.nouveau' }); dbNewRes.length.should.equal(1); dbNewRes[0].secondary_email.should.equal(secondaryEmail); }); - it('should update secondary email', async() => { + it('should update secondary email', async () => { const username = 'membre.nouveau'; const secondaryEmail = 'membre.nouveau.perso@example.com'; const newSecondaryEmail = 'membre.nouveau.new@example.com'; @@ -761,27 +786,30 @@ describe('User', () => { }) .update({ secondary_email: secondaryEmail, - }) - await chai.request(app) + }); + await chai + .request(app) .post(`/users/${username}/secondary_email/`) .type('form') .send({ username, secondaryEmail: newSecondaryEmail, }); - const dbNewRes = await knex('users').select().where({ username: 'membre.nouveau' }) + const dbNewRes = await knex('users') + .select() + .where({ username: 'membre.nouveau' }); dbNewRes.length.should.equal(1); dbNewRes[0].secondary_email.should.equal(newSecondaryEmail); await knex('users').where({ username: 'membre.nouveau' }).update({ - secondary_email: null - }) + secondary_email: null, + }); }); }); describe('POST /users/:username/primary_email', () => { - let mattermostGetUserByEmailStub - let isPublicServiceEmailStub - let getToken + let mattermostGetUserByEmailStub; + let isPublicServiceEmailStub; + let getToken; beforeEach(() => { mattermostGetUserByEmailStub = sinon @@ -790,124 +818,138 @@ describe('User', () => { isPublicServiceEmailStub = sinon .stub(controllerUtils, 'isPublicServiceEmail') .returns(Promise.resolve(true)); - getToken = sinon.stub(session, 'getToken') - getToken.returns(utils.getJWT('membre.nouveau')) - }) + getToken = sinon.stub(session, 'getToken'); + getToken.returns(utils.getJWT('membre.nouveau')); + }); afterEach(() => { mattermostGetUserByEmailStub.restore(); isPublicServiceEmailStub.restore(); - getToken.restore() - }) + getToken.restore(); + }); - it('should not update primary email if user is not current user', async() => { + it('should not update primary email if user is not current user', async () => { const username = 'membre.nouveau'; const primaryEmail = 'membre.nouveau.new@example.com'; - getToken.returns(utils.getJWT('julien.dauphant')) + getToken.returns(utils.getJWT('julien.dauphant')); - await chai.request(app) + await chai + .request(app) .post(`/users/${username}/primary_email/`) .type('form') .send({ username, primaryEmail: primaryEmail, }); - isPublicServiceEmailStub.called.should.be.false; - mattermostGetUserByEmailStub.called.should.be.false; - }); + isPublicServiceEmailStub.called.should.be.false; + mattermostGetUserByEmailStub.called.should.be.false; + }); - it('should not update primary email if email is not public service email', async() => { + it('should not update primary email if email is not public service email', async () => { const username = 'membre.nouveau'; const primaryEmail = 'membre.nouveau.new@example.com'; isPublicServiceEmailStub.returns(Promise.resolve(false)); - getToken.returns(utils.getJWT('membre.nouveau')) + getToken.returns(utils.getJWT('membre.nouveau')); - await chai.request(app) + await chai + .request(app) .post(`/users/${username}/primary_email/`) .type('form') .send({ username, primaryEmail: primaryEmail, }); - const dbNewRes = await knex('users').select().where({ username: 'membre.nouveau' }) + const dbNewRes = await knex('users') + .select() + .where({ username: 'membre.nouveau' }); dbNewRes.length.should.equal(1); dbNewRes[0].primary_email.should.not.equal(primaryEmail); isPublicServiceEmailStub.called.should.be.true; mattermostGetUserByEmailStub.called.should.be.false; }); - it('should not update primary email if email does not exist on mattermost', async() => { + it('should not update primary email if email does not exist on mattermost', async () => { isPublicServiceEmailStub.returns(Promise.resolve(true)); mattermostGetUserByEmailStub.returns(Promise.reject('404 error')); const username = 'membre.nouveau'; const primaryEmail = 'membre.nouveau.new@example.com'; - getToken.returns(utils.getJWT('membre.nouveau')) + getToken.returns(utils.getJWT('membre.nouveau')); await knex('users').where({ username: 'membre.nouveau' }).update({ - primary_email: `membre.nouveau@otherdomaine.gouv.fr` - }) + primary_email: `membre.nouveau@otherdomaine.gouv.fr`, + }); - await chai.request(app) + await chai + .request(app) .post(`/users/${username}/primary_email/`) .type('form') .send({ username, primaryEmail: primaryEmail, }); - const dbNewRes = await knex('users').select().where({ username: 'membre.nouveau' }) + const dbNewRes = await knex('users') + .select() + .where({ username: 'membre.nouveau' }); dbNewRes.length.should.equal(1); dbNewRes[0].primary_email.should.not.equal(primaryEmail); mattermostGetUserByEmailStub.called.should.be.true; - await knex('users').where({ username: 'membre.nouveau' }).update({ - primary_email: `membre.nouveau@${config.domain}` - }) + await knex('users') + .where({ username: 'membre.nouveau' }) + .update({ + primary_email: `membre.nouveau@${config.domain}`, + }); }); - it('should update primary email', async() => { + it('should update primary email', async () => { isPublicServiceEmailStub.returns(Promise.resolve(true)); mattermostGetUserByEmailStub.returns(Promise.resolve(true)); const createRedirectionStub = sinon - .stub(betagouv, 'createRedirection') - .returns(Promise.resolve(true)); - const deleteEmailStub = sinon - .stub(betagouv, 'deleteEmail') - .returns(Promise.resolve(true)); + .stub(betagouv, 'createRedirection') + .returns(Promise.resolve(true)); + const deleteEmailStub = sinon + .stub(betagouv, 'deleteEmail') + .returns(Promise.resolve(true)); const username = 'membre.nouveau'; const primaryEmail = 'membre.nouveau.new@example.com'; - getToken.returns(utils.getJWT('membre.nouveau')) + getToken.returns(utils.getJWT('membre.nouveau')); - await chai.request(app) + await chai + .request(app) .post(`/users/${username}/primary_email/`) .type('form') .send({ username, primaryEmail: primaryEmail, }); - const dbNewRes = await knex('users').select().where({ username: 'membre.nouveau' }) + const dbNewRes = await knex('users') + .select() + .where({ username: 'membre.nouveau' }); dbNewRes.length.should.equal(1); dbNewRes[0].primary_email.should.equal(primaryEmail); - await knex('users').where({ username: 'membre.nouveau' }).update({ - primary_email: `${username}@${config.domain}` - }) - createRedirectionStub.called.should.be.true - deleteEmailStub.called.should.be.true + await knex('users') + .where({ username: 'membre.nouveau' }) + .update({ + primary_email: `${username}@${config.domain}`, + }); + createRedirectionStub.called.should.be.true; + deleteEmailStub.called.should.be.true; isPublicServiceEmailStub.called.should.be.true; mattermostGetUserByEmailStub.called.should.be.false; - createRedirectionStub.restore() - deleteEmailStub.restore() + createRedirectionStub.restore(); + deleteEmailStub.restore(); }); }); describe('POST /users/:username/redirections/:email/delete authenticated', () => { - let getToken + let getToken; beforeEach(() => { - getToken = sinon.stub(session, 'getToken') - getToken.returns(utils.getJWT('membre.actif')) - }) + getToken = sinon.stub(session, 'getToken'); + getToken.returns(utils.getJWT('membre.actif')); + }); afterEach(() => { - getToken.restore() - }) + getToken.restore(); + }); it('should ask OVH to delete all redirections', (done) => { nock.cleanAll(); @@ -991,7 +1033,7 @@ describe('User', () => { const ovhRedirectionDeletion = nock(/.*ovh.com/) .delete(/^.*email\/domain\/.*\/redirection\/123123/) .reply(200); - getToken.returns(utils.getJWT('membre.nouveau')) + getToken.returns(utils.getJWT('membre.nouveau')); chai .request(app) .post('/users/membre.actif/email/delete') @@ -1105,28 +1147,31 @@ describe('User', () => { const ovhEmailCreation = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/account/) .reply(200); - await knex('login_tokens').truncate() - await knex('users').where({ - username: newMember.id, - }).update({ - primary_email: null, - primary_email_status: EmailStatusCode.EMAIL_UNSET, - secondary_email: 'membre.nouveau.perso@example.com', - }); + await knex('login_tokens').truncate(); + await knex('users') + .where({ + username: newMember.id, + }) + .update({ + primary_email: null, + primary_email_status: EmailStatusCode.EMAIL_UNSET, + secondary_email: 'membre.nouveau.perso@example.com', + }); const val = await knex('users').where({ username: newMember.id, - }) + }); await createEmailAddresses(); ovhEmailCreation.isDone().should.be.true; betagouvCreateEmail.firstCall.args[0].should.equal(newMember.id); - await knex('users').where({ username: newMember.id }).update({ - secondary_email: null, - primary_email: `${newMember.id}@${config.domain}`, - }); + await knex('users') + .where({ username: newMember.id }) + .update({ + secondary_email: null, + primary_email: `${newMember.id}@${config.domain}`, + }); }); - - it('should not create email accounts if already created', async() => { + it('should not create email accounts if already created', async () => { // For this case we need to reset the basic nocks in order to return // a different response to indicate that newcomer.test has an // email address @@ -1148,9 +1193,9 @@ describe('User', () => { .post(/^.*email\/domain\/.*\/account/) .reply(200); - await createEmailAddresses(); - betagouvCreateEmail.notCalled.should.be.true; - ovhEmailCreation.isDone().should.be.false; + await createEmailAddresses(); + betagouvCreateEmail.notCalled.should.be.true; + ovhEmailCreation.isDone().should.be.false; }); it('should not create email accounts if we dont have the secondary email', async () => { @@ -1182,9 +1227,8 @@ describe('User', () => { }, ], }, - ]) - const subscribeSpy = sinon - .spy(Betagouv, 'subscribeToMailingList') + ]); + const subscribeSpy = sinon.spy(Betagouv, 'subscribeToMailingList'); const newMember = testUsers.find((user) => user.id === 'membre.nouveau'); nock(/.*ovh.com/) .get(/^.*email\/domain\/.*\/account/) @@ -1194,13 +1238,18 @@ describe('User', () => { .reply(200, []); const ovhMailingListSubscription = nock(/.*ovh.com/) .post(/^.*email\/domain\/.*\/mailingList\/.*\/subscriber/) - .reply(200).persist(); + .reply(200) + .persist(); await subscribeEmailAddresses(); ovhMailingListSubscription.isDone().should.be.true; - subscribeSpy.firstCall.args[0].should.equal(config.incubateurMailingListName) - subscribeSpy.firstCall.args[1].should.equal(`membre.nouveau@${config.domain}`) - subscribeSpy.restore() + subscribeSpy.firstCall.args[0].should.equal( + config.incubateurMailingListName + ); + subscribeSpy.firstCall.args[1].should.equal( + `membre.nouveau@${config.domain}` + ); + subscribeSpy.restore(); }); it('should unsubscribe user from incubateur mailing list', async () => { @@ -1222,9 +1271,8 @@ describe('User', () => { }, ], }, - ]) - const unsubscribeSpy = sinon - .spy(Betagouv, 'unsubscribeFromMailingList') + ]); + const unsubscribeSpy = sinon.spy(Betagouv, 'unsubscribeFromMailingList'); const newMember = testUsers.find((user) => user.id === 'membre.nouveau'); nock(/.*ovh.com/) .get(/^.*email\/domain\/.*\/account/) @@ -1234,18 +1282,23 @@ describe('User', () => { .reply(200, [`membre.nouveau@${config.domain}`]); const ovhMailingListUnsubscription = nock(/.*ovh.com/) .delete(/^.*email\/domain\/.*\/mailingList\/.*\/subscriber.*/) - .reply(200).persist(); + .reply(200) + .persist(); await unsubscribeEmailAddresses(); ovhMailingListUnsubscription.isDone().should.be.true; - unsubscribeSpy.firstCall.args[0].should.equal(config.incubateurMailingListName) - unsubscribeSpy.firstCall.args[1].should.equal(`membre.nouveau@${config.domain}`) - unsubscribeSpy.restore() + unsubscribeSpy.firstCall.args[0].should.equal( + config.incubateurMailingListName + ); + unsubscribeSpy.firstCall.args[1].should.equal( + `membre.nouveau@${config.domain}` + ); + unsubscribeSpy.restore(); }); it('should create redirection missing email accounts', async () => { utils.cleanMocks(); - let createRedirection = sinon.spy(betagouv, 'createRedirection') + let createRedirection = sinon.spy(betagouv, 'createRedirection'); const url = process.env.USERS_API || 'https://beta.gouv.fr'; nock(url) .get((uri) => uri.includes('authors.json')) @@ -1300,31 +1353,36 @@ describe('User', () => { .post(/^.*email\/domain\/.*\/redirection/) .reply(200); - await knex('login_tokens').truncate() - await knex('users').where({ - username: newMember.id, - }).update({ - primary_email: null, - primary_email_status: EmailStatusCode.EMAIL_UNSET, - secondary_email: 'membre.nouveau.perso@example.com', - email_is_redirection: true - }); + await knex('login_tokens').truncate(); + await knex('users') + .where({ + username: newMember.id, + }) + .update({ + primary_email: null, + primary_email_status: EmailStatusCode.EMAIL_UNSET, + secondary_email: 'membre.nouveau.perso@example.com', + email_is_redirection: true, + }); const val = await knex('users').where({ username: newMember.id, - }) + }); await createEmailAddresses(); ovhRedirectionCreation.isDone().should.be.false; await createRedirectionEmailAdresses(); ovhRedirectionCreation.isDone().should.be.true; - createRedirection.firstCall.args[0].should.equal(`${newMember.id}-attr@${config.domain}`); - createRedirection.calledOnce.should.be.true - await knex('users').where({ username: newMember.id }).update({ - secondary_email: null, - primary_email: `${newMember.id}@${config.domain}`, - email_is_redirection: false, - }); + createRedirection.firstCall.args[0].should.equal( + `${newMember.id}-attr@${config.domain}` + ); + createRedirection.calledOnce.should.be.true; + await knex('users') + .where({ username: newMember.id }) + .update({ + secondary_email: null, + primary_email: `${newMember.id}@${config.domain}`, + email_is_redirection: false, + }); }); - }); describe('createEmail', () => { @@ -1333,62 +1391,88 @@ describe('User', () => { beforeEach(async () => { sandbox.stub(Betagouv, 'createEmail'); sandbox.stub(Betagouv, 'createEmailForExchange'); + sandbox.stub(Betagouv, 'createEmailPro'); sandbox.stub(Betagouv, 'sendInfoToChat'); }); afterEach(async () => { sandbox.restore(); - await knex('users').where({ username: 'membre.nouveau-email' }).delete(); }); - it('should create an OVH email account', async () => { - await knex('users').insert({ - username: 'membre.nouveau-email', - primary_email: null, - primary_email_status: EmailStatusCode.EMAIL_UNSET, - secondary_email: 'membre.nouveau-email.perso@example.com', + context('when the user needs an MX PLAN account', () => { + it('should create an OVH MX Plam account', async () => { + await knex('users').insert({ + username: 'membre.nouveau-email', + primary_email: null, + primary_email_status: EmailStatusCode.EMAIL_UNSET, + secondary_email: 'membre.nouveau-email.perso@example.com', + }); + await createEmail('membre.nouveau-email', 'Test'); + Betagouv.createEmail.calledWith('membre.nouveau-email').should.be.true; }); + }); - await createEmail('membre.nouveau-email', 'Test'); + context('when the user needs an OVH Pro account', () => { + beforeEach(async () => { + sandbox.stub(Betagouv, 'usersInfos').resolves([ + { + id: 'membre.nouveau-email', + fullname: 'Membre Nouveau test email', + startups: ['itou', 'missing-startup'], + } as Member, + ]); + sandbox + .stub(config, 'EMAIL_DEFAULT_PLAN') + .value(EMAIL_PLAN_TYPE.EMAIL_PLAN_PRO); + }); + it('should create an OVH Pro email account', async () => { + await knex('users').insert({ + username: 'membre.nouveau-email', + primary_email: null, + primary_email_status: EmailStatusCode.EMAIL_UNSET, + secondary_email: 'membre.nouveau-email.perso@example.com', + }); - Betagouv.createEmail.calledWith('membre.nouveau-email').should.be.true; + await createEmail('membre.nouveau-email', 'Test'); + Betagouv.createEmailPro.firstCall.args.should.deep.equal([ + 'membre.nouveau-email', + { + displayName: 'Membre Nouveau test email', + firstName: 'Membre', + lastName: 'Nouveau test email', + }, + ]); + }); }); - context('when the user needs an Exchange account', ()=> { + context('when the user needs an Exchange account', () => { beforeEach(async () => { - sandbox.stub(Betagouv, 'startupsInfos').resolves( - [ - { - "type": "startup", - "id": "itou", - "attributes": { - "name": "Itou", - }, - "relationships": { - "incubator": { - "data": { - "type": "incubator", - "id": "gip-inclusion" - } - } + sandbox.stub(Betagouv, 'startupsInfos').resolves([ + { + type: 'startup', + id: 'itou', + attributes: { + name: 'Itou', + }, + relationships: { + incubator: { + data: { + type: 'incubator', + id: 'gip-inclusion', + }, }, - } - ] - ); - - sandbox.stub(Betagouv, 'usersInfos').resolves( - [ - { - id: 'membre.nouveau-email', - fullname: 'Membre Nouveau test email', - startups: [ - "itou", - "missing-startup", - ], }, - ] - ); + }, + ]); + + sandbox.stub(Betagouv, 'usersInfos').resolves([ + { + id: 'membre.nouveau-email', + fullname: 'Membre Nouveau test email', + startups: ['itou', 'missing-startup'], + } as Member, + ]); }); it('should create an Exchange email account', async () => { @@ -1401,17 +1485,15 @@ describe('User', () => { await createEmail('membre.nouveau-email', 'Test'); - Betagouv.createEmailForExchange.firstCall.args.should.deep.equal( - [ - 'membre.nouveau-email', - { - displayName: 'Membre Nouveau test email', - firstName: 'Membre', - lastName: 'Nouveau test email', - } - ]); + Betagouv.createEmailForExchange.firstCall.args.should.deep.equal([ + 'membre.nouveau-email', + { + displayName: 'Membre Nouveau test email', + firstName: 'Membre', + lastName: 'Nouveau test email', + }, + ]); }); }); - }); });