From 6c47ab3946e76b7dcbe53944fa631f76a2523406 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Thu, 17 Aug 2017 10:50:37 +0200 Subject: [PATCH 01/23] :sparkles: feat(bot): add status update --- bots/messageTypes/message/status_update.js | 44 ++++++++++++++ diagnostics/cron.js | 70 ++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 bots/messageTypes/message/status_update.js create mode 100644 diagnostics/cron.js diff --git a/bots/messageTypes/message/status_update.js b/bots/messageTypes/message/status_update.js new file mode 100644 index 0000000..8949620 --- /dev/null +++ b/bots/messageTypes/message/status_update.js @@ -0,0 +1,44 @@ +"use strict"; + +const Bluebird = require("bluebird"); +const utils = require("../../../utils/ovh"); +const { TextMessage } = require("../../../platforms/generics"); +const translator = require("../../../utils/translator"); + + +class StatusUpdate { + static action (senderId, message, entities, res, locale) { + return utils.getOvhClient(senderId) + .then((ovhClient) => Bluebird.props({ + cloudStatus: ovhClient.requestPromised("GET", "/status/task").filter((incident) => incident.status !== "finished"), + xdslStatus: getXdslStatus(ovhClient) + })) + .then(({ cloudStatus, xdslStatus }) => { + let responses = [ + ...cloudStatus.map((cloudIncident) => new TextMessage(translator("cloud-incident", locale, cloudIncident.title, translator(`cloud-${cloudIncident.status}`, locale), cloudIncident.progress, cloudIncident.details))), + ...xdslStatus.map((xdslIncident) => new TextMessage(translator("xdsl-incident", locale, xdslIncident.comment, xdslIncident.endDate, `http://travaux.ovh.net/?do=details&id=${xdslIncident.taskId}`))) + ]; + + if (!responses.length) { + responses = [new TextMessage(translator("allOk", locale))]; + } + + return { responses, feedback: false }; + }); + } +} + +function getXdslStatus (ovhClient) { + return ovhClient.requestPromised("GET", "/xdsl") + .map((service) => ovhClient.requestPromised("GET", `/xdsl/${service}/incidents`).catch((err) => { + if (err.error === 404 || err.statusCode === 404) { + return null; + } + + return Bluebird.reject(err); + })) + .filter((incident) => incident != null) + .map((incidentId) => ovhClient.requestPromised("GET", `/xdsl/incidents/${incidentId}`)); +} + +module.exports = { status_update: StatusUpdate }; diff --git a/diagnostics/cron.js b/diagnostics/cron.js new file mode 100644 index 0000000..2c35bd1 --- /dev/null +++ b/diagnostics/cron.js @@ -0,0 +1,70 @@ +"use strict"; + +const Users = require("../models/users.model"); +const utils = require("../utils/ovh"); +const Bluebird = require("bluebird"); +const { TextMessage } = require("../platform/generics"); +const translator = require("../utils/translator"); + +/** entry point **/ +function performUpdate () { + return Users.find({}).then((users) => { + users.forEach((user) => getServicesStatus(user.senderId, user.platform)); + }); +} + +function getServicesStatus (senderId, platform) { + let ovhClient; + let locale; + + return utils.getOvhClient(senderId) + .then((localOvhClient) => { ovhClient = localOvhClient; }) + .then(() => ovhClient.requestPromised("GET", "/me/preference/manager/CHATBOT_PREF")) + .then(({ value }) => { + // check if user wants update + if (value.update) { + return ovhClient.requestPromised("GET", "/me"); + } + return Bluebird.reject(); + }) + .then((meInfos) => { locale = meInfos.language; }) + .then(() => Bluebird.props({ + cloudStatus: ovhClient.requestPromised("GET", "/status/task").filter((incident) => incident.status !== "finished"), + xdslStatus: getXdslStatus(ovhClient) + })) + .then(({ cloudStatus, xdslStatus }) => [ + ...cloudStatus.map((cloudIncident) => new TextMessage(translator("cloud-incident", locale, cloudIncident.title, translator(`cloud-${cloudIncident.status}`, locale), cloudIncident.progress, cloudIncident.details))), + ...xdslStatus.map((xdslIncident) => new TextMessage(translator("xdsl-incident", locale, xdslIncident.comment, xdslIncident.endDate, `http://travaux.ovh.net/?do=details&id=${xdslIncident.taskId}`))) + ]) + .catch(() => []) + .then((responses) => responses ? sendStatus(senderId, platform, responses) : null); +} + +function sendStatus (senderId, platform, responses) { + switch (platform) { + case "slack": + console.log("slack!", responses); + return; + case "facebook_messenger": + console.log("messenger!", responses); + break; + default: + } +} + +function getXdslStatus (ovhClient) { + return ovhClient.requestPromised("GET", "/xdsl") + .map((service) => ovhClient.requestPromised("GET", `/xdsl/${service}/incidents`).catch((err) => { + if (err.error === 404 || err.statusCode === 404) { + return null; + } + + return Bluebird.reject(err); + })) + .filter((incident) => incident != null) + .map((incidentId) => ovhClient.requestPromised("GET", `/xdsl/incidents/${incidentId}`)); +} + +module.exports = { + performUpdate +}; From 03304629045c9de8f9b1c7b1aa2844e416770946 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Fri, 18 Aug 2017 09:30:04 +0200 Subject: [PATCH 02/23] :sparkles: feat(bot): inform user when service doesn't work anymore --- bots/common.js | 2 + bots/messageTypes/message/status_update.js | 15 +++- bots/messageTypes/postback/index.js | 3 +- bots/messageTypes/postback/settings.js | 20 +++++ diagnostics/cron.js | 87 ++++++++++++++++------ diagnostics/hosting.js | 9 +-- index.js | 3 +- models/users.model.js | 4 + package-lock.json | 5 ++ package.json | 1 + translations/translation_fr_FR.json | 4 + 11 files changed, 119 insertions(+), 34 deletions(-) create mode 100644 bots/messageTypes/postback/settings.js diff --git a/bots/common.js b/bots/common.js index 9adbf24..937db72 100644 --- a/bots/common.js +++ b/bots/common.js @@ -6,6 +6,7 @@ const Bluebird = require("bluebird"); const Users = require("../models/users.model"); const { TextMessage } = require("../platforms/generics"); const translator = require("../utils/translator"); +const logger = require("../providers/logging/logger"); module.exports = () => ({ ask (type, senderId, message, intent, entities, res, locale) { @@ -43,6 +44,7 @@ function isDisconnected (err, locale) { if (err.statusCode === 403 || err.statusCode === 401) { error = Object.assign({}, err, { message: translator("disconnected", locale) }); } else { + logger.error(err); error = err; } diff --git a/bots/messageTypes/message/status_update.js b/bots/messageTypes/message/status_update.js index 8949620..50b73bc 100644 --- a/bots/messageTypes/message/status_update.js +++ b/bots/messageTypes/message/status_update.js @@ -2,19 +2,21 @@ const Bluebird = require("bluebird"); const utils = require("../../../utils/ovh"); -const { TextMessage } = require("../../../platforms/generics"); +const { TextMessage, ButtonsMessage, Button, BUTTON_TYPE } = require("../../../platforms/generics"); const translator = require("../../../utils/translator"); +const Users = require("../../../models/users.model"); class StatusUpdate { static action (senderId, message, entities, res, locale) { + let responses; return utils.getOvhClient(senderId) .then((ovhClient) => Bluebird.props({ cloudStatus: ovhClient.requestPromised("GET", "/status/task").filter((incident) => incident.status !== "finished"), xdslStatus: getXdslStatus(ovhClient) })) .then(({ cloudStatus, xdslStatus }) => { - let responses = [ + responses = [ ...cloudStatus.map((cloudIncident) => new TextMessage(translator("cloud-incident", locale, cloudIncident.title, translator(`cloud-${cloudIncident.status}`, locale), cloudIncident.progress, cloudIncident.details))), ...xdslStatus.map((xdslIncident) => new TextMessage(translator("xdsl-incident", locale, xdslIncident.comment, xdslIncident.endDate, `http://travaux.ovh.net/?do=details&id=${xdslIncident.taskId}`))) ]; @@ -23,6 +25,15 @@ class StatusUpdate { responses = [new TextMessage(translator("allOk", locale))]; } + return Users.findOne({ senderId }).exec(); + }).then((user) => { + if (user) { + let buttons = [ + new Button(BUTTON_TYPE.POSTBACK, "SETTINGS_UPDATES_true", translator("on", locale)), + new Button(BUTTON_TYPE.POSTBACK, "SETTINGS_UPDATES_false", translator("off", locale)) + ]; + responses.push(new ButtonsMessage(translator(`settings-updates-${user.updates}`, locale), buttons)); + } return { responses, feedback: false }; }); } diff --git a/bots/messageTypes/postback/index.js b/bots/messageTypes/postback/index.js index 0f22e6d..1bd2079 100644 --- a/bots/messageTypes/postback/index.js +++ b/bots/messageTypes/postback/index.js @@ -4,5 +4,6 @@ const hosting = require("./hosting"); const feedback = require("./feedback"); const xdslBreak = require("./xdsl"); const telephony = require("./telephony"); +const settings = require("./settings"); -module.exports = [...hosting, ...feedback, ...xdslBreak, ...telephony]; +module.exports = [...hosting, ...feedback, ...xdslBreak, ...telephony, ...settings]; diff --git a/bots/messageTypes/postback/settings.js b/bots/messageTypes/postback/settings.js new file mode 100644 index 0000000..4eec80d --- /dev/null +++ b/bots/messageTypes/postback/settings.js @@ -0,0 +1,20 @@ +"use strict"; + +const { TextMessage } = require("../../../platforms/generics"); +const translator = require("../../../utils/translator"); +const Users = require("../../../models/users.model"); + +module.exports = [ + { + regx: "SETTINGS_UPDATES_(true|false)", + action (senderId, postback, regx, entities, res, locale) { + const updates = postback.match(new RegExp(regx))[1]; + + return Users.findOne({ senderId }).exec() + .then((user) => { + user.updates = updates; + return user.save(); + }).then(() => ({ responses: [new TextMessage(translator(`settings-updates-${updates}`, locale))], feedback: false })); + } + } +]; diff --git a/diagnostics/cron.js b/diagnostics/cron.js index 2c35bd1..78259e4 100644 --- a/diagnostics/cron.js +++ b/diagnostics/cron.js @@ -3,14 +3,22 @@ const Users = require("../models/users.model"); const utils = require("../utils/ovh"); const Bluebird = require("bluebird"); -const { TextMessage } = require("../platform/generics"); +const { TextMessage } = require("../platforms/generics"); const translator = require("../utils/translator"); +const messenger = require("../platforms/messenger/messenger"); +const slack = require("../platforms/slack/slack"); +const request = require("request-promise"); +const hostingDiagnostics = require("./hosting"); +const cron = require("node-cron"); +const _ = require("lodash"); +const logger = require("../providers/logging/logger"); + +module.exports = cron.schedule("0 */2 * * *", performUpdate, true); -/** entry point **/ function performUpdate () { - return Users.find({}).then((users) => { - users.forEach((user) => getServicesStatus(user.senderId, user.platform)); - }); + logger.info("Status update:", new Date()); + return Users.find({ updates: true }).then((users) => Bluebird.map(users, (user) => getServicesStatus(user.senderId, user.platform))) + .then(() => logger.info("Status update done")); } function getServicesStatus (senderId, platform) { @@ -18,37 +26,35 @@ function getServicesStatus (senderId, platform) { let locale; return utils.getOvhClient(senderId) - .then((localOvhClient) => { ovhClient = localOvhClient; }) - .then(() => ovhClient.requestPromised("GET", "/me/preference/manager/CHATBOT_PREF")) - .then(({ value }) => { - // check if user wants update - if (value.update) { - return ovhClient.requestPromised("GET", "/me"); - } - return Bluebird.reject(); + .then((localOvhClient) => { + ovhClient = localOvhClient; + return ovhClient.requestPromised("GET", "/me"); }) .then((meInfos) => { locale = meInfos.language; }) .then(() => Bluebird.props({ cloudStatus: ovhClient.requestPromised("GET", "/status/task").filter((incident) => incident.status !== "finished"), - xdslStatus: getXdslStatus(ovhClient) + xdslStatus: getXdslStatus(ovhClient), + hostingStatus: getHostingStatus(ovhClient) })) - .then(({ cloudStatus, xdslStatus }) => [ + .then(({ cloudStatus, xdslStatus, hostingStatus }) => [ ...cloudStatus.map((cloudIncident) => new TextMessage(translator("cloud-incident", locale, cloudIncident.title, translator(`cloud-${cloudIncident.status}`, locale), cloudIncident.progress, cloudIncident.details))), - ...xdslStatus.map((xdslIncident) => new TextMessage(translator("xdsl-incident", locale, xdslIncident.comment, xdslIncident.endDate, `http://travaux.ovh.net/?do=details&id=${xdslIncident.taskId}`))) + ...xdslStatus.map((xdslIncident) => new TextMessage(translator("xdsl-incident", locale, xdslIncident.comment, xdslIncident.endDate, `http://travaux.ovh.net/?do=details&id=${xdslIncident.taskId}`))), + ...hostingStatus ]) .catch(() => []) - .then((responses) => responses ? sendStatus(senderId, platform, responses) : null); + .then((responses) => responses && responses.length ? sendStatus(senderId, platform, responses) : null); } function sendStatus (senderId, platform, responses) { switch (platform) { case "slack": - console.log("slack!", responses); - return; + return Users.findOne({ senderId }) + .then((user) => slack.getSlackApi(user.team_id)) + .then((slackTeam) => Bluebird.mapSeries(responses, (response) => slackTeam.send(senderId, response))); case "facebook_messenger": - console.log("messenger!", responses); - break; + return Bluebird.mapSeries(responses, (response) => messenger.send(senderId, response)); default: + return Bluebird.resolve(); } } @@ -65,6 +71,39 @@ function getXdslStatus (ovhClient) { .map((incidentId) => ovhClient.requestPromised("GET", `/xdsl/incidents/${incidentId}`)); } -module.exports = { - performUpdate -}; + +function getHostingStatus (ovhClient, locale) { + return ovhClient.requestPromised("GET", "/hosting/web/") + .then((websites) => Bluebird.map(websites, (site) => request(`http://${site}`) + .then(() => []) + .catch(() => ovhClient.requestPromised("GET", `/hosting/web/${site}/attachedDomain`) // sites has issue do advance check + .then((domains) => Bluebird.map(domains, (domain) => hostingAdvanceCheck(ovhClient, site, domain, locale).catch(() => [])))) + )).then((responses) => _.flattenDeep(responses)); +} + +function hostingAdvanceCheck (ovhClient, site, domain, locale) { + return Bluebird.props({ + hosting: ovhClient.requestPromised("GET", `/hosting/web/${site}`), + attachedDomain: ovhClient.requestPromised("GET", `/hosting/web/${site}/attachedDomain/${domain}`), + hostingEmails: ovhClient.requestPromised("GET", `/hosting/web/${site}/email`), + ssl: getSSLState(ovhClient, site), + dns: getDNSState(ovhClient, domain) + }) + .then(({ hosting, attachedDomain, hostingEmails, ssl, dns }) => hostingDiagnostics.checkWebsite(null, hosting, attachedDomain, hostingEmails, ssl, dns, locale)); + +} + +function getSSLState (ovhClient, hosting) { + return Bluebird.props({ + infos: ovhClient.requestPromised("GET", `/hosting/web/${hosting}/ssl`).catch((err) => err.error === 404 || err.statusCode === 404 ? Bluebird.resolve(null) : Bluebird.reject(err)), + domains: ovhClient.requestPromised("GET", `/hosting/web/${hosting}/ssl/domains`).catch((err) => err.error === 404 || err.statusCode === 404 ? Bluebird.resolve([]) : Bluebird.reject(err)) + }); +} + +function getDNSState (ovhClient, domain) { + return Bluebird.props({ + target: ovhClient.requestPromised("GET", `/domain/zone/${domain}/record`, { fieldType: "NS" }) + .then((ids) => Bluebird.mapSeries(ids, (id) => ovhClient.requestPromised("GET", `/domain/zone/${domain}/record/${id}`))), + real: ovhClient.requestPromised("GET", `/domain/zone/${domain}`) + }); +} diff --git a/diagnostics/hosting.js b/diagnostics/hosting.js index d99f9d2..73c3f5b 100644 --- a/diagnostics/hosting.js +++ b/diagnostics/hosting.js @@ -7,12 +7,12 @@ const Bluebird = require("bluebird").config({ }); const _ = require("lodash"); const request = require("request-promise"); +const logger = require("../providers/logging/logger"); const translator = require("../utils/translator"); module.exports = { checkWebsite (res, hosting, domain, hostingEmails, ssl, dns, locale) { - res.logger.info(domain); const protocol = domain.ssl ? "https://" : "http://"; let responses = this.checkEmailsState(hosting, hostingEmails, locale); const sslState = this.checkSSL(hosting, domain, ssl, locale); @@ -22,11 +22,8 @@ module.exports = { return utils .dig(domain.domain) .then((ip) => { - res.logger.info(hosting); - res.logger.info(ip); const isDNSInvalid = this.checkDNS(ip, hosting, domain, dns); - res.logger.info(isDNSInvalid); if (isDNSInvalid) { return Bluebird.reject(isDNSInvalid); } @@ -37,7 +34,7 @@ module.exports = { switch (hosting.state) { case "active": if (responses.length) { - responses.push(new TextMessage(translator("hosting.hostingButActive", locale))); + responses.push(new TextMessage(translator("hosting-hostingButActive", locale))); } else { responses.push(new TextMessage(translator("hosting-hostingActive", locale))); } @@ -65,7 +62,7 @@ module.exports = { .catch((err) => { let managerButton; - res.logger.info(err); + logger.error(err); if (Array.isArray(err) && err.length && (typeof err[0] === "string" || err[0] instanceof TextMessage)) { return err; } diff --git a/index.js b/index.js index 4dbdaa4..de95689 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,7 @@ const http = require("http"); const app = exports.app = require("./config/express")(config); const port = config.server.port; const logger = require("./providers/logging/logger"); +const task = require("./diagnostics/cron"); let httpserver; @@ -15,7 +16,7 @@ if (require.main === module) { process.on("SIGTERM", () => { logger.info("SIGTERM Signal received, trying to close connections..."); - + task.destroy(); process.env.NODE_IS_CLOSING = "true"; httpserver.close(() => { diff --git a/models/users.model.js b/models/users.model.js index 5643146..715bf78 100644 --- a/models/users.model.js +++ b/models/users.model.js @@ -42,6 +42,10 @@ const UserSchema = new mongoose.Schema({ messageNumber: { type: Number, "default": 0 + }, + updates: { + type: Boolean, + "default": false } }); diff --git a/package-lock.json b/package-lock.json index 74084a1..1feb0f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3335,6 +3335,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, "node-emoji": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", diff --git a/package.json b/package.json index 3e10185..ef24a49 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "mongodb": "^2.2.11", "mongoose": "^4.8.1", "morgan": "^1.8.0", + "node-cron": "^1.2.1", "node-emoji": "^1.7.0", "node-wit": "^4.2.0", "npm": "^4.2.0", diff --git a/translations/translation_fr_FR.json b/translations/translation_fr_FR.json index 0b99b63..b5f04ee 100644 --- a/translations/translation_fr_FR.json +++ b/translations/translation_fr_FR.json @@ -51,6 +51,8 @@ "noIntent": "Je n'ai pas bien compris ta demande, pour voir la liste des questions auxquelles je peux répondre consulte ce site :point_right: https://www.ovh.com/manager/web/#/labs/chatbot", "notConnected": "Tu n'es pas connecté, mais tu peux te connecter en me demandant : 'connecte moi'", "moreButton": "Voir plus (%s)", + "on": "Activé", + "off": "Desactivé", "signIn": "Se connecter à son compte OVH :link:", "signInFirst": ":warning: Tu dois d'abord te connecter. Pour ce faire tu peux me le demander", "slackAuthor": "Assistant personnel OVH", @@ -92,6 +94,8 @@ "hosting-web500db": "Ton site n'arrive pas à se connecter à la base de données, je te conseille de vérifier le login et mot de passe de la base de données.", "hosting-web500dev": "Il semblerait que tu aies fait une erreur de programmation sur ton site web. Dans ce genre de situation le support OVH n'intervient pas.", "hosting-unknown": "Problème non diagnostiquable. :thinking_face:", + "settings-updates-true": "La notification lors d'incidents est activé.", + "settings-updates-false": "La notification lors d'incidents est desactivé.", "telephony-accountClosed": "Ton compte est clôturé :cry:", "telephony-accountDeleted": "Ton compte a été supprimé :cry:", "telephony-accountExpired": "Ton compte est expiré :cry:", From a6d7f3c060c6c31c1844e234f1eb79b28caffb23 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Mon, 21 Aug 2017 16:17:48 +0200 Subject: [PATCH 03/23] :sparkles: feat(bot): add when will my service expires ? --- bots/messageTypes/message/index.js | 3 +- bots/messageTypes/message/service_expires.js | 40 ++++++ bots/messageTypes/message/status_update.js | 31 +---- bots/messageTypes/postback/settings.js | 42 +++++- diagnostics/cron.js | 139 +++++++++++++------ models/users.model.js | 8 ++ platforms/generics.js | 2 +- translations/translation_fr_FR.json | 7 + 8 files changed, 199 insertions(+), 73 deletions(-) create mode 100644 bots/messageTypes/message/service_expires.js diff --git a/bots/messageTypes/message/index.js b/bots/messageTypes/message/index.js index a365f15..20af5c1 100644 --- a/bots/messageTypes/message/index.js +++ b/bots/messageTypes/message/index.js @@ -10,5 +10,6 @@ const xdslBreak = require("./xdsl_break"); const whoami = require("./whoami"); const telephonyBreak = require("./telephony_break"); const statusUpdate = require("./status_update"); +const serviceExpires = require("./service_expires"); -module.exports = Object.assign({}, dnsServerConfig, domainToHosting, thanks, websiteBreak, goodAnswer, ndhQuestion, xdslBreak, whoami, telephonyBreak, statusUpdate); +module.exports = Object.assign({}, dnsServerConfig, domainToHosting, thanks, websiteBreak, goodAnswer, ndhQuestion, xdslBreak, whoami, telephonyBreak, statusUpdate, serviceExpires); diff --git a/bots/messageTypes/message/service_expires.js b/bots/messageTypes/message/service_expires.js new file mode 100644 index 0000000..ab99f05 --- /dev/null +++ b/bots/messageTypes/message/service_expires.js @@ -0,0 +1,40 @@ +"use strict"; + +const utils = require("../../../utils/ovh"); +const { TextMessage, ButtonsMessage, Button, BUTTON_TYPE } = require("../../../platforms/generics"); +const translator = require("../../../utils/translator"); +const Users = require("../../../models/users.model"); +const { getServicesExpires } = require("../../../diagnostics/cron"); + + +class ServiceExpires { + static action (senderId, message, entities, res, locale) { + let user; + return Users.findOne({ senderId }).exec() + .then((userLocal) => { + user = userLocal; + return utils.getOvhClient(senderId); + }) + .then((ovhClient) => getServicesExpires(ovhClient, locale, user.expiresPeriod || 14)) + .then((responsesCron) => { + let responses = responsesCron; + if (!responses.length) { + responses = [new TextMessage(translator("expires-allOk", locale))]; + } + return responses; + }) + .then((responses) => { + if (user) { + let buttons = [ + new Button(BUTTON_TYPE.POSTBACK, "SETTINGS_EXPIRES_true", translator("on", locale)), + new Button(BUTTON_TYPE.POSTBACK, "SETTINGS_EXPIRES_false", translator("off", locale)), + new Button(BUTTON_TYPE.POSTBACK, "SETTINGS_EXPIRES_edit", translator("settings-expires-edit", locale)) + ]; + responses.push(new ButtonsMessage(translator(`settings-expires-${user.expires}`, locale, user.expiresPeriod), buttons)); + } + return { responses, feedback: true }; + }); + } +} + +module.exports = { service_expires: ServiceExpires }; diff --git a/bots/messageTypes/message/status_update.js b/bots/messageTypes/message/status_update.js index 50b73bc..eff9f4f 100644 --- a/bots/messageTypes/message/status_update.js +++ b/bots/messageTypes/message/status_update.js @@ -1,30 +1,22 @@ "use strict"; -const Bluebird = require("bluebird"); const utils = require("../../../utils/ovh"); const { TextMessage, ButtonsMessage, Button, BUTTON_TYPE } = require("../../../platforms/generics"); const translator = require("../../../utils/translator"); const Users = require("../../../models/users.model"); +const { getServicesStatus } = require("../../../diagnostics/cron"); class StatusUpdate { static action (senderId, message, entities, res, locale) { let responses; return utils.getOvhClient(senderId) - .then((ovhClient) => Bluebird.props({ - cloudStatus: ovhClient.requestPromised("GET", "/status/task").filter((incident) => incident.status !== "finished"), - xdslStatus: getXdslStatus(ovhClient) - })) - .then(({ cloudStatus, xdslStatus }) => { - responses = [ - ...cloudStatus.map((cloudIncident) => new TextMessage(translator("cloud-incident", locale, cloudIncident.title, translator(`cloud-${cloudIncident.status}`, locale), cloudIncident.progress, cloudIncident.details))), - ...xdslStatus.map((xdslIncident) => new TextMessage(translator("xdsl-incident", locale, xdslIncident.comment, xdslIncident.endDate, `http://travaux.ovh.net/?do=details&id=${xdslIncident.taskId}`))) - ]; - + .then((ovhClient) => getServicesStatus(ovhClient, locale)) + .then((responsesCron) => { + responses = responsesCron; if (!responses.length) { responses = [new TextMessage(translator("allOk", locale))]; } - return Users.findOne({ senderId }).exec(); }).then((user) => { if (user) { @@ -34,22 +26,9 @@ class StatusUpdate { ]; responses.push(new ButtonsMessage(translator(`settings-updates-${user.updates}`, locale), buttons)); } - return { responses, feedback: false }; + return { responses, feedback: true }; }); } } -function getXdslStatus (ovhClient) { - return ovhClient.requestPromised("GET", "/xdsl") - .map((service) => ovhClient.requestPromised("GET", `/xdsl/${service}/incidents`).catch((err) => { - if (err.error === 404 || err.statusCode === 404) { - return null; - } - - return Bluebird.reject(err); - })) - .filter((incident) => incident != null) - .map((incidentId) => ovhClient.requestPromised("GET", `/xdsl/incidents/${incidentId}`)); -} - module.exports = { status_update: StatusUpdate }; diff --git a/bots/messageTypes/postback/settings.js b/bots/messageTypes/postback/settings.js index 4eec80d..f289657 100644 --- a/bots/messageTypes/postback/settings.js +++ b/bots/messageTypes/postback/settings.js @@ -1,6 +1,6 @@ "use strict"; -const { TextMessage } = require("../../../platforms/generics"); +const { TextMessage, Button, ButtonsListMessage, BUTTON_TYPE } = require("../../../platforms/generics"); const translator = require("../../../utils/translator"); const Users = require("../../../models/users.model"); @@ -16,5 +16,45 @@ module.exports = [ return user.save(); }).then(() => ({ responses: [new TextMessage(translator(`settings-updates-${updates}`, locale))], feedback: false })); } + }, + { + regx: "SETTINGS_EXPIRES_(\\d+)", + action (senderId, postback, regx, entities, res, locale) { + const period = parseInt(postback.match(new RegExp(regx))[1], 10); + + return Users.findOne({ senderId }).exec() + .then((user) => { + user.expiresPeriod = period; + return user.save(); + }).then(() => ({ responses: [new TextMessage(translator("settings-expires-true", locale, period))], feedback: false })); + + + } + }, + { + regx: "SETTINGS_EXPIRES_edit", + action (senderId, postback, regx, entities, res, locale) { + const days = [1, 7, 14, 30, 60]; + + return Users.findOne({ senderId }).exec() + .then((user) => { + let buttons = days.map((day) => new Button(BUTTON_TYPE.POSTBACK, `SETTINGS_EXPIRES_${days}`, translator("settings-expires-period", locale, day))); + + return { responses: [new ButtonsListMessage(translator("settings-expires-true", locale, user.expiresPeriod), buttons)], feedback: false }; + }); + } + }, + { + regx: "SETTINGS_EXPIRES_(true|false)", + action (senderId, postback, regx, entities, res, locale) { + const expires = postback.match(new RegExp(regx))[1]; + + return Users.findOne({ senderId }).exec() + .then((user) => { + user.expires = expires; + return user.save(); + }).then((user) => ({ responses: [new TextMessage(translator(`settings-expires-${expires}`, locale, user.expiresPeriod))], feedback: false })); + + } } ]; diff --git a/diagnostics/cron.js b/diagnostics/cron.js index 78259e4..5a9053e 100644 --- a/diagnostics/cron.js +++ b/diagnostics/cron.js @@ -1,7 +1,8 @@ "use strict"; const Users = require("../models/users.model"); -const utils = require("../utils/ovh"); + +// const utils = require("../utils/ovh"); const Bluebird = require("bluebird"); const { TextMessage } = require("../platforms/generics"); const translator = require("../utils/translator"); @@ -13,44 +14,43 @@ const cron = require("node-cron"); const _ = require("lodash"); const logger = require("../providers/logging/logger"); -module.exports = cron.schedule("0 */2 * * *", performUpdate, true); +module.exports = { + getServicesStatus, + getServicesExpires +}; +cron.schedule("0 */2 * * *", performUpdate, false); function performUpdate () { logger.info("Status update:", new Date()); - return Users.find({ updates: true }).then((users) => Bluebird.map(users, (user) => getServicesStatus(user.senderId, user.platform))) - .then(() => logger.info("Status update done")); + Users.find({ updates: true }).then((users) => Bluebird.map(users, (user) => getServicesExpires(user.senderId, user.platform).then((resp) => send(user.senderId, user.platform, resp)))) + .then(() => logger.info("Status update done")); } -function getServicesStatus (senderId, platform) { - let ovhClient; - let locale; - - return utils.getOvhClient(senderId) - .then((localOvhClient) => { - ovhClient = localOvhClient; - return ovhClient.requestPromised("GET", "/me"); - }) - .then((meInfos) => { locale = meInfos.language; }) - .then(() => Bluebird.props({ - cloudStatus: ovhClient.requestPromised("GET", "/status/task").filter((incident) => incident.status !== "finished"), - xdslStatus: getXdslStatus(ovhClient), - hostingStatus: getHostingStatus(ovhClient) - })) - .then(({ cloudStatus, xdslStatus, hostingStatus }) => [ - ...cloudStatus.map((cloudIncident) => new TextMessage(translator("cloud-incident", locale, cloudIncident.title, translator(`cloud-${cloudIncident.status}`, locale), cloudIncident.progress, cloudIncident.details))), - ...xdslStatus.map((xdslIncident) => new TextMessage(translator("xdsl-incident", locale, xdslIncident.comment, xdslIncident.endDate, `http://travaux.ovh.net/?do=details&id=${xdslIncident.taskId}`))), - ...hostingStatus - ]) - .catch(() => []) - .then((responses) => responses && responses.length ? sendStatus(senderId, platform, responses) : null); +// performUpdate(); + +/** +what is my service status ? +*/ +function getServicesStatus (ovhClient, locale) { + return Bluebird.props({ + cloudStatus: ovhClient.requestPromised("GET", "/status/task").filter((incident) => incident.status !== "finished"), + xdslStatus: getXdslStatus(ovhClient), + hostingStatus: getHostingStatus(ovhClient) + }) + .then(({ cloudStatus, xdslStatus, hostingStatus }) => [ + ...cloudStatus.map((cloudIncident) => new TextMessage(translator("cloud-incident", locale, cloudIncident.title, translator(`cloud-${cloudIncident.status}`, locale), cloudIncident.progress, cloudIncident.details))), + ...xdslStatus.map((xdslIncident) => new TextMessage(translator("xdsl-incident", locale, xdslIncident.comment, xdslIncident.endDate, `http://travaux.ovh.net/?do=details&id=${xdslIncident.taskId}`))), + ...hostingStatus + ]) + .catch(() => []); } -function sendStatus (senderId, platform, responses) { +function send (senderId, platform, responses) { switch (platform) { case "slack": return Users.findOne({ senderId }) - .then((user) => slack.getSlackApi(user.team_id)) - .then((slackTeam) => Bluebird.mapSeries(responses, (response) => slackTeam.send(senderId, response))); + .then((user) => slack.getSlackApi(user.team_id)) + .then((slackTeam) => Bluebird.mapSeries(responses, (response) => slackTeam.send(senderId, response))); case "facebook_messenger": return Bluebird.mapSeries(responses, (response) => messenger.send(senderId, response)); default: @@ -60,25 +60,25 @@ function sendStatus (senderId, platform, responses) { function getXdslStatus (ovhClient) { return ovhClient.requestPromised("GET", "/xdsl") - .map((service) => ovhClient.requestPromised("GET", `/xdsl/${service}/incidents`).catch((err) => { - if (err.error === 404 || err.statusCode === 404) { - return null; - } - - return Bluebird.reject(err); - })) - .filter((incident) => incident != null) - .map((incidentId) => ovhClient.requestPromised("GET", `/xdsl/incidents/${incidentId}`)); + .map((service) => ovhClient.requestPromised("GET", `/xdsl/${service}/incidents`).catch((err) => { + if (err.error === 404 || err.statusCode === 404) { + return null; + } + + return Bluebird.reject(err); + })) + .filter((incident) => incident != null) + .map((incidentId) => ovhClient.requestPromised("GET", `/xdsl/incidents/${incidentId}`)); } function getHostingStatus (ovhClient, locale) { return ovhClient.requestPromised("GET", "/hosting/web/") - .then((websites) => Bluebird.map(websites, (site) => request(`http://${site}`) - .then(() => []) - .catch(() => ovhClient.requestPromised("GET", `/hosting/web/${site}/attachedDomain`) // sites has issue do advance check - .then((domains) => Bluebird.map(domains, (domain) => hostingAdvanceCheck(ovhClient, site, domain, locale).catch(() => [])))) - )).then((responses) => _.flattenDeep(responses)); + .then((websites) => Bluebird.map(websites, (site) => request(`http://${site}`) + .then(() => []) + .catch(() => ovhClient.requestPromised("GET", `/hosting/web/${site}/attachedDomain`) // sites has issue do advance check + .then((domains) => Bluebird.map(domains, (domain) => hostingAdvanceCheck(ovhClient, site, domain, locale).catch(() => [])))) +)).then((responses) => _.flattenDeep(responses)); } function hostingAdvanceCheck (ovhClient, site, domain, locale) { @@ -103,7 +103,58 @@ function getSSLState (ovhClient, hosting) { function getDNSState (ovhClient, domain) { return Bluebird.props({ target: ovhClient.requestPromised("GET", `/domain/zone/${domain}/record`, { fieldType: "NS" }) - .then((ids) => Bluebird.mapSeries(ids, (id) => ovhClient.requestPromised("GET", `/domain/zone/${domain}/record/${id}`))), + .then((ids) => Bluebird.mapSeries(ids, (id) => ovhClient.requestPromised("GET", `/domain/zone/${domain}/record/${id}`))), real: ovhClient.requestPromised("GET", `/domain/zone/${domain}`) }); } + + +/** +When will my service expires ? +*/ +function getServicesExpires (ovhClient, locale, expiresPeriod) { + let services = ["/allDom", "/caas/containers", "/caas/registry", "/cdn/dedicated", "/cdn/website", + "/cdn/webstorage", "/cloud/project", "/cluster/hadoop", "/dbaas/logs", "/dbaas/queue", "/dbaas/timeseries", + "/dedicated/ceph", "/dedicated/housing", "/dedicated/nas", "/dedicated/nasha", "/dedicated/server", "/dedicatedCloud", + "/deskaas", "/domain", "/domain/zone", "/email/domain", "/email/pro", "/freefax", "/horizonView", "/hosting/privateDatabase", + "/hosting/reseller", "/hosting/web", "/hpcspot", "/ip/loadBalancing", "/ipLoadbalancing", "/license/cloudLinux", "/license/cpanel", + "/license/directadmin", "/license/office", "/license/plesk", "/license/sqlserver", "/license/virtuozzo", "/license/windows", "/license/worklight", + "/metrics", "/msServices/sharepoint", "/overTheBox", "/paas/database/", "/paas/monitoring", "/pack/siptrunk", "/pack/xdsl", "/router", "/saas/csp2", + "/sms", "/ssl", "/sslGateway", "/stack/mis", "/telephony", "/veeamCloudConnect", "/vps", "/xdsl", "/xdsl/spare"]; + + // TODO email/exchange + return Bluebird.all(services.map((service) => getServicesExpirationDate(ovhClient, service, expiresPeriod))) + .then((infoArray) => infoArray.map((serviceInfosArray) => { + if (serviceInfosArray.length) { + + let string = serviceInfosArray.map((info) => + translator(info.diff > 0 ? "serviceWillExpired" : "serviceHasExpired", locale, info.serviceName, info.status, Math.abs(info.diff), info.expireDate.toLocaleDateString(locale.replace("_", "-")))).join("\n"); + return new TextMessage(`${serviceInfosArray[0].baseUrl}:\n${string}`); + } + return null; + }).filter((element) => !!element)); +} + + +function getServicesExpirationDate (ovhClient, baseUrl, expiresPeriod) { + return ovhClient.requestPromised("GET", baseUrl) + .then((servicesNames) => Bluebird.mapSeries(servicesNames, (serviceName) => ovhClient.requestPromised("GET", `${baseUrl}/${serviceName}/serviceInfos`) + .then((serviceInfos) => { + let expireDate = new Date(serviceInfos.expiration); + let diff = Math.ceil((expireDate - new Date()) / (1000 * 3600 * 24)); // conversion to diff in days + if (diff <= expiresPeriod && serviceInfos.renewalType === "manual") { + return { + baseUrl, + serviceName, + diff, + expireDate: new Date(serviceInfos.expiration), + renewalType: serviceInfos.renewalType, + status: serviceInfos.status + }; + } + return null; + }).catch((err) => { + console.error(err, baseUrl, serviceName); + return null; + }))).then((infos) => infos.filter((info) => !!info)); +} diff --git a/models/users.model.js b/models/users.model.js index 715bf78..00596c7 100644 --- a/models/users.model.js +++ b/models/users.model.js @@ -46,6 +46,14 @@ const UserSchema = new mongoose.Schema({ updates: { type: Boolean, "default": false + }, + expires: { + type: Boolean, + "default": false + }, + expiresPeriod: { + type: Number, + "default": 14 } }); diff --git a/platforms/generics.js b/platforms/generics.js index 15e5b50..c44d006 100644 --- a/platforms/generics.js +++ b/platforms/generics.js @@ -90,7 +90,7 @@ function createFeedback (intent, messageRaw, locale) { new Button(BUTTON_TYPE.POSTBACK, `FEEDBACK_BAD_${camelCase(intent)}_${message}`, translator("feedbackNo", locale)), new Button(BUTTON_TYPE.POSTBACK, `FEEDBACK_GOOD_${camelCase(intent)}_${message}`, translator("feedbackYes", locale)) ]; - return new ButtonsListMessage(translator("feedbackHelp", locale), buttons); + return new ButtonsMessage(translator("feedbackHelp", locale), buttons); } module.exports = { diff --git a/translations/translation_fr_FR.json b/translations/translation_fr_FR.json index b5f04ee..15465dc 100644 --- a/translations/translation_fr_FR.json +++ b/translations/translation_fr_FR.json @@ -21,6 +21,7 @@ "domainEditDns": "Tu dois modifier la zone DNS de ton domaine afin d'y ajouter le champ A avec l'IP de ton hébergement web, cette IP se trouve sur la page d'informations de ton hébergement dans l'espace client OVH.", "disconnected": "Tu n'es pas correctement connecté à ton compte OVH :( , il te suffit de me demander 'connecte-moi' pour te reconnecter.", "dnsEditDns": "Tu peux modifier tes serveurs via l'espace client OVH", + "expires-allOk": "Rien n'est sur le point d'expiré :+1:", "feedbackBadUnderstanding": "Mauvaise compréhension", "feedbackHelp": "Est-ce que cette réponse t'a aidé ?", "feedbackNo": "Non", @@ -53,6 +54,8 @@ "moreButton": "Voir plus (%s)", "on": "Activé", "off": "Desactivé", + "serviceHasExpired": "Le service \"%1$s\" (état actuel: %2$s) est expiré depuis %3$s jour(s) (%4$s)", + "serviceWillExpired": "Le service \"%1$s\" (état actuel: %2$s) va expiré dans %3$s jour(s) (%4$s)", "signIn": "Se connecter à son compte OVH :link:", "signInFirst": ":warning: Tu dois d'abord te connecter. Pour ce faire tu peux me le demander", "slackAuthor": "Assistant personnel OVH", @@ -96,6 +99,10 @@ "hosting-unknown": "Problème non diagnostiquable. :thinking_face:", "settings-updates-true": "La notification lors d'incidents est activé.", "settings-updates-false": "La notification lors d'incidents est desactivé.", + "settings-expires-true": "La notification lors de l'arrivé à expiration de service est activé. Tu vas etre informé %s jour(s) en avance", + "settings-expires-false": "La notification lors de l'arrivé à expiration de service est desactivé", + "settings-expires-edit": "Changer la periode de notification", + "settings-expires-period": "%s jour(s)", "telephony-accountClosed": "Ton compte est clôturé :cry:", "telephony-accountDeleted": "Ton compte a été supprimé :cry:", "telephony-accountExpired": "Ton compte est expiré :cry:", From 32dde248f6f412e5948a05bfeb8b49efe9ed946a Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Mon, 21 Aug 2017 16:48:20 +0200 Subject: [PATCH 04/23] :ambulance: fix(cron): fix request-promise was not a node_module --- diagnostics/cron.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/diagnostics/cron.js b/diagnostics/cron.js index 644d7d1..6868628 100644 --- a/diagnostics/cron.js +++ b/diagnostics/cron.js @@ -8,7 +8,7 @@ const { TextMessage } = require("../platforms/generics"); const translator = require("../utils/translator"); const messenger = require("../platforms/messenger/messenger"); const slack = require("../platforms/slack/slack"); -const request = require("request-promise"); +const request = require("request"); const hostingDiagnostics = require("./hosting"); const cron = require("node-cron"); const _ = require("lodash"); @@ -74,7 +74,7 @@ function getXdslStatus (ovhClient) { function getHostingStatus (ovhClient, locale) { return ovhClient.requestPromised("GET", "/hosting/web/") - .then((websites) => Bluebird.map(websites, (site) => request(`http://${site}`) + .then((websites) => Bluebird.map(websites, (site) => new Bluebird((resolve, reject) => request(`http://${site}`, (err) => err ? reject() : resolve())) .then(() => []) .catch(() => ovhClient.requestPromised("GET", `/hosting/web/${site}/attachedDomain`) // sites has issue do advance check .then((domains) => Bluebird.map(domains, (domain) => hostingAdvanceCheck(ovhClient, site, domain, locale).catch(() => [])))) From 0d6da79d49edf51173371e3871d4ff142cab67dc Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Mon, 21 Aug 2017 17:06:43 +0200 Subject: [PATCH 05/23] :ambulance: fix(controller/slack): fix locale missing for feedback --- controllers/slack.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/controllers/slack.js b/controllers/slack.js index 29eca32..55b9d77 100644 --- a/controllers/slack.js +++ b/controllers/slack.js @@ -61,7 +61,7 @@ module.exports = () => ({ quickResponses = [{ speech: apiaiResponse.result.fulfillment.speech, type: 0 }]; } - return sendQuickResponses(res, channel, quickResponses, slack).then(() => sendFeedback(res, channel, apiaiResponse.result.action, message, slack)); + return sendQuickResponses(res, channel, quickResponses, slack).then(() => sendFeedback(res, channel, apiaiResponse.result.action, message, slack, locale)); } return bot @@ -73,7 +73,7 @@ module.exports = () => ({ }) .then(() => { if (needFeedback) { - return sendFeedback(res, channel, apiaiResponse.result.action, message, slack); + return sendFeedback(res, channel, apiaiResponse.result.action, message, slack, locale); } return null; }) @@ -97,16 +97,19 @@ module.exports = () => ({ const message_ts = payload.message_ts; let slackClient; let needFeedback = false; + let locale; // We have to respond with a 200 within 3000ms Bluebird.delay(2000).then(() => res.headersSent ? null : res.status(200).end()); return getUserLocale(channel) - .then((locale) => - Bluebird.props({ + .then((localeLocal) => { + locale = localeLocal; + return Bluebird.props({ botResut: bot.ask("postback", channel, value, "", {}, res, locale), slackClient: slackSDK(payload.team.id) - })) + }); + }) .then(({ botResut, slackClientLocal }) => { slackClient = slackClientLocal; needFeedback = botResut.feedback || needFeedback; @@ -116,7 +119,7 @@ module.exports = () => ({ .then(() => res.headersSent ? null : res.status(200).end()) .then(() => { if (needFeedback) { - return sendFeedback(res, channel, value, "message", slackClient); + return sendFeedback(res, channel, value, "message", slackClient, locale); } return null; From 1b416e28eb6ef38eb7252a5aa60e4af8a42943c4 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Mon, 21 Aug 2017 17:06:43 +0200 Subject: [PATCH 06/23] :ambulance: fix(controller/slack): fix locale missing for feedback --- controllers/slack.js | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/controllers/slack.js b/controllers/slack.js index 29eca32..e70ae61 100644 --- a/controllers/slack.js +++ b/controllers/slack.js @@ -61,7 +61,7 @@ module.exports = () => ({ quickResponses = [{ speech: apiaiResponse.result.fulfillment.speech, type: 0 }]; } - return sendQuickResponses(res, channel, quickResponses, slack).then(() => sendFeedback(res, channel, apiaiResponse.result.action, message, slack)); + return sendQuickResponses(res, channel, quickResponses, slack).then(() => sendFeedback(res, channel, apiaiResponse.result.action, message, slack, locale)); } return bot @@ -69,11 +69,11 @@ module.exports = () => ({ .then((answer) => { needFeedback = answer.feedback || needFeedback; - return sendResponses(res, channel, answer.responses, slack); + return sendResponses(res, channel, answer.responses, slack, locale); }) .then(() => { if (needFeedback) { - return sendFeedback(res, channel, apiaiResponse.result.action, message, slack); + return sendFeedback(res, channel, apiaiResponse.result.action, message, slack, locale); } return null; }) @@ -97,26 +97,29 @@ module.exports = () => ({ const message_ts = payload.message_ts; let slackClient; let needFeedback = false; + let locale; // We have to respond with a 200 within 3000ms Bluebird.delay(2000).then(() => res.headersSent ? null : res.status(200).end()); return getUserLocale(channel) - .then((locale) => - Bluebird.props({ + .then((localeLocal) => { + locale = localeLocal; + return Bluebird.props({ botResut: bot.ask("postback", channel, value, "", {}, res, locale), slackClient: slackSDK(payload.team.id) - })) + }); + }) .then(({ botResut, slackClientLocal }) => { slackClient = slackClientLocal; needFeedback = botResut.feedback || needFeedback; - return sendResponses(res, channel, botResut.responses, slackClient, message_ts); + return sendResponses(res, channel, botResut.responses, slackClient, message_ts, locale); }) .then(() => res.headersSent ? null : res.status(200).end()) .then(() => { if (needFeedback) { - return sendFeedback(res, channel, value, "message", slackClient); + return sendFeedback(res, channel, value, "message", slackClient, locale); } return null; @@ -166,27 +169,27 @@ module.exports = () => ({ }); function sendFeedback (res, senderId, intent, messageRaw, slack, locale) { - return sendResponse(res, senderId, createFeedback(intent, messageRaw, locale), slack); + return sendResponse(res, senderId, createFeedback(intent, messageRaw, locale), slack, locale); } -function sendQuickResponses (res, senderId, responses, slack) { +function sendQuickResponses (res, senderId, responses, slack, locale) { return Bluebird.mapSeries(responses, (response) => { switch (response.type) { case 0: - return sendResponse(res, senderId, response.speech, slack); + return sendResponse(res, senderId, response.speech, slack, null, locale); default: - return sendResponse(res, senderId, response.speech, slack); + return sendResponse(res, senderId, response.speech, slack, null, locale); } }); } -function sendResponses (res, channel, responses, slack, message_ts) { +function sendResponses (res, channel, responses, slack, message_ts, locale) { return Bluebird.mapSeries(responses, (response, index) => Bluebird.resolve(response) - .then((resp) => Array.isArray(resp) ? sendResponses(res, channel, resp, slack, message_ts) : sendResponse(res, channel, resp, slack, index === 0 ? message_ts : null))); + .then((resp) => Array.isArray(resp) ? sendResponses(res, channel, resp, slack, message_ts, locale) : sendResponse(res, channel, resp, slack, index === 0 ? message_ts : null, locale))); } -function sendResponse (res, channel, response, slack, message_ts) { - return slack.send(channel, response, message_ts) +function sendResponse (res, channel, response, slack, message_ts, locale) { + return slack.send(channel, response, message_ts, locale) .then((result) => !result.ok ? logger.error(`failed sending: ${response} to ${channel}, code: ${result.error}`) : logger.debug(`Sucessfully sent ${result.ts} to ${result.channel}`)); } From a34d1aa7a32873e0060455ccd4eb533fd14e632e Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Tue, 22 Aug 2017 11:01:11 +0200 Subject: [PATCH 07/23] :ambulance: fix(platforms): fix reaching message length limit --- bots/messageTypes/postback/settings.js | 2 +- controllers/slack.js | 2 +- diagnostics/cron.js | 44 ++++++++++++++++++++++---- index.js | 4 +-- platforms/messenger/messenger.js | 13 ++++++-- translations/translation_fr_FR.json | 6 ++-- 6 files changed, 56 insertions(+), 15 deletions(-) diff --git a/bots/messageTypes/postback/settings.js b/bots/messageTypes/postback/settings.js index f289657..3ef96d4 100644 --- a/bots/messageTypes/postback/settings.js +++ b/bots/messageTypes/postback/settings.js @@ -38,7 +38,7 @@ module.exports = [ return Users.findOne({ senderId }).exec() .then((user) => { - let buttons = days.map((day) => new Button(BUTTON_TYPE.POSTBACK, `SETTINGS_EXPIRES_${days}`, translator("settings-expires-period", locale, day))); + let buttons = days.map((day) => new Button(BUTTON_TYPE.POSTBACK, `SETTINGS_EXPIRES_${day}`, translator("settings-expires-period", locale, day))); return { responses: [new ButtonsListMessage(translator("settings-expires-true", locale, user.expiresPeriod), buttons)], feedback: false }; }); diff --git a/controllers/slack.js b/controllers/slack.js index eb13e39..eecf439 100644 --- a/controllers/slack.js +++ b/controllers/slack.js @@ -191,5 +191,5 @@ function sendResponses (res, channel, responses, slack, message_ts, locale) { function sendResponse (res, channel, response, slack, message_ts, locale) { return slack.send(channel, response, message_ts, locale) - .then((result) => !result.ok ? logger.error(`failed sending: ${response} to ${channel}, code: ${result.error}`) : logger.debug(`Sucessfully sent ${result.ts} to ${result.channel}`)); + .then((result) => !result.ok ? logger.error(`failed channel: ${channel}, code: ${result.error}`) : logger.debug(`Sucessfully sent ${result.ts} to ${result.channel}`)); } diff --git a/diagnostics/cron.js b/diagnostics/cron.js index 6868628..5cda705 100644 --- a/diagnostics/cron.js +++ b/diagnostics/cron.js @@ -13,20 +13,50 @@ const hostingDiagnostics = require("./hosting"); const cron = require("node-cron"); const _ = require("lodash"); const logger = require("../providers/logging/logger"); +const ovh = require("../utils/ovh"); module.exports = { getServicesStatus, - getServicesExpires + getServicesExpires, + tasks: [cron.schedule("0 */2 * * *", performStatusUpdate, false), cron.schedule("0 2 * * *", performExpiresUpdate, false)] }; -cron.schedule("0 */2 * * *", performUpdate, false); -function performUpdate () { +performStatusUpdate(); +performExpiresUpdate(); + +function performStatusUpdate () { logger.info("Status update:", new Date()); - Users.find({ updates: true }).then((users) => Bluebird.map(users, (user) => getServicesExpires(user.senderId, user.platform).then((resp) => send(user.senderId, user.platform, resp)))) - .then(() => logger.info("Status update done")); + Users.find({ updates: true }) + .then((users) => + Bluebird.mapSeries(users, (user) => { + let ovhClient; + return ovh.getOvhClient(user.senderId) + .then((ovhClientLocale) => { + ovhClient = ovhClientLocale; + return ovhClient.requestPromised("GET", "/me"); + }) + .then((meInfos) => getServicesStatus(ovhClient, meInfos.language)) + .then((resp) => send(user.senderId, user.platform, resp)); + })) + .then(() => logger.info("Status update done")); } -// performUpdate(); +function performExpiresUpdate () { + logger.info("Expires update:", new Date()); + Users.find({ expires: true }) + .then((users) => + Bluebird.mapSeries(users, (user) => { + let ovhClient; + return ovh.getOvhClient(user.senderId) + .then((ovhClientLocale) => { + ovhClient = ovhClientLocale; + return ovhClient.requestPromised("GET", "/me"); + }) + .then((meInfos) => getServicesExpires(ovhClient, meInfos.language, user.expiresPeriod)) + .then((resp) => send(user.senderId, user.platform, resp)); + })) + .then(() => logger.info("Expires update done")); +} /** what is my service status ? @@ -128,7 +158,7 @@ function getServicesExpires (ovhClient, locale, expiresPeriod) { if (serviceInfosArray.length) { let string = serviceInfosArray.map((info) => - translator(info.diff > 0 ? "serviceWillExpired" : "serviceHasExpired", locale, info.serviceName, info.status, Math.abs(info.diff), info.expireDate.toLocaleDateString(locale.replace("_", "-")))).join("\n"); + translator(info.diff > 0 ? "serviceWillExpired" : "serviceHasExpired", locale, info.serviceName, translator(`service-${info.status}`, locale), Math.abs(info.diff), info.expireDate.toLocaleDateString(locale.replace("_", "-")))).join("\n"); return new TextMessage(`${serviceInfosArray[0].baseUrl}:\n${string}`); } return null; diff --git a/index.js b/index.js index de95689..66d23b1 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,7 @@ const http = require("http"); const app = exports.app = require("./config/express")(config); const port = config.server.port; const logger = require("./providers/logging/logger"); -const task = require("./diagnostics/cron"); +const { tasks } = require("./diagnostics/cron"); let httpserver; @@ -16,7 +16,7 @@ if (require.main === module) { process.on("SIGTERM", () => { logger.info("SIGTERM Signal received, trying to close connections..."); - task.destroy(); + tasks.forEach((task) => task.destroy()); process.env.NODE_IS_CLOSING = "true"; httpserver.close(() => { diff --git a/platforms/messenger/messenger.js b/platforms/messenger/messenger.js index a16910e..20a73d1 100644 --- a/platforms/messenger/messenger.js +++ b/platforms/messenger/messenger.js @@ -322,7 +322,7 @@ function sendButtonMessage (recipientId, buttonMessage) { } }; - sendMessageToAPI(messageData); + return sendMessageToAPI(messageData); } /* @@ -453,7 +453,7 @@ function sendQuickReply (recipientId, message) { message }; - sendMessageToAPI(messageData); + return sendMessageToAPI(messageData); } /* @@ -537,11 +537,20 @@ function sendQuickReply (recipientId, message) { function send (recipientId, message) { + const regx = /^([\S\s]{0,640})(?:\n|[.,]\s)([\S\s]*$)/g; // Regex for "smart" splitting (str.length limit is 640) if (typeof message === "string") { + if (message.length > 640) { + let matchs = regx.exec(message); + return send(recipientId, matchs[1]).then(() => send(recipientId, matchs[2])); + } return sendTextMessage(recipientId, emojify(message)); } if (message instanceof TextMessage) { + if (message.text.length > 640) { + let matchs = regx.exec(message.text); + return send(recipientId, matchs[1]).then(() => send(recipientId, matchs[2])); + } return sendTextMessage(recipientId, textMessageAdapter(message)); } diff --git a/translations/translation_fr_FR.json b/translations/translation_fr_FR.json index ec5b36b..8875eff 100644 --- a/translations/translation_fr_FR.json +++ b/translations/translation_fr_FR.json @@ -54,8 +54,10 @@ "moreButton": "Voir plus (%s)", "on": "Activé", "off": "Desactivé", - "serviceHasExpired": "Le service \"%1$s\" (état actuel: %2$s) est expiré depuis %3$s jour(s) (%4$s)", - "serviceWillExpired": "Le service \"%1$s\" (état actuel: %2$s) va expiré dans %3$s jour(s) (%4$s)", + "serviceHasExpired": "\t- Le service \"%1$s\" (état actuel: %2$s) est expiré depuis %3$s jour(s) (%4$s)", + "serviceWillExpired": "\t- Le service \"%1$s\" (état actuel: %2$s) va expiré dans %3$s jour(s) (%4$s)", + "service-ok": "En fonctionement", + "service-expired": "Expiré", "signIn": "Se connecter à son compte OVH :link:", "signInFirst": ":warning: Tu dois d'abord te connecter. Pour ce faire tu peux me le demander", "slackAuthor": "Assistant personnel OVH", From 0f5504117e95c4b9fa75b56160db7143de082f80 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 23 Aug 2017 09:08:24 +0200 Subject: [PATCH 08/23] :lipstick: style(cron): add /email/exchange + perf --- diagnostics/cron.js | 74 ++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/diagnostics/cron.js b/diagnostics/cron.js index 5cda705..5b30934 100644 --- a/diagnostics/cron.js +++ b/diagnostics/cron.js @@ -18,13 +18,11 @@ const ovh = require("../utils/ovh"); module.exports = { getServicesStatus, getServicesExpires, - tasks: [cron.schedule("0 */2 * * *", performStatusUpdate, false), cron.schedule("0 2 * * *", performExpiresUpdate, false)] + tasks: [cron.schedule("0 */2 * * *", performStatusUpdate, true), cron.schedule("0 2 * * *", performExpiresUpdate, true)] }; -performStatusUpdate(); -performExpiresUpdate(); - function performStatusUpdate () { + let now = Date.now(); logger.info("Status update:", new Date()); Users.find({ updates: true }) .then((users) => @@ -36,12 +34,14 @@ function performStatusUpdate () { return ovhClient.requestPromised("GET", "/me"); }) .then((meInfos) => getServicesStatus(ovhClient, meInfos.language)) - .then((resp) => send(user.senderId, user.platform, resp)); + .then((resp) => send(user.senderId, user.platform, resp)) + .then(() => logger.debug("Status update done for user %s, platform: %s", user.senderId, user.platform)); })) - .then(() => logger.info("Status update done")); + .then(() => logger.info("Status update done, took %d seconds", (Date.now() - now) / 1000)); } function performExpiresUpdate () { + let now = Date.now(); logger.info("Expires update:", new Date()); Users.find({ expires: true }) .then((users) => @@ -53,9 +53,10 @@ function performExpiresUpdate () { return ovhClient.requestPromised("GET", "/me"); }) .then((meInfos) => getServicesExpires(ovhClient, meInfos.language, user.expiresPeriod)) - .then((resp) => send(user.senderId, user.platform, resp)); + .then((resp) => send(user.senderId, user.platform, resp)) + .then(() => logger.debug("Expires update done for user %s, platform: %s", user.senderId, user.platform)); })) - .then(() => logger.info("Expires update done")); + .then(() => logger.info("Expires update done, took %d seconds", (Date.now() - now) / 1000)); } /** @@ -104,11 +105,12 @@ function getXdslStatus (ovhClient) { function getHostingStatus (ovhClient, locale) { return ovhClient.requestPromised("GET", "/hosting/web/") - .then((websites) => Bluebird.map(websites, (site) => new Bluebird((resolve, reject) => request(`http://${site}`, (err) => err ? reject() : resolve())) - .then(() => []) - .catch(() => ovhClient.requestPromised("GET", `/hosting/web/${site}/attachedDomain`) // sites has issue do advance check - .then((domains) => Bluebird.map(domains, (domain) => hostingAdvanceCheck(ovhClient, site, domain, locale).catch(() => [])))) -)).then((responses) => _.flattenDeep(responses)); + .then((websites) => Bluebird.all(websites.map((site) => new Bluebird((resolve, reject) => request(`http://${site}`, (err) => err ? reject() : resolve())) + .then(() => []) + .catch(() => ovhClient.requestPromised("GET", `/hosting/web/${site}/attachedDomain`) // sites has issue do advance check + .then((domains) => Bluebird.all(domains.map((domain) => hostingAdvanceCheck(ovhClient, site, domain, locale).catch(() => []))))) + ))) + .then((responses) => _.flattenDeep(responses)); } function hostingAdvanceCheck (ovhClient, site, domain, locale) { @@ -152,11 +154,12 @@ function getServicesExpires (ovhClient, locale, expiresPeriod) { "/metrics", "/msServices/sharepoint", "/overTheBox", "/paas/database/", "/paas/monitoring", "/pack/siptrunk", "/pack/xdsl", "/router", "/saas/csp2", "/sms", "/ssl", "/sslGateway", "/stack/mis", "/telephony", "/veeamCloudConnect", "/vps", "/xdsl", "/xdsl/spare"]; - // TODO email/exchange - return Bluebird.all(services.map((service) => getServicesExpirationDate(ovhClient, service, expiresPeriod))) + return ovhClient.requestPromised("GET", "/email/exchange") + .then((orgNames) => orgNames.map((name) => `/email/exchange/${name}/service`)) + .then((exchanges) => [...services, ...exchanges]) + .then((serviceArray) => Bluebird.all(serviceArray.map((service) => getServicesExpirationDate(ovhClient, service, expiresPeriod)))) .then((infoArray) => infoArray.map((serviceInfosArray) => { if (serviceInfosArray.length) { - let string = serviceInfosArray.map((info) => translator(info.diff > 0 ? "serviceWillExpired" : "serviceHasExpired", locale, info.serviceName, translator(`service-${info.status}`, locale), Math.abs(info.diff), info.expireDate.toLocaleDateString(locale.replace("_", "-")))).join("\n"); return new TextMessage(`${serviceInfosArray[0].baseUrl}:\n${string}`); @@ -168,23 +171,24 @@ function getServicesExpires (ovhClient, locale, expiresPeriod) { function getServicesExpirationDate (ovhClient, baseUrl, expiresPeriod) { return ovhClient.requestPromised("GET", baseUrl) - .then((servicesNames) => Bluebird.mapSeries(servicesNames, (serviceName) => ovhClient.requestPromised("GET", `${baseUrl}/${serviceName}/serviceInfos`) - .then((serviceInfos) => { - let expireDate = new Date(serviceInfos.expiration); - let diff = Math.ceil((expireDate - new Date()) / (1000 * 3600 * 24)); // conversion to diff in days - if (diff <= expiresPeriod && serviceInfos.renewalType === "manual") { - return { - baseUrl, - serviceName, - diff, - expireDate: new Date(serviceInfos.expiration), - renewalType: serviceInfos.renewalType, - status: serviceInfos.status - }; - } - return null; - }).catch((err) => { - logger.error(err, baseUrl, serviceName); - return null; - }))).then((infos) => infos.filter((info) => !!info)); + .then((servicesNames) => Bluebird.all(servicesNames.map((serviceName) => + ovhClient.requestPromised("GET", `${baseUrl}/${serviceName}/serviceInfos`) + .then((serviceInfos) => { + let expireDate = new Date(serviceInfos.expiration); + let diff = Math.ceil((expireDate - new Date()) / (1000 * 3600 * 24)); // conversion to diff in days + if (diff <= expiresPeriod && serviceInfos.renewalType === "manual") { + return { + baseUrl, + serviceName, + diff, + expireDate: new Date(serviceInfos.expiration), + renewalType: serviceInfos.renewalType, + status: serviceInfos.status + }; + } + return null; + }).catch((err) => logger.error(err, baseUrl, serviceName)) + ))) + .then((infos) => infos.filter((info) => !!info)) + .catch((err) => logger.error(err, baseUrl)); } From dd734254479799b90f67ee7efd1719a6001d8b8e Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 23 Aug 2017 09:44:33 +0200 Subject: [PATCH 09/23] fix(slack): fix locale and message_ts failing to send --- controllers/slack.js | 26 +++++++++++++++++--------- diagnostics/cron.js | 1 - platforms/slack/slack.js | 6 +++--- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/controllers/slack.js b/controllers/slack.js index eecf439..5ef6b9a 100644 --- a/controllers/slack.js +++ b/controllers/slack.js @@ -48,8 +48,8 @@ module.exports = () => ({ if (apiaiResponse.status && apiaiResponse.status.code === 200 && apiaiResponse.result) { if (apiaiResponse.result.action === "connection" || apiaiResponse.result.action === "welcome") { const accountLinkButton = new Button(BUTTON_TYPE.URL, `${config.server.url}${config.server.basePath}/authorize?state=${channel}-slack-${req.body.team_id}`, translator("signIn", locale)); - return sendResponse(res, channel, new TextMessage(translator("welcome", locale)), slack) - .then(() => sendResponse(res, channel, new ButtonsListMessage("", [accountLinkButton]), slack)); + return sendResponse(res, channel, new TextMessage(translator("welcome", locale)), slack, locale) + .then(() => sendResponse(res, channel, new ButtonsListMessage("", [accountLinkButton]), slack, locale)); } if (apiaiResponse.result.fulfillment && apiaiResponse.result.fulfillment.speech && Array.isArray(apiaiResponse.result.fulfillment.messages) && apiaiResponse.result.fulfillment.messages.length) { @@ -61,7 +61,7 @@ module.exports = () => ({ quickResponses = [{ speech: apiaiResponse.result.fulfillment.speech, type: 0 }]; } - return sendQuickResponses(res, channel, quickResponses, slack).then(() => sendFeedback(res, channel, apiaiResponse.result.action, message, slack, locale)); + return sendQuickResponses(res, channel, quickResponses, slack, locale).then(() => sendFeedback(res, channel, apiaiResponse.result.action, message, slack, locale)); } return bot @@ -83,7 +83,7 @@ module.exports = () => ({ }); } - return slack.send(channel, translator("noIntent", locale)); + return sendResponse(null, channel, translator("noIntent", locale), slack, locale); }) .catch(res.logger.error); @@ -176,9 +176,9 @@ function sendQuickResponses (res, senderId, responses, slack, locale) { return Bluebird.mapSeries(responses, (response) => { switch (response.type) { case 0: - return sendResponse(res, senderId, response.speech, slack, null, locale); + return sendResponse(res, senderId, response.speech, slack, locale); default: - return sendResponse(res, senderId, response.speech, slack, null, locale); + return sendResponse(res, senderId, response.speech, slack, locale); } }); } @@ -186,10 +186,18 @@ function sendQuickResponses (res, senderId, responses, slack, locale) { function sendResponses (res, channel, responses, slack, message_ts, locale) { return Bluebird.mapSeries(responses, (response, index) => Bluebird.resolve(response) - .then((resp) => Array.isArray(resp) ? sendResponses(res, channel, resp, slack, message_ts, locale) : sendResponse(res, channel, resp, slack, index === 0 ? message_ts : null, locale))); + .then((resp) => Array.isArray(resp) ? sendResponses(res, channel, resp, slack, index === 0 ? message_ts : undefined, locale) : sendResponse(res, channel, resp, slack, index === 0 ? message_ts : undefined, locale))); } -function sendResponse (res, channel, response, slack, message_ts, locale) { +function sendResponse (res, channel, response, slack, message_ts_raw, locale_raw) { + let locale = locale_raw; + let message_ts = message_ts_raw; + + if (!locale_raw) { + locale = message_ts_raw; + message_ts = undefined; + } return slack.send(channel, response, message_ts, locale) - .then((result) => !result.ok ? logger.error(`failed channel: ${channel}, code: ${result.error}`) : logger.debug(`Sucessfully sent ${result.ts} to ${result.channel}`)); + .then((result) => !result.ok ? logger.error(`failed sending to channel: ${channel}, error: ${result.error || result}`) : logger.debug(`Sucessfully sent ${result.ts} to ${result.channel}`)) + .catch(logger.error); } diff --git a/diagnostics/cron.js b/diagnostics/cron.js index 5b30934..51003f2 100644 --- a/diagnostics/cron.js +++ b/diagnostics/cron.js @@ -2,7 +2,6 @@ const Users = require("../models/users.model"); -// const utils = require("../utils/ovh"); const Bluebird = require("bluebird"); const { TextMessage } = require("../platforms/generics"); const translator = require("../utils/translator"); diff --git a/platforms/slack/slack.js b/platforms/slack/slack.js index c7d48e6..3b0d751 100644 --- a/platforms/slack/slack.js +++ b/platforms/slack/slack.js @@ -12,13 +12,13 @@ function getSlackApi (team_id) { return SlackModel.findOne({ team_id }).exec().then((slackInfos) => { const slack = Bluebird.promisifyAll(new Slack(slackInfos.bot.bot_access_token)); - slack.send = (channel, message, message_ts = null, locale) => { + slack.send = (channel, message, message_ts, locale) => { if (typeof message === "string" || message instanceof TextMessage) { - return slack.apiAsync(message_ts != null ? UPDATE_MESSAGE : POST_MESSAGE, textMessageAdapter(channel, message, message_ts, locale)); + return slack.apiAsync(message_ts ? UPDATE_MESSAGE : POST_MESSAGE, textMessageAdapter(channel, message, message_ts, locale)); } if (message instanceof ButtonsListMessage || message instanceof ButtonsMessage) { - return slack.apiAsync(message_ts != null ? UPDATE_MESSAGE : POST_MESSAGE, buttonsMessageAdapter(channel, message, message_ts, locale)); + return slack.apiAsync(message_ts ? UPDATE_MESSAGE : POST_MESSAGE, buttonsMessageAdapter(channel, message, message_ts, locale)); } return slack.apiAsync(POST_MESSAGE, message); From d8d45d1ff2bf7cae05160da74436004a09345174 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 23 Aug 2017 11:28:33 +0200 Subject: [PATCH 10/23] :lipstick: style(cron): beautify display --- bots/messageTypes/message/service_expires.js | 2 +- bots/messageTypes/postback/settings.js | 8 +++---- diagnostics/cron.js | 2 +- translations/translation_fr_FR.json | 23 +++++++++++--------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/bots/messageTypes/message/service_expires.js b/bots/messageTypes/message/service_expires.js index ab99f05..7aa4613 100644 --- a/bots/messageTypes/message/service_expires.js +++ b/bots/messageTypes/message/service_expires.js @@ -28,7 +28,7 @@ class ServiceExpires { let buttons = [ new Button(BUTTON_TYPE.POSTBACK, "SETTINGS_EXPIRES_true", translator("on", locale)), new Button(BUTTON_TYPE.POSTBACK, "SETTINGS_EXPIRES_false", translator("off", locale)), - new Button(BUTTON_TYPE.POSTBACK, "SETTINGS_EXPIRES_edit", translator("settings-expires-edit", locale)) + new Button(BUTTON_TYPE.POSTBACK, "SETTINGS_EXPIRES_edit", translator("preferences", locale)) ]; responses.push(new ButtonsMessage(translator(`settings-expires-${user.expires}`, locale, user.expiresPeriod), buttons)); } diff --git a/bots/messageTypes/postback/settings.js b/bots/messageTypes/postback/settings.js index 3ef96d4..29fdca6 100644 --- a/bots/messageTypes/postback/settings.js +++ b/bots/messageTypes/postback/settings.js @@ -26,7 +26,7 @@ module.exports = [ .then((user) => { user.expiresPeriod = period; return user.save(); - }).then(() => ({ responses: [new TextMessage(translator("settings-expires-true", locale, period))], feedback: false })); + }).then(() => ({ responses: [new TextMessage(translator("settings-expires-period", locale, period))], feedback: false })); } @@ -34,13 +34,13 @@ module.exports = [ { regx: "SETTINGS_EXPIRES_edit", action (senderId, postback, regx, entities, res, locale) { - const days = [1, 7, 14, 30, 60]; + const days = [2, 7, 14, 30, 60]; return Users.findOne({ senderId }).exec() .then((user) => { - let buttons = days.map((day) => new Button(BUTTON_TYPE.POSTBACK, `SETTINGS_EXPIRES_${day}`, translator("settings-expires-period", locale, day))); + let buttons = days.map((day) => new Button(BUTTON_TYPE.POSTBACK, `SETTINGS_EXPIRES_${day}`, translator("settings-expires-days", locale, day))); - return { responses: [new ButtonsListMessage(translator("settings-expires-true", locale, user.expiresPeriod), buttons)], feedback: false }; + return { responses: [new ButtonsListMessage(translator("settings-expires-edit", locale, user.expiresPeriod), buttons)], feedback: false }; }); } }, diff --git a/diagnostics/cron.js b/diagnostics/cron.js index 51003f2..741c73c 100644 --- a/diagnostics/cron.js +++ b/diagnostics/cron.js @@ -161,7 +161,7 @@ function getServicesExpires (ovhClient, locale, expiresPeriod) { if (serviceInfosArray.length) { let string = serviceInfosArray.map((info) => translator(info.diff > 0 ? "serviceWillExpired" : "serviceHasExpired", locale, info.serviceName, translator(`service-${info.status}`, locale), Math.abs(info.diff), info.expireDate.toLocaleDateString(locale.replace("_", "-")))).join("\n"); - return new TextMessage(`${serviceInfosArray[0].baseUrl}:\n${string}`); + return new TextMessage(translator("serviceInfo", locale, serviceInfosArray[0].baseUrl, string)); } return null; }).filter((element) => !!element)); diff --git a/translations/translation_fr_FR.json b/translations/translation_fr_FR.json index 8875eff..1270e0e 100644 --- a/translations/translation_fr_FR.json +++ b/translations/translation_fr_FR.json @@ -16,11 +16,11 @@ "guides-modifDns": "https://docs.ovh.com/fr/fr/web/domains/editer-ma-zone-dns/#modification-de-votre-zone-dns", "guides-modifDnsServer": "https://docs.ovh.com/fr/fr/web/domains/generalites-serveurs-dns/#modification-de-vos-serveurs-dns", "guides-homeLabs": "https://www.ovh.com/manager/sunrise/uxlabs/#!/chatbot", - "allOk": "Tout est ok :+1:", + "allOk": "Tout est ok :tada:", "connectedAs": "Tu es connecté en tant que %s :ok_hand:", "domainEditDns": "Tu dois modifier la zone DNS de ton domaine afin d'y ajouter le champ A avec l'IP de ton hébergement web, cette IP se trouve sur la page d'informations de ton hébergement dans l'espace client OVH.", "disconnected": "Tu n'es pas correctement connecté à ton compte OVH :( , il te suffit de me demander 'connecte-moi' pour te reconnecter.", - "expires-allOk": "Rien n'est sur le point d'expiré :+1:", + "expires-allOk": "Rien n'est sur le point d'expiré :tada:", "dnsEditDns": "Tu peux modifier tes serveurs DNS via l'espace client OVH", "feedbackBadUnderstanding": "Mauvaise compréhension", "feedbackHelp": "Est-ce que cette réponse t'a aidé ?", @@ -54,8 +54,10 @@ "moreButton": "Voir plus (%s)", "on": "Activé", "off": "Desactivé", - "serviceHasExpired": "\t- Le service \"%1$s\" (état actuel: %2$s) est expiré depuis %3$s jour(s) (%4$s)", - "serviceWillExpired": "\t- Le service \"%1$s\" (état actuel: %2$s) va expiré dans %3$s jour(s) (%4$s)", + "preferences": "Préférences", + "serviceInfo": ":pushpin: %1$s:\n%2$s", + "serviceHasExpired": "\t• Le service \"%1$s\" (état actuel: %2$s) est expiré depuis %3$s jour(s) (%4$s)", + "serviceWillExpired": "\t• Le service \"%1$s\" (état actuel: %2$s) va expiré dans %3$s jour(s) (%4$s)", "service-ok": "En fonctionement", "service-expired": "Expiré", "signIn": "Se connecter à son compte OVH :link:", @@ -99,12 +101,13 @@ "hosting-web500db": "Ton site n'arrive pas à se connecter à la base de données, je te conseille de vérifier le login et mot de passe de la base de données.", "hosting-web500dev": "Il semblerait que tu aies fait une erreur de programmation sur ton site web. Dans ce genre de situation le support OVH n'intervient pas.", "hosting-unknown": "Problème non diagnostiquable. :thinking_face:", - "settings-updates-true": "La notification lors d'incidents est activé.", - "settings-updates-false": "La notification lors d'incidents est desactivé.", - "settings-expires-true": "La notification lors de l'arrivé à expiration de service est activé. Tu vas etre informé %s jour(s) en avance", - "settings-expires-false": "La notification lors de l'arrivé à expiration de service est desactivé", - "settings-expires-edit": "Changer la periode de notification", - "settings-expires-period": "%s jour(s)", + "settings-updates-true": ":sound: La notification lors d'incidents est activé.", + "settings-updates-false": ":mute: La notification lors d'incidents est desactivé.", + "settings-expires-true": ":bell: La notification lors de l'arrivé à expiration de service est activé. Tu vas etre informé %s jours en avance", + "settings-expires-period": "Tu vas etre informé %s jours en avance", + "settings-expires-false": ":no_bell: La notification lors de l'arrivé à expiration de service est desactivé", + "settings-expires-edit": "Combien de jours dois-je te prévenir à l'avance avant que tes services expirent ? (actuellement: %s jours)", + "settings-expires-days": "%s jours", "telephony-accountClosed": "Ton compte est clôturé :cry:", "telephony-accountDeleted": "Ton compte a été supprimé :cry:", "telephony-accountExpired": "Ton compte est expiré :cry:", From a2307c4bae537e083964b5bebcfd7734ef8aba5e Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 23 Aug 2017 13:46:31 +0200 Subject: [PATCH 11/23] :lipstick: style(bot): add waiting message --- bots/messageTypes/message/service_expires.js | 7 +++++-- bots/messageTypes/message/status_update.js | 9 ++++++--- bots/messageTypes/postback/xdsl.js | 2 +- translations/translation_fr_FR.json | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/bots/messageTypes/message/service_expires.js b/bots/messageTypes/message/service_expires.js index 7aa4613..e1bfb12 100644 --- a/bots/messageTypes/message/service_expires.js +++ b/bots/messageTypes/message/service_expires.js @@ -5,12 +5,13 @@ const { TextMessage, ButtonsMessage, Button, BUTTON_TYPE } = require("../../../p const translator = require("../../../utils/translator"); const Users = require("../../../models/users.model"); const { getServicesExpires } = require("../../../diagnostics/cron"); +const Bluebird = require("bluebird"); class ServiceExpires { static action (senderId, message, entities, res, locale) { let user; - return Users.findOne({ senderId }).exec() + let promise = Users.findOne({ senderId }).exec() .then((userLocal) => { user = userLocal; return utils.getOvhClient(senderId); @@ -32,8 +33,10 @@ class ServiceExpires { ]; responses.push(new ButtonsMessage(translator(`settings-expires-${user.expires}`, locale, user.expiresPeriod), buttons)); } - return { responses, feedback: true }; + return responses; }); + + return Bluebird.resolve({ responses: [new TextMessage(translator("diagInProgress", locale)), promise], feedback: false }); } } diff --git a/bots/messageTypes/message/status_update.js b/bots/messageTypes/message/status_update.js index eff9f4f..fa97f69 100644 --- a/bots/messageTypes/message/status_update.js +++ b/bots/messageTypes/message/status_update.js @@ -5,12 +5,12 @@ const { TextMessage, ButtonsMessage, Button, BUTTON_TYPE } = require("../../../p const translator = require("../../../utils/translator"); const Users = require("../../../models/users.model"); const { getServicesStatus } = require("../../../diagnostics/cron"); - +const Bluebird = require("bluebird"); class StatusUpdate { static action (senderId, message, entities, res, locale) { let responses; - return utils.getOvhClient(senderId) + let promise = utils.getOvhClient(senderId) .then((ovhClient) => getServicesStatus(ovhClient, locale)) .then((responsesCron) => { responses = responsesCron; @@ -26,8 +26,11 @@ class StatusUpdate { ]; responses.push(new ButtonsMessage(translator(`settings-updates-${user.updates}`, locale), buttons)); } - return { responses, feedback: true }; + return responses; }); + + return Bluebird.resolve({ responses: [new TextMessage(translator("diagInProgress", locale)), promise], feedback: false }); + } } diff --git a/bots/messageTypes/postback/xdsl.js b/bots/messageTypes/postback/xdsl.js index 521736b..4fbe487 100644 --- a/bots/messageTypes/postback/xdsl.js +++ b/bots/messageTypes/postback/xdsl.js @@ -80,7 +80,7 @@ module.exports = [ }); }, 1000); }).then((diag) => xDSLDiag.checkxDSLDiagAdvanced(diag)); - return Bluebird.resolve({ responses: [new TextMessage(translator("xdslDiagInProgress", locale)), promise], feedback: false }); + return Bluebird.resolve({ responses: [new TextMessage(translator("diagInProgress", locale)), promise], feedback: false }); }) .catch((err) => { if (err.statusCode === 401 || err.errorCode === 401) { diff --git a/translations/translation_fr_FR.json b/translations/translation_fr_FR.json index 1270e0e..e2848d6 100644 --- a/translations/translation_fr_FR.json +++ b/translations/translation_fr_FR.json @@ -22,6 +22,7 @@ "disconnected": "Tu n'es pas correctement connecté à ton compte OVH :( , il te suffit de me demander 'connecte-moi' pour te reconnecter.", "expires-allOk": "Rien n'est sur le point d'expiré :tada:", "dnsEditDns": "Tu peux modifier tes serveurs DNS via l'espace client OVH", + "diagInProgress": ":hourglass: Diagnostic en cours... Patiente quelques instants, le diagnostic peut prendre quelques minutes :hourglass: ", "feedbackBadUnderstanding": "Mauvaise compréhension", "feedbackHelp": "Est-ce que cette réponse t'a aidé ?", "feedbackNo": "Non", @@ -77,7 +78,6 @@ "welcomeWeb": "Bienvenue %s, en quoi puis-je t'être utile ?", "xdslSelect": "Sélectionne ton offre xDSL (%1$s/%2$s)", "xdslNone": ":satellite: Il semblerait que tu n'as pas d'offre xDSL.", - "xdslDiagInProgress": "Diagnostic en cours... Patiente quelques instants, le diagnostic peut prendre queleques minutes, merci :)", "xdslQuotaReached": "Ton quota de diagnostics a été atteint", "cloud-incident": "Il y a un incident: %1$s; Cet incident est $2%s ($3%s %), Plus de details: $4%s", "hosting-dns": "Ton site ne pointe pas sur la bonne IP (actuellement %1$s), ton domaine \"%2$s\" devrait pointer sur l'IP %3$s", From 9badb8e4fa5147342032c4d95a55044125c0cf27 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 23 Aug 2017 16:12:02 +0200 Subject: [PATCH 12/23] chore(apiai): update archives of apiai --- apiai/archives/ovh-chatbot.zip | Bin 22781 -> 41125 bytes apiai/template.json | 583 +++++++++++++++---- apiai/translations/apiai_fr.json | 419 ++++++++----- bots/messageTypes/message/service_expires.js | 2 +- 4 files changed, 743 insertions(+), 261 deletions(-) diff --git a/apiai/archives/ovh-chatbot.zip b/apiai/archives/ovh-chatbot.zip index fb20ae93e3dfaa8b93b107eee29a6f77010ba3ee..79d76b12d79a27d809848de246889f6849d1c61a 100644 GIT binary patch delta 20999 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 Q0%w7%Q^w(@3xxmuKOJ%C5C8xG delta 4643 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 X87~1L1>AJp5N^l>SQc7?pI`q2F+4S< diff --git a/apiai/template.json b/apiai/template.json index d77c5ed..fcc3e8b 100644 --- a/apiai/template.json +++ b/apiai/template.json @@ -110,117 +110,134 @@ "userSays": [ 68, 69, - 70, - 71 + 70 ], - "responses": [], - "action": "dns_server_config", + "responses": [ + 71, + 72, + 73 + ], + "action": "hosting_commerciale_activerstart10m", "contextAdd": {}, "contextNeed": [], "auto": true }, - "72": { + "74": { "userSays": [ - 73, - 74 + 75, + 76, + 77, + 78 ], "responses": [], - "action": "domain_to_hosting", + "action": "dns_server_config", "contextAdd": {}, "contextNeed": [], "auto": true }, - "75": { + "79": { "userSays": [ - 76, - 77, - 78, - 79, 80, - 81 + 81, + 82, + 83 ], "responses": [], - "action": "website_break", + "action": "dns_server_config", "contextAdd": {}, "contextNeed": [], "auto": true }, - "82": { + "84": { "userSays": [ - 83, - 84, - 85 - ], - "responses": [ + 85, 86 ], + "responses": [], + "action": "domain_to_hosting", "contextAdd": {}, - "contextNeed": [ - "ndh_question" - ], + "contextNeed": [], "auto": true }, "87": { "userSays": [ 88, - 89, - 90, + 89 + ], + "responses": [], + "action": "domain_to_hosting", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "90": { + "userSays": [ 91, 92, 93, 94, 95, - 96, - 97, + 96 + ], + "responses": [], + "action": "website_break", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "97": { + "userSays": [ 98, 99, 100, 101, - 102 + 102, + 103 ], "responses": [], - "action": "good_answer", + "action": "website_break", "contextAdd": {}, "contextNeed": [], - "auto": false + "auto": true }, - "103": { + "104": { "userSays": [ - 104, 105, 106, - 107, + 107 + ], + "responses": [ 108 ], - "responses": [], - "action": "ndh_question", - "contextAdd": { - "ndh_question": 10 - }, - "contextNeed": [], + "contextAdd": {}, + "contextNeed": [ + "ndh_question" + ], "auto": true }, "109": { "userSays": [ 110, 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119 + 112 + ], + "responses": [ + 113 ], - "responses": [], - "action": "telephony_break", "contextAdd": {}, - "contextNeed": [], + "contextNeed": [ + "ndh_question" + ], "auto": true }, - "120": { + "114": { "userSays": [ + 115, + 116, + 117, + 118, + 119, + 120, 121, 122, 123, @@ -229,11 +246,121 @@ 126, 127, 128, - 129, - 130, + 129 + ], + "responses": [], + "action": "good_answer", + "contextAdd": {}, + "contextNeed": [], + "auto": false + }, + "130": { + "userSays": [ 131, 132, - 133 + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145 + ], + "responses": [], + "action": "good_answer", + "contextAdd": {}, + "contextNeed": [], + "auto": false + }, + "146": { + "userSays": [ + 147, + 148, + 149, + 150, + 151 + ], + "responses": [], + "action": "ndh_question", + "contextAdd": { + "ndh_question": 10 + }, + "contextNeed": [], + "auto": true + }, + "152": { + "userSays": [ + 153, + 154, + 155, + 156, + 157 + ], + "responses": [], + "action": "ndh_question", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "158": { + "userSays": [ + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168 + ], + "responses": [], + "action": "telephony_break", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "169": { + "userSays": [ + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179 + ], + "responses": [], + "action": "telephony_break", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "180": { + "userSays": [ + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193 ], "responses": [], "action": "xdsl_break", @@ -241,40 +368,91 @@ "contextNeed": [], "auto": true }, - "134": { + "194": { "userSays": [ - 135, - 136, - 137, - 138 + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207 + ], + "responses": [], + "action": "xdsl_break", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "208": { + "userSays": [ + 209, + 210, + 211, + 212 ], "responses": [ - 139 + 213 ], "action": "account_become_client", "contextAdd": {}, "contextNeed": [], "auto": true }, - "140": { + "214": { "userSays": [ - 141, - 142, - 143 + 215, + 216, + 217, + 218 + ], + "responses": [ + 219 + ], + "action": "account_become_client", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "220": { + "userSays": [ + 221, + 222, + 223 ], "responses": [ - 144 + 224 ], "action": "transverse_compte_devenirclient", "contextAdd": {}, "contextNeed": [], "auto": true }, - "145": { + "225": { "userSays": [ - 146, - 147, - 148 + 226, + 227, + 228 + ], + "responses": [ + 229 + ], + "action": "transverse_compte_devenirclient", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "230": { + "userSays": [ + 231, + 232, + 233 ], "responses": [], "action": "connection", @@ -282,12 +460,24 @@ "contextNeed": [], "auto": true }, - "149": { + "234": { "userSays": [ - 150, - 151, - 152, - 153 + 235, + 236, + 237 + ], + "responses": [], + "action": "connection", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "238": { + "userSays": [ + 239, + 240, + 241, + 242 ], "responses": [], "action": "who_am_i", @@ -295,56 +485,126 @@ "contextNeed": [], "auto": true }, - "154": { + "243": { "userSays": [ - 155, - 156, - 157 + 244, + 245, + 246, + 247 + ], + "responses": [], + "action": "who_am_i", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "248": { + "userSays": [ + 249, + 250, + 251 ], "responses": [ - 158 + 252 ], "action": "transverse_culture_postuler", "contextAdd": {}, "contextNeed": [], "auto": true }, - "159": { + "253": { "userSays": [ - 160, - 161, - 162, - 163 + 254, + 255, + 256 + ], + "responses": [ + 257 + ], + "action": "transverse_culture_postuler", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "258": { + "userSays": [ + 259, + 260, + 261, + 262 ], "responses": [ - 164 + 263 ], "action": "billing_show_bill", "contextAdd": {}, "contextNeed": [], "auto": true }, - "165": { + "264": { "userSays": [ - 166, - 167, - 168, - 169, - 170 + 265, + 266, + 267, + 268 ], "responses": [ - 171 + 269 + ], + "action": "billing_show_bill", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "270": { + "userSays": [ + 271, + 272, + 273, + 274, + 275 + ], + "responses": [ + 276 ], "action": "tranverse_facture_dateexpiration", "contextAdd": {}, "contextNeed": [], "auto": true }, - "172": { + "277": { "userSays": [ - 173, - 174, - 175 + 278, + 279, + 280, + 281, + 282 + ], + "responses": [ + 283 + ], + "action": "tranverse_facture_dateexpiration", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "284": { + "userSays": [ + 285, + 286 + ], + "responses": [], + "action": "service_expires", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "287": { + "userSays": [ + 288, + 289, + 290, + 291 ], "responses": [], "action": "status_update", @@ -352,63 +612,138 @@ "contextNeed": [], "auto": true }, - "176": { + "292": { "userSays": [ - 177, - 178, - 179, - 180, - 181 + 293, + 294, + 295 + ], + "responses": [], + "action": "status_update", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "296": { + "userSays": [ + 297, + 298, + 299, + 300, + 301 ], "responses": [ - 182 + 302 ], "action": "email_account_create", "contextAdd": {}, "contextNeed": [], "auto": true }, - "183": { + "303": { "userSays": [ - 184, - 185 + 304, + 305, + 306, + 307, + 308 ], "responses": [ - 186 + 309 + ], + "action": "email_account_create", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "310": { + "userSays": [ + 311, + 312 + ], + "responses": [ + 313 ], "action": "hosting_db_create", "contextAdd": {}, "contextNeed": [], "auto": true }, - "187": { + "314": { "userSays": [ - 188, - 189, - 190, - 191 + 315, + 316 ], "responses": [ - 192, - 193 + 317 + ], + "action": "hosting_db_create", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "318": { + "userSays": [ + 319, + 320, + 321, + 322 + ], + "responses": [ + 323, + 324 ], "action": "hosting_ftp_connect", "contextAdd": {}, "contextNeed": [], "auto": true }, - "194": { + "325": { "userSays": [ - 195, - 196, - 197, - 198, - 199, - 200, - 201 + 326, + 327, + 328, + 329 + ], + "responses": [ + 330, + 331 + ], + "action": "hosting_ftp_connect", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "332": { + "userSays": [ + 333, + 334, + 335, + 336, + 337, + 338, + 339 + ], + "responses": [ + 340 + ], + "action": "hosting_seo_partners", + "contextAdd": {}, + "contextNeed": [], + "auto": true + }, + "341": { + "userSays": [ + 342, + 343, + 344, + 345, + 346, + 347, + 348 ], "responses": [ - 202 + 349 ], "action": "hosting_seo_partners", "contextAdd": {}, diff --git a/apiai/translations/apiai_fr.json b/apiai/translations/apiai_fr.json index 8569c22..c8f449c 100644 --- a/apiai/translations/apiai_fr.json +++ b/apiai/translations/apiai_fr.json @@ -65,140 +65,287 @@ "64": "Lorsque vous disposez d'un nom de domaine, vous pouvez activer un \"Start 10m\" qui vous permet de créer une adresse email et de disposer d'un petit hébergement FTP de 10 Mo.", "65": "Pour l'activer, il vous suffit de vous rendre sur votre nom de domaine sur , puis de cliquez sur le bouton \"Activer\" à la ligne \"Hébergement Web et e-mail gratuit\".", "66": "L'activation ne prendra que quelques minutes et vous pourrez ensuite créer une adresse email.", - "67": "Hosting_Web_Comment je fais pour changer mes serveurs dns de mon site benjtest.ovh _", - "68": "J'aimerai changer mes serveur DNS", - "69": "Comment changer mes serveurs dns ?", - "70": "Comment je fais pour changer mes serveurs dns de mon site <@sys.url|url|benjtest.ovh> ?", - "71": "Comment je peux changer mes serveurs dns ?", - "72": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon hébergement web _", - "73": "Comment faire pour que <@sys.url|url|benjtest.ovh> pointe sur mon hébergement web", - "74": "Comment je peux faire pointer mon domaine <@sys.url|url|benjtest.ovh> sur mon hébergement web ?", - "75": "Hosting_web_website_break", - "76": "Mon site ne marche pas", - "77": "Mon site <<@sys.url|url|http://testalldom.fr>|testalldom.fr> est cassé", - "78": "mon site web <@sys.url|url|benjamincoenen.com> ne répond plus", - "79": "<@sys.ignore|undefined|Mon> site ne fonctionne plus ☹", - "80": "Mon site <@sys.url|url|benjtest.ovh> est cassé", - "81": "Mon site web est cassé", - "82": "NDH_bad responses", - "83": "<@sys.number|number|3>", - "84": "<@sys.number|number|434321>", - "85": "<@sys.number|number|45353>", - "86": "Mauvaise réponse 🙁", - "87": "NDH_Good answer", - "88": "on vous heberge", - "89": "20", - "90": "5", - "91": "54", - "92": "10", - "93": "6 min", - "94": "6minutes", - "95": "6min", - "96": "6 minutes", - "97": "1.1.0", - "98": "On vous héberge", - "99": "78", - "100": "roubaix", - "101": "#122844", - "102": "6120", - "103": "NDH_ndh_question", - "104": "J'ai soif je veux boire", - "105": "Donne <@sys.date-period|date-period|moi> à boire", - "106": "Je veux <@sys.number|number|une> boisson", - "107": "Je suis à la nuit du hack pour la boisson", - "108": "Je veux gagner <@sys.number|number|une> boisson gratuite", - "109": "Telecom_Telephone_Telephony_break", - "110": "mon <@31|31|téléphone> est cassé", - "111": "Mon <@31|31|téléphone> ne marche pas", - "112": "peux tu faire <@sys.ignore|undefined|un> diagnostic de mon <@31|31|téléphone>", - "113": "Pourquoi je ne peux pas <@31|31|téléphoner> ?", - "114": "je n'arrive pas à appeler", - "115": "ma ligne <@31|31|téléphonique> ne marche pas", - "116": "impossible de passer <@sys.ignore|undefined|un> coup de fil", - "117": "Quand est-ce que ma ligne sera portée ?", - "118": "J'arrive pas à <@31|31|téléphoner>", - "119": "mon <@31|31|téléphone> ne fonctionne plus", - "120": "Telecom_xdsl_xdsl_break", - "121": "mon internet ne marche pas", - "122": "Peut tu faire <@sys.ignore|undefined|un> diagnostic de ma ligne ADSL ?", - "123": "Comment se passe ma comande de ligne xDSL", - "124": "mon internet est cassé", - "125": "Qu'est-ce qui va pas sur mon internet ?", - "126": "la SDSL ne répond plus", - "127": "mon VDSL est en panne", - "128": "ma ligne ADSL ne fonctionne plus", - "129": "mon modem ne capte plus", - "130": "ma box ne fonctionne plus", - "131": "je n'arrive pas à me connecter à internet", - "132": "Je n'ai plus d'internet", - "133": "Ma connection internet ne fonctionne plus", - "134": "Transverse_Compte Client_Comment devenir client _", - "135": "comment devenir cliente", - "136": "etre client ?", - "137": "Créer compte client ?", - "138": "Comment devenir client ?", - "139": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site OVH.com et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", - "140": "Transverse_Compte_Comment devenir client _", - "141": "je veux être client", - "142": "je souhaite devenir client", - "143": "comment devenir client", - "144": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", - "145": "Transverse_Compte_Je veux me connecter à mon compte OVH", - "146": "Je veux me connecter à <@sys.ignore|undefined|mon> compte OVH", - "147": "Je veux me connecter", - "148": "Connecte <@sys.ignore|undefined|moi>", - "149": "Transverse_Compte_Qui suis je _", - "150": "Qui suis je ?", - "151": "je suis connecté sur quel compte ?", - "152": "Suis-je connecté ?", - "153": "Qui je suis ?", - "154": "Transverse_Culture_Comment postuler chez OVH _", - "155": "Je veux travailler chez OVH", - "156": "comment postuler chez OVH", - "157": "je souhaite travailler chez OVH", - "158": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", - "159": "Transverse_Facture_Comment consulter ma facture _", - "160": "Obtenir ma facture", - "161": "Je veux ma facture", - "162": "Je souhaite voir ma facture", - "163": "Consulter ma dernière facture", - "164": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", - "165": "Transverse_Facture_Quelle est la date d_expiration _", - "166": "échéance de paiement ?", - "167": "expiration", - "168": "Date d'expiration", - "169": "Je souhaite connaître la date d'expiration de mon service ?", - "170": "Quelle est la date d'expiration ?", - "171": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", - "172": "transverse_status_update", - "173": "Etat de mes lignes", - "174": "quel est le status de mon cloud", - "175": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", - "176": "Web_Emails_Compte_Comment créer un compte e-mail _", - "177": "créer <@sys.number|number|un> <@1|1|compte mail>", - "178": "Comment créer une <@1|1|adresse mail> ?", - "179": "créer <@1|1|mail>", - "180": "créer <@1|1|adresse email>", - "181": "<@1|1|e-mail>", - "182": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", - "183": "Web_Hosting_Database_Comment créer une base de données _", - "184": "Créer <@9|9|database> ?", - "185": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", - "186": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", - "187": "Web_Hosting_FTP_Comment me connecter en FTP _", - "188": "connexion <@9|9|serveur> <@9|9|FTP>", - "189": "accéder à mon <@9|9|FTP>", - "190": "mettre en ligne mon site", - "191": "connecter <@9|9|hébergement>", - "192": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", - "193": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", - "194": "Web_Hosting_SEO_Référencer mon site sur Google", - "195": "résultat google", - "196": "google", - "197": "je veux référencer mon site", - "198": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", - "199": "je veux <@sys.ignore|undefined|référencer> mon site", - "200": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", - "201": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", - "202": "Contactez nos partenaires pour ce type de demande." + "67": "Hosting_Commerciale_Comment activer un start 10m _1", + "68": "je veux mon start10m", + "69": "Comment activer mon start <@sys.ignore|undefined|10>M ?", + "70": "Je souhaite avoir <@sys.number|number|un> <@9|9|hébergement> gratuit", + "71": "Lorsque vous disposez d'un nom de domaine, vous pouvez activer un \"Start 10m\" qui vous permet de créer une adresse email et de disposer d'un petit hébergement FTP de 10 Mo.", + "72": "Pour l'activer, il vous suffit de vous rendre sur votre nom de domaine sur , puis de cliquez sur le bouton \"Activer\" à la ligne \"Hébergement Web et e-mail gratuit\".", + "73": "L'activation ne prendra que quelques minutes et vous pourrez ensuite créer une adresse email.", + "74": "Hosting_Web_Comment je fais pour changer mes serveurs dns de mon site benjtest.ovh _", + "75": "J'aimerai changer mes serveur DNS", + "76": "Comment changer mes serveurs dns ?", + "77": "Comment je fais pour changer mes serveurs dns de mon site <@sys.url|url|benjtest.ovh> ?", + "78": "Comment je peux changer mes serveurs dns ?", + "79": "Hosting_Web_Comment je fais pour changer mes serveurs dns de mon site benjtest.ovh _1", + "80": "J'aimerai changer mes serveur DNS", + "81": "Comment changer mes serveurs dns ?", + "82": "Comment je fais pour changer mes serveurs dns de mon site <@sys.url|url|benjtest.ovh> ?", + "83": "Comment je peux changer mes serveurs dns ?", + "84": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon hébergement web _", + "85": "Comment faire pour que <@sys.url|url|benjtest.ovh> pointe sur mon hébergement web", + "86": "Comment je peux faire pointer mon domaine <@sys.url|url|benjtest.ovh> sur mon hébergement web ?", + "87": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon hébergement web _1", + "88": "Comment faire pour que <@sys.url|url|benjtest.ovh> pointe sur mon hébergement web", + "89": "Comment je peux faire pointer mon domaine <@sys.url|url|benjtest.ovh> sur mon hébergement web ?", + "90": "Hosting_web_website_break", + "91": "Mon site ne marche pas", + "92": "Mon site <<@sys.url|url|http://testalldom.fr>|testalldom.fr> est cassé", + "93": "mon site web <@sys.url|url|benjamincoenen.com> ne répond plus", + "94": "<@sys.ignore|undefined|Mon> site ne fonctionne plus ☹", + "95": "Mon site <@sys.url|url|benjtest.ovh> est cassé", + "96": "Mon site web est cassé", + "97": "Hosting_web_website_break1", + "98": "Mon site ne marche pas", + "99": "Mon site <<@sys.url|url|http://testalldom.fr>|testalldom.fr> est cassé", + "100": "mon site web <@sys.url|url|benjamincoenen.com> ne répond plus", + "101": "<@sys.ignore|undefined|Mon> site ne fonctionne plus ☹", + "102": "Mon site <@sys.url|url|benjtest.ovh> est cassé", + "103": "Mon site web est cassé", + "104": "NDH_bad responses", + "105": "<@sys.number|number|3>", + "106": "<@sys.number|number|434321>", + "107": "<@sys.number|number|45353>", + "108": "Mauvaise réponse 🙁", + "109": "NDH_bad responses1", + "110": "<@sys.number|number|3>", + "111": "<@sys.number|number|434321>", + "112": "<@sys.number|number|45353>", + "113": "Mauvaise réponse 🙁", + "114": "NDH_Good answer", + "115": "on vous heberge", + "116": "20", + "117": "5", + "118": "54", + "119": "10", + "120": "6 min", + "121": "6minutes", + "122": "6min", + "123": "6 minutes", + "124": "1.1.0", + "125": "On vous héberge", + "126": "78", + "127": "roubaix", + "128": "#122844", + "129": "6120", + "130": "NDH_Good answer1", + "131": "on vous heberge", + "132": "20", + "133": "5", + "134": "54", + "135": "10", + "136": "6 min", + "137": "6minutes", + "138": "6min", + "139": "6 minutes", + "140": "1.1.0", + "141": "On vous héberge", + "142": "78", + "143": "roubaix", + "144": "#122844", + "145": "6120", + "146": "NDH_ndh_question", + "147": "J'ai soif je veux boire", + "148": "Donne <@sys.date-period|date-period|moi> à boire", + "149": "Je veux <@sys.number|number|une> boisson", + "150": "Je suis à la nuit du hack pour la boisson", + "151": "Je veux gagner <@sys.number|number|une> boisson gratuite", + "152": "NDH_ndh_question1", + "153": "J'ai soif je veux boire", + "154": "Donne <@sys.date-period|date-period|moi> à boire", + "155": "Je veux <@sys.number|number|une> boisson", + "156": "Je suis à la nuit du hack pour la boisson", + "157": "Je veux gagner <@sys.number|number|une> boisson gratuite", + "158": "Telecom_Telephone_Telephony_break", + "159": "mon <@31|31|téléphone> est cassé", + "160": "Mon <@31|31|téléphone> ne marche pas", + "161": "peux tu faire <@sys.ignore|undefined|un> diagnostic de mon <@31|31|téléphone>", + "162": "Pourquoi je ne peux pas <@31|31|téléphoner> ?", + "163": "je n'arrive pas à appeler", + "164": "ma ligne <@31|31|téléphonique> ne marche pas", + "165": "impossible de passer <@sys.ignore|undefined|un> coup de fil", + "166": "Quand est-ce que ma ligne sera portée ?", + "167": "J'arrive pas à <@31|31|téléphoner>", + "168": "mon <@31|31|téléphone> ne fonctionne plus", + "169": "Telecom_Telephone_Telephony_break1", + "170": "mon <@31|31|téléphone> est cassé", + "171": "Mon <@31|31|téléphone> ne marche pas", + "172": "peux tu faire <@sys.ignore|undefined|un> diagnostic de mon <@31|31|téléphone>", + "173": "Pourquoi je ne peux pas <@31|31|téléphoner> ?", + "174": "je n'arrive pas à appeler", + "175": "ma ligne <@31|31|téléphonique> ne marche pas", + "176": "impossible de passer <@sys.ignore|undefined|un> coup de fil", + "177": "Quand est-ce que ma ligne sera portée ?", + "178": "J'arrive pas à <@31|31|téléphoner>", + "179": "mon <@31|31|téléphone> ne fonctionne plus", + "180": "Telecom_xdsl_xdsl_break", + "181": "mon internet ne marche pas", + "182": "Peut tu faire <@sys.ignore|undefined|un> diagnostic de ma ligne ADSL ?", + "183": "Comment se passe ma comande de ligne xDSL", + "184": "mon internet est cassé", + "185": "Qu'est-ce qui va pas sur mon internet ?", + "186": "la SDSL ne répond plus", + "187": "mon VDSL est en panne", + "188": "ma ligne ADSL ne fonctionne plus", + "189": "mon modem ne capte plus", + "190": "ma box ne fonctionne plus", + "191": "je n'arrive pas à me connecter à internet", + "192": "Je n'ai plus d'internet", + "193": "Ma connection internet ne fonctionne plus", + "194": "Telecom_xdsl_xdsl_break1", + "195": "mon internet ne marche pas", + "196": "Peut tu faire <@sys.ignore|undefined|un> diagnostic de ma ligne ADSL ?", + "197": "Comment se passe ma comande de ligne xDSL", + "198": "mon internet est cassé", + "199": "Qu'est-ce qui va pas sur mon internet ?", + "200": "la SDSL ne répond plus", + "201": "mon VDSL est en panne", + "202": "ma ligne ADSL ne fonctionne plus", + "203": "mon modem ne capte plus", + "204": "ma box ne fonctionne plus", + "205": "je n'arrive pas à me connecter à internet", + "206": "Je n'ai plus d'internet", + "207": "Ma connection internet ne fonctionne plus", + "208": "Transverse_Compte Client_Comment devenir client _", + "209": "comment devenir cliente", + "210": "etre client ?", + "211": "Créer compte client ?", + "212": "Comment devenir client ?", + "213": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site OVH.com et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", + "214": "Transverse_Compte Client_Comment devenir client _1", + "215": "comment devenir cliente", + "216": "etre client ?", + "217": "Créer compte client ?", + "218": "Comment devenir client ?", + "219": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site OVH.com et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", + "220": "Transverse_Compte_Comment devenir client _", + "221": "je veux être client", + "222": "je souhaite devenir client", + "223": "comment devenir client", + "224": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", + "225": "Transverse_Compte_Comment devenir client _1", + "226": "je veux être client", + "227": "je souhaite devenir client", + "228": "comment devenir client", + "229": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", + "230": "Transverse_Compte_Je veux me connecter à mon compte OVH", + "231": "Je veux me connecter à <@sys.ignore|undefined|mon> compte OVH", + "232": "Je veux me connecter", + "233": "Connecte <@sys.ignore|undefined|moi>", + "234": "Transverse_Compte_Je veux me connecter à mon compte OVH1", + "235": "Je veux me connecter à <@sys.ignore|undefined|mon> compte OVH", + "236": "Je veux me connecter", + "237": "Connecte <@sys.ignore|undefined|moi>", + "238": "Transverse_Compte_Qui suis je _", + "239": "Qui suis je ?", + "240": "je suis connecté sur quel compte ?", + "241": "Suis-je connecté ?", + "242": "Qui je suis ?", + "243": "Transverse_Compte_Qui suis je _1", + "244": "Qui suis je ?", + "245": "je suis connecté sur quel compte ?", + "246": "Suis-je connecté ?", + "247": "Qui je suis ?", + "248": "Transverse_Culture_Comment postuler chez OVH _", + "249": "Je veux travailler chez OVH", + "250": "comment postuler chez OVH", + "251": "je souhaite travailler chez OVH", + "252": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", + "253": "Transverse_Culture_Comment postuler chez OVH _1", + "254": "Je veux travailler chez OVH", + "255": "comment postuler chez OVH", + "256": "je souhaite travailler chez OVH", + "257": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", + "258": "Transverse_Facture_Comment consulter ma facture _", + "259": "Obtenir ma facture", + "260": "Je veux ma facture", + "261": "Je souhaite voir ma facture", + "262": "Consulter ma dernière facture", + "263": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", + "264": "Transverse_Facture_Comment consulter ma facture _1", + "265": "Obtenir ma facture", + "266": "Je veux ma facture", + "267": "Je souhaite voir ma facture", + "268": "Consulter ma dernière facture", + "269": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", + "270": "Transverse_Facture_Quelle est la date d_expiration _", + "271": "échéance de paiement ?", + "272": "expiration", + "273": "Date d'expiration", + "274": "Je souhaite connaître la date d'expiration de mon service ?", + "275": "Quelle est la date d'expiration ?", + "276": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", + "277": "Transverse_Facture_Quelle est la date d_expiration _1", + "278": "échéance de paiement ?", + "279": "expiration", + "280": "Date d'expiration", + "281": "Je souhaite connaître la date d'expiration de mon service ?", + "282": "Quelle est la date d'expiration ?", + "283": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", + "284": "Transverse_service expires", + "285": "Quand renouveler mes abonements ?", + "286": "Quand est-ce que mes services expirent ?", + "287": "transverse_status_update", + "288": "comment vont mes services ?", + "289": "Etat de mes lignes", + "290": "quel est le status de mon cloud", + "291": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", + "292": "transverse_status_update1", + "293": "Etat de mes lignes", + "294": "quel est le status de mon cloud", + "295": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", + "296": "Web_Emails_Compte_Comment créer un compte e-mail _", + "297": "créer <@sys.number|number|un> <@1|1|compte mail>", + "298": "Comment créer une <@1|1|adresse mail> ?", + "299": "créer <@1|1|mail>", + "300": "créer <@1|1|adresse email>", + "301": "<@1|1|e-mail>", + "302": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", + "303": "Web_Emails_Compte_Comment créer un compte e-mail _1", + "304": "créer <@sys.number|number|un> <@1|1|compte mail>", + "305": "Comment créer une <@1|1|adresse mail> ?", + "306": "créer <@1|1|mail>", + "307": "créer <@1|1|adresse email>", + "308": "<@1|1|e-mail>", + "309": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", + "310": "Web_Hosting_Database_Comment créer une base de données _", + "311": "Créer <@9|9|database> ?", + "312": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", + "313": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", + "314": "Web_Hosting_Database_Comment créer une base de données _1", + "315": "Créer <@9|9|database> ?", + "316": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", + "317": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", + "318": "Web_Hosting_FTP_Comment me connecter en FTP _", + "319": "connexion <@9|9|serveur> <@9|9|FTP>", + "320": "accéder à mon <@9|9|FTP>", + "321": "mettre en ligne mon site", + "322": "connecter <@9|9|hébergement>", + "323": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", + "324": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", + "325": "Web_Hosting_FTP_Comment me connecter en FTP _1", + "326": "connexion <@9|9|serveur> <@9|9|FTP>", + "327": "accéder à mon <@9|9|FTP>", + "328": "mettre en ligne mon site", + "329": "connecter <@9|9|hébergement>", + "330": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", + "331": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", + "332": "Web_Hosting_SEO_Référencer mon site sur Google", + "333": "résultat google", + "334": "google", + "335": "je veux référencer mon site", + "336": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", + "337": "je veux <@sys.ignore|undefined|référencer> mon site", + "338": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", + "339": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", + "340": "Contactez nos partenaires pour ce type de demande.", + "341": "Web_Hosting_SEO_Référencer mon site sur Google1", + "342": "résultat google", + "343": "google", + "344": "je veux référencer mon site", + "345": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", + "346": "je veux <@sys.ignore|undefined|référencer> mon site", + "347": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", + "348": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", + "349": "Contactez nos partenaires pour ce type de demande." } diff --git a/bots/messageTypes/message/service_expires.js b/bots/messageTypes/message/service_expires.js index e1bfb12..54bb9d4 100644 --- a/bots/messageTypes/message/service_expires.js +++ b/bots/messageTypes/message/service_expires.js @@ -16,7 +16,7 @@ class ServiceExpires { user = userLocal; return utils.getOvhClient(senderId); }) - .then((ovhClient) => getServicesExpires(ovhClient, locale, user.expiresPeriod || 14)) + .then((ovhClient) => getServicesExpires(ovhClient, locale, user ? user.expiresPeriod : 14)) .then((responsesCron) => { let responses = responsesCron; if (!responses.length) { From 0ce998f76843bdd6ffce26a4eddba838f825bd98 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 23 Aug 2017 16:12:38 +0200 Subject: [PATCH 13/23] :ambulance: fix(controller/web): fix promise in response not resolved --- controllers/web.js | 35 ++++++++++++++++++------- platforms/web/web.js | 62 +++++++++++++++++--------------------------- utils/ovh.js | 2 +- 3 files changed, 51 insertions(+), 48 deletions(-) diff --git a/controllers/web.js b/controllers/web.js index ce8230b..430ed47 100644 --- a/controllers/web.js +++ b/controllers/web.js @@ -4,7 +4,7 @@ const web = require("../platforms/web/web"); const bot = require("../bots/common")(); const apiai = require("../utils/apiai"); const Bluebird = require("bluebird"); -const { TextMessage } = require("../platforms/generics"); +const { TextMessage, createFeedback } = require("../platforms/generics"); const translator = require("../utils/translator"); module.exports = () => { @@ -13,11 +13,11 @@ module.exports = () => { switch (response.type) { case 0: { const textResponse = response.speech.replace(/<(.*)\|+(.*)>/, "$1"); - return Bluebird.resolve(textResponse); + return Bluebird.resolve({ responses: [textResponse] }); } default: { const textResponse = response.speech.replace(/<(.*)\|+(.*)>/, "$1"); - return Bluebird.resolve(textResponse); + return Bluebird.resolve({ responses: [textResponse] }); } } }); @@ -107,6 +107,7 @@ module.exports = () => { const nichandle = req.user.nichandle; const locale = req.user.language; const type = req.body.type; + let result; // check the data sent first; if (!nichandle) { @@ -141,20 +142,36 @@ module.exports = () => { } throw new Error(`unknown type, ${type}`); }) - .then((result) => { - // if result.responses then the origin is the bot, ie there might be a feedback request - if (result.responses) { - return web.send(res, nichandle, result.responses, result, locale); + .then((resultLocal) => { + result = resultLocal; + return sendResponses(res, nichandle, result.responses, locale); + }) + .then((array) => res.status(200).json(array)) + .then(() => { + if (result.feedback) { + return sendResponses(res, nichandle, [createFeedback(result.intent, result.message, locale)]); } - return web.send(res, nichandle, result, locale); + return null; }) - .then((result) => res.status(200).json(result)) .catch((err) => { res.logger.error(err); return res.status(503).json(err); }); } + function sendResponses (res, nichandle, responses, result, locale) { + let promises = responses.filter((response) => response instanceof Bluebird); + let generics = responses.filter((response) => !(response instanceof Bluebird)); + + if (promises.length) { + Bluebird.mapSeries(promises, (response) => + Bluebird.resolve(response) + .then((resp) => sendResponses(res, nichandle, resp, result, locale))); + } + + return Bluebird.all(generics.map((uGeneric) => web.send(res, nichandle, uGeneric))); + } + return { onGet, onPost diff --git a/platforms/web/web.js b/platforms/web/web.js index 1e6c504..9dbd317 100644 --- a/platforms/web/web.js +++ b/platforms/web/web.js @@ -1,44 +1,38 @@ "use strict"; const Bluebird = require("bluebird"); -const { ButtonsListMessage, Button, TextMessage, ButtonsMessage, createFeedback } = require("../generics"); +const { ButtonsListMessage, Button, TextMessage, ButtonsMessage } = require("../generics"); const WebMessage = require("../../models/web.model"); const config = require("../../config/config-loader").load(); const { textMessageAdapter, buttonAdapter, buttonListAdapter } = require("./web_adapters"); -function parseMsg (RawResponses) { - const responses = RawResponses.length == null || typeof RawResponses === "string" ? [RawResponses] : RawResponses; +function parseMsg (uResponse) { - return responses.map((uResponse) => { - if (typeof uResponse === "string") { - return textMessageAdapter(uResponse); - } - - if (uResponse instanceof TextMessage) { - return textMessageAdapter(uResponse.text); - } + if (typeof uResponse === "string") { + return textMessageAdapter(uResponse); + } - if (uResponse instanceof Button) { - return buttonAdapter(uResponse); - } + if (uResponse instanceof TextMessage) { + return textMessageAdapter(uResponse.text); + } - if (uResponse instanceof ButtonsListMessage || uResponse instanceof ButtonsMessage) { - return buttonListAdapter(uResponse); - } + if (uResponse instanceof Button) { + return buttonAdapter(uResponse); + } - return uResponse; - }); -} + if (uResponse instanceof ButtonsListMessage || uResponse instanceof ButtonsMessage) { + return buttonListAdapter(uResponse); + } -function sendFeedback (nichandle, intent, rawMessage, locale) { - return send(null, nichandle, createFeedback(intent, rawMessage, locale)); + return uResponse; } -function send (res, id, rawResponsesPar, opt, locale) { +function send (res, id, rawResponsesPar) { let flagUseRes = true; let nichandle = id; let rawResponses = rawResponsesPar; - let responses; + let response; + let histResponse; // input validation if (!rawResponses) { @@ -63,27 +57,19 @@ function send (res, id, rawResponsesPar, opt, locale) { } // parse the rawResponses into a suitable format - responses = parseMsg(rawResponses); + response = parseMsg(rawResponses); // push the message to db for conversation history - if (responses.length > 0) { - return Bluebird.map(responses, (historyMessage) => { - historyMessage.origin = "bot"; - return pushToHistory(nichandle, historyMessage); - }).then(() => { + histResponse = response; + histResponse.origin = "bot"; + return pushToHistory(nichandle, histResponse) + .then(() => { // if we cant answer, we save to db for later if (flagUseRes) { - return Bluebird.resolve(responses).then((result) => { - if (opt && opt.feedback) { - sendFeedback(nichandle, opt.intent, opt.message, locale); - } - return result; - }); + return Bluebird.resolve(response); } return Bluebird.resolve(); }); - } - return null; } function getHistory (res, nichandle) { diff --git a/utils/ovh.js b/utils/ovh.js index 21a2eec..1486a03 100644 --- a/utils/ovh.js +++ b/utils/ovh.js @@ -35,7 +35,7 @@ class OvhWebClient { }; return request(Object.assign(opt, this.options), (err, resp, body) => { if (err || resp.statusCode >= 400) { - return reject({ statusCode: resp.statusCode, data: body }); + return reject(err ? { statusCode: 500, data: err } : { statusCode: resp.statusCode, data: body }); } return resolve(body); }); From cb49cb1b3c814ffd2f19a21d618e507bdf1d8ca3 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 23 Aug 2017 16:29:38 +0200 Subject: [PATCH 14/23] chore(apiai): update apiai archives --- apiai/archives/ovh-chatbot.zip | Bin 41125 -> 25525 bytes apiai/template.json | 579 +++++++------------------------ apiai/translations/apiai_fr.json | 423 ++++++++-------------- 3 files changed, 268 insertions(+), 734 deletions(-) diff --git a/apiai/archives/ovh-chatbot.zip b/apiai/archives/ovh-chatbot.zip index 79d76b12d79a27d809848de246889f6849d1c61a..b619c80f6e0792b14af8cb94dd1759ca15c58bda 100644 GIT binary patch delta 6206 zcmb7|du&r>7{C=e#@#M4FHL-7`FGezk_}8o|_N;OR-Tt7x(V0qgZ|{mW ziJzf$=|rPHltoDFi%5a*NeXFf$*yTV=+U{ggk+}^Qpiy}p+L~@t@3+at-gRmpi8$K z$Hd4VIigMCCr3VN&@R{3vGlUV#~V5|gk=pXt}2G;Ypxti1q&8$i&`3DWd%fqWVz;XaI; z-}`%YJ>U*PxTQR9?;fi>uG=?H!bx$QE-vf4D!B{uxJ6NCEQM~j(6LhRLel27g4?`I zIfV^vzhT?ow1+DG0iA1*LJ_ZX$~{)z_RsErvF)>a4%D?n0tX%0DP=qj8kUc7Fh z!yNJnX16OKn3uy}zt0!{eL&3&AJ6O1qAU5qvkU)d0nuR~>g7dU&LtM*T&~x-G4suw z)s9kN7Cb7H!^LD4&geZW%^KkCm6M1?0FPgv=R?97S99npIe>t_ovr+VXB% z2Hao4>Li|fv0|LOO*4`6?_9ow{F#u29c&=Z#%p@eYh$ z%UkS^j-Y3oifDehLEfsh{1wTnbd$W0TdV&Zu$Az>tmm;ay0V7DV{(}zcC=Q+zS46q z=gVu%wV%csX&cv{ybKzDCDLfvXf?#acMEgn!J}+faL(bEHiTzG&eu~2so~8J6Q;$h!M0quuC%Xqi%XO5S5+LyT(;}-Qg@|_T9!Ei#R@wf>Si)d+vg2VER z1vt-Nme^0-ggh_9@Dq4s&yGBKhd&zs##yeJ{_y5z7C=CA95Ir7z-O5Yv9EQQq0D3Zy6(1>YZO@V)zE^)l z6VYh%bjh~u9N5CdkKyFj4DnyQdmG}rH@6)()QH4nn|GWDuF2s|vqfS$v(D4{?V}@& zPT(fkx_K_%xmj*11j0IHH*h(2EQQFR(qSTO4Aqdw%fF z&T4eQdxO;wH+Ti>@q<2icaLM^2mMdDOciy_4|XV)gEgQYEZ#h1!DVg+iN$=7%#JYHvEc;jU zv%z(NMYrb-LdVL(gIUM5f#t8ZaC|5cs%_)?z+zLZ92UyNgIUHkf@Pa*9GfW>%GMLs z2^K$jB8N{_E>vsbTES{J_wD%?68D90)O6s1>u%M{ONx=;SKlz delta 20214 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 diff --git a/apiai/template.json b/apiai/template.json index fcc3e8b..4137b99 100644 --- a/apiai/template.json +++ b/apiai/template.json @@ -110,134 +110,117 @@ "userSays": [ 68, 69, - 70 + 70, + 71 ], - "responses": [ - 71, - 72, - 73 - ], - "action": "hosting_commerciale_activerstart10m", + "responses": [], + "action": "dns_server_config", "contextAdd": {}, "contextNeed": [], "auto": true }, - "74": { + "72": { "userSays": [ - 75, - 76, - 77, - 78 + 73, + 74 ], "responses": [], - "action": "dns_server_config", + "action": "domain_to_hosting", "contextAdd": {}, "contextNeed": [], "auto": true }, - "79": { + "75": { "userSays": [ + 76, + 77, + 78, + 79, 80, - 81, - 82, - 83 + 81 ], "responses": [], - "action": "dns_server_config", + "action": "website_break", "contextAdd": {}, "contextNeed": [], "auto": true }, - "84": { + "82": { "userSays": [ - 85, + 83, + 84, + 85 + ], + "responses": [ 86 ], - "responses": [], - "action": "domain_to_hosting", "contextAdd": {}, - "contextNeed": [], + "contextNeed": [ + "ndh_question" + ], "auto": true }, "87": { "userSays": [ 88, - 89 - ], - "responses": [], - "action": "domain_to_hosting", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "90": { - "userSays": [ + 89, + 90, 91, 92, 93, 94, 95, - 96 - ], - "responses": [], - "action": "website_break", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "97": { - "userSays": [ + 96, + 97, 98, 99, 100, 101, - 102, - 103 + 102 ], "responses": [], - "action": "website_break", + "action": "good_answer", "contextAdd": {}, "contextNeed": [], - "auto": true + "auto": false }, - "104": { + "103": { "userSays": [ + 104, 105, 106, - 107 - ], - "responses": [ + 107, 108 ], - "contextAdd": {}, - "contextNeed": [ - "ndh_question" - ], + "responses": [], + "action": "ndh_question", + "contextAdd": { + "ndh_question": 10 + }, + "contextNeed": [], "auto": true }, "109": { "userSays": [ 110, 111, - 112 - ], - "responses": [ - 113 + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119 ], + "responses": [], + "action": "telephony_break", "contextAdd": {}, - "contextNeed": [ - "ndh_question" - ], + "contextNeed": [], "auto": true }, - "114": { + "120": { "userSays": [ - 115, - 116, - 117, - 118, - 119, - 120, 121, 122, 123, @@ -246,143 +229,11 @@ 126, 127, 128, - 129 - ], - "responses": [], - "action": "good_answer", - "contextAdd": {}, - "contextNeed": [], - "auto": false - }, - "130": { - "userSays": [ + 129, + 130, 131, 132, - 133, - 134, - 135, - 136, - 137, - 138, - 139, - 140, - 141, - 142, - 143, - 144, - 145 - ], - "responses": [], - "action": "good_answer", - "contextAdd": {}, - "contextNeed": [], - "auto": false - }, - "146": { - "userSays": [ - 147, - 148, - 149, - 150, - 151 - ], - "responses": [], - "action": "ndh_question", - "contextAdd": { - "ndh_question": 10 - }, - "contextNeed": [], - "auto": true - }, - "152": { - "userSays": [ - 153, - 154, - 155, - 156, - 157 - ], - "responses": [], - "action": "ndh_question", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "158": { - "userSays": [ - 159, - 160, - 161, - 162, - 163, - 164, - 165, - 166, - 167, - 168 - ], - "responses": [], - "action": "telephony_break", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "169": { - "userSays": [ - 170, - 171, - 172, - 173, - 174, - 175, - 176, - 177, - 178, - 179 - ], - "responses": [], - "action": "telephony_break", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "180": { - "userSays": [ - 181, - 182, - 183, - 184, - 185, - 186, - 187, - 188, - 189, - 190, - 191, - 192, - 193 - ], - "responses": [], - "action": "xdsl_break", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "194": { - "userSays": [ - 195, - 196, - 197, - 198, - 199, - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207 + 133 ], "responses": [], "action": "xdsl_break", @@ -390,81 +241,40 @@ "contextNeed": [], "auto": true }, - "208": { - "userSays": [ - 209, - 210, - 211, - 212 - ], - "responses": [ - 213 - ], - "action": "account_become_client", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "214": { + "134": { "userSays": [ - 215, - 216, - 217, - 218 + 135, + 136, + 137, + 138 ], "responses": [ - 219 + 139 ], "action": "account_become_client", "contextAdd": {}, "contextNeed": [], "auto": true }, - "220": { + "140": { "userSays": [ - 221, - 222, - 223 - ], - "responses": [ - 224 - ], - "action": "transverse_compte_devenirclient", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "225": { - "userSays": [ - 226, - 227, - 228 + 141, + 142, + 143 ], "responses": [ - 229 + 144 ], "action": "transverse_compte_devenirclient", "contextAdd": {}, "contextNeed": [], "auto": true }, - "230": { + "145": { "userSays": [ - 231, - 232, - 233 - ], - "responses": [], - "action": "connection", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "234": { - "userSays": [ - 235, - 236, - 237 + 146, + 147, + 148 ], "responses": [], "action": "connection", @@ -472,25 +282,12 @@ "contextNeed": [], "auto": true }, - "238": { + "149": { "userSays": [ - 239, - 240, - 241, - 242 - ], - "responses": [], - "action": "who_am_i", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "243": { - "userSays": [ - 244, - 245, - 246, - 247 + 150, + 151, + 152, + 153 ], "responses": [], "action": "who_am_i", @@ -498,100 +295,55 @@ "contextNeed": [], "auto": true }, - "248": { + "154": { "userSays": [ - 249, - 250, - 251 - ], - "responses": [ - 252 - ], - "action": "transverse_culture_postuler", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "253": { - "userSays": [ - 254, - 255, - 256 + 155, + 156, + 157 ], "responses": [ - 257 + 158 ], "action": "transverse_culture_postuler", "contextAdd": {}, "contextNeed": [], "auto": true }, - "258": { - "userSays": [ - 259, - 260, - 261, - 262 - ], - "responses": [ - 263 - ], - "action": "billing_show_bill", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "264": { + "159": { "userSays": [ - 265, - 266, - 267, - 268 + 160, + 161, + 162, + 163 ], "responses": [ - 269 + 164 ], "action": "billing_show_bill", "contextAdd": {}, "contextNeed": [], "auto": true }, - "270": { - "userSays": [ - 271, - 272, - 273, - 274, - 275 - ], - "responses": [ - 276 - ], - "action": "tranverse_facture_dateexpiration", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "277": { + "165": { "userSays": [ - 278, - 279, - 280, - 281, - 282 + 166, + 167, + 168, + 169, + 170 ], "responses": [ - 283 + 171 ], "action": "tranverse_facture_dateexpiration", "contextAdd": {}, "contextNeed": [], "auto": true }, - "284": { + "172": { "userSays": [ - 285, - 286 + 173, + 174 ], "responses": [], "action": "service_expires", @@ -599,24 +351,12 @@ "contextNeed": [], "auto": true }, - "287": { - "userSays": [ - 288, - 289, - 290, - 291 - ], - "responses": [], - "action": "status_update", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "292": { + "175": { "userSays": [ - 293, - 294, - 295 + 176, + 177, + 178, + 179 ], "responses": [], "action": "status_update", @@ -624,126 +364,63 @@ "contextNeed": [], "auto": true }, - "296": { - "userSays": [ - 297, - 298, - 299, - 300, - 301 - ], - "responses": [ - 302 - ], - "action": "email_account_create", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "303": { + "180": { "userSays": [ - 304, - 305, - 306, - 307, - 308 + 181, + 182, + 183, + 184, + 185 ], "responses": [ - 309 + 186 ], "action": "email_account_create", "contextAdd": {}, "contextNeed": [], "auto": true }, - "310": { - "userSays": [ - 311, - 312 - ], - "responses": [ - 313 - ], - "action": "hosting_db_create", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "314": { + "187": { "userSays": [ - 315, - 316 + 188, + 189 ], "responses": [ - 317 + 190 ], "action": "hosting_db_create", "contextAdd": {}, "contextNeed": [], "auto": true }, - "318": { + "191": { "userSays": [ - 319, - 320, - 321, - 322 - ], - "responses": [ - 323, - 324 - ], - "action": "hosting_ftp_connect", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "325": { - "userSays": [ - 326, - 327, - 328, - 329 + 192, + 193, + 194, + 195 ], "responses": [ - 330, - 331 + 196, + 197 ], "action": "hosting_ftp_connect", "contextAdd": {}, "contextNeed": [], "auto": true }, - "332": { - "userSays": [ - 333, - 334, - 335, - 336, - 337, - 338, - 339 - ], - "responses": [ - 340 - ], - "action": "hosting_seo_partners", - "contextAdd": {}, - "contextNeed": [], - "auto": true - }, - "341": { + "198": { "userSays": [ - 342, - 343, - 344, - 345, - 346, - 347, - 348 + 199, + 200, + 201, + 202, + 203, + 204, + 205 ], "responses": [ - 349 + 206 ], "action": "hosting_seo_partners", "contextAdd": {}, diff --git a/apiai/translations/apiai_fr.json b/apiai/translations/apiai_fr.json index c8f449c..8ef5668 100644 --- a/apiai/translations/apiai_fr.json +++ b/apiai/translations/apiai_fr.json @@ -65,287 +65,144 @@ "64": "Lorsque vous disposez d'un nom de domaine, vous pouvez activer un \"Start 10m\" qui vous permet de créer une adresse email et de disposer d'un petit hébergement FTP de 10 Mo.", "65": "Pour l'activer, il vous suffit de vous rendre sur votre nom de domaine sur , puis de cliquez sur le bouton \"Activer\" à la ligne \"Hébergement Web et e-mail gratuit\".", "66": "L'activation ne prendra que quelques minutes et vous pourrez ensuite créer une adresse email.", - "67": "Hosting_Commerciale_Comment activer un start 10m _1", - "68": "je veux mon start10m", - "69": "Comment activer mon start <@sys.ignore|undefined|10>M ?", - "70": "Je souhaite avoir <@sys.number|number|un> <@9|9|hébergement> gratuit", - "71": "Lorsque vous disposez d'un nom de domaine, vous pouvez activer un \"Start 10m\" qui vous permet de créer une adresse email et de disposer d'un petit hébergement FTP de 10 Mo.", - "72": "Pour l'activer, il vous suffit de vous rendre sur votre nom de domaine sur , puis de cliquez sur le bouton \"Activer\" à la ligne \"Hébergement Web et e-mail gratuit\".", - "73": "L'activation ne prendra que quelques minutes et vous pourrez ensuite créer une adresse email.", - "74": "Hosting_Web_Comment je fais pour changer mes serveurs dns de mon site benjtest.ovh _", - "75": "J'aimerai changer mes serveur DNS", - "76": "Comment changer mes serveurs dns ?", - "77": "Comment je fais pour changer mes serveurs dns de mon site <@sys.url|url|benjtest.ovh> ?", - "78": "Comment je peux changer mes serveurs dns ?", - "79": "Hosting_Web_Comment je fais pour changer mes serveurs dns de mon site benjtest.ovh _1", - "80": "J'aimerai changer mes serveur DNS", - "81": "Comment changer mes serveurs dns ?", - "82": "Comment je fais pour changer mes serveurs dns de mon site <@sys.url|url|benjtest.ovh> ?", - "83": "Comment je peux changer mes serveurs dns ?", - "84": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon hébergement web _", - "85": "Comment faire pour que <@sys.url|url|benjtest.ovh> pointe sur mon hébergement web", - "86": "Comment je peux faire pointer mon domaine <@sys.url|url|benjtest.ovh> sur mon hébergement web ?", - "87": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon hébergement web _1", - "88": "Comment faire pour que <@sys.url|url|benjtest.ovh> pointe sur mon hébergement web", - "89": "Comment je peux faire pointer mon domaine <@sys.url|url|benjtest.ovh> sur mon hébergement web ?", - "90": "Hosting_web_website_break", - "91": "Mon site ne marche pas", - "92": "Mon site <<@sys.url|url|http://testalldom.fr>|testalldom.fr> est cassé", - "93": "mon site web <@sys.url|url|benjamincoenen.com> ne répond plus", - "94": "<@sys.ignore|undefined|Mon> site ne fonctionne plus ☹", - "95": "Mon site <@sys.url|url|benjtest.ovh> est cassé", - "96": "Mon site web est cassé", - "97": "Hosting_web_website_break1", - "98": "Mon site ne marche pas", - "99": "Mon site <<@sys.url|url|http://testalldom.fr>|testalldom.fr> est cassé", - "100": "mon site web <@sys.url|url|benjamincoenen.com> ne répond plus", - "101": "<@sys.ignore|undefined|Mon> site ne fonctionne plus ☹", - "102": "Mon site <@sys.url|url|benjtest.ovh> est cassé", - "103": "Mon site web est cassé", - "104": "NDH_bad responses", - "105": "<@sys.number|number|3>", - "106": "<@sys.number|number|434321>", - "107": "<@sys.number|number|45353>", - "108": "Mauvaise réponse 🙁", - "109": "NDH_bad responses1", - "110": "<@sys.number|number|3>", - "111": "<@sys.number|number|434321>", - "112": "<@sys.number|number|45353>", - "113": "Mauvaise réponse 🙁", - "114": "NDH_Good answer", - "115": "on vous heberge", - "116": "20", - "117": "5", - "118": "54", - "119": "10", - "120": "6 min", - "121": "6minutes", - "122": "6min", - "123": "6 minutes", - "124": "1.1.0", - "125": "On vous héberge", - "126": "78", - "127": "roubaix", - "128": "#122844", - "129": "6120", - "130": "NDH_Good answer1", - "131": "on vous heberge", - "132": "20", - "133": "5", - "134": "54", - "135": "10", - "136": "6 min", - "137": "6minutes", - "138": "6min", - "139": "6 minutes", - "140": "1.1.0", - "141": "On vous héberge", - "142": "78", - "143": "roubaix", - "144": "#122844", - "145": "6120", - "146": "NDH_ndh_question", - "147": "J'ai soif je veux boire", - "148": "Donne <@sys.date-period|date-period|moi> à boire", - "149": "Je veux <@sys.number|number|une> boisson", - "150": "Je suis à la nuit du hack pour la boisson", - "151": "Je veux gagner <@sys.number|number|une> boisson gratuite", - "152": "NDH_ndh_question1", - "153": "J'ai soif je veux boire", - "154": "Donne <@sys.date-period|date-period|moi> à boire", - "155": "Je veux <@sys.number|number|une> boisson", - "156": "Je suis à la nuit du hack pour la boisson", - "157": "Je veux gagner <@sys.number|number|une> boisson gratuite", - "158": "Telecom_Telephone_Telephony_break", - "159": "mon <@31|31|téléphone> est cassé", - "160": "Mon <@31|31|téléphone> ne marche pas", - "161": "peux tu faire <@sys.ignore|undefined|un> diagnostic de mon <@31|31|téléphone>", - "162": "Pourquoi je ne peux pas <@31|31|téléphoner> ?", - "163": "je n'arrive pas à appeler", - "164": "ma ligne <@31|31|téléphonique> ne marche pas", - "165": "impossible de passer <@sys.ignore|undefined|un> coup de fil", - "166": "Quand est-ce que ma ligne sera portée ?", - "167": "J'arrive pas à <@31|31|téléphoner>", - "168": "mon <@31|31|téléphone> ne fonctionne plus", - "169": "Telecom_Telephone_Telephony_break1", - "170": "mon <@31|31|téléphone> est cassé", - "171": "Mon <@31|31|téléphone> ne marche pas", - "172": "peux tu faire <@sys.ignore|undefined|un> diagnostic de mon <@31|31|téléphone>", - "173": "Pourquoi je ne peux pas <@31|31|téléphoner> ?", - "174": "je n'arrive pas à appeler", - "175": "ma ligne <@31|31|téléphonique> ne marche pas", - "176": "impossible de passer <@sys.ignore|undefined|un> coup de fil", - "177": "Quand est-ce que ma ligne sera portée ?", - "178": "J'arrive pas à <@31|31|téléphoner>", - "179": "mon <@31|31|téléphone> ne fonctionne plus", - "180": "Telecom_xdsl_xdsl_break", - "181": "mon internet ne marche pas", - "182": "Peut tu faire <@sys.ignore|undefined|un> diagnostic de ma ligne ADSL ?", - "183": "Comment se passe ma comande de ligne xDSL", - "184": "mon internet est cassé", - "185": "Qu'est-ce qui va pas sur mon internet ?", - "186": "la SDSL ne répond plus", - "187": "mon VDSL est en panne", - "188": "ma ligne ADSL ne fonctionne plus", - "189": "mon modem ne capte plus", - "190": "ma box ne fonctionne plus", - "191": "je n'arrive pas à me connecter à internet", - "192": "Je n'ai plus d'internet", - "193": "Ma connection internet ne fonctionne plus", - "194": "Telecom_xdsl_xdsl_break1", - "195": "mon internet ne marche pas", - "196": "Peut tu faire <@sys.ignore|undefined|un> diagnostic de ma ligne ADSL ?", - "197": "Comment se passe ma comande de ligne xDSL", - "198": "mon internet est cassé", - "199": "Qu'est-ce qui va pas sur mon internet ?", - "200": "la SDSL ne répond plus", - "201": "mon VDSL est en panne", - "202": "ma ligne ADSL ne fonctionne plus", - "203": "mon modem ne capte plus", - "204": "ma box ne fonctionne plus", - "205": "je n'arrive pas à me connecter à internet", - "206": "Je n'ai plus d'internet", - "207": "Ma connection internet ne fonctionne plus", - "208": "Transverse_Compte Client_Comment devenir client _", - "209": "comment devenir cliente", - "210": "etre client ?", - "211": "Créer compte client ?", - "212": "Comment devenir client ?", - "213": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site OVH.com et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", - "214": "Transverse_Compte Client_Comment devenir client _1", - "215": "comment devenir cliente", - "216": "etre client ?", - "217": "Créer compte client ?", - "218": "Comment devenir client ?", - "219": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site OVH.com et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", - "220": "Transverse_Compte_Comment devenir client _", - "221": "je veux être client", - "222": "je souhaite devenir client", - "223": "comment devenir client", - "224": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", - "225": "Transverse_Compte_Comment devenir client _1", - "226": "je veux être client", - "227": "je souhaite devenir client", - "228": "comment devenir client", - "229": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", - "230": "Transverse_Compte_Je veux me connecter à mon compte OVH", - "231": "Je veux me connecter à <@sys.ignore|undefined|mon> compte OVH", - "232": "Je veux me connecter", - "233": "Connecte <@sys.ignore|undefined|moi>", - "234": "Transverse_Compte_Je veux me connecter à mon compte OVH1", - "235": "Je veux me connecter à <@sys.ignore|undefined|mon> compte OVH", - "236": "Je veux me connecter", - "237": "Connecte <@sys.ignore|undefined|moi>", - "238": "Transverse_Compte_Qui suis je _", - "239": "Qui suis je ?", - "240": "je suis connecté sur quel compte ?", - "241": "Suis-je connecté ?", - "242": "Qui je suis ?", - "243": "Transverse_Compte_Qui suis je _1", - "244": "Qui suis je ?", - "245": "je suis connecté sur quel compte ?", - "246": "Suis-je connecté ?", - "247": "Qui je suis ?", - "248": "Transverse_Culture_Comment postuler chez OVH _", - "249": "Je veux travailler chez OVH", - "250": "comment postuler chez OVH", - "251": "je souhaite travailler chez OVH", - "252": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", - "253": "Transverse_Culture_Comment postuler chez OVH _1", - "254": "Je veux travailler chez OVH", - "255": "comment postuler chez OVH", - "256": "je souhaite travailler chez OVH", - "257": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", - "258": "Transverse_Facture_Comment consulter ma facture _", - "259": "Obtenir ma facture", - "260": "Je veux ma facture", - "261": "Je souhaite voir ma facture", - "262": "Consulter ma dernière facture", - "263": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", - "264": "Transverse_Facture_Comment consulter ma facture _1", - "265": "Obtenir ma facture", - "266": "Je veux ma facture", - "267": "Je souhaite voir ma facture", - "268": "Consulter ma dernière facture", - "269": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", - "270": "Transverse_Facture_Quelle est la date d_expiration _", - "271": "échéance de paiement ?", - "272": "expiration", - "273": "Date d'expiration", - "274": "Je souhaite connaître la date d'expiration de mon service ?", - "275": "Quelle est la date d'expiration ?", - "276": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", - "277": "Transverse_Facture_Quelle est la date d_expiration _1", - "278": "échéance de paiement ?", - "279": "expiration", - "280": "Date d'expiration", - "281": "Je souhaite connaître la date d'expiration de mon service ?", - "282": "Quelle est la date d'expiration ?", - "283": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", - "284": "Transverse_service expires", - "285": "Quand renouveler mes abonements ?", - "286": "Quand est-ce que mes services expirent ?", - "287": "transverse_status_update", - "288": "comment vont mes services ?", - "289": "Etat de mes lignes", - "290": "quel est le status de mon cloud", - "291": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", - "292": "transverse_status_update1", - "293": "Etat de mes lignes", - "294": "quel est le status de mon cloud", - "295": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", - "296": "Web_Emails_Compte_Comment créer un compte e-mail _", - "297": "créer <@sys.number|number|un> <@1|1|compte mail>", - "298": "Comment créer une <@1|1|adresse mail> ?", - "299": "créer <@1|1|mail>", - "300": "créer <@1|1|adresse email>", - "301": "<@1|1|e-mail>", - "302": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", - "303": "Web_Emails_Compte_Comment créer un compte e-mail _1", - "304": "créer <@sys.number|number|un> <@1|1|compte mail>", - "305": "Comment créer une <@1|1|adresse mail> ?", - "306": "créer <@1|1|mail>", - "307": "créer <@1|1|adresse email>", - "308": "<@1|1|e-mail>", - "309": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", - "310": "Web_Hosting_Database_Comment créer une base de données _", - "311": "Créer <@9|9|database> ?", - "312": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", - "313": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", - "314": "Web_Hosting_Database_Comment créer une base de données _1", - "315": "Créer <@9|9|database> ?", - "316": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", - "317": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", - "318": "Web_Hosting_FTP_Comment me connecter en FTP _", - "319": "connexion <@9|9|serveur> <@9|9|FTP>", - "320": "accéder à mon <@9|9|FTP>", - "321": "mettre en ligne mon site", - "322": "connecter <@9|9|hébergement>", - "323": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", - "324": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", - "325": "Web_Hosting_FTP_Comment me connecter en FTP _1", - "326": "connexion <@9|9|serveur> <@9|9|FTP>", - "327": "accéder à mon <@9|9|FTP>", - "328": "mettre en ligne mon site", - "329": "connecter <@9|9|hébergement>", - "330": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", - "331": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", - "332": "Web_Hosting_SEO_Référencer mon site sur Google", - "333": "résultat google", - "334": "google", - "335": "je veux référencer mon site", - "336": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", - "337": "je veux <@sys.ignore|undefined|référencer> mon site", - "338": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", - "339": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", - "340": "Contactez nos partenaires pour ce type de demande.", - "341": "Web_Hosting_SEO_Référencer mon site sur Google1", - "342": "résultat google", - "343": "google", - "344": "je veux référencer mon site", - "345": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", - "346": "je veux <@sys.ignore|undefined|référencer> mon site", - "347": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", - "348": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", - "349": "Contactez nos partenaires pour ce type de demande." + "67": "Hosting_Web_Comment je fais pour changer mes serveurs dns de mon site benjtest.ovh _", + "68": "J'aimerai changer mes serveur DNS", + "69": "Comment changer mes serveurs dns ?", + "70": "Comment je fais pour changer mes serveurs dns de mon site <@sys.url|url|benjtest.ovh> ?", + "71": "Comment je peux changer mes serveurs dns ?", + "72": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon h├йbergement web _", + "73": "Comment faire pour que <@sys.url|url|benjtest.ovh> pointe sur mon hébergement web", + "74": "Comment je peux faire pointer mon domaine <@sys.url|url|benjtest.ovh> sur mon hébergement web ?", + "75": "Hosting_web_website_break", + "76": "Mon site ne marche pas", + "77": "Mon site <<@sys.url|url|http://testalldom.fr>|testalldom.fr> est cassé", + "78": "mon site web <@sys.url|url|benjamincoenen.com> ne répond plus", + "79": "<@sys.ignore|undefined|Mon> site ne fonctionne plus ☹", + "80": "Mon site <@sys.url|url|benjtest.ovh> est cassé", + "81": "Mon site web est cassé", + "82": "NDH_bad responses", + "83": "<@sys.number|number|3>", + "84": "<@sys.number|number|434321>", + "85": "<@sys.number|number|45353>", + "86": "Mauvaise réponse 🙁", + "87": "NDH_Good answer", + "88": "on vous heberge", + "89": "20", + "90": "5", + "91": "54", + "92": "10", + "93": "6 min", + "94": "6minutes", + "95": "6min", + "96": "6 minutes", + "97": "1.1.0", + "98": "On vous héberge", + "99": "78", + "100": "roubaix", + "101": "#122844", + "102": "6120", + "103": "NDH_ndh_question", + "104": "J'ai soif je veux boire", + "105": "Donne <@sys.date-period|date-period|moi> à boire", + "106": "Je veux <@sys.number|number|une> boisson", + "107": "Je suis à la nuit du hack pour la boisson", + "108": "Je veux gagner <@sys.number|number|une> boisson gratuite", + "109": "Telecom_Telephone_Telephony_break", + "110": "mon <@31|31|téléphone> est cassé", + "111": "Mon <@31|31|téléphone> ne marche pas", + "112": "peux tu faire <@sys.ignore|undefined|un> diagnostic de mon <@31|31|téléphone>", + "113": "Pourquoi je ne peux pas <@31|31|téléphoner> ?", + "114": "je n'arrive pas à appeler", + "115": "ma ligne <@31|31|téléphonique> ne marche pas", + "116": "impossible de passer <@sys.ignore|undefined|un> coup de fil", + "117": "Quand est-ce que ma ligne sera portée ?", + "118": "J'arrive pas à <@31|31|téléphoner>", + "119": "mon <@31|31|téléphone> ne fonctionne plus", + "120": "Telecom_xdsl_xdsl_break", + "121": "mon internet ne marche pas", + "122": "Peut tu faire <@sys.ignore|undefined|un> diagnostic de ma ligne ADSL ?", + "123": "Comment se passe ma comande de ligne xDSL", + "124": "mon internet est cassé", + "125": "Qu'est-ce qui va pas sur mon internet ?", + "126": "la SDSL ne répond plus", + "127": "mon VDSL est en panne", + "128": "ma ligne ADSL ne fonctionne plus", + "129": "mon modem ne capte plus", + "130": "ma box ne fonctionne plus", + "131": "je n'arrive pas à me connecter à internet", + "132": "Je n'ai plus d'internet", + "133": "Ma connection internet ne fonctionne plus", + "134": "Transverse_Compte Client_Comment devenir client _", + "135": "comment devenir cliente", + "136": "etre client ?", + "137": "Créer compte client ?", + "138": "Comment devenir client ?", + "139": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site OVH.com et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", + "140": "Transverse_Compte_Comment devenir client _", + "141": "je veux être client", + "142": "je souhaite devenir client", + "143": "comment devenir client", + "144": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", + "145": "Transverse_Compte_Je veux me connecter ├а mon compte OVH", + "146": "Je veux me connecter à <@sys.ignore|undefined|mon> compte OVH", + "147": "Je veux me connecter", + "148": "Connecte <@sys.ignore|undefined|moi>", + "149": "Transverse_Compte_Qui suis je _", + "150": "Qui suis je ?", + "151": "je suis connecté sur quel compte ?", + "152": "Suis-je connecté ?", + "153": "Qui je suis ?", + "154": "Transverse_Culture_Comment postuler chez OVH _", + "155": "Je veux travailler chez OVH", + "156": "comment postuler chez OVH", + "157": "je souhaite travailler chez OVH", + "158": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", + "159": "Transverse_Facture_Comment consulter ma facture _", + "160": "Obtenir ma facture", + "161": "Je veux ma facture", + "162": "Je souhaite voir ma facture", + "163": "Consulter ma dernière facture", + "164": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", + "165": "Transverse_Facture_Quelle est la date d_expiration _", + "166": "échéance de paiement ?", + "167": "expiration", + "168": "Date d'expiration", + "169": "Je souhaite connaître la date d'expiration de mon service ?", + "170": "Quelle est la date d'expiration ?", + "171": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", + "172": "Transverse_service expires", + "173": "Quand renouveler mes abonements ?", + "174": "Quand est-ce que mes services expirent ?", + "175": "transverse_status_update", + "176": "comment vont mes services ?", + "177": "Etat de mes lignes", + "178": "quel est le status de mon cloud", + "179": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", + "180": "Web_Emails_Compte_Comment cr├йer un compte e-mail _", + "181": "créer <@sys.number|number|un> <@1|1|compte mail>", + "182": "Comment créer une <@1|1|adresse mail> ?", + "183": "créer <@1|1|mail>", + "184": "créer <@1|1|adresse email>", + "185": "<@1|1|e-mail>", + "186": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", + "187": "Web_Hosting_Database_Comment cr├йer une base de donn├йes _", + "188": "Créer <@9|9|database> ?", + "189": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", + "190": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", + "191": "Web_Hosting_FTP_Comment me connecter en FTP _", + "192": "connexion <@9|9|serveur> <@9|9|FTP>", + "193": "accéder à mon <@9|9|FTP>", + "194": "mettre en ligne mon site", + "195": "connecter <@9|9|hébergement>", + "196": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", + "197": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", + "198": "Web_Hosting_SEO_R├йf├йrencer mon site sur Google", + "199": "résultat google", + "200": "google", + "201": "je veux référencer mon site", + "202": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", + "203": "je veux <@sys.ignore|undefined|référencer> mon site", + "204": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", + "205": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", + "206": "Contactez nos partenaires pour ce type de demande." } From ce25d968b27db262d3730897065bc58c28495a2f Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 23 Aug 2017 16:36:05 +0200 Subject: [PATCH 15/23] :lipstick: style(translations): better phrasing --- bots/messageTypes/message/service_expires.js | 2 +- bots/messageTypes/message/status_update.js | 2 +- translations/translation_fr_FR.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bots/messageTypes/message/service_expires.js b/bots/messageTypes/message/service_expires.js index 54bb9d4..081f964 100644 --- a/bots/messageTypes/message/service_expires.js +++ b/bots/messageTypes/message/service_expires.js @@ -36,7 +36,7 @@ class ServiceExpires { return responses; }); - return Bluebird.resolve({ responses: [new TextMessage(translator("diagInProgress", locale)), promise], feedback: false }); + return Bluebird.resolve({ responses: [new TextMessage(translator("scanInProgress", locale)), promise], feedback: false }); } } diff --git a/bots/messageTypes/message/status_update.js b/bots/messageTypes/message/status_update.js index fa97f69..0eae76c 100644 --- a/bots/messageTypes/message/status_update.js +++ b/bots/messageTypes/message/status_update.js @@ -29,7 +29,7 @@ class StatusUpdate { return responses; }); - return Bluebird.resolve({ responses: [new TextMessage(translator("diagInProgress", locale)), promise], feedback: false }); + return Bluebird.resolve({ responses: [new TextMessage(translator("scanInProgress", locale)), promise], feedback: false }); } } diff --git a/translations/translation_fr_FR.json b/translations/translation_fr_FR.json index e2848d6..ff28c76 100644 --- a/translations/translation_fr_FR.json +++ b/translations/translation_fr_FR.json @@ -22,7 +22,8 @@ "disconnected": "Tu n'es pas correctement connecté à ton compte OVH :( , il te suffit de me demander 'connecte-moi' pour te reconnecter.", "expires-allOk": "Rien n'est sur le point d'expiré :tada:", "dnsEditDns": "Tu peux modifier tes serveurs DNS via l'espace client OVH", - "diagInProgress": ":hourglass: Diagnostic en cours... Patiente quelques instants, le diagnostic peut prendre quelques minutes :hourglass: ", + "scanInProgress": ":hourglass: Analyse en cours... Patiente quelques instants, l'analyse peut prendre quelques minutes :hourglass:", + "diagInProgress": ":hourglass: Diagnostic en cours... Patiente quelques instants, le diagnostic peut prendre quelques minutes :hourglass:", "feedbackBadUnderstanding": "Mauvaise compréhension", "feedbackHelp": "Est-ce que cette réponse t'a aidé ?", "feedbackNo": "Non", From a2be3fb1d742a82072570b4e919c37d3b7c78b76 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Thu, 24 Aug 2017 15:09:17 +0200 Subject: [PATCH 16/23] :books: docs(package): update the documenation --- README.md | 28 +++++++++++++++++++++------- apiai/README.md | 1 + tools/README.md | 8 +++++--- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 46abc42..2bd66df 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,28 @@ The bot uses [api.ai](https://www.api.ai) as a language processor. > + **Intent**: what the user *ask* to the bot. > + **Response**: What the bot *respond* to an user. -All the intents needing dynamic responses can be found [here](bots/README.md). However, the responses to intents which doesn't need a dynamic response are stored in [api.ai](https://www.api.ai) database. +All the intents needing processed responses can be found [here](bots/). + +The intents which doesn't need processed responses (aka: answers to basic questions) are stored in the [api.ai](https://www.api.ai) database, have a look at the [api.ai folder](apiai/). + +This intents and response are translated in: ++ Dutch ++ English (US, CA, GB) ++ French ++ German ++ Italian ++ Portuguese ++ Spanish ### Diagnostics -Currently, this bot is able to diagnose a website, a xdsl line or a phone line. -More details [here](diagnostics/README.md) +Currently, this bot is able to: ++ diagnose a website ++ diagnose a xDSL line ++ diagnose a land line ++ warn about the expiration of a service ++ warn when an incident happens + +More details [here](diagnostics/) ## Contributing @@ -67,10 +84,7 @@ Have a look at the [Contributing section](CONTRIBUTING.md). If you have any ques + Refactor to typescript + Docker compose + Documentation -+ Translations -+ When will my service expire? -+ Monitoring -+ Alerting ++ Cloud diagnostics ## License See https://github.com/ovh-ux/ovh-chatbot/blob/master/LICENSE diff --git a/apiai/README.md b/apiai/README.md index 8be92a9..a6569de 100644 --- a/apiai/README.md +++ b/apiai/README.md @@ -3,6 +3,7 @@ > All the files related to apiai agents - `translations/`: contains the translation files. +- `archives/`: contains an archive of the chatbot api.ai setup. It is used to generate the other archives - `template.json`: template file where every number is replaced by its corresponding value from the translations files Have a look at [/tools](../tools)! diff --git a/tools/README.md b/tools/README.md index 3035975..52ad20a 100644 --- a/tools/README.md +++ b/tools/README.md @@ -28,7 +28,9 @@ Tool to update all the api.ai agents at once. 4. Provide all the translations files needed based of the generated translation file: `translations/apiai_fr.json` -5. Set the `APIAI_COOKIE` environment variable, how to do it: +5. Update the translations + +6. Set the `APIAI_COOKIE` environment variable, how to do it: - Login to api.ai. - Open the developer tools. - Go to https://console.api.ai/api-client/user/. @@ -36,6 +38,6 @@ Tool to update all the api.ai agents at once. - Find the request. - The cookie value, in the request headers is what you need. -6. `$ grunt import`: it will generate back the different archives and upload it to api.ai +7. `$ grunt import`: it will generate back the different archives and upload it to api.ai -7. You're done! Each agent in api.ai has been updated to the last translations files and the new intents and entities have been added :tada: +8. You're done! Each agent in api.ai has been updated to the last translations files and the new intents and entities have been added :tada: From 63ea0e32a9a348335045aaf1fae0e83c92fa5a4d Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Tue, 29 Aug 2017 11:10:24 +0200 Subject: [PATCH 17/23] chore: update apiai --- apiai/archives/ovh-chatbot.zip | Bin 25525 -> 22864 bytes apiai/template.json | 55 ++++++++++++----------- apiai/translations/apiai_fr.json | 75 ++++++++++++++++--------------- 3 files changed, 67 insertions(+), 63 deletions(-) diff --git a/apiai/archives/ovh-chatbot.zip b/apiai/archives/ovh-chatbot.zip index b619c80f6e0792b14af8cb94dd1759ca15c58bda..43a8b0b7bfd9c0239356788c2f85f4554c6413dc 100644 GIT binary patch literal 22864 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 literal 25525 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 diff --git a/apiai/template.json b/apiai/template.json index b243fc6..1f2b76a 100644 --- a/apiai/template.json +++ b/apiai/template.json @@ -166,7 +166,7 @@ "ndh_question" ], "auto": true, - "priority": 500000 + "priority": 0 }, "87": { "userSays": [ @@ -189,9 +189,11 @@ "responses": [], "action": "good_answer", "contextAdd": {}, - "contextNeed": [], + "contextNeed": [ + "ndh_question" + ], "auto": false, - "priority": 500000 + "priority": 0 }, "103": { "userSays": [ @@ -208,7 +210,7 @@ }, "contextNeed": [], "auto": true, - "priority": 500000 + "priority": 0 }, "109": { "userSays": [ @@ -362,7 +364,9 @@ "172": { "userSays": [ "173", - "174" + "174", + "175", + "176" ], "responses": [], "action": "service_expires", @@ -371,12 +375,11 @@ "auto": true, "priority": 500000 }, - "175": { + "177": { "userSays": [ - "176", - "177", "178", - "179" + "179", + "180" ], "responses": [], "action": "status_update", @@ -385,16 +388,16 @@ "auto": true, "priority": 500000 }, - "180": { + "181": { "userSays": [ - "181", "182", "183", "184", - "185" + "185", + "186" ], "responses": [ - "186" + "187" ], "action": "email_account_create", "contextAdd": {}, @@ -402,13 +405,13 @@ "auto": true, "priority": 500000 }, - "187": { + "188": { "userSays": [ - "188", - "189" + "189", + "190" ], "responses": [ - "190" + "191" ], "action": "hosting_db_create", "contextAdd": {}, @@ -416,16 +419,16 @@ "auto": true, "priority": 500000 }, - "191": { + "192": { "userSays": [ - "192", "193", "194", - "195" + "195", + "196" ], "responses": [ - "196", - "197" + "197", + "198" ], "action": "hosting_ftp_connect", "contextAdd": {}, @@ -433,18 +436,18 @@ "auto": true, "priority": 500000 }, - "198": { + "199": { "userSays": [ - "199", "200", "201", "202", "203", "204", - "205" + "205", + "206" ], "responses": [ - "206" + "207" ], "action": "hosting_seo_partners", "contextAdd": {}, diff --git a/apiai/translations/apiai_fr.json b/apiai/translations/apiai_fr.json index 8ef5668..9df7dfa 100644 --- a/apiai/translations/apiai_fr.json +++ b/apiai/translations/apiai_fr.json @@ -70,7 +70,7 @@ "69": "Comment changer mes serveurs dns ?", "70": "Comment je fais pour changer mes serveurs dns de mon site <@sys.url|url|benjtest.ovh> ?", "71": "Comment je peux changer mes serveurs dns ?", - "72": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon h├йbergement web _", + "72": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon hébergement web _", "73": "Comment faire pour que <@sys.url|url|benjtest.ovh> pointe sur mon hébergement web", "74": "Comment je peux faire pointer mon domaine <@sys.url|url|benjtest.ovh> sur mon hébergement web ?", "75": "Hosting_web_website_break", @@ -143,7 +143,7 @@ "142": "je souhaite devenir client", "143": "comment devenir client", "144": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", - "145": "Transverse_Compte_Je veux me connecter ├а mon compte OVH", + "145": "Transverse_Compte_Je veux me connecter à mon compte OVH", "146": "Je veux me connecter à <@sys.ignore|undefined|mon> compte OVH", "147": "Je veux me connecter", "148": "Connecte <@sys.ignore|undefined|moi>", @@ -170,39 +170,40 @@ "169": "Je souhaite connaître la date d'expiration de mon service ?", "170": "Quelle est la date d'expiration ?", "171": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", - "172": "Transverse_service expires", - "173": "Quand renouveler mes abonements ?", - "174": "Quand est-ce que mes services expirent ?", - "175": "transverse_status_update", - "176": "comment vont mes services ?", - "177": "Etat de mes lignes", - "178": "quel est le status de mon cloud", - "179": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", - "180": "Web_Emails_Compte_Comment cr├йer un compte e-mail _", - "181": "créer <@sys.number|number|un> <@1|1|compte mail>", - "182": "Comment créer une <@1|1|adresse mail> ?", - "183": "créer <@1|1|mail>", - "184": "créer <@1|1|adresse email>", - "185": "<@1|1|e-mail>", - "186": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", - "187": "Web_Hosting_Database_Comment cr├йer une base de donn├йes _", - "188": "Créer <@9|9|database> ?", - "189": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", - "190": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", - "191": "Web_Hosting_FTP_Comment me connecter en FTP _", - "192": "connexion <@9|9|serveur> <@9|9|FTP>", - "193": "accéder à mon <@9|9|FTP>", - "194": "mettre en ligne mon site", - "195": "connecter <@9|9|hébergement>", - "196": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", - "197": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", - "198": "Web_Hosting_SEO_R├йf├йrencer mon site sur Google", - "199": "résultat google", - "200": "google", - "201": "je veux référencer mon site", - "202": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", - "203": "je veux <@sys.ignore|undefined|référencer> mon site", - "204": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", - "205": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", - "206": "Contactez nos partenaires pour ce type de demande." + "172": "Transverse_service_expire", + "173": "Quand mes services vont ils expirer ?", + "174": "Quand se termine l'utilisation de mes services ?", + "175": "Quand finissent mes services ?", + "176": "quand-est-ce que mes services expirent ?", + "177": "transverse_status_update", + "178": "Etat de mes lignes", + "179": "quel est le status de mon cloud", + "180": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", + "181": "Web_Emails_Compte_Comment créer un compte e-mail _", + "182": "créer <@sys.number|number|un> <@1|1|compte mail>", + "183": "Comment créer une <@1|1|adresse mail> ?", + "184": "créer <@1|1|mail>", + "185": "créer <@1|1|adresse email>", + "186": "<@1|1|e-mail>", + "187": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", + "188": "Web_Hosting_Database_Comment créer une base de données _", + "189": "Créer <@9|9|database> ?", + "190": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", + "191": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", + "192": "Web_Hosting_FTP_Comment me connecter en FTP _", + "193": "connexion <@9|9|serveur> <@9|9|FTP>", + "194": "accéder à mon <@9|9|FTP>", + "195": "mettre en ligne mon site", + "196": "connecter <@9|9|hébergement>", + "197": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", + "198": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", + "199": "Web_Hosting_SEO_Référencer mon site sur Google", + "200": "résultat google", + "201": "google", + "202": "je veux référencer mon site", + "203": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", + "204": "je veux <@sys.ignore|undefined|référencer> mon site", + "205": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", + "206": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", + "207": "Contactez nos partenaires pour ce type de demande." } From 979c0259f866aad5ec8c79d694fda76f04397b1b Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Tue, 29 Aug 2017 17:09:26 +0200 Subject: [PATCH 18/23] :lipstick: style(expire): update apiai & translations --- README.md | 4 +- apiai/archives/ovh-chatbot.zip | Bin 22864 -> 24308 bytes apiai/template.json | 130 +++++++++++-------- apiai/translations/apiai_fr.json | 120 +++++++++-------- bots/messageTypes/message/service_expires.js | 1 + controllers/web.js | 8 +- translations/translation_fr_FR.json | 1 + 7 files changed, 150 insertions(+), 114 deletions(-) diff --git a/README.md b/README.md index 2bd66df..191c24e 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,9 @@ Have a look at the [Contributing section](CONTRIBUTING.md). If you have any ques + Refactor to typescript + Docker compose + Documentation -+ Cloud diagnostics ++ Cloud diagnostics (vps) ++ Order followup ++ Improve conversation skill ## License See https://github.com/ovh-ux/ovh-chatbot/blob/master/LICENSE diff --git a/apiai/archives/ovh-chatbot.zip b/apiai/archives/ovh-chatbot.zip index 43a8b0b7bfd9c0239356788c2f85f4554c6413dc..13de7d91308f1dfc3a87077da7a28a3a9e7f96ae 100644 GIT binary patch delta 4352 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 W(8%N97z%+1fS*@jZ(ubit^NZFvD}FO delta 2739 zcmZuzc|25Y8$L7En6XR@GK;-rpGKjvjIGJUs2KZ1H5Ednp;D6;6-7ES5qgo5B}8bl zlwE`f711Io*+O2t_-0Pu+n3+(JO5n2dpXyAJ@@lG_c=3_u#Sf?gd+g&m+B{nOkuBQ?yJ-43D;bw8oy)oJ?{xc0b z3)E8B%|Ai}xab#71n+7q4uf#`;k`3v@e!w!_M^*@9eX>8fjN;o*A-5tRlxmUs^rF< zH9|3+z;4`6-&r=y)xAx2v2gy?x23_hZ;>fb(*BQbE;#++c2mTIHCBq@}QAD>Hb@ z9<~?$?79&j`^1FFI{TDs(b9`&+9rCJj-+y9O+Tp_ynamTF_O1k3%AfkR2iR5JG*V4TNEmXeb_sN`>+B6wwbMyIsK=!aRHl zKM#yUtt*aDdCT{Kt{P74gl8eQ^rfOEj*B5HZA$?kB@V8$xui1m?VZOZ*me~i@>&Z7 ziq%P!OrY*j(W9@~8VjBvd`h}&=3UgX9AUojVff57Z~fP|YaXqMZQ2s%(DWia6szu~ z;~gwtBx994M7m27uqB_rJ{+Q9Q#XCZN&#cmN+~Sd`IfHu1YMBF?yaa^+r5M>fnT=n zjI0s%pbiM%iV5n?#VazIZG~U`3P)t@vXO!AmXi6s%zYnz9^oLzjbeDhzyB`zp&Yy>8oknKoCr{SzK5md3&jn_wAYd zJ8lOyud#$_b)e$15;)o+1#Ctqsnuw>SY?NT;+UWgo5&y;jiwule@C{_EMBKK z&g(AEqZcBwfOFjr&wkcYzBIY72sTV~Mc?1n^|j}HEG^ML-Sl)yxL;@F-#53CMknc^ zpOf3B4_AuCZDL-o$snDMHDGNWN%a{`Nb6A~3hS1Nt_*aKwwZ5Wm3tAf8QG-wk8y~v zGlfrYoAn>aX6JiU-VE3oDc{g-`Q#0wh3sZ!mRi03z{vK>Gy`n;WQ_Z~-nb=fYSz`M zhc$f2#7md6wlZ78a!Z%6`@xLcb_sUni_h=-sWa?1_Pq+adm+cao3Udl>eMqdr#j^U z2P+i(Q1xmp$7qtHgdj&b$a0V)gZmmmr07cIG=aveb?JrG~2GO1mQRHxy>H zC|}ziuZO?>R$D$sIBs0H$Bet*eB@Tqiy0a&w;BD}SvxBS$+6o{+T>fW+%7~5@eu=u z-40lXPNCSD%1_O@f=infCylQdS4(vGm0Gt`BABvRx|ib308;Ij0h7@0yG!Ew#~rGF z5_$$dJ`7S)%G%Ts-v7jDOGze$q);kXV30+iE8L0Bwf0Ms%?{7s_1?YCRoppCc4%VX zk0v-bD#g8#j6Vp+**Xa{adOm6CrFzOgkdVHo_E*DatiO@$&x^6=46@|^SY^fP(VrZD%*#7FO z?-~hR&v@o|?cQI5mQpxK7ULbLNTJmS3T)k^UfiMi2pXmrwZB8dvYoQ7I8ILm@)aA% zLD;&f6~g4r51_$nXQB$(L8M3sPm{|bG_oc_7-+i(!gk6p|7EHPG<@qF=J<2EiiUvZ zb*rN_gs5Ez7;=JwrT+dRfLgn?plQ7u18;?a6EH0J)eXV-r0>SS!oaFu;Za`rr3grK zl?8E5L_D8DwRU&9Id82YyvwugkLv;ezF@Euolnv1gn?s`papV0DB%o|Vw^Fs{h+Zk zjUSG7#=s*`;BAx!*!C-|NyoqyWk4-78N5VCDDlf6t1_bocxCR20)WY?GVOBUpaKb; zq(jV(E*QA1A{gir#HSwQSuI#_$%O!s{CUyIt4N+H^A<&elK$L0ja5mFYW$Te|DO@y zNQJ>=fPepdz`tBEaP{?2n>sYLz-3oR8o~_&hiwGeBs6H@hU3fg=6NQx!P9O~?{j&U zjvmSGl(*2CiZLJCfvy z=QD75UQhD>ytdjP-V0*V@xs6>t-wJF9`yU=3FmpjY7VBlOTc!{CPSDDYV W0DG{7p(ud|@PMv303aOrZ~q6+8FCi@ diff --git a/apiai/template.json b/apiai/template.json index 1f2b76a..9360af8 100644 --- a/apiai/template.json +++ b/apiai/template.json @@ -315,12 +315,24 @@ }, "154": { "userSays": [ - "155", - "156", - "157" + "155" ], "responses": [ - "158" + "156" + ], + "contextAdd": {}, + "contextNeed": [], + "auto": true, + "priority": 500000 + }, + "157": { + "userSays": [ + "158", + "159", + "160" + ], + "responses": [ + "161" ], "action": "transverse_culture_postuler", "contextAdd": {}, @@ -328,15 +340,15 @@ "auto": true, "priority": 500000 }, - "159": { + "162": { "userSays": [ - "160", - "161", - "162", - "163" + "163", + "164", + "165", + "166" ], "responses": [ - "164" + "167" ], "action": "billing_show_bill", "contextAdd": {}, @@ -344,110 +356,122 @@ "auto": true, "priority": 500000 }, - "165": { + "168": { "userSays": [ - "166", - "167", - "168", "169", - "170" + "170", + "171", + "172", + "173", + "174" ], "responses": [ - "171" + "175" ], - "action": "tranverse_facture_dateexpiration", + "action": "service_expires", "contextAdd": {}, "contextNeed": [], "auto": true, "priority": 500000 }, - "172": { + "176": { "userSays": [ - "173", - "174", - "175", - "176" + "177" + ], + "responses": [ + "178" ], - "responses": [], - "action": "service_expires", "contextAdd": {}, "contextNeed": [], "auto": true, "priority": 500000 }, - "177": { + "179": { "userSays": [ - "178", - "179", - "180" + "180", + "181" + ], + "responses": [ + "182" ], - "responses": [], - "action": "status_update", "contextAdd": {}, "contextNeed": [], "auto": true, "priority": 500000 }, - "181": { + "183": { "userSays": [ - "182", - "183", "184", "185", "186" ], - "responses": [ - "187" - ], - "action": "email_account_create", + "responses": [], + "action": "status_update", "contextAdd": {}, "contextNeed": [], "auto": true, "priority": 500000 }, - "188": { + "187": { "userSays": [ + "188", "189", - "190" + "190", + "191", + "192" ], "responses": [ - "191" + "193" ], - "action": "hosting_db_create", + "action": "email_account_create", "contextAdd": {}, "contextNeed": [], "auto": true, "priority": 500000 }, - "192": { + "194": { "userSays": [ - "193", - "194", "195", "196" ], "responses": [ - "197", - "198" + "197" ], - "action": "hosting_ftp_connect", + "action": "hosting_db_create", "contextAdd": {}, "contextNeed": [], "auto": true, "priority": 500000 }, - "199": { + "198": { "userSays": [ + "199", "200", "201", - "202", + "202" + ], + "responses": [ "203", - "204", - "205", - "206" + "204" + ], + "action": "hosting_ftp_connect", + "contextAdd": {}, + "contextNeed": [], + "auto": true, + "priority": 500000 + }, + "205": { + "userSays": [ + "206", + "207", + "208", + "209", + "210", + "211", + "212" ], "responses": [ - "207" + "213" ], "action": "hosting_seo_partners", "contextAdd": {}, diff --git a/apiai/translations/apiai_fr.json b/apiai/translations/apiai_fr.json index 9df7dfa..852f813 100644 --- a/apiai/translations/apiai_fr.json +++ b/apiai/translations/apiai_fr.json @@ -103,7 +103,7 @@ "102": "6120", "103": "NDH_ndh_question", "104": "J'ai soif je veux boire", - "105": "Donne <@sys.date-period|date-period|moi> à boire", + "105": "Donne moi à boire", "106": "Je veux <@sys.number|number|une> boisson", "107": "Je suis à la nuit du hack pour la boisson", "108": "Je veux gagner <@sys.number|number|une> boisson gratuite", @@ -144,66 +144,72 @@ "143": "comment devenir client", "144": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", "145": "Transverse_Compte_Je veux me connecter à mon compte OVH", - "146": "Je veux me connecter à <@sys.ignore|undefined|mon> compte OVH", + "146": "Je veux me connecter à mon compte OVH", "147": "Je veux me connecter", - "148": "Connecte <@sys.ignore|undefined|moi>", + "148": "Connecte moi", "149": "Transverse_Compte_Qui suis je _", "150": "Qui suis je ?", "151": "je suis connecté sur quel compte ?", "152": "Suis-je connecté ?", "153": "Qui je suis ?", - "154": "Transverse_Culture_Comment postuler chez OVH _", - "155": "Je veux travailler chez OVH", - "156": "comment postuler chez OVH", - "157": "je souhaite travailler chez OVH", - "158": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", - "159": "Transverse_Facture_Comment consulter ma facture _", - "160": "Obtenir ma facture", - "161": "Je veux ma facture", - "162": "Je souhaite voir ma facture", - "163": "Consulter ma dernière facture", - "164": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", - "165": "Transverse_Facture_Quelle est la date d_expiration _", - "166": "échéance de paiement ?", - "167": "expiration", - "168": "Date d'expiration", - "169": "Je souhaite connaître la date d'expiration de mon service ?", - "170": "Quelle est la date d'expiration ?", - "171": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", - "172": "Transverse_service_expire", - "173": "Quand mes services vont ils expirer ?", - "174": "Quand se termine l'utilisation de mes services ?", - "175": "Quand finissent mes services ?", - "176": "quand-est-ce que mes services expirent ?", - "177": "transverse_status_update", - "178": "Etat de mes lignes", - "179": "quel est le status de mon cloud", - "180": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", - "181": "Web_Emails_Compte_Comment créer un compte e-mail _", - "182": "créer <@sys.number|number|un> <@1|1|compte mail>", - "183": "Comment créer une <@1|1|adresse mail> ?", - "184": "créer <@1|1|mail>", - "185": "créer <@1|1|adresse email>", - "186": "<@1|1|e-mail>", - "187": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", - "188": "Web_Hosting_Database_Comment créer une base de données _", - "189": "Créer <@9|9|database> ?", - "190": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", - "191": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", - "192": "Web_Hosting_FTP_Comment me connecter en FTP _", - "193": "connexion <@9|9|serveur> <@9|9|FTP>", - "194": "accéder à mon <@9|9|FTP>", - "195": "mettre en ligne mon site", - "196": "connecter <@9|9|hébergement>", - "197": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", - "198": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", - "199": "Web_Hosting_SEO_Référencer mon site sur Google", - "200": "résultat google", - "201": "google", - "202": "je veux référencer mon site", - "203": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", - "204": "je veux <@sys.ignore|undefined|référencer> mon site", - "205": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", - "206": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", - "207": "Contactez nos partenaires pour ce type de demande." + "154": "Transverse_contact", + "155": "Contacté OVH", + "156": "Pour nous contacter, rend tois sur notre ", + "157": "Transverse_Culture_Comment postuler chez OVH _", + "158": "Je veux travailler chez OVH", + "159": "comment postuler chez OVH", + "160": "je souhaite travailler chez OVH", + "161": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", + "162": "Transverse_Facture_Comment consulter ma facture _", + "163": "Obtenir ma facture", + "164": "Je veux ma facture", + "165": "Je souhaite voir ma facture", + "166": "Consulter ma dernière facture", + "167": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", + "168": "Transverse_Facture_Quelle est la date d_expiration _", + "169": "Quand est-ce que mes services arivent à expiration ?", + "170": "échéance de paiement ?", + "171": "expiration", + "172": "Date d'expiration", + "173": "Je souhaite connaître la date d'expiration de mon service ?", + "174": "Quelle est la date d'expiration ?", + "175": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", + "176": "Transverse_lost_password", + "177": "j'ai perdu mon mot de passe", + "178": "Rends toi sur la page de connexion ici :https://www.ovh.com/auth/ et clique sur \"Forgotten your username or password?\". Puis indique ton email ou ton nichandle et clique sur submit. Tu recevras alors un email pour réinialisé ton mot de passe. Plus d'information ici : https://docs.ovh.com/fr/fr/account/customer/tout-savoir-sur-identifiant-client/#id7", + "179": "Transverse_Report_abuse", + "180": "Je veux signaler <@sys.ignore|undefined|une> tentative de phishing", + "181": "J'ai réçu <@sys.ignore|undefined|un> <@1|1|mail> frauduleux", + "182": "pour signaler un abus, ou un contenu illicite rends toi ici : https://www.ovh.com/fr/abuse", + "183": "transverse_status_update", + "184": "Etat de mes lignes", + "185": "quel est le status de mon cloud", + "186": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", + "187": "Web_Emails_Compte_Comment créer un compte e-mail _", + "188": "créer <@sys.number|number|un> <@1|1|compte mail>", + "189": "Comment créer une <@1|1|adresse mail> ?", + "190": "créer <@1|1|mail>", + "191": "créer <@1|1|adresse email>", + "192": "<@1|1|e-mail>", + "193": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", + "194": "Web_Hosting_Database_Comment créer une base de données _", + "195": "Créer <@9|9|database> ?", + "196": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", + "197": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", + "198": "Web_Hosting_FTP_Comment me connecter en FTP _", + "199": "connexion <@9|9|serveur> <@9|9|FTP>", + "200": "accéder à mon <@9|9|FTP>", + "201": "mettre en ligne mon site", + "202": "connecter <@9|9|hébergement>", + "203": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", + "204": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", + "205": "Web_Hosting_SEO_Référencer mon site sur Google", + "206": "résultat google", + "207": "google", + "208": "je veux référencer mon site", + "209": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", + "210": "je veux <@sys.ignore|undefined|référencer> mon site", + "211": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", + "212": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", + "213": "Contactez nos partenaires pour ce type de demande." } diff --git a/bots/messageTypes/message/service_expires.js b/bots/messageTypes/message/service_expires.js index 081f964..82e6333 100644 --- a/bots/messageTypes/message/service_expires.js +++ b/bots/messageTypes/message/service_expires.js @@ -22,6 +22,7 @@ class ServiceExpires { if (!responses.length) { responses = [new TextMessage(translator("expires-allOk", locale))]; } + responses.push(new TextMessage(translator("serviceExpireInfo", locale))); return responses; }) .then((responses) => { diff --git a/controllers/web.js b/controllers/web.js index 430ed47..c159dec 100644 --- a/controllers/web.js +++ b/controllers/web.js @@ -9,17 +9,19 @@ const translator = require("../utils/translator"); module.exports = () => { const sendQuickResponses = (res, nichandle, responses) => - Bluebird.mapSeries(responses, (response) => { + ({ responses: responses.map((response) => { switch (response.type) { case 0: { const textResponse = response.speech.replace(/<(.*)\|+(.*)>/, "$1"); - return Bluebird.resolve({ responses: [textResponse] }); + return new TextMessage(textResponse); } default: { const textResponse = response.speech.replace(/<(.*)\|+(.*)>/, "$1"); - return Bluebird.resolve({ responses: [textResponse] }); + return new TextMessage(textResponse); } } + }), + feedback: true }); const postbackReceived = (res, nichandle, payload, locale) => diff --git a/translations/translation_fr_FR.json b/translations/translation_fr_FR.json index ff28c76..7b304e5 100644 --- a/translations/translation_fr_FR.json +++ b/translations/translation_fr_FR.json @@ -58,6 +58,7 @@ "off": "Desactivé", "preferences": "Préférences", "serviceInfo": ":pushpin: %1$s:\n%2$s", + "serviceExpireInfo": "Tu peux gérer le renouvellement automatique de tes services ici :point_right: https://www.ovh.com/manager/dedicated/index.html#/billing/autoRenew", "serviceHasExpired": "\t• Le service \"%1$s\" (état actuel: %2$s) est expiré depuis %3$s jour(s) (%4$s)", "serviceWillExpired": "\t• Le service \"%1$s\" (état actuel: %2$s) va expiré dans %3$s jour(s) (%4$s)", "service-ok": "En fonctionement", From 4a6f5927a6fa7a886fa7604e5979959b614fad40 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 30 Aug 2017 15:46:09 +0200 Subject: [PATCH 19/23] chore(apiai): add some training to AI --- apiai/archives/ovh-chatbot.zip | Bin 24308 -> 25041 bytes apiai/template.json | 257 +++++++++--------- apiai/translations/apiai_fr.json | 429 ++++++++++++++++--------------- 3 files changed, 347 insertions(+), 339 deletions(-) diff --git a/apiai/archives/ovh-chatbot.zip b/apiai/archives/ovh-chatbot.zip index 13de7d91308f1dfc3a87077da7a28a3a9e7f96ae..778de49f4e8cc36f3bc65e248f2f0299c0639f8d 100644 GIT binary patch delta 7311 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 VT^aq>m7ekPCc!~L$=ALr{RbVVl579~ delta 6761 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 ?", - "63": "Je souhaite avoir <@sys.number|number|un> <@9|9|hébergement> gratuit", - "64": "Lorsque vous disposez d'un nom de domaine, vous pouvez activer un \"Start 10m\" qui vous permet de créer une adresse email et de disposer d'un petit hébergement FTP de 10 Mo.", - "65": "Pour l'activer, il vous suffit de vous rendre sur votre nom de domaine sur , puis de cliquez sur le bouton \"Activer\" à la ligne \"Hébergement Web et e-mail gratuit\".", - "66": "L'activation ne prendra que quelques minutes et vous pourrez ensuite créer une adresse email.", - "67": "Hosting_Web_Comment je fais pour changer mes serveurs dns de mon site benjtest.ovh _", - "68": "J'aimerai changer mes serveur DNS", - "69": "Comment changer mes serveurs dns ?", - "70": "Comment je fais pour changer mes serveurs dns de mon site <@sys.url|url|benjtest.ovh> ?", - "71": "Comment je peux changer mes serveurs dns ?", - "72": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon hébergement web _", - "73": "Comment faire pour que <@sys.url|url|benjtest.ovh> pointe sur mon hébergement web", - "74": "Comment je peux faire pointer mon domaine <@sys.url|url|benjtest.ovh> sur mon hébergement web ?", - "75": "Hosting_web_website_break", - "76": "Mon site ne marche pas", - "77": "Mon site <<@sys.url|url|http://testalldom.fr>|testalldom.fr> est cassé", - "78": "mon site web <@sys.url|url|benjamincoenen.com> ne répond plus", - "79": "<@sys.ignore|undefined|Mon> site ne fonctionne plus ☹", - "80": "Mon site <@sys.url|url|benjtest.ovh> est cassé", - "81": "Mon site web est cassé", - "82": "NDH_bad responses", - "83": "<@sys.number|number|3>", - "84": "<@sys.number|number|434321>", - "85": "<@sys.number|number|45353>", - "86": "Mauvaise réponse 🙁", - "87": "NDH_Good answer", - "88": "on vous heberge", - "89": "20", - "90": "5", - "91": "54", - "92": "10", - "93": "6 min", - "94": "6minutes", - "95": "6min", - "96": "6 minutes", - "97": "1.1.0", - "98": "On vous héberge", - "99": "78", - "100": "roubaix", - "101": "#122844", - "102": "6120", - "103": "NDH_ndh_question", - "104": "J'ai soif je veux boire", - "105": "Donne moi à boire", - "106": "Je veux <@sys.number|number|une> boisson", - "107": "Je suis à la nuit du hack pour la boisson", - "108": "Je veux gagner <@sys.number|number|une> boisson gratuite", - "109": "Telecom_Telephone_Telephony_break", - "110": "mon <@31|31|téléphone> est cassé", - "111": "Mon <@31|31|téléphone> ne marche pas", - "112": "peux tu faire <@sys.ignore|undefined|un> diagnostic de mon <@31|31|téléphone>", - "113": "Pourquoi je ne peux pas <@31|31|téléphoner> ?", - "114": "je n'arrive pas à appeler", - "115": "ma ligne <@31|31|téléphonique> ne marche pas", - "116": "impossible de passer <@sys.ignore|undefined|un> coup de fil", - "117": "Quand est-ce que ma ligne sera portée ?", - "118": "J'arrive pas à <@31|31|téléphoner>", - "119": "mon <@31|31|téléphone> ne fonctionne plus", - "120": "Telecom_xdsl_xdsl_break", - "121": "mon internet ne marche pas", - "122": "Peut tu faire <@sys.ignore|undefined|un> diagnostic de ma ligne ADSL ?", - "123": "Comment se passe ma comande de ligne xDSL", - "124": "mon internet est cassé", - "125": "Qu'est-ce qui va pas sur mon internet ?", - "126": "la SDSL ne répond plus", - "127": "mon VDSL est en panne", - "128": "ma ligne ADSL ne fonctionne plus", - "129": "mon modem ne capte plus", - "130": "ma box ne fonctionne plus", - "131": "je n'arrive pas à me connecter à internet", - "132": "Je n'ai plus d'internet", - "133": "Ma connection internet ne fonctionne plus", - "134": "Transverse_Compte Client_Comment devenir client _", - "135": "comment devenir cliente", - "136": "etre client ?", - "137": "Créer compte client ?", - "138": "Comment devenir client ?", - "139": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site OVH.com et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", - "140": "Transverse_Compte_Comment devenir client _", - "141": "je veux être client", - "142": "je souhaite devenir client", - "143": "comment devenir client", - "144": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", - "145": "Transverse_Compte_Je veux me connecter à mon compte OVH", - "146": "Je veux me connecter à mon compte OVH", - "147": "Je veux me connecter", - "148": "Connecte moi", - "149": "Transverse_Compte_Qui suis je _", - "150": "Qui suis je ?", - "151": "je suis connecté sur quel compte ?", - "152": "Suis-je connecté ?", - "153": "Qui je suis ?", - "154": "Transverse_contact", - "155": "Contacté OVH", - "156": "Pour nous contacter, rend tois sur notre ", - "157": "Transverse_Culture_Comment postuler chez OVH _", - "158": "Je veux travailler chez OVH", - "159": "comment postuler chez OVH", - "160": "je souhaite travailler chez OVH", - "161": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", - "162": "Transverse_Facture_Comment consulter ma facture _", - "163": "Obtenir ma facture", - "164": "Je veux ma facture", - "165": "Je souhaite voir ma facture", - "166": "Consulter ma dernière facture", - "167": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", - "168": "Transverse_Facture_Quelle est la date d_expiration _", - "169": "Quand est-ce que mes services arivent à expiration ?", - "170": "échéance de paiement ?", - "171": "expiration", - "172": "Date d'expiration", - "173": "Je souhaite connaître la date d'expiration de mon service ?", - "174": "Quelle est la date d'expiration ?", - "175": "Vous pouvez consultez la date d'expiration de chacun de vos produits OVH sur l'espace client via .", - "176": "Transverse_lost_password", - "177": "j'ai perdu mon mot de passe", - "178": "Rends toi sur la page de connexion ici :https://www.ovh.com/auth/ et clique sur \"Forgotten your username or password?\". Puis indique ton email ou ton nichandle et clique sur submit. Tu recevras alors un email pour réinialisé ton mot de passe. Plus d'information ici : https://docs.ovh.com/fr/fr/account/customer/tout-savoir-sur-identifiant-client/#id7", - "179": "Transverse_Report_abuse", - "180": "Je veux signaler <@sys.ignore|undefined|une> tentative de phishing", - "181": "J'ai réçu <@sys.ignore|undefined|un> <@1|1|mail> frauduleux", - "182": "pour signaler un abus, ou un contenu illicite rends toi ici : https://www.ovh.com/fr/abuse", - "183": "transverse_status_update", - "184": "Etat de mes lignes", - "185": "quel est le status de mon cloud", - "186": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", - "187": "Web_Emails_Compte_Comment créer un compte e-mail _", - "188": "créer <@sys.number|number|un> <@1|1|compte mail>", - "189": "Comment créer une <@1|1|adresse mail> ?", - "190": "créer <@1|1|mail>", - "191": "créer <@1|1|adresse email>", - "192": "<@1|1|e-mail>", - "193": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", - "194": "Web_Hosting_Database_Comment créer une base de données _", - "195": "Créer <@9|9|database> ?", - "196": "Comment créer <@sys.number|number|une> <@9|9|base de données> ?", - "197": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", - "198": "Web_Hosting_FTP_Comment me connecter en FTP _", - "199": "connexion <@9|9|serveur> <@9|9|FTP>", - "200": "accéder à mon <@9|9|FTP>", - "201": "mettre en ligne mon site", - "202": "connecter <@9|9|hébergement>", - "203": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", - "204": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", - "205": "Web_Hosting_SEO_Référencer mon site sur Google", - "206": "résultat google", - "207": "google", - "208": "je veux référencer mon site", - "209": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", - "210": "je veux <@sys.ignore|undefined|référencer> mon site", - "211": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", - "212": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", - "213": "Contactez nos partenaires pour ce type de demande." + "26": "Référencement", + "27": "résultat google", + "28": "referencement", + "29": "recherche google", + "30": "Telephone", + "31": "téléphone", + "32": "telephone", + "33": "phone", + "34": "fixe", + "35": "tube", + "36": "tel", + "37": "téléphoner", + "38": "téléphonique", + "39": "téléphoner", + "40": "Default Fallback Intent", + "41": "J'ai du mal à comprendre cette question.", + "42": "J'ai mal compris ta demande.", + "43": "Je n'ai pas bien compris ce que tu as dit.", + "44": "Default Welcome Intent", + "45": "Bonsoir", + "46": "Bonjour", + "47": "Hello", + "48": "Coucou", + "49": "Salut", + "50": "En te remerciant", + "51": "Merci", + "52": "En te remerciant", + "53": "Merci bien", + "54": "Je te remercie", + "55": "Merci beaucoup", + "56": "De rien", + "57": "Avec plaisir", + "58": "Pas de soucis", + "59": "Hosting_Commerciale_Comment activer un start 10m _", + "60": "je veux mon start10m", + "61": "Comment activer mon start <@sys.ignore|undefined|10>M ?", + "62": "Je souhaite avoir <@sys.number|number|un> <@15|15|hébergement> gratuit", + "63": "Lorsque vous disposez d'un nom de domaine, vous pouvez activer un \"Start 10m\" qui vous permet de créer une adresse email et de disposer d'un petit hébergement FTP de 10 Mo.", + "64": "Pour l'activer, il vous suffit de vous rendre sur votre nom de domaine sur , puis de cliquez sur le bouton \"Activer\" à la ligne \"Hébergement Web et e-mail gratuit\".", + "65": "L'activation ne prendra que quelques minutes et vous pourrez ensuite créer une adresse email.", + "66": "Hosting_Web_Comment je fais pour changer mes serveurs dns de mon site benjtest.ovh _", + "67": "J'aimerai changer mes serveur DNS", + "68": "Comment changer mes serveurs dns ?", + "69": "Comment je fais pour changer mes serveurs dns de mon site <@sys.url|url|benjtest.ovh> ?", + "70": "Comment je peux changer mes serveurs dns ?", + "71": "Hosting_web_Comment je peux faire pointer mon domaine benjtest.ovh sur mon hébergement web _", + "72": "Comment faire pour que <@sys.url|url|benjtest.ovh> pointe sur mon <@15|15|hébergement web>", + "73": "Comment je peux faire pointer mon domaine <@sys.url|url|benjtest.ovh> sur mon <@15|15|hébergement web> ?", + "74": "Hosting_web_website_break", + "75": "J'ai des problèmes avec mes mails", + "76": "Mes emails ne fonctionnent pas correctement", + "77": "Mon site ne marche pas", + "78": "Mon site <<@sys.url|url|http://testalldom.fr>|testalldom.fr> est cassé", + "79": "mon site web <@sys.url|url|benjamincoenen.com> ne répond plus", + "80": "<@sys.ignore|undefined|Mon> site ne fonctionne plus ☹", + "81": "Mon site <@sys.url|url|benjtest.ovh> est cassé", + "82": "Mon site web est cassé", + "83": "NDH_bad responses", + "84": "<@sys.number|number|3>", + "85": "<@sys.number|number|434321>", + "86": "<@sys.number|number|45353>", + "87": "Mauvaise réponse 🙁", + "88": "NDH_Good answer", + "89": "on vous heberge", + "90": "20", + "91": "5", + "92": "54", + "93": "10", + "94": "6 min", + "95": "6minutes", + "96": "6min", + "97": "6 minutes", + "98": "1.1.0", + "99": "On vous héberge", + "100": "78", + "101": "roubaix", + "102": "#122844", + "103": "6120", + "104": "NDH_ndh_question", + "105": "J'ai soif je veux boire", + "106": "Donne <@sys.date-period|date-period|moi> à boire", + "107": "Je veux <@sys.number|number|une> boisson", + "108": "Je suis à la nuit du hack pour la boisson", + "109": "Je veux gagner <@sys.number|number|une> boisson gratuite", + "110": "Telecom_Telephone_Telephony_break", + "111": "mon <@30|30|téléphone> est cassé", + "112": "Mon <@30|30|téléphone> ne marche pas", + "113": "peux tu faire <@sys.ignore|undefined|un> diagnostic de mon <@30|30|téléphone>", + "114": "Pourquoi je ne peux pas <@30|30|téléphoner> ?", + "115": "je n'arrive pas à appeler", + "116": "ma ligne <@30|30|téléphonique> ne marche pas", + "117": "impossible de passer <@sys.ignore|undefined|un> coup de fil", + "118": "Quand est-ce que ma ligne sera portée ?", + "119": "J'arrive pas à <@30|30|téléphoner>", + "120": "mon <@30|30|téléphone> ne fonctionne plus", + "121": "Telecom_xdsl_xdsl_break", + "122": "mon internet ne marche pas", + "123": "Peut tu faire <@sys.ignore|undefined|un> diagnostic de ma ligne ADSL ?", + "124": "Comment se passe ma comande de ligne xDSL", + "125": "mon internet est cassé", + "126": "Qu'est-ce qui va pas sur mon internet ?", + "127": "la SDSL ne répond plus", + "128": "mon VDSL est en panne", + "129": "ma ligne ADSL ne fonctionne plus", + "130": "mon modem ne capte plus", + "131": "ma box ne fonctionne plus", + "132": "je n'arrive pas à me connecter à internet", + "133": "Je n'ai plus d'internet", + "134": "Ma connection internet ne fonctionne plus", + "135": "Transverse_Compte Client_Comment devenir client _", + "136": "comment devenir cliente", + "137": "etre client ?", + "138": "Créer compte client ?", + "139": "Comment devenir client ?", + "140": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site OVH.com et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", + "141": "Transverse_Compte_Comment devenir client _", + "142": "je veux être client", + "143": "je souhaite devenir client", + "144": "comment devenir client", + "145": "Pour devenir client chez OVH, retrouvez toutes nos offres sur notre site et n'hésitez pas à passer commande. Vous pouvez également créer un compte client directement via .", + "146": "Transverse_Compte_Je veux me connecter à mon compte OVH", + "147": "Je veux me connecter à <@sys.ignore|undefined|mon> compte OVH", + "148": "Je veux me connecter", + "149": "Connecte <@sys.ignore|undefined|moi>", + "150": "Transverse_Compte_Qui suis je _", + "151": "Qui suis je ?", + "152": "je suis connecté sur quel compte ?", + "153": "Suis-je connecté ?", + "154": "Qui je suis ?", + "155": "Transverse_contact", + "156": "je voulais le rediriger mais je ne trouve pas d'adresse mail de contact", + "157": "comment contacter par mail ovh?", + "158": "Contacté OVH", + "159": "Pour nous contacter, rend tois sur notre ", + "160": "Transverse_Culture_Comment postuler chez OVH _", + "161": "Je veux travailler chez OVH", + "162": "comment postuler chez OVH", + "163": "je souhaite travailler chez OVH", + "164": "Retrouvez toutes nos offres d'emplois sur . Vous pourrez de cette manière postuler à l'offre qui vous correspond.", + "165": "Transverse_Facture_Comment consulter ma facture _", + "166": "Obtenir ma facture", + "167": "Je veux ma facture", + "168": "Je souhaite voir ma facture", + "169": "Consulter ma dernière facture", + "170": "Afin de consulter vos factures, rendez-vous sur pour vous connecter à votre espace client et ainsi consulter vos dernières factures.", + "171": "Transverse_Facture_Quelle est la date d_expiration _", + "172": "Quand est-ce que mes services arivent à expiration ?", + "173": "échéance de paiement ?", + "174": "expiration", + "175": "Date d'expiration", + "176": "Je souhaite connaître la date d'expiration de mon service ?", + "177": "Quelle est la date d'expiration ?", + "178": "", + "179": "Transverse_lost_password", + "180": "je ne peux pas me connecter peux-tu m'aider?", + "181": "je ne peux pas me connecter, comment faire?", + "182": "j'ai perdu mon mot de passe", + "183": "Rends toi sur la page de connexion ici :https://www.ovh.com/auth/ et clique sur \"Forgotten your username or password?\". Puis indique ton email ou ton nichandle et clique sur submit. Tu recevras alors un email pour réinialisé ton mot de passe. Plus d'information ici : https://docs.ovh.com/fr/fr/account/customer/tout-savoir-sur-identifiant-client/#id7", + "184": "Transverse_Report_abuse", + "185": "Je veux signaler <@sys.ignore|undefined|une> tentative de phishing", + "186": "J'ai réçu <@sys.ignore|undefined|un> <@7|7|mail> frauduleux", + "187": "pour signaler un abus, ou un contenu illicite rends toi ici : https://www.ovh.com/fr/abuse", + "188": "transverse_status_update", + "189": "Etat de mes lignes", + "190": "quel est le status de mon cloud", + "191": "y a t'il <@sys.ignore|undefined|un> probleme sur mes produits ?", + "192": "Web_Emails_Compte_Comment créer un compte e-mail _", + "193": "créer <@sys.number|number|un> <@7|7|compte mail>", + "194": "Comment créer une <@7|7|adresse mail> ?", + "195": "créer <@7|7|mail>", + "196": "créer <@7|7|adresse email>", + "197": "<@7|7|e-mail>", + "198": "Pour créer votre adresse e-mail chez OVH, rendez-vous sur votre espace client, sélectionnez votre offre MX Plan, E-mail Pro, ou Exchange, et cliquez sur \"Créer un compte\"", + "199": "Web_Hosting_Database_Comment créer une base de données _", + "200": "Créer <@1|1|database> ?", + "201": "Comment créer <@sys.ignore|undefined|une> <@1|1|base de données> ?", + "202": "Pour créer une base de données, rendez-vous dans votre espace client (https://www.ovh.com/auth/) dans l'onglet \"Bases de données\" puis cliquez sur \"Créer une base de données\".", + "203": "Web_Hosting_FTP_Comment me connecter en FTP _", + "204": "connexion <@sys.ignore|undefined|serveur> <@sys.ignore|undefined|FTP>", + "205": "accéder à mon <@sys.ignore|undefined|FTP>", + "206": "mettre en ligne mon site", + "207": "connecter <@15|15|hébergement>", + "208": "Pour vous connecter à votre serveur FTP, utilisez un logiciel comme et entrez votre identifiant FTP et son mot de passe associé.", + "209": "Vous pouvez les retrouver et/ou les modifier depuis votre espace client, section hébergement, onglet FTP/SSH.", + "210": "Web_Hosting_SEO_Référencer mon site sur Google", + "211": "résultat google", + "212": "google", + "213": "je veux référencer mon site", + "214": "Pourquoi mon site n'est pas sur <@sys.ignore|undefined|google> ?", + "215": "je veux <@sys.ignore|undefined|référencer> mon site", + "216": "Comment trouver mon site sur <@sys.ignore|undefined|google> ?", + "217": "j'aimerai <@sys.ignore|undefined|référencer> mon site sur google", + "218": "Contactez nos partenaires pour ce type de demande." } From 88b263b6ebb15b1111209cb178f892f4af213820 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 30 Aug 2017 16:06:46 +0200 Subject: [PATCH 20/23] chore(bump): update for Release 1.2.0 --- CHANGELOG.md | 43 +++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a36ba51..160d8f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,46 @@ + +# :gem: [1.2.0](https://github.com/ovh-ux/ovh-chatbot/compare/1.1.0...1.2.0) inexpensive-science (2017-08-30) :gem: + + +### :ambulance: Bug Fixes :ambulance: + + **controller/web:** + + * fix promise in response not resolved ([0ce998f](https://github.com/ovh-ux/ovh-chatbot/commit/0ce998f)) + + **platforms:** + + * fix reaching message length limit ([a34d1aa](https://github.com/ovh-ux/ovh-chatbot/commit/a34d1aa)) + + **security:** + + * fix x-hub-signature wasn't properly checked ([cf7ad8e](https://github.com/ovh-ux/ovh-chatbot/commit/cf7ad8e)) + +### :sparkles: Features :sparkles: + + **apiai:** + + * support for multiple apiai ([0de6eac](https://github.com/ovh-ux/ovh-chatbot/commit/0de6eac)) + + **bot:** + + * add when will my service expires ? ([a6d7f3c](https://github.com/ovh-ux/ovh-chatbot/commit/a6d7f3c)) + * inform user when service doesn't work anymore ([0330462](https://github.com/ovh-ux/ovh-chatbot/commit/0330462)) + + **express:** + + * add cache for web users ([fe57549](https://github.com/ovh-ux/ovh-chatbot/commit/fe57549)) + + **Grunt:** + + * add grunt for compiling api.ai zip configs ([a1ee7f7](https://github.com/ovh-ux/ovh-chatbot/commit/a1ee7f7)) + * add i18n feature ([e971185](https://github.com/ovh-ux/ovh-chatbot/commit/e971185)) + * add loggin ([d8ba0cf](https://github.com/ovh-ux/ovh-chatbot/commit/d8ba0cf)) + + **tools:** + + * add api ai update task ([c4c7b81](https://github.com/ovh-ux/ovh-chatbot/commit/c4c7b81)) + # :gem: [1.1.0](https://github.com/ovh-ux/ovh-chatbot/compare/1.0.0...v1.1.0) Moving Smoke (2017-08-07) :gem: diff --git a/package.json b/package.json index 2856ca8..d84f1a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "OvhChatbot", - "version": "1.1.0", + "version": "1.2.0", "description": "Chatbot OVH to help support", "main": "app.js", "scripts": { From df1d3510b2ec7d7c3332ec85a73cd16a96698c8f Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Wed, 30 Aug 2017 16:44:40 +0200 Subject: [PATCH 21/23] :books: docs(apiai): doc on training --- apiai/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apiai/README.md b/apiai/README.md index 801a039..808946f 100644 --- a/apiai/README.md +++ b/apiai/README.md @@ -23,6 +23,19 @@ In order to have the good api.ai token used (ie: use the right language), you ha } ``` +## Training apiai + +Once in production, you'll find that sometimes, api.ai doesn't find the right answer. Here is a step by step procedure to add new intent in production when you work with a preproduction agent. + +1. add the **new intents** to **preproduction** +2. In the **production** agent, do the training with the **knwon** intents +3. once you are done, export the **production** and import it in the **preproduction** (**DO NOT RESTORE**, you'll lose your progress) +4. Now you can export your **preproduction** (it should have the new intents + the updated intents from production). +5. You can test you archive by importing it in **production** and see in the training tab, if the answers are good. +6. Repeat this process until your are satisfied. +7. Once your done, follow the step in the [`tools`](../tools) folder to translate the agent + + ## tools Have a look at [/tools](../tools)! From 254cbc604c89b0a1de8aa7e8cf91be3503fe5b23 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Thu, 31 Aug 2017 08:59:51 +0200 Subject: [PATCH 22/23] chore(translation): french typos --- translations/translation_fr_FR.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/translations/translation_fr_FR.json b/translations/translation_fr_FR.json index 7b304e5..4ff809a 100644 --- a/translations/translation_fr_FR.json +++ b/translations/translation_fr_FR.json @@ -20,10 +20,10 @@ "connectedAs": "Tu es connecté en tant que %s :ok_hand:", "domainEditDns": "Tu dois modifier la zone DNS de ton domaine afin d'y ajouter le champ A avec l'IP de ton hébergement web, cette IP se trouve sur la page d'informations de ton hébergement dans l'espace client OVH.", "disconnected": "Tu n'es pas correctement connecté à ton compte OVH :( , il te suffit de me demander 'connecte-moi' pour te reconnecter.", - "expires-allOk": "Rien n'est sur le point d'expiré :tada:", + "expires-allOk": "Rien n'est sur le point d'expirer :tada:", "dnsEditDns": "Tu peux modifier tes serveurs DNS via l'espace client OVH", - "scanInProgress": ":hourglass: Analyse en cours... Patiente quelques instants, l'analyse peut prendre quelques minutes :hourglass:", - "diagInProgress": ":hourglass: Diagnostic en cours... Patiente quelques instants, le diagnostic peut prendre quelques minutes :hourglass:", + "scanInProgress": ":hourglass: Analyse en cours… Patiente quelques instants, l'analyse peut prendre quelques minutes :hourglass:", + "diagInProgress": ":hourglass: Diagnostic en cours… Patiente quelques instants, le diagnostic peut prendre quelques minutes :hourglass:", "feedbackBadUnderstanding": "Mauvaise compréhension", "feedbackHelp": "Est-ce que cette réponse t'a aidé ?", "feedbackNo": "Non", @@ -105,8 +105,8 @@ "hosting-unknown": "Problème non diagnostiquable. :thinking_face:", "settings-updates-true": ":sound: La notification lors d'incidents est activé.", "settings-updates-false": ":mute: La notification lors d'incidents est desactivé.", - "settings-expires-true": ":bell: La notification lors de l'arrivé à expiration de service est activé. Tu vas etre informé %s jours en avance", - "settings-expires-period": "Tu vas etre informé %s jours en avance", + "settings-expires-true": ":bell: La notification lors de l'arrivé à expiration de service est activé. Tu vas être informé %s jours en avance", + "settings-expires-period": "Tu vas être informé %s jours en avance", "settings-expires-false": ":no_bell: La notification lors de l'arrivé à expiration de service est desactivé", "settings-expires-edit": "Combien de jours dois-je te prévenir à l'avance avant que tes services expirent ? (actuellement: %s jours)", "settings-expires-days": "%s jours", @@ -166,5 +166,5 @@ "xdsl-resultLastDiag": "Voici le résultat du dernier diagnostic réalisé.", "xdsl-resultDiagRemaining": "Tu peux encore effectuer %s diagnostic(s) aujourd'hui.", "view-title": "Connecté", - "view-connected":"Tu es connecté en tant que: %s. Tu peux fermer cette fenetre et poser des questions au bot" + "view-connected":"Tu es connecté en tant que: %s. Tu peux fermer cette fenêtre et poser des questions au bot" } From f29beab664515101dad177956a1627f7b4eafeb1 Mon Sep 17 00:00:00 2001 From: Julien DONQUE Date: Thu, 31 Aug 2017 16:19:14 +0200 Subject: [PATCH 23/23] chore(translations): add it_IT --- apiai/translations/apiai_it.json | 204 ++++++++++++++++++++++++++++ translations/translation_it_IT.json | 154 +++++++++++++++++++++ 2 files changed, 358 insertions(+) create mode 100644 apiai/translations/apiai_it.json create mode 100644 translations/translation_it_IT.json diff --git a/apiai/translations/apiai_it.json b/apiai/translations/apiai_it.json new file mode 100644 index 0000000..f55d7b4 --- /dev/null +++ b/apiai/translations/apiai_it.json @@ -0,0 +1,204 @@ +{ + "1": "Email", + "2": "mail", + "3": "account email", + "4": "indirizzo mail", + "5": "indirizzo email", + "6": "indirizzo e-mail", + "7": "e-mail", + "8": "email", + "9": "Hosting", + "10": "Database", + "11": "db", + "12": "database", + "13": "db", + "14": "Hosting", + "15": "hosting", + "16": "server", + "17": "condiviso", + "18": "hosting web", + "19": "web hosting", + "20": "condiviso", + "21": "offerta condivisa", + "22": "FTP", + "23": "login FTP", + "24": "user FTP", + "25": "SEO", + "26": "SEO", + "27": "Indicizzazione", + "28": "risultato google", + "29": "posizionamento", + "30": "ricerca google", + "31": "Telefono", + "32": "telefono", + "33": "telefono", + "34": "telefono", + "35": "fisso", + "36": "apparecchio telefonico", + "37": "tel", + "38": "telefonare", + "39": "telefonico", + "40": "telefonare", + "41": "Default Fallback Intent", + "42": "Non riesco a capire questa domanda.", + "43": "Ho capito male la tua domanda.", + "44": "Non ho capito bene cosa hai detto.", + "45": "Default Welcome Intent", + "46": "Buonasera", + "47": "Buongiorno", + "48": "Hello", + "49": "Ehi", + "50": "Ciao", + "51": "Grazie mille", + "52": "Grazie", + "53": "Grazie mille", + "54": "Grazie tante", + "55": "Ti ringrazio", + "56": "Grazie mille", + "57": "Di niente", + "58": "Con piacere", + "59": "Nessun problema", + "60": "Hosting_Commerciale_Come attivare uno Start 10M _", + "61": "Voglio Start 10M", + "62": "Come attivare Start <@sys.ignore|undefined|10>M?", + "63": "Vorrei attivare <@sys.number|number|un> <@9|9|hosting> gratuito", + "64": "Se hai un dominio attivo puoi usufruire dell’offerta \"Start 10M\", che ti permette di creare un indirizzo email e di disporre di un piccolo hosting FTP da 10 MB.", + "65": "Per attivarla, accedi al tuo , seleziona il tuo dominio e clicca sul pulsante \"Attiva\" in corrispondenza della voce \"Hosting Web e email gratis\".", + "66": "L’attivazione richiederà solo pochi minuti e in seguito potrai creare un indirizzo email.", + "67": "Hosting_Web_Come modificare i server dns del mio sito benjtest.ovh _", + "68": "Vorrei modificare i miei server DNS", + "69": "Come modificare i miei server DNS?", + "70": "Come posso modificare i server DNS del mio sito <@sys.url|url|benjtest.ovh>?", + "71": "Come posso modificare i miei server DNS?", + "72": "Hosting_Web_Come far puntare il mio dominio benjtest.ovh al mio hosting Web _", + "73": "Come fare in modo che <@sys.url|url|benjtest.ovh> punti al mio hosting Web", + "74": "Come far puntare il mio dominio <@sys.url|url|benjtest.ovh> al mio hosting Web?", + "75": "Hosting_web_website_break", + "76": "Il mio sito non funziona", + "77": "Il mio sito <<@sys.url|url|http://testalldom.fr>|testalldom.it> è down", + "78": "Il mio sito Web <@sys.url|url|benjamincoenen.com> non risponde più", + "79": "<@sys.ignore|undefined|Il mio> sito non funziona più ☹", + "80": "Il mio sito <@sys.url|url|benjtest.ovh> è down", + "81": "Il mio sito web è down", + "82": "NDH_bad responses", + "83": "<@sys.number|number|3>", + "84": "<@sys.number|number|434321>", + "85": "<@sys.number|number|45353>", + "86": "Risposta sbagliata 🙁", + "87": "NDH_Good answer", + "88": "on vous héberge", + "89": "20", + "90": "5", + "91": "54", + "92": "10", + "93": "6 min", + "94": "6minuti", + "95": "6min", + "96": "6 minuti", + "97": "1.1.0", + "98": "On Vous Héberge", + "99": "78", + "100": "roubaix", + "101": "#122844", + "102": "6120", + "103": "NDH_ndh_question", + "104": "Ho sete, vorrei bere", + "105": "Dammi un drink", + "106": "Vorrei <@sys.number|number|un> drink", + "107": "Mi trovo alla Nuit du Hack per il drink", + "108": "Voglio vincere <@sys.number|number|un> drink gratuito", + "109": "Telecom_Telephone_Telephony_break", + "110": "Il mio<@31|31|telefono> è rotto", + "111": "Il mio <@31|31|telefono> non funziona", + "112": "Puoi eseguire <@sys.ignore|undefined|una> diagnostica del mio <@31|31|telefono>", + "113": "Perché non posso <@31|31|telefonare> ?", + "114": "Non riesco a chiamare", + "115": "La mia linea <@31|31|telefonica> non funziona", + "116": "impossibile fare <@sys.ignore|undefined|una> chiamata", + "117": "Quando verrà trasferita la mia linea?", + "118": "Non riesco a <@31|31|telefonare>", + "119": "Il mio <@31|31|telefono> non funziona più", + "120": "Telecom_xdsl_xdsl_break", + "121": "Internet non funziona", + "122": "Puoi eseguire <@sys.ignore|undefined|una> diagnostica della mia linea ADSL?", + "123": "Qual è lo stato dell’ordine della mia linea xDSL?", + "124": "Internet non funziona", + "125": "Perché Internet non funziona?", + "126": "La SDSL non risponde più", + "127": "La VDSL è guasta", + "128": "La mia linea ADSL non funziona più", + "129": "Il mio modem non riceve più", + "130": "il mio modem non funziona più", + "131": "Non riesco a connettermi a Internet", + "132": "Non ho più Internet", + "133": "La mia connessione Internet non funziona più", + "134": "Transverse_Account Cliente_Come diventare cliente _", + "135": "come diventare cliente", + "136": "essere cliente?", + "137": "Creare un account cliente?", + "138": "Come diventare cliente?", + "139": "Per diventare cliente OVH, consulta tutte le offerte sul nostro sito ed effettua l’ordine. Oppure crea il tuo account cliente direttamente tramite .", + "140": "Transverse_Account_Come diventare cliente _", + "141": "Voglio diventare cliente", + "142": "Vorrei diventare cliente", + "143": "come diventare cliente", + "144": "Per diventare cliente, consulta tutte le offerte sul sito ed effettua l’ordine. Oppure crea il tuo account cliente direttamente tramite .", + "145": "Transverse_Account_Voglio accedere al mio account OVH", + "146": "Voglio accedere al <@sys.ignore|undefined|mio> account OVH", + "147": "Voglio connettermi", + "148": "Connettimi", + "149": "Transverse_Account_Chi sono _", + "150": "Chi sono?", + "151": "Su quale account sono connesso?", + "152": "Sono connesso?", + "153": "Chi sono?", + "154": "Transverse_Cultura_Come inviare la candidatura in OVH _", + "155": "Voglio lavorare in OVH", + "156": "Come inviare la candidatura in OVH", + "157": "Vorrei lavorare in OVH", + "158": "Puoi consultare tutte le posizioni aperte sul . In questo modo, puoi candidarti alla posizione più adatta a te.", + "159": "Transverse_Fattura_Come consultare la mia fattura _", + "160": "Ottenere la mia fattura", + "161": "Voglio la mia fattura", + "162": "Vorrei visualizzare la mia fattura", + "163": "Consultare la mia ultima fattura", + "164": "Per consultare le tue fatture, clicca su e accedi alla sezione “Fatturazione” del tuo Spazio Cliente OVH.", + "165": "Transverse_Fattura_Qual è la data di scadenza _", + "166": "scadenza di pagamento?", + "167": "scadenza", + "168": "Data di scadenza", + "169": "Vorrei sapere la data di scadenza del mio servizio", + "170": "Qual è la data di scadenza?", + "171": "Puoi visualizzare la data di scadenza di tutti i tuoi prodotti OVH nello Spazio Cliente, tramite .", + "172": "transverse_status_update", + "173": "Stato delle mie linee", + "174": "Qual è lo stato del mio Cloud", + "175": "Si è verificato <@sys.ignore|undefined|un> problema sui miei prodotti?", + "176": "Web_Email_Account_Come creare un account email _", + "177": "creare <@sys.number|number|un> <@1|1|account email>", + "178": "Come creare un <@1|1|indirizzo email>?", + "179": "Creare <@1|1|email>", + "180": "Creare <@1|1|indirizzo email>", + "181": "<@1|1|email>", + "182": "Per creare il tuo indirizzo email OVH, accedi al tuo Spazio Cliente, seleziona la tua offerta MX Plan, Email Pro o Exchange e clicca su \"Crea un account\"", + "183": "Web_Hosting_Database_Come creare un database _", + "184": "Creare <@9|9|database>?", + "185": "Come creare <@sys.number|number|un> <@9|9|database>?", + "186": "Per creare un database, accedi allo Spazio Cliente OVH (https://www.ovh.com/auth/), seleziona la sezione \"Database\" e clicca su \"Ordina database\".", + "187": "Web_Hosting_FTP_Come accedere in FTP _", + "188": "accesso <@9|9|server> <@9|9|FTP>", + "189": "accedere al mio <@9|9|FTP>", + "190": "mettere online il mio sito", + "191": "connettere <@9|9|hosting>", + "192": "Per accedere al tuo server FTP, utilizza un software come e inserisci il tuo identificativo FTP e la password associata.", + "193": "Puoi ritrovare e/o modificare queste informazioni nel tuo Spazio Cliente OVH, sezione “Hosting”, scheda “FTP - SSH”.", + "194": "Web_Hosting_SEO_Indicizzare il mio sito su Google", + "195": "risultato google", + "196": "google", + "197": "voglio indicizzare il mio sito", + "198": "Perché il mio sito non è su <@sys.ignore|undefined|google>?", + "199": "voglio <@sys.ignore|undefined|indicizzare> il mio sito", + "200": "Come trovare il mio sito su <@sys.ignore|undefined|google>?", + "201": "vorrei <@sys.ignore|undefined|indicizzare> il mio sito su google", + "202": "Per questo tipo di richiesta, contatta i nostri partner." +} diff --git a/translations/translation_it_IT.json b/translations/translation_it_IT.json new file mode 100644 index 0000000..a41fa05 --- /dev/null +++ b/translations/translation_it_IT.json @@ -0,0 +1,154 @@ +{ + "guides-help": "Se hai bisogno di aiuto, ti consiglio di consultare questa guida: %s", + "guides-error500": "https://www.ovh.it/g1987.hosting_condiviso_errore_500_internal_server_error", + "guides-blankPage": "https://www.ovh.it/g1562.web_hosting_come_fai_a_diagnosticare_una_pagina_bianca", + "guides-errorApache": "https://www.ovh.it/g1991.hosting_condiviso_codici_di_stato_server-http", + "guides-pointingError": "https://www.ovh.it/g1585.hosting_web_errore_sito_non_installato", + "guides-dbError": "https://www.ovh.it/g1943.gestisci_un_database_dal_tuo_hosting_condiviso", + "guides-perfImprovements": "https://www.ovh.it/g1396.web_hosting_ottimizza_le_performance_del_tuo_sito", + "guides-stats": "https://www.ovh.it/g1344.hosting_condiviso_consulta_le_statistiche_e_i_log_del_tuo_sito", + "guides-mailBlock": "https://www.ovh.it/g1974.hosting_web_gestisci_linvio_delle_tue_email_automatiche", + "guides-renewOvh": "https://www.ovh.it/g1271.imposta_il_rinnovo_automatico_dei_tuoi_servizi_ovh", + "guides-websiteHack": "https://www.ovh.it/g1392.procedura-chiusura-hack-ovh", + "guides-wordpressHack": "https://www.ovh.it/g1874.hacking_del_tuo_sito_wordpress_consigli_e_casi_pratici", + "guides-leError": "https://www.ovh.it/g1594.i_certificati_ssl_sugli_hosting_web_ovh", + "guides-dnsConfig": "https://www.ovh.it/g1604.web_hosting_modifica_la_tua_zona_dns", + "guides-modifDns": "https://www.ovh.it/g1604.web_hosting_modifica_la_tua_zona_dns#modifica_la_tua_zona_dns", + "guides-modifDnsServer": "https://www.ovh.it/g2015.web_hosting_gestisci_il_tuo_server_dns#modifica_i_tuoi_server_dns", + "guides-homeLabs": "https://www.ovh.com/manager/sunrise/uxlabs/#!/chatbot", + "allOk": "È tutto ok :+1:", + "connectedAs": "Sei connesso come %s :ok_hand:", + "domainEditDns": "Per aggiungere il record A con l’IP del tuo hosting Web, è necessario modificare la zona DNS del tuo dominio. Questo IP è disponibile nel tuo Spazio Cliente OVH, nella scheda “Informazioni generali” del tuo hosting.", + "disconnected": "Non sei connesso correttamente al tuo account OVH :( . Per effettuare un nuovo accesso, è sufficiente chiedermi 'Connettimi'.", + "dnsEditDns": "Puoi modificare i tuoi server tramite lo Spazio Cliente OVH", + "feedbackBadUnderstanding": "Interpretazione errata ", + "feedbackHelp": "Questa risposta è stata utile?", + "feedbackNo": "No", + "feedbackThanks": "Grazie per il tuo parere :+1:", + "feedbackYes": "Sì", + "goToManager": "Accedi allo Spazio Cliente OVH :point_right:", + "hostingSelectSite": "Seleziona il sito interessato (%1$s/%2$s)", + "hostingSelectHost": "Seleziona l'hosting Web su cui è installato il tuo sito (%1$s/%2$s)", + "hostingNoSite": ":globe_with_meridians: Non hai hosting Web :(", + "hostingWrongSite": "Sembra che l’hosting Web selezionato non sia quello associato a questo dominio :thinking_face:", + "hostingSuspended": "Sembra che il tuo hosting sia sospeso. Per riattivarlo, rinnovalo dal tuo Spazio Cliente OVH :zzz:", + "ndhGetQR": "Ottieni il QR Code", + "ndhQuestionStart": "Ciao :wave:, hai sete? :beer: Se la vuoi, devi meritarla! ", + "ndhQuestions": [ + "Potresti dirci il risultato della moltiplicazione di questi 3 numeri. Il numero di datacenter OVH, il numero dei Paesi in cui siamo presenti e l’età della società OVH?", + "Di che colore è il logo OVH?", + "Dove si trova la sede legale di OVH?", + "In quante lingue è disponibile il sito OVH?", + "Cosa significa OVH?", + "Qual è la mia versione? Piccolo indizio: sono open source", + "Quanti contributori ho (su GitHub)?", + "Con quanti partner tecnici collabora OVH? Indizio: https://www.ovh.it/aproposito/partner-tecnici.xml", + "Quanto tempo è necessario per leggere l’articolo sul mio sviluppo? Piccolo indizio: l’articolo è pubblicato sul blog di OVH", + "A quante domande posso rispondere? Piccolo indizio: sono open source :hugging_face: " + ], + "ndhWin": "Bravo, ce l’hai fatta! Ecco la tua ricompensa :)", + "noAnswer": "Non posso ancora rispondere a questa domanda :disappointed_relieved:", + "noIntent": "Credo di non aver capito bene la tua domanda. Per visualizzare la lista delle domande a cui posso rispondere, consulta questo sito :point_right: https://www.ovh.com/manager/web/#/labs/chatbot", + "notConnected": "Non sei connesso ma puoi effettuare l’accesso chiedendomi: 'Connettimi'", + "moreButton": "Maggiori dettagli (%s)", + "on": "Attivato", + "off": "Disattivato", + "signIn": "Accedi al tuo account OVH :link:", + "signInFirst": ":warning: Devi prima effettuare l’accesso. Puoi chiedermi di farlo per te.", + "slackAuthor": "Assistente personale OVH", + "slackColor": "#59d2e", + "slackImg": "https://www.ovh.com/fr/images/support/livechat/chatbot_20px.png", + "slackLink": "https://www.ovh.com/manager/sunrise/uxlabs/#!/chatbot", + "slackFallback": "Il browser che stai utilizzando non supporta questa funzionalità", + "telephonySelectAccount": "Seleziona il tuo account (%1$s/%2$s)", + "telephonyNoAccount": ":telephone_receiver: Non hai offerte di telefonia. ", + "thanks": "Di niente, è un piacere :wink:", + "upsellingWeb": "Puoi ordinare un hosting Web accedendo alla pagina https://www.ovh.it/hosting-web/", + "upsellingXDSL": "Puoi ordinare una linea xDSL accedendo alla pagina https://www.ovhtelecom.fr/offre-internet/", + "upsellingPhone": "Puoi ordinare una linea telefonica accedendo alla pagina https://www.ovhtelecom.fr/telephonie/", + "welcome": "Buongiorno! Al momento posso rispondere solo a domande relative a malfunzionamenti del tuo sito Web o della tua linea xDSL/telefonica. Ecco alcuni esempi di domande che puoi farmi: • Il mio sito non funziona più • Come faccio a modificare i server DNS della mia zona esempio.ovh? • Come far puntare il mio dominio esempio.ovh al mio hosting Web? • Puoi eseguire una diagnostica della mia linea ADSL? • Perché non posso telefonare?", + "welcomeWeb": "Benvenuto %s, come posso aiutarti?", + "xdslSelect": "Seleziona la tua offerta xDSL (%1$s/%2$s)", + "xdslNone": ":satellite: Sembra che tu non abbia offerte xDSL.", + "xdslDiagInProgress": "Diagnostica in corso... Attendi, la diagnostica può richiedere qualche minuto. Grazie :)", + "xdslQuotaReached": "Hai raggiunto il numero massimo di diagnostiche.", + "cloud-incident": "Si è verificato un incidente: %1$s; Questo incidente è $2%s ($3%s %), Maggiori dettagli: $4%s", + "hosting-dns": "Il tuo sito non punta sull’IP corretto (al momento, %1$s). Il dominio \"%2$s\" dovrebbe puntare all’IP %3$s", + "hosting-dnsWrongConfig": "Al momento utilizzi i server DNS: %1$s, ma dovresti utilizzare i seguenti: %2$s.", + "hosting-errorConnRefused": "Sembra che si tratti di un problema di puntamento al tuo sito. Ti consiglio di verificare la configurazione DNS per assicurarti che il tuo dominio punti verso l'IP %s", + "hosting-errorNotFound": "Sembra che la tua zona DNS non sia configurata correttamente", + "hosting-errorEaiAgain": "Sembra che la tua zona DNS non sia configurata correttamente Il tuo sito non risulta associato a nessun hosting Web.", + "hosting-hostingActive": "Sembra che il tuo sito funzioni correttamente :v:", + "hosting-hostingButActive": "Comunque, sembra che il tuo sito funzioni correttamente :v:", + "hosting-hostingBloqued": "Sembra che si sia verificato un problema sul tuo server condiviso e al momento è bloccato :skull:", + "hosting-hostingMaintenance": "Sembra che si sia verificato un problema sul tuo server condiviso e al momento è in manutenzione :wrench:", + "hosting-hostingUnknown": "Il tuo server si trova in uno stato sconosciuto. Per maggiori informazioni, contatta il supporto", + "hosting-mailBounce": "Sembra che le tue email inviate siano state bloccate perché oltre il 50% ha generato errori di consegna", + "hosting-mailKo": "Sembra che le tue email inviate siano state bloccate perché oltre il 5% ha generato errori di consegna", + "hosting-mailSpam": ":no_entry_sign: Sembra che le tue email inviate siano state bloccate per Spam", + "hosting-sslRegenerate": "Hai attivato l’SSL sul tuo sito ma il certificato SSL non contiene il tuo dominio Devi rigenerare il tuo certificato dallo Spazio Cliente OVH", + "hosting-sslHttpsToHttpWarning": ":warning: Attenzione: il tuo sito è incluso nel certificato SSL utilizzato e al momento funziona in HTTPS. Tuttavia la tua configurazione indica che durante la rigenerazione automatica del certificato il tuo sito non sarà più accessibile in HTTPS. Se questo comportamento è voluto o se non utilizzi l’HTTPS per il tuo sito, ignora questo messaggio.", + "hosting-web404": "Sembra che la pagina a cui stai cercando di accedere non esista: impossibile trovare il file corrispondente.", + "hosting-web401": ":no_entry: Sembra che il tuo sito stia tentando di accedere a un file o a uno spazio a cui non è autorizzato.", + "hosting-web403": ":no_entry: Sembra che sul tuo sito si siano verificati problemi di permessi. Accedi alla scheda “Multisito” dello Spazio Cliente OVH e verifica che il tuo sito punti alla cartella di destinazione corretta.", + "hosting-web500db": "Il tuo sito non riesce a connettersi al database. Ti consiglio di verificare l’identificativo e la password del database.", + "hosting-web500dev": "Sembra che ci sia un errore di programmazione sul tuo sito Web. In questi casi, il supporto OVH non interviene.", + "hosting-unknown": "Problema non diagnosticabile. :thinking_face:", + "settings-updates-true": "La notifica degli incidenti è stata attivata.", + "settings-updates-false": "La notifica degli incidenti è stata disattivata.", + "telephony-accountClosed": "Il tuo account è stato chiuso :cry:", + "telephony-accountDeleted": "Il tuo account è stato eliminato :cry:", + "telephony-accountExpired": "Il tuo account è scaduto :cry:", + "telephony-lineInCreation": "La creazione della tua linea è in corso", + "telephony-lineUnPaid": "Sembra che tu abbia dimenticato di effettuare il pagamento. Accedi al tuo Spazio Cliente OVH per gestire la fatturazione :point_right: %s", + "telephony-overOutplan": "Hai superato l’importo massimo aggiuntivo autorizzato. Per modificare questo limite, accedi al tuo Spazio Cliente OVH :point_right: %s", + "telephony-portabilityProgress": "La portabilità è in corso su %s delle tue linee.", + "telephony-portabilityLineOperator": "%1$s presso %2$s :\n", + "telephony-portabilityStep": "\t -%1$s, Stato: %2$s, descrizione: %3$s, ETA: %4$s\n", + "telephony-portabilityExecutionDate": "Data di esecuzione prevista: %s", + "telephony-portabilityManager": "`Per modificare la portabilità, accedi al tuo Spazio Cliente OVH :point_right: %s", + "telephony-noIssue": "Non abbiamo rilevato alcun problema :v:", + "telephony-seeManager": "Per maggiori informazioni, accedi al tuo Spazio Cliente OVH :point_right: %s", + "xdsl-day": "giorno/i", + "xdsl-hour": "ora/e", + "xdsl-minute": "minuto/i", + "xdsl-checkInfrastructure": "Conferma la creazione del tuo accesso", + "xdsl-configureAccessOnOVH": "Configurazione dell’accesso sui dispositivi OVH", + "xdsl-orderPayed": "Pagamento dell’ordine", + "xdsl-orderReceived": "Ordine ricevuto", + "xdsl-orderTreatment": "Gestione dell’ordine", + "xdsl-sendModem": "Invio del modem", + "xdsl-sendOrderToProvider": "Trasmissione dell’ordine presso il fornitore del servizio", + "xdsl-setupCustomerPremisesEquipment": "Invio dei dispositivi", + "xdsl-waitingForProviderInstallReport": "Attesa del report del fornitore del servizio", + "xdsl-waitingForWithdrawalPeriodToBeOver": "Attesa della fine del periodo di recesso", + "xdsl-sync": "sincronizzato", + "xdsl-unsync": "non sincronizzato", + "xdsl-doing": "in corso", + "xdsl-todo": "da fare", + "xdsl-error": "errore", + "xdsl-diagnosticTime": "Diagnostica effettuata a %s\n", + "xdsl-callSupport": "Contatta il servizio clienti :phone:", + "xdsl-launchDiag": "Esegui una diagnostica avanzata", + "xdsl-diagnosticModemUnplug": ":x: Il tuo modem non è collegato. Verifica la presa elettrica e la presa xDSL :electric_plug: \n", + "xdsl-diagnosticModemPlug": ":heavy_check_mark: Il tuo modem è connesso\n", + "xdsl-diagnosticLineStatus": "- Stato delle tue linee:\n", + "xdsl-diagnosticLineSync": "\t• %1$s : %2$s\n", + "xdsl-diagnosticCustomerSideProblem": "\t Si tratta di un problema con la tua installazione\n", + "xdsl-diagnosticOvhSideProblem": "\t Si tratta di un problema da parte nostra\n", + "xdsl-diagnosticError": "\t Si è verificato un errore durante la diagnostica\n", + "xdsl-diagnosticPing": ":x: Il tuo modem non risponde ai ping\n", + "xdsl-diagnosticNoPing": ":heavy_check_mark: Il tuo modem risponde ai ping\n", + "xdsl-diagnosticResultOk": ":heavy_check_mark: Non abbiamo rilevato alcun problema. Il problema dipende probabilmente dalla tua installazione :thinking_face:\n", + "xdsl-diagnosticResultNOk": ":x: In effetti si è verificato un problema sulla tua installazione\n", + "xdsl-diagnosticResultMore": "Se la tua linea continua a non funzionare, accedi alla pagina :point_right: https://docs.ovh.com/display/public/CRXDSL/Interruption+de+service\n", + "xdsl-incident": ":construction: Si è verificato un incidente sulla linea %1$s, la risoluzione del problema è prevista per %2$s. Per maggiori dettagli: point_right: %3$s", + "xdsl-orderStepStatus": "\t- lo step %1$s non è ancora completato, è al %2$s. Questo step durerà circa %3$s.\n", + "xdsl-orderNotReady": "Il tuo ordine non è ancora finalizzato: %1$s. Per maggiori dettagli, accedi al tuo Spazio Cliente OVH :point_right: %2$s", + "xdsl-lineSlamming": "Sembra che un altro operatore abbia attivato una linea sulla tua linea attuale.", + "xdsl-lineUnPaid": "Sembra che tu abbia dimenticato di effettuare il pagamento. Accedi al tuo Spazio Cliente OVH :point_right: https://www.ovhtelecom.fr/manager/index.html#/\n", + "xdsl-resultOk": "Non abbiamo rilevato problemi né sulla fatturazione né sulla tua linea. :v: Puoi accedere al tuo Spazio Cliente OVH:point_right: %s", + "xdsl-resultAdvancedDiag": "Vuoi eseguire una diagnostica avanzata del tuo dispositivo :mag: ? :zap: Verifica di aver collegato correttamente il tuo modem :zap:", + "xdsl-resultLastDiag": "Ecco il risultato dell’ultima diagnostica effettuata.", + "xdsl-resultDiagRemaining": "Oggi puoi ancora effettuare %s diagnostiche." +}