Notification Layout

8 vues Markdown

The four endpoints managing the frame and logos every notification shares.

Overview

Every notification goes out inside a shared frame: a heading at the top, the template's own body in the middle and a sign-off at the bottom. This article manages that frame and the logos inside it.

The frame is kept per language, since its words and its direction follow the language. The template engine is one choice for the whole installation and decides which syntax the variables use.

The write call checks the frame before saving it: an unknown variable or broken syntax is turned down. A broken frame never takes every notification down with it.

Reference

Reading the Layout

get/api/v1/admin/notifications/settings
Notifications/GetNotificationSettings admin

Returns the frame every notification shares, along with the logos.

Response fields data — 3
enginestringThe template engine. It decides which syntax the variables use.
layoutobjectThe frame pieces per language.
headerstringThe top piece.
contentstringThe middle piece the body lands in.
footerstringThe bottom piece.
logosobjectThe addresses of the top and bottom logo. Empty when none was uploaded.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/notifications/settings' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.example.com/api/v1/admin/notifications/settings', {
  headers: { Authorization: `Bearer ${apiKey}` },
});

const { data } = await res.json();
const syntax = data.engine;   // degiskenlerin yazimi buna bagli
$ch = curl_init('https://panel.example.com/api/v1/admin/notifications/settings');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Changing the engine changes the variable syntax in EVERY template; read which one you are on first.
$cfg = Api::Notifications()->GetNotificationSettings()['data'];
$engine = $cfg['engine'];

Writing the Layout

put/api/v1/admin/notifications/settings
Notifications/UpdateNotificationSettings admin the syntax is checked

Changes the template engine and the frame pieces.

Body 2
enginestringThe template engine: none, Smarty or Twig.
layoutobjectThe frame pieces per language. Every language sent is checked for its variables and syntax.
headerstringThe top piece.
contentstringThe middle piece the body lands in.
footerstringThe bottom piece.
Response fields data — 3
dataobjectThe layout as it now stands. Same shape as the read endpoint.
Errors 3
invalid_variable422An unknown variable was used.
invalid_syntax422The template syntax is wrong.
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/notifications/settings' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"engine":"twig","layout":{"en":{"header":"<header></header>","content":"{{ content }}","footer":"<footer></footer>"}}}'
const res = await fetch('https://panel.example.com/api/v1/admin/notifications/settings', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    engine: 'twig',
    layout: { en: { header, content: '{{ content }}', footer } },
  }),
});

if (res.status === 422) showSyntaxError(await res.json());
$ch = curl_init('https://panel.example.com/api/v1/admin/notifications/settings');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['engine' => 'twig', 'layout' => $layout]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The check looks at the frame pieces ALONE: the templates' own bodies go unchecked when the engine changes.
Api::Notifications()->UpdateNotificationSettings([
    'engine' => 'twig', 'layout' => $layout,
]);

Uploading a Logo

post/api/v1/admin/notifications/logos/{type}
Notifications/UploadNotificationLogo admin

Uploads the top or bottom logo of the notifications.

Body 1
filestringreqThe image. It goes as encoded content or as a remote address.
Response fields data — 2
typestringThe logo kind.
logostringThe full address of the logo uploaded.
Errors 5
invalid_type422The logo kind is neither top nor bottom.
file_required422No file was given.
file_invalid422The file could not be read.
upload_failed422The upload failed.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/notifications/logos/header' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"file":"data:image/png;base64,iVBORw0KGgo..."}'
const res = await fetch(`https://panel.example.com/api/v1/admin/notifications/logos/${type}`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ file: dataUri }),
});

const { data } = await res.json();
$uri = 'data:image/png;base64,' . base64_encode(file_get_contents($path));

$ch = curl_init('https://panel.example.com/api/v1/admin/notifications/logos/' . $type);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['file' => $uri]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// A new logo REMOVES the old one and there is no way back; download and keep the current file first.
$cur = Api::Notifications()->GetNotificationSettings()['data']['logos']['header'] ?? '';
if ($cur) file_put_contents('logo-backup.png', file_get_contents($cur));

Api::Notifications()->UploadNotificationLogo(['type' => 'header', 'file' => $uri]);

Removing a Logo

delete/api/v1/admin/notifications/logos/{type}
Notifications/DeleteNotificationLogo admin

Removes the top or bottom logo.

Response fields data — 2
typestringThe logo kind.
deletedboolWhether the delete ran.
Errors 2
invalid_type422The logo kind is neither top nor bottom.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/notifications/logos/header' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch(`https://panel.example.com/api/v1/admin/notifications/logos/${type}`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/notifications/logos/' . $type);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Removing the logo DOES NOT remove the image tag in the layout: the frame can show a broken image.
Api::Notifications()->DeleteNotificationLogo(['type' => 'header']);
// clear the <img> line in the layout as well

Pitfalls

Changing the engine reaches every template

The template engine is one setting for the whole installation, and changing it changes the variable syntax of every notification. The write call checks the frame you send and never checks the templates' own bodies. Confirm the template text matches the new syntax before switching.

A new logo removes the old one

Uploading a logo takes the old file off the server and no version history is kept. Uploading the wrong image loses the previous one for good. Download the current logo from its address and keep it before uploading.

Removing a logo does not fix the frame

Removing a logo deletes the file and the setting while leaving the image tag in the frame. A frame still pointing at that address shows a broken image in the e-mail the client receives. Edit the frame after removing the logo.

The frame is per language and the engine is not

You write the frame pieces per language while the engine is one installation-wide setting. Writing one language's frame for the new engine and leaving the others behind shows raw variable text in the ones left. Move every language together when switching engines.

The check covers the languages sent alone

The write call checks the joined frame of every language you send in the body. The languages you leave out go unchecked and stay broken where they were. Send every language when you want the whole installation verified.

Cet article vous a-t-il été utile ?

Merci pour votre retour !

Besoin d'aide supplémentaire ?

Notre équipe d'assistance est disponible 24h/24 pour tout ce que vous ne trouvez pas ci-dessus.