From 1a03e3a519c45227b9d3bc632df8edf203d330b5 Mon Sep 17 00:00:00 2001 From: philc Date: Wed, 18 Mar 2026 16:07:34 +0100 Subject: [PATCH] checkemail end point notification --- apxtri/routes/notifications.js | 54 +++++++ schema/contracts.json | 262 +++++++++++++++++++++++++++++++++ template/checkemail_en.js | 60 ++++++++ template/checkemail_fr.js | 60 ++++++++ 4 files changed, 436 insertions(+) create mode 100644 schema/contracts.json create mode 100644 template/checkemail_en.js create mode 100644 template/checkemail_fr.js diff --git a/apxtri/routes/notifications.js b/apxtri/routes/notifications.js index 3111d25..95d2c0d 100644 --- a/apxtri/routes/notifications.js +++ b/apxtri/routes/notifications.js @@ -1,4 +1,6 @@ const express = require("express"); +const fs = require("fs-extra"); +const path = require("path"); // Classes const Notifications = require("../models/Notifications.js"); @@ -247,4 +249,56 @@ router.get("/contact", checkHeaders, isAuthenticated, (req, res) => { res.status(200).json({ data: {} }); }); +router.get("/checkemail/:email/:digit6", checkHeaders, async (req, res) => { + const { email, digit6 } = req.params; + const tmpDir = path.join(__dirname, "../../../../tmp"); + const tmpFile = path.join(tmpDir, email); + + if (digit6 === "0") { + const code = Math.floor(100000 + Math.random() * 900000).toString(); + fs.ensureDirSync(tmpDir); + fs.writeFileSync(tmpFile, code); + + const sendresult = await Notifications.manageemail( + { + emailsto: [{ to: email, code }] + }, + "checkemail", + "adminapi", + req.session.header.xlang || "fr", + 1, + ["anonymous"] + ); + + res.status(sendresult.status).json(sendresult); + } else { + if (!fs.existsSync(tmpFile)) { + return res.status(404).json({ + status: 404, + ref: "Notifications", + msg: "codenotfound", + data: { email } + }); + } + + const storedCode = fs.readFileSync(tmpFile, "utf8").trim(); + if (digit6 === storedCode) { + fs.removeSync(tmpFile); + res.status(200).json({ + status: 200, + ref: "Notifications", + msg: "emailverified", + data: { email, verified: true } + }); + } else { + res.status(400).json({ + status: 400, + ref: "Notifications", + msg: "invalidcode", + data: { email } + }); + } + } +}); + module.exports = router; diff --git a/schema/contracts.json b/schema/contracts.json new file mode 100644 index 0000000..1bfe7d9 --- /dev/null +++ b/schema/contracts.json @@ -0,0 +1,262 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "/schema/contracts", + "title": "Contract", + "description": "Scheduled contracts that can trigger actions (email, push, blockchain, etc.) based on conditions", + "type": "object", + "properties": { + "contractid": { + "title": "Unique identification", + "description": "A unique uuid string identifying a contract", + "type": "string", + "format": "uuid" + }, + "owner": { + "title": "Owner of this contract", + "description": "For accessright purpose this is always equal as alias, owner can read, update or cancel", + "type": "string" + }, + "status": { + "title": "Contract status", + "description": "todo = pending execution, done = successfully executed, error = failed, cancelled = manually stopped", + "type": "string", + "enum": ["todo", "done", "error", "cancelled"] + }, + "tribe": { + "title": "Tribe", + "description": "Tribe ID where this contract belongs and where the rule is defined", + "type": "string" + }, + "action": { + "title": "Action to execute", + "description": "Name of the action function to execute (e.g., sendEmail, sendPush, webhook, blockchainWrite)", + "type": "string" + }, + "payload": { + "title": "Action payload", + "description": "Data to pass to the action handler", + "type": "object" + }, + "rule": { + "title": "Rule function name", + "description": "Name of the rule function in apxtri/Models/Rules.js to evaluate before execution", + "type": "string" + }, + "ruleData": { + "title": "Rule data", + "description": "Data object passed to the rule function, which returns {result, error}", + "type": "object" + }, + "ruleResult": { + "title": "Rule evaluation result", + "description": "Result returned by the rule function after evaluation", + "type": "object" + }, + "ruleError": { + "title": "Rule evaluation error", + "description": "Error message if rule evaluation failed", + "type": "string" + }, + "scheduledFor": { + "title": "Scheduled execution date", + "description": "Date and time when the contract should run (YYYYMMDD HH:mm:ss)", + "type": "string" + }, + "scheduledDay": { + "title": "Scheduled day for cron filtering", + "description": "Day portion for efficient cron filtering (YYYYMMDD)", + "type": "string" + }, + "maxRetries": { + "title": "Maximum retry attempts", + "description": "Number of times to retry on error", + "type": "integer", + "minimum": 0, + "maximum": 10, + "default": 0 + }, + "retryCount": { + "title": "Current retry count", + "description": "Number of times the contract has been retried", + "type": "integer", + "minimum": 0 + }, + "result": { + "title": "Execution result", + "description": "Result data after successful execution", + "type": "object" + }, + "error": { + "title": "Error message", + "description": "Error message if execution failed", + "type": "string" + }, + "datesRun": { + "title": "Execution timestamps", + "description": "Array of timestamps when the contract was executed", + "type": "array", + "items": { + "type": "string" + } + }, + "blockchainTxHash": { + "title": "Blockchain transaction hash", + "description": "Transaction hash if action involved blockchain write", + "type": "string" + }, + "dt_create": { + "title": "Creation date", + "type": "string", + "format": "date-time" + }, + "dt_update": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "contractid", + "owner", + "tribe", + "status", + "action" + ], + "additionalProperties": true, + "apxref": [], + "apxid": "contractid", + "apxuniquekey": [ + "contractid" + ], + "apxidx": [ + { + "name": "lst_contractid", + "type": "array", + "keyval": "contractid" + }, + { + "name": "lst_owner", + "type": "array", + "keyval": "owner" + }, + { + "name": "lst_tribe", + "type": "array", + "keyval": "tribe" + }, + { + "name": "contractid", + "type": "view", + "keyval": "contractid", + "objkey": [ + "contractid", + "owner", + "tribe", + "status", + "action", + "payload", + "rule", + "ruleData", + "ruleResult", + "ruleError", + "scheduledFor", + "scheduledDay", + "maxRetries", + "retryCount", + "result", + "error", + "datesRun", + "blockchainTxHash", + "dt_create", + "dt_update" + ], + "filter": "" + }, + { + "name": "status_scheduledDay", + "type": "view", + "keyval": "contractid", + "objkey": [ + "contractid", + "tribe", + "status", + "action", + "scheduledFor", + "scheduledDay", + "rule", + "ruleData", + "payload", + "owner" + ], + "filter": "status=todo" + }, + { + "name": "tribe_status", + "type": "distribution", + "keyval": "tribe", + "filter": "status" + }, + { + "name": "status_contractid", + "type": "distribution", + "keyval": "status", + "filter": "" + } + ], + "apxaccessrights": { + "owner": { + "C": [], + "D": [], + "R": [], + "U": [ + "status", + "tribe", + "payload", + "rule", + "ruleData", + "ruleResult", + "ruleError", + "scheduledFor", + "scheduledDay", + "maxRetries", + "result", + "error", + "datesRun", + "blockchainTxHash" + ] + }, + "druid": { + "R": [ + "contractid", + "owner", + "tribe", + "status", + "action", + "payload", + "rule", + "ruleData", + "ruleResult", + "ruleError", + "scheduledFor", + "scheduledDay", + "maxRetries", + "retryCount", + "result", + "error", + "datesRun", + "blockchainTxHash", + "dt_create", + "dt_update" + ] + }, + "anonymous": { + "R": [ + "contractid", + "status", + "action", + "scheduledFor", + "scheduledDay", + "dt_create" + ] + } + } +} diff --git a/template/checkemail_en.js b/template/checkemail_en.js new file mode 100644 index 0000000..ac9f250 --- /dev/null +++ b/template/checkemail_en.js @@ -0,0 +1,60 @@ +const tplemail = {}; +tplemail.allowedprofils = ["anonymous", "druid"]; +tplemail.subject = "Verification code - Email verification"; +tplemail.html = ` + + + + + + + + + + + + + +
+

+ smatchit +

+
+

Email verification

+

Hello,

+

+ You requested to verify your email address. Please use the following code to confirm your identity: +

+

+ {{code}} +

+

+ This code is valid for 10 minutes. If you did not request this, you can ignore this email. +

+
+ + + + +
+

+ smatchit +

+
+ + +`; +tplemail.text = ` +Email verification + +Hello, + +You requested to verify your email address. Please use the following code to confirm your identity: + +{{code}} + +This code is valid for 10 minutes. If you did not request this, you can ignore this email. +`; +module.exports = tplemail; diff --git a/template/checkemail_fr.js b/template/checkemail_fr.js new file mode 100644 index 0000000..4bf13ce --- /dev/null +++ b/template/checkemail_fr.js @@ -0,0 +1,60 @@ +const tplemail = {}; +tplemail.allowedprofils = ["anonymous", "druid"]; +tplemail.subject = "Code de vérification - Vérification de votre email"; +tplemail.html = ` + + + + + + + + + + + + + +
+

+ smatchit +

+
+

Vérification de votre adresse email

+

Bonjour,

+

+ Vous avez demandé à vérifier votre adresse email. Veuillez utiliser le code suivant pour confirmer votre identité : +

+

+ {{code}} +

+

+ Ce code est valable pendant 10 minutes. Si vous n'êtes pas à l'origine de cette demande, vous pouvez ignorer cet email. +

+
+ + + + +
+

+ smatchit +

+
+ + +`; +tplemail.text = ` +Vérification de votre adresse email + +Bonjour, + +Vous avez demandé à vérifier votre adresse email. Veuillez utiliser le code suivant pour confirmer votre identité : + +{{code}} + +Ce code est valable pendant 10 minutes. Si vous n'êtes pas à l'origine de cette demande, vous pouvez ignorer cet email. +`; +module.exports = tplemail;