aktueller stand
This commit is contained in:
@@ -30,6 +30,9 @@ const DAILY_BOOKMARK_TITLE_MAX_LENGTH = 160;
|
||||
const DAILY_BOOKMARK_URL_MAX_LENGTH = 800;
|
||||
const DAILY_BOOKMARK_NOTES_MAX_LENGTH = 800;
|
||||
const DAILY_BOOKMARK_MARKER_MAX_LENGTH = 120;
|
||||
const AUTOMATION_TYPE_REQUEST = 'request';
|
||||
const AUTOMATION_TYPE_EMAIL = 'email';
|
||||
const AUTOMATION_TYPE_FLOW = 'flow';
|
||||
const AUTOMATION_MAX_NAME_LENGTH = 160;
|
||||
const AUTOMATION_MAX_URL_LENGTH = 2000;
|
||||
const AUTOMATION_MAX_BODY_LENGTH = 12000;
|
||||
@@ -40,6 +43,9 @@ const AUTOMATION_DEFAULT_INTERVAL_MINUTES = 60;
|
||||
const AUTOMATION_MAX_JITTER_MINUTES = 120;
|
||||
const AUTOMATION_MAX_RESPONSE_PREVIEW = 4000;
|
||||
const AUTOMATION_WORKER_INTERVAL_MS = 30000;
|
||||
const AUTOMATION_MAX_STEPS = 3;
|
||||
const AUTOMATION_MAX_EMAIL_TO_LENGTH = 320;
|
||||
const AUTOMATION_MAX_EMAIL_SUBJECT_LENGTH = 320;
|
||||
const SPORTS_SCORING_DEFAULTS = {
|
||||
enabled: 1,
|
||||
threshold: 5,
|
||||
@@ -90,6 +96,54 @@ if (!fs.existsSync(screenshotDir)) {
|
||||
fs.mkdirSync(screenshotDir, { recursive: true });
|
||||
}
|
||||
|
||||
const automationConfigPath = path.join(__dirname, 'data', 'automation-config.json');
|
||||
const defaultAutomationConfig = {
|
||||
smtp: {
|
||||
host: '',
|
||||
port: 587,
|
||||
secure: false,
|
||||
user: '',
|
||||
pass: '',
|
||||
from: ''
|
||||
}
|
||||
};
|
||||
|
||||
function ensureAutomationConfigFile() {
|
||||
try {
|
||||
if (!fs.existsSync(automationConfigPath)) {
|
||||
const dir = path.dirname(automationConfigPath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(automationConfigPath, JSON.stringify(defaultAutomationConfig, null, 2), 'utf8');
|
||||
console.log('Automation-Config angelegt unter', automationConfigPath);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Konnte Automation-Config nicht erstellen:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
ensureAutomationConfigFile();
|
||||
|
||||
function loadAutomationConfig() {
|
||||
try {
|
||||
const raw = fs.readFileSync(automationConfigPath, 'utf8');
|
||||
const parsed = JSON.parse(raw);
|
||||
return parsed && typeof parsed === 'object' ? parsed : { ...defaultAutomationConfig };
|
||||
} catch (error) {
|
||||
return { ...defaultAutomationConfig };
|
||||
}
|
||||
}
|
||||
|
||||
const automationConfig = loadAutomationConfig();
|
||||
|
||||
let nodemailer = null;
|
||||
try {
|
||||
nodemailer = require('nodemailer');
|
||||
} catch (error) {
|
||||
nodemailer = null;
|
||||
}
|
||||
|
||||
// Middleware - Enhanced CORS for extension
|
||||
app.use(cors({
|
||||
origin: (origin, callback) => {
|
||||
@@ -1292,10 +1346,15 @@ db.exec(`
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
type TEXT NOT NULL DEFAULT 'request',
|
||||
method TEXT NOT NULL DEFAULT 'GET',
|
||||
url_template TEXT NOT NULL,
|
||||
url_template TEXT,
|
||||
headers_json TEXT,
|
||||
body_template TEXT,
|
||||
email_to TEXT,
|
||||
email_subject_template TEXT,
|
||||
email_body_template TEXT,
|
||||
steps_json TEXT,
|
||||
interval_minutes INTEGER NOT NULL DEFAULT ${AUTOMATION_DEFAULT_INTERVAL_MINUTES},
|
||||
jitter_minutes INTEGER DEFAULT 0,
|
||||
start_at DATETIME,
|
||||
@@ -1311,6 +1370,12 @@ db.exec(`
|
||||
);
|
||||
`);
|
||||
|
||||
ensureColumn('automation_requests', 'type', 'type TEXT NOT NULL DEFAULT \'request\'');
|
||||
ensureColumn('automation_requests', 'email_to', 'email_to TEXT');
|
||||
ensureColumn('automation_requests', 'email_subject_template', 'email_subject_template TEXT');
|
||||
ensureColumn('automation_requests', 'email_body_template', 'email_body_template TEXT');
|
||||
ensureColumn('automation_requests', 'steps_json', 'steps_json TEXT');
|
||||
|
||||
db.exec(`
|
||||
CREATE INDEX IF NOT EXISTS idx_automation_requests_next_run
|
||||
ON automation_requests(next_run_at);
|
||||
@@ -1342,10 +1407,15 @@ const listAutomationRequestsStmt = db.prepare(`
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
type,
|
||||
method,
|
||||
url_template,
|
||||
headers_json,
|
||||
body_template,
|
||||
email_to,
|
||||
email_subject_template,
|
||||
email_body_template,
|
||||
steps_json,
|
||||
interval_minutes,
|
||||
jitter_minutes,
|
||||
start_at,
|
||||
@@ -1356,6 +1426,11 @@ const listAutomationRequestsStmt = db.prepare(`
|
||||
last_status_code,
|
||||
last_error,
|
||||
next_run_at,
|
||||
(
|
||||
SELECT COUNT(1)
|
||||
FROM automation_request_runs r
|
||||
WHERE r.request_id = automation_requests.id
|
||||
) AS runs_count,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM automation_requests
|
||||
@@ -1367,10 +1442,15 @@ const getAutomationRequestStmt = db.prepare(`
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
type,
|
||||
method,
|
||||
url_template,
|
||||
headers_json,
|
||||
body_template,
|
||||
email_to,
|
||||
email_subject_template,
|
||||
email_body_template,
|
||||
steps_json,
|
||||
interval_minutes,
|
||||
jitter_minutes,
|
||||
start_at,
|
||||
@@ -1389,11 +1469,13 @@ const getAutomationRequestStmt = db.prepare(`
|
||||
|
||||
const insertAutomationRequestStmt = db.prepare(`
|
||||
INSERT INTO automation_requests (
|
||||
id, name, description, method, url_template, headers_json, body_template,
|
||||
id, name, description, type, method, url_template, headers_json, body_template,
|
||||
email_to, email_subject_template, email_body_template, steps_json,
|
||||
interval_minutes, jitter_minutes, start_at, run_until, active, last_run_at,
|
||||
last_status, last_status_code, last_error, next_run_at
|
||||
) VALUES (
|
||||
@id, @name, @description, @method, @url_template, @headers_json, @body_template,
|
||||
@id, @name, @description, @type, @method, @url_template, @headers_json, @body_template,
|
||||
@email_to, @email_subject_template, @email_body_template, @steps_json,
|
||||
@interval_minutes, @jitter_minutes, @start_at, @run_until, @active, @last_run_at,
|
||||
@last_status, @last_status_code, @last_error, @next_run_at
|
||||
)
|
||||
@@ -1403,10 +1485,15 @@ const updateAutomationRequestStmt = db.prepare(`
|
||||
UPDATE automation_requests
|
||||
SET name = @name,
|
||||
description = @description,
|
||||
type = @type,
|
||||
method = @method,
|
||||
url_template = @url_template,
|
||||
headers_json = @headers_json,
|
||||
body_template = @body_template,
|
||||
email_to = @email_to,
|
||||
email_subject_template = @email_subject_template,
|
||||
email_body_template = @email_body_template,
|
||||
steps_json = @steps_json,
|
||||
interval_minutes = @interval_minutes,
|
||||
jitter_minutes = @jitter_minutes,
|
||||
start_at = @start_at,
|
||||
@@ -1486,7 +1573,6 @@ ensureColumn('ai_credentials', 'usage_24h_count', 'usage_24h_count INTEGER DEFAU
|
||||
ensureColumn('ai_credentials', 'usage_24h_reset_at', 'usage_24h_reset_at DATETIME');
|
||||
ensureColumn('search_seen_posts', 'manually_hidden', 'manually_hidden INTEGER NOT NULL DEFAULT 0');
|
||||
ensureColumn('search_seen_posts', 'sports_auto_hidden', 'sports_auto_hidden INTEGER NOT NULL DEFAULT 0');
|
||||
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS ai_usage_events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -1927,6 +2013,14 @@ function renderAutomationTemplate(template, context = {}) {
|
||||
return shifted.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
const dayOffsetMatch = key.match(/^day([+-]\d+)?$/);
|
||||
if (dayOffsetMatch) {
|
||||
const offset = dayOffsetMatch[1] ? parseInt(dayOffsetMatch[1], 10) : 0;
|
||||
const shifted = new Date(baseDate);
|
||||
shifted.setDate(baseDate.getDate() + (Number.isNaN(offset) ? 0 : offset));
|
||||
return String(shifted.getDate()).padStart(2, '0');
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case 'today':
|
||||
case 'date':
|
||||
@@ -2082,11 +2176,24 @@ function serializeAutomationRequest(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
type: row.type || AUTOMATION_TYPE_REQUEST,
|
||||
description: row.description || '',
|
||||
method: row.method || 'GET',
|
||||
url_template: row.url_template,
|
||||
headers,
|
||||
body_template: row.body_template || '',
|
||||
email_to: row.email_to || '',
|
||||
email_subject_template: row.email_subject_template || '',
|
||||
email_body_template: row.email_body_template || '',
|
||||
steps: row.steps_json ? (() => {
|
||||
try {
|
||||
const parsed = JSON.parse(row.steps_json);
|
||||
return Array.isArray(parsed) ? parsed : [];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
})() : [],
|
||||
runs_count: row.runs_count || 0,
|
||||
interval_minutes: clampAutomationIntervalMinutes(row.interval_minutes),
|
||||
jitter_minutes: clampAutomationJitterMinutes(row.jitter_minutes || 0),
|
||||
start_at: row.start_at ? ensureIsoDate(row.start_at) : null,
|
||||
@@ -2124,6 +2231,14 @@ function normalizeAutomationPayload(payload, existing = {}) {
|
||||
const errors = [];
|
||||
const normalized = {};
|
||||
|
||||
const rawType = typeof payload.type === 'string'
|
||||
? payload.type.trim().toLowerCase()
|
||||
: (existing.type || AUTOMATION_TYPE_REQUEST);
|
||||
const type = [AUTOMATION_TYPE_REQUEST, AUTOMATION_TYPE_EMAIL, AUTOMATION_TYPE_FLOW].includes(rawType)
|
||||
? rawType
|
||||
: AUTOMATION_TYPE_REQUEST;
|
||||
normalized.type = type;
|
||||
|
||||
const nameSource = typeof payload.name === 'string'
|
||||
? payload.name
|
||||
: existing.name || '';
|
||||
@@ -2152,11 +2267,17 @@ function normalizeAutomationPayload(payload, existing = {}) {
|
||||
const rawUrl = typeof payload.url_template === 'string'
|
||||
? payload.url_template
|
||||
: (typeof payload.url === 'string' ? payload.url : existing.url_template || '');
|
||||
const urlTemplate = rawUrl.trim();
|
||||
if (!urlTemplate) {
|
||||
errors.push('URL-Template fehlt');
|
||||
const urlTemplate = (rawUrl || '').trim();
|
||||
|
||||
if (type === AUTOMATION_TYPE_REQUEST || type === AUTOMATION_TYPE_FLOW) {
|
||||
if (!urlTemplate && type === AUTOMATION_TYPE_REQUEST) {
|
||||
errors.push('URL-Template fehlt');
|
||||
}
|
||||
normalized.url_template = urlTemplate
|
||||
? truncateString(urlTemplate, AUTOMATION_MAX_URL_LENGTH)
|
||||
: null;
|
||||
} else {
|
||||
normalized.url_template = truncateString(urlTemplate, AUTOMATION_MAX_URL_LENGTH);
|
||||
normalized.url_template = null;
|
||||
}
|
||||
|
||||
const headersInput = payload.headers
|
||||
@@ -2184,6 +2305,82 @@ function normalizeAutomationPayload(payload, existing = {}) {
|
||||
: '';
|
||||
}
|
||||
|
||||
if (type === AUTOMATION_TYPE_EMAIL) {
|
||||
const toValue = (payload.email_to || payload.to || existing.email_to || '').trim();
|
||||
if (!toValue) {
|
||||
errors.push('E-Mail Empfänger fehlt');
|
||||
} else {
|
||||
normalized.email_to = truncateString(toValue, AUTOMATION_MAX_EMAIL_TO_LENGTH);
|
||||
}
|
||||
const subjectValue = (payload.email_subject_template || payload.subject || existing.email_subject_template || '').trim();
|
||||
if (!subjectValue) {
|
||||
errors.push('E-Mail Betreff fehlt');
|
||||
} else {
|
||||
normalized.email_subject_template = truncateString(subjectValue, AUTOMATION_MAX_EMAIL_SUBJECT_LENGTH);
|
||||
}
|
||||
const bodyValue = typeof payload.email_body_template === 'string'
|
||||
? payload.email_body_template
|
||||
: (typeof payload.body_template === 'string' ? payload.body_template : existing.email_body_template || '');
|
||||
if (!bodyValue || !String(bodyValue).trim()) {
|
||||
errors.push('E-Mail Body fehlt');
|
||||
} else {
|
||||
normalized.email_body_template = truncateString(String(bodyValue), AUTOMATION_MAX_BODY_LENGTH);
|
||||
}
|
||||
normalized.steps_json = null;
|
||||
normalized.url_template = '';
|
||||
normalized.headers_json = null;
|
||||
normalized.body_template = null;
|
||||
} else if (type === AUTOMATION_TYPE_FLOW) {
|
||||
const stepsInput = Array.isArray(payload.steps)
|
||||
? payload.steps
|
||||
: (typeof payload.steps_json === 'string' ? (() => {
|
||||
try { return JSON.parse(payload.steps_json); } catch (err) { return []; }
|
||||
})() : []);
|
||||
|
||||
const steps = [];
|
||||
for (const rawStep of stepsInput) {
|
||||
if (!rawStep || typeof rawStep !== 'object') continue;
|
||||
const stepUrl = typeof rawStep.url === 'string' ? rawStep.url.trim() : '';
|
||||
if (!stepUrl) continue;
|
||||
const stepMethod = typeof rawStep.method === 'string'
|
||||
? rawStep.method.toUpperCase()
|
||||
: 'GET';
|
||||
const allowed = allowedMethods.includes(stepMethod) ? stepMethod : 'GET';
|
||||
const stepHeaders = normalizeAutomationHeaders(rawStep.headers || rawStep.headers_json || {});
|
||||
const stepHeadersSerialized = serializeAutomationHeaders(stepHeaders);
|
||||
steps.push({
|
||||
method: allowed,
|
||||
url: truncateString(stepUrl, AUTOMATION_MAX_URL_LENGTH),
|
||||
headers: stepHeadersSerialized ? JSON.parse(stepHeadersSerialized) : {},
|
||||
body: typeof rawStep.body === 'string'
|
||||
? truncateString(rawStep.body, AUTOMATION_MAX_BODY_LENGTH)
|
||||
: ''
|
||||
});
|
||||
if (steps.length >= AUTOMATION_MAX_STEPS) break;
|
||||
}
|
||||
|
||||
if (!steps.length) {
|
||||
errors.push('Mindestens ein Schritt mit URL ist erforderlich');
|
||||
} else {
|
||||
try {
|
||||
const serializedSteps = JSON.stringify(steps);
|
||||
normalized.steps_json = serializedSteps;
|
||||
} catch (error) {
|
||||
errors.push('Schritte konnten nicht gespeichert werden');
|
||||
}
|
||||
}
|
||||
|
||||
normalized.email_to = null;
|
||||
normalized.email_subject_template = null;
|
||||
normalized.email_body_template = null;
|
||||
normalized.url_template = normalized.url_template || '';
|
||||
} else {
|
||||
normalized.email_to = null;
|
||||
normalized.email_subject_template = null;
|
||||
normalized.email_body_template = null;
|
||||
normalized.steps_json = null;
|
||||
}
|
||||
|
||||
const scheduleType = typeof payload.schedule_type === 'string'
|
||||
? payload.schedule_type
|
||||
: payload.interval_type;
|
||||
@@ -3173,6 +3370,14 @@ function broadcastPostDeletion(postId, options = {}) {
|
||||
broadcastSseEvent(payload);
|
||||
}
|
||||
|
||||
function broadcastAutomationEvent(eventType, payload = {}) {
|
||||
if (!eventType) {
|
||||
return;
|
||||
}
|
||||
const data = { type: eventType, ...payload };
|
||||
broadcastSseEvent(data);
|
||||
}
|
||||
|
||||
const automationRunningRequests = new Set();
|
||||
let automationWorkerTimer = null;
|
||||
let automationWorkerBusy = false;
|
||||
@@ -3196,36 +3401,187 @@ async function executeAutomationRequest(request, options = {}) {
|
||||
automationRunningRequests.add(current.id);
|
||||
|
||||
const context = buildAutomationTemplateContext(new Date());
|
||||
const method = (current.method || 'GET').toUpperCase();
|
||||
const url = renderAutomationTemplate(current.url_template, context);
|
||||
const headers = renderAutomationHeaders(current.headers_json, context);
|
||||
const shouldSendBody = !['GET', 'HEAD'].includes(method);
|
||||
const body = shouldSendBody && current.body_template
|
||||
? renderAutomationTemplate(current.body_template, context)
|
||||
: null;
|
||||
|
||||
const startedAt = new Date();
|
||||
let status = 'success';
|
||||
let statusCode = null;
|
||||
let responseText = '';
|
||||
let errorMessage = null;
|
||||
const stepResults = [];
|
||||
|
||||
async function executeHttpStep(step, stepIndex, inheritedContext) {
|
||||
const method = (step.method || 'GET').toUpperCase();
|
||||
const url = renderAutomationTemplate(step.url_template || step.url, inheritedContext);
|
||||
const headers = renderAutomationHeaders(step.headers_json || serializeAutomationHeaders(step.headers || {}), inheritedContext);
|
||||
const shouldSendBody = !['GET', 'HEAD'].includes(method);
|
||||
const body = shouldSendBody && (step.body_template || step.body)
|
||||
? renderAutomationTemplate(step.body_template || step.body, inheritedContext)
|
||||
: null;
|
||||
|
||||
let localStatus = 'success';
|
||||
let localStatusCode = null;
|
||||
let localResponseText = '';
|
||||
let localError = null;
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers,
|
||||
body: shouldSendBody && body !== null ? body : undefined,
|
||||
redirect: 'follow'
|
||||
});
|
||||
localStatusCode = response.status;
|
||||
try {
|
||||
localResponseText = await response.text();
|
||||
} catch (error) {
|
||||
localResponseText = '';
|
||||
}
|
||||
if (!response.ok) {
|
||||
localStatus = 'error';
|
||||
localError = `HTTP ${response.status}`;
|
||||
}
|
||||
} catch (error) {
|
||||
localStatus = 'error';
|
||||
localError = error.message || 'Unbekannter Fehler';
|
||||
}
|
||||
|
||||
let parsedJson = null;
|
||||
if (localResponseText) {
|
||||
try {
|
||||
parsedJson = JSON.parse(localResponseText);
|
||||
} catch (error) {
|
||||
parsedJson = null;
|
||||
}
|
||||
}
|
||||
|
||||
const resultContext = {
|
||||
...inheritedContext,
|
||||
[`step${stepIndex}_text`]: localResponseText,
|
||||
[`step${stepIndex}_status`]: localStatus,
|
||||
[`step${stepIndex}_status_code`]: localStatusCode,
|
||||
[`step${stepIndex}_json`]: parsedJson || null
|
||||
};
|
||||
|
||||
return {
|
||||
status: localStatus,
|
||||
statusCode: localStatusCode,
|
||||
responseText: localResponseText,
|
||||
error: localError,
|
||||
context: resultContext
|
||||
};
|
||||
}
|
||||
|
||||
async function executeEmailStep(stepContext) {
|
||||
if (!nodemailer) {
|
||||
throw new Error('E-Mail Versand nicht verfügbar (nodemailer fehlt)');
|
||||
}
|
||||
const {
|
||||
SMTP_HOST,
|
||||
SMTP_PORT,
|
||||
SMTP_USER,
|
||||
SMTP_PASS,
|
||||
SMTP_SECURE,
|
||||
SMTP_FROM
|
||||
} = process.env;
|
||||
|
||||
const configSmtp = (automationConfig && automationConfig.smtp) || {};
|
||||
|
||||
const host = SMTP_HOST || configSmtp.host;
|
||||
if (!host) {
|
||||
throw new Error('SMTP_HOST nicht gesetzt und keine Konfiguration in automation-config.json');
|
||||
}
|
||||
|
||||
const port = SMTP_PORT ? Number(SMTP_PORT) : (configSmtp.port || 587);
|
||||
const secure = SMTP_SECURE === 'true' || SMTP_SECURE === '1'
|
||||
? true
|
||||
: (typeof configSmtp.secure === 'boolean' ? configSmtp.secure : port === 465);
|
||||
const user = SMTP_USER || configSmtp.user || '';
|
||||
const pass = SMTP_PASS || configSmtp.pass || '';
|
||||
const from = SMTP_FROM || configSmtp.from || user || 'automation@example.com';
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host,
|
||||
port,
|
||||
secure,
|
||||
auth: user ? { user, pass } : undefined
|
||||
});
|
||||
|
||||
const to = renderAutomationTemplate(current.email_to || '', stepContext);
|
||||
const subject = renderAutomationTemplate(current.email_subject_template || '', stepContext);
|
||||
const body = renderAutomationTemplate(current.email_body_template || '', stepContext);
|
||||
const bodyHtml = body ? body.replace(/\n/g, '<br>') : '';
|
||||
|
||||
if (!to || !subject || !body) {
|
||||
throw new Error('E-Mail Felder unvollständig');
|
||||
}
|
||||
|
||||
const info = await transporter.sendMail({
|
||||
from,
|
||||
to,
|
||||
subject,
|
||||
text: body,
|
||||
html: bodyHtml || body
|
||||
});
|
||||
|
||||
return {
|
||||
status: 'success',
|
||||
statusCode: info && info.accepted ? 200 : null,
|
||||
responseText: info ? JSON.stringify({ messageId: info.messageId }) : '',
|
||||
error: null,
|
||||
context: { ...stepContext }
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers,
|
||||
body: shouldSendBody && body !== null ? body : undefined,
|
||||
redirect: 'follow'
|
||||
});
|
||||
statusCode = response.status;
|
||||
try {
|
||||
responseText = await response.text();
|
||||
} catch (error) {
|
||||
responseText = '';
|
||||
}
|
||||
if (!response.ok) {
|
||||
status = 'error';
|
||||
errorMessage = `HTTP ${response.status}`;
|
||||
if (current.type === AUTOMATION_TYPE_EMAIL) {
|
||||
const emailResult = await executeEmailStep(context);
|
||||
status = emailResult.status;
|
||||
statusCode = emailResult.statusCode;
|
||||
responseText = emailResult.responseText;
|
||||
errorMessage = emailResult.error;
|
||||
} else if (current.type === AUTOMATION_TYPE_FLOW) {
|
||||
let flowContext = { ...context };
|
||||
const steps = current.steps_json ? (() => {
|
||||
try {
|
||||
const parsed = JSON.parse(current.steps_json);
|
||||
return Array.isArray(parsed) ? parsed : [];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
})() : [];
|
||||
let stepIndex = 1;
|
||||
for (const step of steps) {
|
||||
const stepResult = await executeHttpStep({
|
||||
method: step.method || step.http_method || 'GET',
|
||||
url_template: step.url_template || step.url,
|
||||
headers_json: serializeAutomationHeaders(step.headers || {}),
|
||||
body_template: step.body_template || step.body
|
||||
}, stepIndex, flowContext);
|
||||
stepResults.push(stepResult);
|
||||
flowContext = { ...flowContext, ...stepResult.context };
|
||||
if (stepResult.status === 'error') {
|
||||
status = 'error';
|
||||
errorMessage = stepResult.error;
|
||||
statusCode = stepResult.statusCode;
|
||||
responseText = stepResult.responseText;
|
||||
break;
|
||||
} else {
|
||||
statusCode = stepResult.statusCode;
|
||||
responseText = stepResult.responseText;
|
||||
}
|
||||
stepIndex += 1;
|
||||
}
|
||||
} else {
|
||||
const result = await executeHttpStep({
|
||||
method: current.method,
|
||||
url_template: current.url_template,
|
||||
headers_json: current.headers_json,
|
||||
body_template: current.body_template
|
||||
}, 1, context);
|
||||
status = result.status;
|
||||
statusCode = result.statusCode;
|
||||
responseText = result.responseText;
|
||||
errorMessage = result.error;
|
||||
stepResults.push(result);
|
||||
}
|
||||
} catch (error) {
|
||||
status = 'error';
|
||||
@@ -3259,6 +3615,15 @@ async function executeAutomationRequest(request, options = {}) {
|
||||
)
|
||||
: null;
|
||||
|
||||
broadcastAutomationEvent('automation-run', {
|
||||
request_id: current.id,
|
||||
status,
|
||||
status_code: statusCode,
|
||||
next_run_at: nextRunAt,
|
||||
last_run_at: runRecord.started_at,
|
||||
runs_count: (current.runs_count || 0) + 1
|
||||
});
|
||||
|
||||
try {
|
||||
updateAutomationRequestStmt.run({
|
||||
...current,
|
||||
|
||||
Reference in New Issue
Block a user