Files
csbot-prototype/scripts/microsoft365.send-mail.js
T
JiriUhlirandClaude Fable 5.1 104ae36783 Revize projektu: prava, vykon, runtime, portal a ARES
Prava a bezpecnost: spravce firmy uz nemuze nastavit priznak spravce
platformy ani clenstvi v cizi firme; pozvanky, konektory a automatizace
kontroluji sve pravo; cizi firma v query je 404; zivy stream posila
udalosti jen firmam, kterych se tykaji; akce nad ticketem maji kontrolu
prava za firmu ticketu a strop viditelnosti; tokeny se nelogujou; limit
pokusu na prihlaseni, kontakt a pozvanky; bezpecnostni hlavicky;
zachyceni chyb v async handlerech; timing-safe porovnani tokenu.

Vykon: audit neskenuje celou kolekci pri kazdem zapisu a konecne maze
firemni zaznamy; ticket se uklada jednou misto trikrat; zapisy do
Postgresu jsou serializovane podle ID; prava se pocitaji jednou na
request; widgety nacitaji tickety jednou; strankovani seznamu; worker
je pool misto kol; na webu udalost ze streamu neodmontuje stranku,
dotazy maji spolecny debounce a cache, ciselniky drzi typovany sklad.

Runtime: opakuji se jen chyby oznacene retryable; smycka nenarazi na
strop 50 kroku (novy strop 1000 akci); podminka nad datem funguje;
vystup MCP nastroje neprepisuje spoustec; sandbox skriptu firmy nejde
opustit; MCP session id se drzi mezi volanimi; incident z kroku patri
firme; jedno rozhodnuti o rezimu uloziste; snapshot neprepise soubor
po chybe cteni.

Refaktory: sdilene typy API v src/shared (web nic nekopiruje, osm
rozjetych tvaru sjednoceno); spolecny modul net/guard pro volani ven;
formularova vrstva ui/form; rozdeleni Connectors a FlowCanvas; jeden
helper pro firmu z query, validaci a CRUD udalosti; pomucky ctx.util
pro skripty konektoru; i18n verejneho webu vcetne anglictiny.

Nova funkce: zalozeni firmy z registru ARES v Nastaveni (IC nebo nazev,
dotazeni IC, DIC, sidla a pravni formy, vyber soucasnych statutarnich
zastupcu a prokury, ucty spravce firmy s nahradnim e-mailem
IC-poradi@placeholder.cz).

Dokumentace: zaznam v 99-zmeny.md a aktualizace 15 dalsich dokumentu.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 10:26:07 +02:00

95 lines
2.8 KiB
JavaScript

/**
* Microsoft 365: odeslani e-mailu pres Graph.
*
* Sluzba: https://services.csbot.cz/apps/microsoft-365-service
* Endpoint: POST /users/{user_id}/mail/send
*
* Napojeni je **aplikacni**, ne uzivatelske: prihlasuje se registrovana
* aplikace, ne clovek. Proto je schranka vzdy soucasti kroku - aplikace sama
* o sobe zadnou nema a bez uvedeneho uzivatele by Graph nevedel, odkud poslat.
*/
export const manifest = {
id: 'microsoft365.send-mail',
name: 'Odeslat e-mail',
description:
'Odešle e-mail ze zvolené schránky Microsoft 365. Příjemců může být víc, ' +
'oddělují se čárkou.',
inputs: [
{
id: 'mailbox',
label: 'Schránka odesílatele',
type: 'string',
required: true,
hint: 'E-mail nebo ID uživatele, například servis@firma.cz.',
},
{
id: 'to',
label: 'Příjemci',
type: 'string',
required: true,
hint: 'E-maily oddělené čárkou.',
},
{ id: 'cc', label: 'Kopie', type: 'string', required: false },
{ id: 'subject', label: 'Předmět', type: 'string', required: true },
{
id: 'body',
label: 'Text zprávy',
type: 'string',
required: true,
multiline: true,
},
{
id: 'html',
label: 'Text je HTML',
type: 'boolean',
required: false,
default: true,
hint: 'Vypnuté odešle zprávu jako čistý text.',
},
{
id: 'replyTo',
label: 'Adresa pro odpověď',
type: 'string',
required: false,
hint: 'Když se má odpovídat jinam než do schránky odesílatele.',
},
],
outputs: [
{ id: 'sent', label: 'Odesláno', type: 'boolean', required: true },
{ id: 'recipients', label: 'Počet příjemců', type: 'number', required: true },
{ id: 'subject', label: 'Předmět', type: 'string', required: true },
],
timeoutMs: 30000,
};
export async function run(inputs, ctx) {
// Graph chce pole objektu, clovek pise carky.
const addresses = (value) => ctx.util.addresses(value).map((address) => ({ address }));
const to = addresses(inputs.to);
if (to.length === 0) ctx.fail('Nezůstal žádný příjemce, zkontrolujte pole Příjemci.');
const payload = {
subject: inputs.subject,
body: inputs.body,
body_content_type: inputs.html ? 'HTML' : 'Text',
to,
};
const cc = addresses(inputs.cc);
if (cc.length > 0) payload.cc = cc;
if (inputs.replyTo) payload.reply_to = addresses(inputs.replyTo);
// Cesta obsahuje e-mail, ktery muze mit znaky mimo ASCII.
await ctx.http.post(`/users/${encodeURIComponent(inputs.mailbox)}/mail/send`, payload);
ctx.log(`Odesláno ${to.length + cc.length} příjemcům ze schránky ${inputs.mailbox}.`);
// Graph na uspesne odeslani nevraci telo, vystup se sklada ze vstupu.
return { sent: true, recipients: to.length + cc.length, subject: inputs.subject };
}