Katalog srovnany s tim, co opravdu bezi na services.csbot.cz/apps: trinact sluzeb dostalo pristupove udaje a levne cteci overeni, opravena appId, ktera nikam nevedla (ppl, microsoft365, transcription), a GA4, Search Console, Google Ads i Sklik ted stoji na aplikaci analytics, kazda s vlastnimi udaji. Nove sluzby SAP Business One, Google Workspace a Meta Ads. K tomu 23 skriptu, ktere s nimi opravdu neco delaji. OpenAI jako prvni sluzba, ktera nebezi u nas: Service.baseUrl s absolutni adresou, prepis pres <SLUZBA>_BASE_URL nebo adresu u konektoru, predpona hlavicky u pole udaju (uzivatel vlepi holy klic, Bearer dopise runtime). Dotaz na model, nahrani souboru, otazka nad souborem, prepis zvuku. Skript umi odeslat soubor pres ctx.http.postForm (multipart, obsah Base64). Sluzba E-mail pres SMTP. Neni to skript, ale vnitrni krok - SMTP neni HTTP. Konektor nese schranku firmy, krok ma HTML telo, ve kterem se dosazene hodnoty escapuji (znacky autora sablony jsou zamer, ostre zavorky od zakaznika ne). Overeni konektoru se prihlasi na server a nic neodesle. Helpdesk: Ticket.helpdeskSourceId drzi firmu, ktera pozadavek poslala, vlastnikem zustava ta, ktera ho resi - jinak by ho resitel nemel ve sve fronte. Komu pozadavek pripadne, urcuje Tenant.helpdeskProviderId. Zadavatel vidi jen svoje pozadavky a smi k nim pripsat komentar. Opravy v portalu: - hlasky o ulozisti a odchozi IP vidi jen spravce platformy - typ ticketu se v automatizaci vybira ze seznamu firmy, nebo dosadi z dat - stav ticketu je otevreny naseptavac, ne ciselnik - ticket jde zalozit rucne, zakaznik u nej neni povinny - kanal se prejmenoval a parametry u webhooku jsou oznacene jako nepovinne - srovnane markdown tabulky v cele dokumentaci Co z teto davky jeste neni: prepinac firmy je porad jen stav uvnitr stranky Prehled, takze se prepnuti neprojevi v Lidech ani jinde. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
147 lines
4.4 KiB
JavaScript
147 lines
4.4 KiB
JavaScript
/**
|
|
* Meta Ads: vykon reklam na Facebooku a Instagramu.
|
|
*
|
|
* Sluzba: https://services.csbot.cz/apps/meta
|
|
* Endpoint: GET /ads/insights/{object_id}
|
|
*
|
|
* Meta pocita **velke reporty asynchronne**. Tenhle krok je synchronni verze
|
|
* pro bezne obdobi a uroven; kdyz Meta odpovi, ze uloha bezi, rekne se to
|
|
* nahlas misto toho, aby krok predstiral prazdny vysledek.
|
|
*
|
|
* Utrata chodi v mene uctu jako text. Prevadi se na cislo tady, aby se s ni
|
|
* v dalsim kroku dalo pocitat.
|
|
*/
|
|
|
|
export const manifest = {
|
|
id: 'meta-ads.insights',
|
|
name: 'Načíst výkon reklam',
|
|
description:
|
|
'Stáhne útratu, zobrazení, prokliky a konverze za období. Objektem může být ' +
|
|
'reklamní účet, kampaň, sestava i jednotlivá reklama.',
|
|
|
|
inputs: [
|
|
{
|
|
id: 'objectId',
|
|
label: 'ID objektu',
|
|
type: 'string',
|
|
required: true,
|
|
hint: 'Reklamní účet jako act_123456789, nebo ID kampaně, sestavy či reklamy.',
|
|
},
|
|
{
|
|
id: 'level',
|
|
label: 'Úroveň',
|
|
type: 'string',
|
|
required: false,
|
|
default: 'campaign',
|
|
options: [
|
|
{ value: 'account', label: 'Účet' },
|
|
{ value: 'campaign', label: 'Kampaň' },
|
|
{ value: 'adset', label: 'Sestava' },
|
|
{ value: 'ad', label: 'Reklama' },
|
|
],
|
|
},
|
|
{
|
|
id: 'period',
|
|
label: 'Období',
|
|
type: 'string',
|
|
required: false,
|
|
default: 'last_7d',
|
|
options: [
|
|
{ value: 'today', label: 'Dnes' },
|
|
{ value: 'yesterday', label: 'Včera' },
|
|
{ value: 'last_7d', label: 'Posledních 7 dní' },
|
|
{ value: 'last_30d', label: 'Posledních 30 dní' },
|
|
{ value: 'this_month', label: 'Tento měsíc' },
|
|
{ value: 'last_month', label: 'Minulý měsíc' },
|
|
],
|
|
hint: 'Použije se, když není vyplněné vlastní datum.',
|
|
},
|
|
{
|
|
id: 'dateFrom',
|
|
label: 'Od',
|
|
type: 'date',
|
|
required: false,
|
|
hint: 'Vyplněné datum od i do přebije volbu období.',
|
|
},
|
|
{ id: 'dateTo', label: 'Do', type: 'date', required: false },
|
|
{
|
|
id: 'fields',
|
|
label: 'Pole',
|
|
type: 'string',
|
|
required: false,
|
|
default: 'campaign_name,impressions,clicks,spend,ctr,cpc,actions',
|
|
hint: 'Oddělená čárkou, podle dokumentace Meta Marketing API.',
|
|
},
|
|
],
|
|
|
|
outputs: [
|
|
{ id: 'count', label: 'Počet řádků', type: 'number', required: true },
|
|
{ id: 'rows', label: 'Řádky reportu', type: 'list', required: true },
|
|
{ id: 'spend', label: 'Útrata celkem', type: 'number', required: true },
|
|
{ id: 'clicks', label: 'Prokliky celkem', type: 'number', required: true },
|
|
{ id: 'impressions', label: 'Zobrazení celkem', type: 'number', required: true },
|
|
],
|
|
|
|
timeoutMs: 60000,
|
|
};
|
|
|
|
export async function run(inputs, ctx) {
|
|
const { pick, num, round } = ctx.util;
|
|
|
|
const query = { level: inputs.level, fields: inputs.fields };
|
|
|
|
if (inputs.dateFrom && inputs.dateTo) {
|
|
// Meta chce rozsah jako JSON v query parametru, ne jako dva parametry.
|
|
query.time_range = JSON.stringify({
|
|
since: inputs.dateFrom.slice(0, 10),
|
|
until: inputs.dateTo.slice(0, 10),
|
|
});
|
|
} else {
|
|
if (inputs.dateFrom || inputs.dateTo) {
|
|
ctx.log('Vyplněné je jen jedno datum, použije se zvolené období.');
|
|
}
|
|
query.date_preset = inputs.period;
|
|
}
|
|
|
|
const { body } = await ctx.http.get(`/ads/insights/${inputs.objectId}`, { query });
|
|
|
|
const raw = pick(body, 'data', 'rows');
|
|
const items = Array.isArray(raw) ? raw : [];
|
|
|
|
if (items.length === 0 && pick(body, 'report_run_id') !== undefined) {
|
|
ctx.fail(
|
|
'Meta report počítá na pozadí, synchronní volání ho nestihlo. ' +
|
|
'Zkraťte období nebo zvolte vyšší úroveň.',
|
|
body,
|
|
);
|
|
}
|
|
|
|
let spend = 0;
|
|
let clicks = 0;
|
|
let impressions = 0;
|
|
|
|
const rows = items.map((row) => {
|
|
// Meta vraci cisla jako text, vcetne utraty.
|
|
const rowSpend = num(pick(row, 'spend'), 0);
|
|
const rowClicks = num(pick(row, 'clicks'), 0);
|
|
const rowImpressions = num(pick(row, 'impressions'), 0);
|
|
|
|
spend += rowSpend;
|
|
clicks += rowClicks;
|
|
impressions += rowImpressions;
|
|
|
|
return {
|
|
...row,
|
|
spend: rowSpend,
|
|
clicks: rowClicks,
|
|
impressions: rowImpressions,
|
|
};
|
|
});
|
|
|
|
if (ctx.util.bool(pick(body, 'truncated'))) {
|
|
ctx.log('Meta vrátila jen část stránek, výsledek není úplný.');
|
|
}
|
|
|
|
return { count: rows.length, rows, spend: round(spend, 2), clicks, impressions };
|
|
}
|