@hartl-services/medusa-base 2.7.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.js +12 -9
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +5 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatures.d.ts +20 -4
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +5 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +20 -4
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.d.ts +0 -5
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.js +0 -5
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.d.ts +4 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.js +4 -0
- package/.medusa/server/src/admin/admin-components/i18n/texts.d.ts +1 -2
- package/.medusa/server/src/admin/admin-components/i18n/texts.js +1 -2
- package/.medusa/server/src/admin/index.js +142 -87
- package/.medusa/server/src/admin/index.mjs +144 -89
- package/.medusa/server/src/api/admin/email/templates/[kind]/send-test/route.js +7 -1
- package/.medusa/server/src/customer-auth/plugin-features.js +10 -10
- package/.medusa/server/src/email/application/warn-credential-expiry.js +77 -0
- package/.medusa/server/src/email/config/index.js +8 -2
- package/.medusa/server/src/email/config/notification-module.js +28 -2
- package/.medusa/server/src/email/domain/business-keys.js +5 -2
- package/.medusa/server/src/email/domain/failure-classification.js +9 -1
- package/.medusa/server/src/email/plugin-features.js +123 -1
- package/.medusa/server/src/email/rendering/default-templates.js +16 -1
- package/.medusa/server/src/email/rendering/render-email.js +2 -1
- package/.medusa/server/src/email/types/email-kinds.js +2 -1
- package/.medusa/server/src/email/types/template-data.js +8 -1
- package/.medusa/server/src/jobs/email-credential-expiry.js +27 -0
- package/.medusa/server/src/modules/email/domain/message-state.js +3 -1
- package/.medusa/server/src/modules/email/migrations/Migration20261011120000.js +20 -0
- package/.medusa/server/src/modules/plugin-features/domain/plugin-settings.js +27 -6
- package/.medusa/server/src/modules/plugin-features/service.js +4 -3
- package/.medusa/server/src/providers/smtp/delivery-settings.js +75 -0
- package/.medusa/server/src/providers/smtp/graph-transport.js +150 -0
- package/.medusa/server/src/providers/smtp/service.js +105 -37
- package/.medusa/server/src/providers/smtp/types.js +7 -1
- package/.medusa/server/src/public/descriptor.js +24 -3
- package/.medusa/server/src/shared/lib/dates.js +8 -2
- package/.medusa/server/src/shop-config/build-food-shop-config.js +3 -5
- package/README.md +100 -65
- package/dist/customer-auth/plugin-features.js +9 -9
- package/dist/email/config/index.d.ts +6 -1
- package/dist/email/config/index.js +7 -1
- package/dist/email/config/notification-module.d.ts +25 -0
- package/dist/email/config/notification-module.js +27 -1
- package/dist/email/types/email-kinds.d.ts +2 -1
- package/dist/email/types/email-kinds.js +1 -0
- package/dist/email/types/template-data.d.ts +10 -0
- package/dist/email/types/template-data.js +7 -0
- package/dist/public/descriptor.js +23 -2
- package/dist/public/types.d.ts +14 -4
- package/dist/shared/lib/dates.d.ts +2 -0
- package/dist/shared/lib/dates.js +7 -1
- package/dist/shop-config/build-food-shop-config.d.ts +1 -1
- package/dist/shop-config/build-food-shop-config.js +2 -4
- package/package.json +2 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
|
|
3
|
-
import { Container, IconBadge, Heading, Text, Tooltip, IconButton, toast, StatusBadge, Button, clx, usePrompt, Label, Switch, Hint, Input, Select, Alert,
|
|
3
|
+
import { Container, IconBadge, Heading, Text, Tooltip, IconButton, toast, StatusBadge, Button, clx, usePrompt, Label, Switch, I18nProvider, DatePicker, Hint, Input, Select, Alert, FocusModal, DropdownMenu, Badge, Table, Prompt } from "@medusajs/ui";
|
|
4
4
|
import { useQuery, useQueryClient, useMutation, keepPreviousData, skipToken } from "@tanstack/react-query";
|
|
5
5
|
import { emailAdminPaths } from "@hartl-services/medusa-food-supplements-contracts/paths/email";
|
|
6
6
|
import Medusa from "@medusajs/js-sdk";
|
|
7
|
-
import { ArrowLongLeft, InformationCircle, Users, TruckFast, Tag, SquaresPlus, ShoppingCart, ShieldCheck, ReceiptPercent, Envelope, DocumentText, CreditCard, CogSixTooth, ClockSolid, Buildings, BuildingStorefront, ArrowPath, ArchiveBox, ArrowUpTray, TriangleRightMini, ChevronDownMini, PaperClip, User, ArrowDownTray } from "@medusajs/icons";
|
|
7
|
+
import { ArrowLongLeft, InformationCircle, Users, TruckFast, Tag, SquaresPlus, ShoppingCart, ShieldCheck, ReceiptPercent, Envelope, DocumentText, CreditCard, CogSixTooth, ClockSolid, Buildings, BuildingStorefront, ArrowPath, ArchiveBox, ArrowUpTray, TriangleRightMini, ChevronDownMini, PaperPlane, PaperClip, User, ArrowDownTray } from "@medusajs/icons";
|
|
8
8
|
import { Link, useLocation, useSearchParams, useParams } from "react-router-dom";
|
|
9
9
|
import { pluginFeaturesAdminPaths } from "@hartl-services/medusa-food-supplements-contracts/paths/plugin-features";
|
|
10
10
|
import { useRef, useEffect, useState, useMemo, Fragment as Fragment$1, useCallback, useLayoutEffect, useId, forwardRef, useImperativeHandle } from "react";
|
|
@@ -22,7 +22,8 @@ const texts = {
|
|
|
22
22
|
},
|
|
23
23
|
breadcrumbs: {
|
|
24
24
|
hub: "Plugins",
|
|
25
|
-
emailAttachments: "Anhänge"
|
|
25
|
+
emailAttachments: "Anhänge",
|
|
26
|
+
emailDelivery: "Versand"
|
|
26
27
|
},
|
|
27
28
|
page: {
|
|
28
29
|
title: "Hartl Services Plugins",
|
|
@@ -88,8 +89,6 @@ const texts = {
|
|
|
88
89
|
secretClearUndoLabel: (label) => `${label} nicht löschen`,
|
|
89
90
|
/** Shown on a secret: the settings whose change deletes it ("A", "A oder B"). */
|
|
90
91
|
invalidatedBy: (labels) => `Wird gelöscht, wenn ${labels.length > 1 ? `${labels.slice(0, -1).join(", ")} oder ${labels[labels.length - 1]}` : labels.join("")} sich ändert.`,
|
|
91
|
-
/** Shown on the changing setting: the secrets its change deletes. */
|
|
92
|
-
invalidates: (labels) => `Beim Ändern muss ${labels} neu eingegeben werden.`,
|
|
93
92
|
invalidNumber: "Bitte eine gültige Zahl eingeben.",
|
|
94
93
|
invalidColor: "Bitte eine Hex-Farbe wie #1a2b3c eingeben.",
|
|
95
94
|
colorPlaceholder: "Standard",
|
|
@@ -390,9 +389,6 @@ const disabledParent = (features, feature) => {
|
|
|
390
389
|
};
|
|
391
390
|
const invalidatedByLabels = (settings, secretKey) => settings.filter((setting) => setting.invalidates.includes(secretKey)).map((setting) => setting.label);
|
|
392
391
|
const isGroupDimmed = (features, requiresFeature) => requiresFeature !== null && features.find((feature) => feature.key === requiresFeature)?.effective_enabled === false;
|
|
393
|
-
const invalidatesLabels = (settings, setting) => setting.invalidates.map(
|
|
394
|
-
(key) => settings.find((candidate) => candidate.key === key)?.label ?? key
|
|
395
|
-
);
|
|
396
392
|
const settingInfoText = (setting) => setting.hint !== null && setting.description !== null && setting.description !== setting.hint ? setting.description : null;
|
|
397
393
|
const headerInfoText = (plugin2) => plugin2.summary !== null && plugin2.description !== null && plugin2.description !== plugin2.summary ? plugin2.description : null;
|
|
398
394
|
const showsSourceHint = (source) => source !== "default";
|
|
@@ -957,6 +953,35 @@ const changedSettingValues = (settings, draft, unparsable = []) => {
|
|
|
957
953
|
}
|
|
958
954
|
return values;
|
|
959
955
|
};
|
|
956
|
+
const DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
957
|
+
const DATE_TIME_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/;
|
|
958
|
+
const pad = (value, length = 2) => String(value).padStart(length, "0");
|
|
959
|
+
const build = ([year, month, day, hour = 0, minute = 0]) => {
|
|
960
|
+
const date = new Date(year, month - 1, day, hour, minute);
|
|
961
|
+
const matches = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day && date.getHours() === hour && date.getMinutes() === minute;
|
|
962
|
+
return matches ? date : null;
|
|
963
|
+
};
|
|
964
|
+
const dateFromInputValue = (value) => {
|
|
965
|
+
const match = value ? DATE_PATTERN.exec(value) : null;
|
|
966
|
+
return match ? build(match.slice(1).map(Number)) : null;
|
|
967
|
+
};
|
|
968
|
+
const inputValueFromDate = (date) => {
|
|
969
|
+
if (!date || Number.isNaN(date.getTime())) {
|
|
970
|
+
return "";
|
|
971
|
+
}
|
|
972
|
+
return `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
973
|
+
};
|
|
974
|
+
const dateTimeFromInputValue = (value) => {
|
|
975
|
+
const match = value ? DATE_TIME_PATTERN.exec(value) : null;
|
|
976
|
+
return match ? build(match.slice(1).map(Number)) : null;
|
|
977
|
+
};
|
|
978
|
+
const inputValueFromDateTime = (date) => {
|
|
979
|
+
if (!date || Number.isNaN(date.getTime())) {
|
|
980
|
+
return "";
|
|
981
|
+
}
|
|
982
|
+
return `${inputValueFromDate(date)}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
983
|
+
};
|
|
984
|
+
const AdminDatePicker = (props) => /* @__PURE__ */ jsx(I18nProvider, { locale: ADMIN_LOCALE, children: /* @__PURE__ */ jsx(DatePicker, { ...props }) });
|
|
960
985
|
const buildSettingBlocks = (settings) => {
|
|
961
986
|
const blocks = [];
|
|
962
987
|
let previousSection = null;
|
|
@@ -1008,11 +1033,13 @@ const buildSettingGroups = (settings, groups, ungroupedTitle) => {
|
|
|
1008
1033
|
description: meta?.description ?? null,
|
|
1009
1034
|
note: meta?.note ?? null,
|
|
1010
1035
|
requiresFeature: meta?.requires_feature ?? null,
|
|
1036
|
+
visibleWhen: meta?.visible_when ?? null,
|
|
1011
1037
|
settings: groupSettings,
|
|
1012
1038
|
blocks: buildSettingBlocks(groupSettings)
|
|
1013
1039
|
};
|
|
1014
1040
|
});
|
|
1015
1041
|
};
|
|
1042
|
+
const isGroupVisible = (group, draft) => group.visibleWhen === null || draft[group.visibleWhen.setting] === group.visibleWhen.equals;
|
|
1016
1043
|
function usePluginSettingsForm(plugin2) {
|
|
1017
1044
|
const mutation = useUpdatePluginSettings(plugin2.plugin_key);
|
|
1018
1045
|
const [draft, setDraft] = useState(
|
|
@@ -1306,13 +1333,13 @@ const SettingField = ({
|
|
|
1306
1333
|
pluginKey,
|
|
1307
1334
|
setting,
|
|
1308
1335
|
invalidatedBy,
|
|
1309
|
-
invalidates,
|
|
1310
1336
|
value,
|
|
1311
1337
|
invalid,
|
|
1312
1338
|
disabled,
|
|
1313
1339
|
onChange
|
|
1314
1340
|
}) => {
|
|
1315
1341
|
const id = fieldId(pluginKey, setting.key);
|
|
1342
|
+
const labelId = `${id}-label`;
|
|
1316
1343
|
const hintId = `${id}-hint`;
|
|
1317
1344
|
const clearPending = setting.type === "secret" && value === null;
|
|
1318
1345
|
const bounds = setting.type === "number" ? boundsText(setting) : void 0;
|
|
@@ -1320,13 +1347,13 @@ const SettingField = ({
|
|
|
1320
1347
|
const info = settingInfoText(setting);
|
|
1321
1348
|
const showBounds = Boolean(bounds) && showsBoundsLine(setting);
|
|
1322
1349
|
const required = setting.required;
|
|
1323
|
-
const hasHints = Boolean(hint) || clearPending || invalidatedBy.length > 0 ||
|
|
1350
|
+
const hasHints = Boolean(hint) || clearPending || invalidatedBy.length > 0 || showBounds || invalid;
|
|
1324
1351
|
const describedBy = hasHints ? hintId : void 0;
|
|
1325
1352
|
const placeholder = setting.placeholder ?? void 0;
|
|
1326
1353
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-2", children: [
|
|
1327
1354
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
1328
1355
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
|
|
1329
|
-
/* @__PURE__ */ jsx(Label, { htmlFor: id, size: "small", weight: "plus", children: labelText(setting) }),
|
|
1356
|
+
/* @__PURE__ */ jsx(Label, { id: labelId, htmlFor: id, size: "small", weight: "plus", children: labelText(setting) }),
|
|
1330
1357
|
info && /* @__PURE__ */ jsx(InfoTooltip, { label: texts.info.label(setting.label), children: info })
|
|
1331
1358
|
] }),
|
|
1332
1359
|
showsSourceHint(setting.source) && /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted shrink-0", children: texts.settings.source[setting.source] })
|
|
@@ -1400,6 +1427,16 @@ const SettingField = ({
|
|
|
1400
1427
|
disabled,
|
|
1401
1428
|
onChange: (next) => onChange(next)
|
|
1402
1429
|
}
|
|
1430
|
+
) : setting.type === "date" ? /* @__PURE__ */ jsx(
|
|
1431
|
+
AdminDatePicker,
|
|
1432
|
+
{
|
|
1433
|
+
id,
|
|
1434
|
+
"aria-labelledby": labelId,
|
|
1435
|
+
"aria-describedby": describedBy,
|
|
1436
|
+
isDisabled: disabled,
|
|
1437
|
+
value: dateFromInputValue(typeof value === "string" ? value : ""),
|
|
1438
|
+
onChange: (date) => onChange(inputValueFromDate(date))
|
|
1439
|
+
}
|
|
1403
1440
|
) : setting.type === "number" ? /* @__PURE__ */ jsx(
|
|
1404
1441
|
Input,
|
|
1405
1442
|
{
|
|
@@ -1434,7 +1471,6 @@ const SettingField = ({
|
|
|
1434
1471
|
hint && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: hint }),
|
|
1435
1472
|
clearPending && /* @__PURE__ */ jsx(Hint, { variant: "info", children: texts.settings.secretClearPending }),
|
|
1436
1473
|
invalidatedBy.length > 0 && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: texts.settings.invalidatedBy(invalidatedBy) }),
|
|
1437
|
-
invalidates.length > 0 && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: texts.settings.invalidates(invalidates.join(", ")) }),
|
|
1438
1474
|
showBounds && !invalid && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: bounds }),
|
|
1439
1475
|
invalid && /* @__PURE__ */ jsx(Hint, { variant: "error", children: setting.type === "color" ? texts.settings.invalidColor : bounds ?? texts.settings.invalidNumber })
|
|
1440
1476
|
] })
|
|
@@ -1447,9 +1483,9 @@ const PluginSettingsForm = ({ plugin: plugin2 }) => {
|
|
|
1447
1483
|
plugin2.settings,
|
|
1448
1484
|
plugin2.setting_groups,
|
|
1449
1485
|
texts.sections.settings
|
|
1450
|
-
);
|
|
1486
|
+
).filter((group) => isGroupVisible(group, form.draft));
|
|
1451
1487
|
const hasTextFields = plugin2.settings.some(
|
|
1452
|
-
(setting) => setting.type === "string" || setting.type === "url" || setting.type === "number" || setting.type === "color"
|
|
1488
|
+
(setting) => setting.type === "string" || setting.type === "url" || setting.type === "number" || setting.type === "color" || setting.type === "date"
|
|
1453
1489
|
);
|
|
1454
1490
|
const renderField = (setting) => /* @__PURE__ */ jsx(
|
|
1455
1491
|
SettingField,
|
|
@@ -1457,7 +1493,6 @@ const PluginSettingsForm = ({ plugin: plugin2 }) => {
|
|
|
1457
1493
|
pluginKey: plugin2.plugin_key,
|
|
1458
1494
|
setting,
|
|
1459
1495
|
invalidatedBy: setting.type === "secret" ? invalidatedByLabels(plugin2.settings, setting.key) : [],
|
|
1460
|
-
invalidates: invalidatesLabels(plugin2.settings, setting),
|
|
1461
1496
|
value: form.draft[setting.key],
|
|
1462
1497
|
invalid: form.invalid.includes(setting.key),
|
|
1463
1498
|
disabled: pending,
|
|
@@ -1635,29 +1670,6 @@ const PluginFeatureDisabledNotice = ({
|
|
|
1635
1670
|
]
|
|
1636
1671
|
}
|
|
1637
1672
|
);
|
|
1638
|
-
const DATE_TIME_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/;
|
|
1639
|
-
const pad = (value, length = 2) => String(value).padStart(length, "0");
|
|
1640
|
-
const build = ([year, month, day, hour = 0, minute = 0]) => {
|
|
1641
|
-
const date = new Date(year, month - 1, day, hour, minute);
|
|
1642
|
-
const matches = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day && date.getHours() === hour && date.getMinutes() === minute;
|
|
1643
|
-
return matches ? date : null;
|
|
1644
|
-
};
|
|
1645
|
-
const inputValueFromDate = (date) => {
|
|
1646
|
-
if (!date || Number.isNaN(date.getTime())) {
|
|
1647
|
-
return "";
|
|
1648
|
-
}
|
|
1649
|
-
return `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
1650
|
-
};
|
|
1651
|
-
const dateTimeFromInputValue = (value) => {
|
|
1652
|
-
const match = value ? DATE_TIME_PATTERN.exec(value) : null;
|
|
1653
|
-
return match ? build(match.slice(1).map(Number)) : null;
|
|
1654
|
-
};
|
|
1655
|
-
const inputValueFromDateTime = (date) => {
|
|
1656
|
-
if (!date || Number.isNaN(date.getTime())) {
|
|
1657
|
-
return "";
|
|
1658
|
-
}
|
|
1659
|
-
return `${inputValueFromDate(date)}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
1660
|
-
};
|
|
1661
1673
|
const fetchPdfObjectUrl = async (path) => {
|
|
1662
1674
|
const response = await sdk.client.fetch(path, {
|
|
1663
1675
|
headers: { accept: "application/pdf" }
|
|
@@ -1745,7 +1757,6 @@ const useDebouncedValue = (value, delayMs) => {
|
|
|
1745
1757
|
}, [value, delayMs]);
|
|
1746
1758
|
return debounced;
|
|
1747
1759
|
};
|
|
1748
|
-
const AdminDatePicker = (props) => /* @__PURE__ */ jsx(I18nProvider, { locale: ADMIN_LOCALE, children: /* @__PURE__ */ jsx(DatePicker, { ...props }) });
|
|
1749
1760
|
const FocusModalShell = ({
|
|
1750
1761
|
open,
|
|
1751
1762
|
onOpenChange,
|
|
@@ -3504,7 +3515,7 @@ const PluginFeaturesSettingsPage = () => {
|
|
|
3504
3515
|
const config = defineRouteConfig({
|
|
3505
3516
|
label: texts.menu.label
|
|
3506
3517
|
});
|
|
3507
|
-
const handle$
|
|
3518
|
+
const handle$b = {
|
|
3508
3519
|
breadcrumb: () => texts.breadcrumbs.hub
|
|
3509
3520
|
};
|
|
3510
3521
|
const KINDS = [
|
|
@@ -3520,7 +3531,8 @@ const KINDS = [
|
|
|
3520
3531
|
"auth.login_code",
|
|
3521
3532
|
"affiliate.consignment_report_due",
|
|
3522
3533
|
"affiliate.application_submitted.admin",
|
|
3523
|
-
"user.invite"
|
|
3534
|
+
"user.invite",
|
|
3535
|
+
"system.credential_expiry.admin"
|
|
3524
3536
|
];
|
|
3525
3537
|
const KIND_LABELS = {
|
|
3526
3538
|
"order.received": "Bestellbestätigung (Kunde)",
|
|
@@ -3535,10 +3547,12 @@ const KIND_LABELS = {
|
|
|
3535
3547
|
"auth.login_code": "Anmeldecode",
|
|
3536
3548
|
"affiliate.consignment_report_due": "Affiliate-Meldung",
|
|
3537
3549
|
"affiliate.application_submitted.admin": "Neue Partner-Bewerbung (Shop)",
|
|
3538
|
-
"user.invite": "Admin-Einladung"
|
|
3550
|
+
"user.invite": "Admin-Einladung",
|
|
3551
|
+
"system.credential_expiry.admin": "Secret läuft ab (Shop)"
|
|
3539
3552
|
};
|
|
3540
3553
|
const EMAIL_PAGE_PATH = `${PLUGIN_HUB_PATH}/email`;
|
|
3541
3554
|
const EMAIL_ATTACHMENTS_PAGE_PATH = `${EMAIL_PAGE_PATH}/attachments`;
|
|
3555
|
+
const EMAIL_DELIVERY_PAGE_PATH = `${EMAIL_PAGE_PATH}/delivery`;
|
|
3542
3556
|
const emailAttachmentPagePath = (attachmentId) => `${EMAIL_ATTACHMENTS_PAGE_PATH}/${encodeURIComponent(attachmentId)}`;
|
|
3543
3557
|
const NO_MAIL_ASSIGNED_LABEL = "keiner Mail zugeordnet";
|
|
3544
3558
|
const MAIL_KIND_OPTIONS = EMAIL_ATTACHABLE_KINDS.map((kind) => ({
|
|
@@ -3796,52 +3810,61 @@ const LinkRow = ({
|
|
|
3796
3810
|
description,
|
|
3797
3811
|
to,
|
|
3798
3812
|
disabled
|
|
3799
|
-
}) => /* @__PURE__ */ jsxs(
|
|
3800
|
-
|
|
3801
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-y-0.5", children: [
|
|
3802
|
-
/* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", weight: "plus", children: title }),
|
|
3803
|
-
/* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: description })
|
|
3804
|
-
] }),
|
|
3805
|
-
disabled ? /* @__PURE__ */ jsx(
|
|
3806
|
-
Button,
|
|
3807
|
-
{
|
|
3808
|
-
"aria-label": texts.plugin.openLabel(title),
|
|
3809
|
-
disabled: true,
|
|
3810
|
-
size: "small",
|
|
3811
|
-
variant: "secondary",
|
|
3812
|
-
children: texts.plugin.open
|
|
3813
|
-
}
|
|
3814
|
-
) : /* @__PURE__ */ jsx(Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsx(Link, { "aria-label": texts.plugin.openLabel(title), to, children: texts.plugin.open }) })
|
|
3815
|
-
] });
|
|
3816
|
-
const EmailManagementSection = ({ disabled }) => /* @__PURE__ */ jsxs(
|
|
3817
|
-
AdminSection,
|
|
3813
|
+
}) => /* @__PURE__ */ jsxs(
|
|
3814
|
+
"div",
|
|
3818
3815
|
{
|
|
3819
|
-
className: `transition-opacity ${disabled ? "opacity-50" : ""}`,
|
|
3820
|
-
title: "Verwaltung",
|
|
3816
|
+
className: `flex items-center gap-4 px-6 py-3 transition-opacity ${disabled ? "opacity-50" : ""}`,
|
|
3821
3817
|
children: [
|
|
3822
|
-
/* @__PURE__ */ jsx(
|
|
3823
|
-
|
|
3824
|
-
{
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
to: EMAIL_ATTACHMENTS_PAGE_PATH
|
|
3830
|
-
}
|
|
3831
|
-
),
|
|
3832
|
-
/* @__PURE__ */ jsx(
|
|
3833
|
-
LinkRow,
|
|
3818
|
+
/* @__PURE__ */ jsx(IconBadge, { children: icon }),
|
|
3819
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-y-0.5", children: [
|
|
3820
|
+
/* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", weight: "plus", children: title }),
|
|
3821
|
+
/* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: description })
|
|
3822
|
+
] }),
|
|
3823
|
+
disabled ? /* @__PURE__ */ jsx(
|
|
3824
|
+
Button,
|
|
3834
3825
|
{
|
|
3835
|
-
|
|
3836
|
-
disabled,
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3826
|
+
"aria-label": texts.plugin.openLabel(title),
|
|
3827
|
+
disabled: true,
|
|
3828
|
+
size: "small",
|
|
3829
|
+
variant: "secondary",
|
|
3830
|
+
children: texts.plugin.open
|
|
3840
3831
|
}
|
|
3841
|
-
)
|
|
3832
|
+
) : /* @__PURE__ */ jsx(Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsx(Link, { "aria-label": texts.plugin.openLabel(title), to, children: texts.plugin.open }) })
|
|
3842
3833
|
]
|
|
3843
3834
|
}
|
|
3844
3835
|
);
|
|
3836
|
+
const EmailManagementSection = ({ disabled }) => /* @__PURE__ */ jsxs(AdminSection, { title: "Verwaltung", children: [
|
|
3837
|
+
/* @__PURE__ */ jsx(
|
|
3838
|
+
LinkRow,
|
|
3839
|
+
{
|
|
3840
|
+
description: "SMTP oder Microsoft 365.",
|
|
3841
|
+
disabled: false,
|
|
3842
|
+
icon: /* @__PURE__ */ jsx(PaperPlane, {}),
|
|
3843
|
+
title: texts.breadcrumbs.emailDelivery,
|
|
3844
|
+
to: EMAIL_DELIVERY_PAGE_PATH
|
|
3845
|
+
}
|
|
3846
|
+
),
|
|
3847
|
+
/* @__PURE__ */ jsx(
|
|
3848
|
+
LinkRow,
|
|
3849
|
+
{
|
|
3850
|
+
description: "PDFs an Kunden-Mails, z. B. AGB.",
|
|
3851
|
+
disabled,
|
|
3852
|
+
icon: /* @__PURE__ */ jsx(PaperClip, {}),
|
|
3853
|
+
title: "Anhänge",
|
|
3854
|
+
to: EMAIL_ATTACHMENTS_PAGE_PATH
|
|
3855
|
+
}
|
|
3856
|
+
),
|
|
3857
|
+
/* @__PURE__ */ jsx(
|
|
3858
|
+
LinkRow,
|
|
3859
|
+
{
|
|
3860
|
+
description: "Status und Zustellversuche.",
|
|
3861
|
+
disabled,
|
|
3862
|
+
icon: /* @__PURE__ */ jsx(ClockSolid, {}),
|
|
3863
|
+
title: "E-Mail-Protokoll",
|
|
3864
|
+
to: EMAIL_LOG_PAGE_PATH
|
|
3865
|
+
}
|
|
3866
|
+
)
|
|
3867
|
+
] });
|
|
3845
3868
|
const EmailOverviewSections = () => {
|
|
3846
3869
|
const plugin2 = usePluginFeature("email").data?.plugin;
|
|
3847
3870
|
if (!plugin2) {
|
|
@@ -3853,7 +3876,7 @@ const EmailOverviewSections = () => {
|
|
|
3853
3876
|
] });
|
|
3854
3877
|
};
|
|
3855
3878
|
const EmailOverviewPage = () => /* @__PURE__ */ jsx(PluginPageShell, { pluginKey: "email", variant: "header", children: /* @__PURE__ */ jsx(EmailOverviewSections, {}) });
|
|
3856
|
-
const handle$
|
|
3879
|
+
const handle$a = {
|
|
3857
3880
|
breadcrumb: (_match) => /* @__PURE__ */ jsx(PluginLabelCrumb, { pluginKey: "email" })
|
|
3858
3881
|
};
|
|
3859
3882
|
const EMAIL_TEMPLATES_PATH = `${EMAIL_PAGE_PATH}/templates`;
|
|
@@ -3973,11 +3996,11 @@ const EmailTemplateGroupPage = ({
|
|
|
3973
3996
|
) })
|
|
3974
3997
|
] });
|
|
3975
3998
|
};
|
|
3976
|
-
const handle$
|
|
3999
|
+
const handle$9 = {
|
|
3977
4000
|
breadcrumb: () => EMAIL_TEMPLATE_GROUPS.account.label
|
|
3978
4001
|
};
|
|
3979
4002
|
const EmailAccountMailsRoute = () => /* @__PURE__ */ jsx(PluginFeatureRoute, { pluginKey: "email", children: /* @__PURE__ */ jsx(EmailTemplateGroupPage, { group: "account" }) });
|
|
3980
|
-
const handle$
|
|
4003
|
+
const handle$8 = {
|
|
3981
4004
|
breadcrumb: () => EMAIL_TEMPLATE_GROUPS.affiliate.label
|
|
3982
4005
|
};
|
|
3983
4006
|
const EmailAffiliateMailsRoute = () => /* @__PURE__ */ jsx(PluginFeatureRoute, { pluginKey: "email", children: /* @__PURE__ */ jsx(EmailTemplateGroupPage, { group: "affiliate" }) });
|
|
@@ -4378,10 +4401,37 @@ const EmailAttachmentsPage = () => {
|
|
|
4378
4401
|
/* @__PURE__ */ jsx(NewAttachmentModal, { onOpenChange: setNewOpen, open: newOpen })
|
|
4379
4402
|
] });
|
|
4380
4403
|
};
|
|
4381
|
-
const handle$
|
|
4404
|
+
const handle$7 = {
|
|
4382
4405
|
breadcrumb: () => texts.breadcrumbs.emailAttachments
|
|
4383
4406
|
};
|
|
4384
4407
|
const EmailAttachmentsRoute = () => /* @__PURE__ */ jsx(PluginFeatureRoute, { pluginKey: "email", children: /* @__PURE__ */ jsx(EmailAttachmentsPage, {}) });
|
|
4408
|
+
const EmailDeliveryPage = () => {
|
|
4409
|
+
const query = usePluginFeature("email");
|
|
4410
|
+
const plugin2 = query.data?.plugin;
|
|
4411
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-3", children: [
|
|
4412
|
+
/* @__PURE__ */ jsx(
|
|
4413
|
+
AdminPageHeader,
|
|
4414
|
+
{
|
|
4415
|
+
badges: plugin2 && /* @__PURE__ */ jsx(StatusBadge, { color: plugin2.configured ? "green" : "orange", children: plugin2.configured ? texts.chips.configured : texts.chips.notConfigured }),
|
|
4416
|
+
description: "SMTP oder Microsoft 365.",
|
|
4417
|
+
icon: /* @__PURE__ */ jsx(PaperPlane, {}),
|
|
4418
|
+
title: texts.breadcrumbs.emailDelivery
|
|
4419
|
+
}
|
|
4420
|
+
),
|
|
4421
|
+
plugin2 ? /* @__PURE__ */ jsx(PluginSettingsForm, { plugin: plugin2 }) : /* @__PURE__ */ jsx(Container, { className: "p-0", children: /* @__PURE__ */ jsx(
|
|
4422
|
+
QueryState,
|
|
4423
|
+
{
|
|
4424
|
+
error: query.error,
|
|
4425
|
+
errorText: texts.states.error,
|
|
4426
|
+
isLoading: query.isPending,
|
|
4427
|
+
loadingText: texts.states.loading
|
|
4428
|
+
}
|
|
4429
|
+
) })
|
|
4430
|
+
] });
|
|
4431
|
+
};
|
|
4432
|
+
const handle$6 = {
|
|
4433
|
+
breadcrumb: () => texts.breadcrumbs.emailDelivery
|
|
4434
|
+
};
|
|
4385
4435
|
const LOG_PAGE_SIZE = 20;
|
|
4386
4436
|
const LOG_MAX_OFFSET = 1e4;
|
|
4387
4437
|
const LOG_MAX_RESOURCE_ID_LENGTH = 255;
|
|
@@ -6681,26 +6731,31 @@ const routeModule = {
|
|
|
6681
6731
|
{
|
|
6682
6732
|
Component: PluginFeaturesSettingsPage,
|
|
6683
6733
|
path: "/settings/hartl-services",
|
|
6684
|
-
handle: { label: config.label, translationNs: config.translationNs, ...handle$
|
|
6734
|
+
handle: { label: config.label, translationNs: config.translationNs, ...handle$b }
|
|
6685
6735
|
},
|
|
6686
6736
|
{
|
|
6687
6737
|
Component: EmailOverviewPage,
|
|
6688
6738
|
path: "/settings/hartl-services/email",
|
|
6689
|
-
handle: handle$
|
|
6739
|
+
handle: handle$a
|
|
6690
6740
|
},
|
|
6691
6741
|
{
|
|
6692
6742
|
Component: EmailAccountMailsRoute,
|
|
6693
6743
|
path: "/settings/hartl-services/email/account",
|
|
6694
|
-
handle: handle$
|
|
6744
|
+
handle: handle$9
|
|
6695
6745
|
},
|
|
6696
6746
|
{
|
|
6697
6747
|
Component: EmailAffiliateMailsRoute,
|
|
6698
6748
|
path: "/settings/hartl-services/email/affiliate",
|
|
6699
|
-
handle: handle$
|
|
6749
|
+
handle: handle$8
|
|
6700
6750
|
},
|
|
6701
6751
|
{
|
|
6702
6752
|
Component: EmailAttachmentsRoute,
|
|
6703
6753
|
path: "/settings/hartl-services/email/attachments",
|
|
6754
|
+
handle: handle$7
|
|
6755
|
+
},
|
|
6756
|
+
{
|
|
6757
|
+
Component: EmailDeliveryPage,
|
|
6758
|
+
path: "/settings/hartl-services/email/delivery",
|
|
6704
6759
|
handle: handle$6
|
|
6705
6760
|
},
|
|
6706
6761
|
{
|
|
@@ -16,6 +16,12 @@ const TEST_SUBJECT_PREFIX = "[Test] ";
|
|
|
16
16
|
/** A German Admin message for a failed test send; the provider's own text never reaches the Admin. */
|
|
17
17
|
const testSendFailure = (error) => {
|
|
18
18
|
const { code } = (0, failure_classification_1.classifyNotificationFailure)(error);
|
|
19
|
+
if (code === "not_configured") {
|
|
20
|
+
return new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Der Versand ist nicht eingerichtet (E-Mail › Versand).");
|
|
21
|
+
}
|
|
22
|
+
if (code === "auth_failed") {
|
|
23
|
+
return new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Die Anmeldung beim Mailanbieter ist fehlgeschlagen. Zugangsdaten unter E-Mail › Versand prüfen.");
|
|
24
|
+
}
|
|
19
25
|
if (code === "permanent_rejection") {
|
|
20
26
|
return new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Der Mailserver hat die Adresse abgelehnt.");
|
|
21
27
|
}
|
|
@@ -176,4 +182,4 @@ const POST = async (req, res) => {
|
|
|
176
182
|
}));
|
|
177
183
|
};
|
|
178
184
|
exports.POST = POST;
|
|
179
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
185
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2VtYWlsL3RlbXBsYXRlcy9ba2luZF0vc2VuZC10ZXN0L3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUlBLHFEQUFpRTtBQUtqRSwyRkFHeUU7QUFRekUsMkdBS3NFO0FBQ3RFLDJHQUlzRTtBQUN0RSxnRkFJc0Q7QUFDdEQsa0dBQW9HO0FBQ3BHLHVHQUFpRztBQUNqRyxpRUFBMEU7QUFFMUUsMkRBQStEO0FBQy9ELGtGQUkyRDtBQUUzRCxvRkFBMkU7QUFFM0UsTUFBTSxtQkFBbUIsR0FBRyxTQUFTLENBQUM7QUFFdEMsc0dBQXNHO0FBQ3RHLE1BQU0sZUFBZSxHQUFHLENBQUMsS0FBYyxFQUFlLEVBQUU7SUFDdEQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLElBQUEsb0RBQTJCLEVBQUMsS0FBSyxDQUFDLENBQUM7SUFDcEQsSUFBSSxJQUFJLEtBQUssZ0JBQWdCLEVBQUUsQ0FBQztRQUM5QixPQUFPLElBQUksbUJBQVcsQ0FDcEIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qix3REFBd0QsQ0FDekQsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUFJLElBQUksS0FBSyxhQUFhLEVBQUUsQ0FBQztRQUMzQixPQUFPLElBQUksbUJBQVcsQ0FDcEIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixpR0FBaUcsQ0FDbEcsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUFJLElBQUksS0FBSyxxQkFBcUIsRUFBRSxDQUFDO1FBQ25DLE9BQU8sSUFBSSxtQkFBVyxDQUNwQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLDJDQUEyQyxDQUM1QyxDQUFDO0lBQ0osQ0FBQztJQUNELElBQ0UsSUFBSSxLQUFLLG1CQUFtQjtRQUM1QixJQUFJLEtBQUsscUJBQXFCO1FBQzlCLElBQUksS0FB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
|
|
@@ -7,32 +7,32 @@ const PASSWORD_RULES = "Passwort-Regeln";
|
|
|
7
7
|
exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
|
|
8
8
|
plugin_key: customer_auth_1.CUSTOMER_AUTH_PLUGIN_KEY,
|
|
9
9
|
label: "Kunden-Login",
|
|
10
|
-
description: "
|
|
10
|
+
description: "Wie sich Kunden anmelden. Mindestens eine Methode bleibt eingeschaltet; Admin-Benutzer melden sich immer mit E-Mail und Passwort an.",
|
|
11
11
|
summary: "Anmeldemethoden und Passwort-Regeln für Kunden.",
|
|
12
12
|
icon: "ShieldCheck",
|
|
13
13
|
switchable: false,
|
|
14
14
|
features_heading: "Anmeldemethoden",
|
|
15
|
-
features_note: "Wirkt nach ca.
|
|
15
|
+
features_note: "Wirkt nach ca. 1 Minute.",
|
|
16
16
|
all_off_warning: "Keine Methode eingeschaltet: Kunden können sich nicht mehr anmelden.",
|
|
17
17
|
require_enabled_feature: true,
|
|
18
18
|
features: [
|
|
19
19
|
{
|
|
20
20
|
key: customer_auth_1.CUSTOMER_AUTH_FEATURES.emailPassword,
|
|
21
21
|
label: "E-Mail + Passwort",
|
|
22
|
-
description: "Anmeldung, Registrierung und Passwort
|
|
22
|
+
description: "Anmeldung, Registrierung und Passwort zurücksetzen.",
|
|
23
23
|
default_enabled: true,
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
key: customer_auth_1.CUSTOMER_AUTH_FEATURES.emailOtp,
|
|
27
27
|
label: "Anmeldecode per E-Mail",
|
|
28
|
-
description: "
|
|
28
|
+
description: "Anmeldung mit einem 6-stelligen Code per E-Mail; für neue Adressen entsteht ein Konto.",
|
|
29
29
|
default_enabled: false,
|
|
30
30
|
},
|
|
31
31
|
],
|
|
32
32
|
setting_groups: [
|
|
33
33
|
{
|
|
34
34
|
name: PASSWORD_RULES,
|
|
35
|
-
description: "
|
|
35
|
+
description: "Für Kunden mit „E-Mail + Passwort“. Admin-Benutzer: mindestens 15 Zeichen.",
|
|
36
36
|
requires_feature: customer_auth_1.CUSTOMER_AUTH_FEATURES.emailPassword,
|
|
37
37
|
},
|
|
38
38
|
],
|
|
@@ -40,8 +40,8 @@ exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
|
|
|
40
40
|
{
|
|
41
41
|
key: "password_min_length",
|
|
42
42
|
label: "Mindestlänge",
|
|
43
|
-
description: "
|
|
44
|
-
hint: "8 bis 128 Zeichen. Empfohlen:
|
|
43
|
+
description: "Gilt bei Registrierung und Passwort-Zurücksetzen; bestehende Passwörter bleiben gültig.",
|
|
44
|
+
hint: "8 bis 128 Zeichen. Empfohlen: 15 (NIST SP 800-63B).",
|
|
45
45
|
group: PASSWORD_RULES,
|
|
46
46
|
width: "half",
|
|
47
47
|
type: "number",
|
|
@@ -54,7 +54,7 @@ exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
|
|
|
54
54
|
key: "password_require_mixed_case",
|
|
55
55
|
label: "Groß- und Kleinbuchstaben verlangen",
|
|
56
56
|
description: "Mindestens ein Groß- und ein Kleinbuchstabe.",
|
|
57
|
-
hint: "NIST rät von
|
|
57
|
+
hint: "NIST rät von Zeichenregeln ab, Länge schützt besser.",
|
|
58
58
|
group: PASSWORD_RULES,
|
|
59
59
|
type: "boolean",
|
|
60
60
|
default: false,
|
|
@@ -70,11 +70,11 @@ exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
|
|
|
70
70
|
{
|
|
71
71
|
key: "password_require_symbol",
|
|
72
72
|
label: "Sonderzeichen verlangen",
|
|
73
|
-
description: "Mindestens ein Sonderzeichen
|
|
73
|
+
description: "Mindestens ein Sonderzeichen.",
|
|
74
74
|
group: PASSWORD_RULES,
|
|
75
75
|
type: "boolean",
|
|
76
76
|
default: false,
|
|
77
77
|
},
|
|
78
78
|
],
|
|
79
79
|
});
|
|
80
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
80
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWZlYXR1cmVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2N1c3RvbWVyLWF1dGgvcGx1Z2luLWZlYXR1cmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJHQUdnRjtBQUVoRixxREFBMkQ7QUFFM0QsTUFBTSxjQUFjLEdBQUcsaUJBQWlCLENBQUE7QUFFM0IsUUFBQSwwQkFBMEIsR0FBRyxJQUFBLGlDQUFvQixFQUFDO0lBQzdELFVBQVUsRUFBRSx3Q0FBd0I7SUFDcEMsS0FBSyxFQUFFLGNBQWM7SUFDckIsV0FBVyxFQUNULHNJQUFzSTtJQUN4SSxPQUFPLEVBQUUsaURBQWlEO0lBQzFELElBQUksRUFBRSxhQUFhO0lBQ25CLFVBQVUsRUFBRSxLQUFLO0lBQ2pCLGdCQUFnQixFQUFFLGlCQUFpQjtJQUNuQyxhQUFhLEVBQUUsMEJBQTBCO0lBQ3pDLGVBQWUsRUFDYixzRUFBc0U7SUFDeEUsdUJBQXVCLEVBQUUsSUFBSTtJQUM3QixRQUFRLEVBQUU7UUFDUjtZQUNFLEdBQUcsRUFBRSxzQ0FBc0IsQ0FBQyxhQUFhO1lBQ3pDLEtBQUssRUFBRSxtQkFBbUI7WUFDMUIsV0FBVyxFQUNULHFEQUFxRDtZQUN2RCxlQUFlLEVBQUUsSUFBSTtTQUN0QjtRQUNEO1lBQ0UsR0FBRyxFQUFFLHNDQUFzQixDQUFDLFFBQVE7WUFDcEMsS0FBSyxFQUFFLHdCQUF3QjtZQUMvQixXQUFXLEVBQ1Qsd0ZBQXdGO1lBQzFGLGVBQWUsRUFBRSxLQUFLO1NBQ3ZCO0tBQ0Y7SUFDRCxjQUFjLEVBQUU7UUFDZDtZQUNFLElBQUksRUFBRSxjQUFjO1lBQ3BCLFdBQVcsRUFDVCw0RUFBNEU7WUFDOUUsZ0JBQWdCLEVBQUUsc0NBQXNCLENBQUMsYUFBYTtTQUN2RDtLQUNGO0lBQ0QsUUFBUSxFQUFFO1FBQ1I7WUFDRSxHQUFHLEVBQUUscUJBQXFCO1lBQzFCLEtBQUssRUFBRSxjQUFjO1lBQ3JCLFdBQVcsRUFDVCx5RkFBeUY7WUFDM0YsSUFBSSxFQUFFLHFEQUFxRDtZQUMzRCxLQUFLLEVBQUUsY0FBYztZQUNyQixLQUFLLEVBQUUsTUFBTTtZQUNiLElBQUksRUFBRSxRQUFRO1lBQ2QsR0FBRyxFQUFFLENBQUM7WUFDTixHQUFHLEVBQUUsR0FBRztZQUNSLE9BQU8sRUFBRSxJQUFJO1lBQ2IsT0FBTyxFQUFFLEVBQUU7U0FDWjtRQUNEO1lBQ0UsR0FBRyxFQUFFLDZCQUE2QjtZQUNsQyxLQUFLLEVBQUUscUNBQXFDO1lBQzVDLFdBQVcsRUFBRSw4Q0FBOEM7WUFDM0QsSUFBSSxFQUFFLHNEQUFzRDtZQUM1RCxLQUFLLEVBQUUsY0FBYztZQUNyQixJQUFJLEVBQUUsU0FBUztZQUNmLE9BQU8sRUFBRSxLQUFLO1NBQ2Y7UUFDRDtZQUNFLEdBQUcsRUFBRSx3QkFBd0I7WUFDN0IsS0FBSyxFQUFFLGtCQUFrQjtZQUN6QixXQUFXLEVBQUUseUJBQXlCO1lBQ3RDLEtBQUssRUFBRSxjQUFjO1lBQ3JCLElBQUksRUFBRSxTQUFTO1lBQ2YsT0FBTyxFQUFFLEtBQUs7U0FDZjtRQUNEO1lBQ0UsR0FBRyxFQUFFLHlCQUF5QjtZQUM5QixLQUFLLEVBQUUseUJBQXlCO1lBQ2hDLFdBQVcsRUFBRSwrQkFBK0I7WUFDNUMsS0FBSyxFQUFFLGNBQWM7WUFDckIsSUFBSSxFQUFFLFNBQVM7WUFDZixPQUFPLEVBQUUsS0FBSztTQUNmO0tBQ0Y7Q0FDRixDQUFDLENBQUEifQ==
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.warnCredentialExpiry = exports.isCredentialExpiryDue = exports.calendarDateIn = exports.CREDENTIAL_EXPIRY_WARNING_DAYS = void 0;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const settings_1 = require("../../public/settings");
|
|
6
|
+
const shop_master_data_1 = require("../../public/shop-master-data");
|
|
7
|
+
const lib_1 = require("../../shared/lib");
|
|
8
|
+
const email_1 = require("../../modules/email");
|
|
9
|
+
const dispatch_email_message_1 = require("../../workflows/email/dispatch-email-message");
|
|
10
|
+
const business_keys_1 = require("../domain/business-keys");
|
|
11
|
+
const plugin_features_1 = require("../plugin-features");
|
|
12
|
+
/** The warning goes out this many days before the secret expires. */
|
|
13
|
+
exports.CREDENTIAL_EXPIRY_WARNING_DAYS = 7;
|
|
14
|
+
const DAY_MS = 86_400_000;
|
|
15
|
+
/** `YYYY-MM-DD` of `now` in `timeZone`. */
|
|
16
|
+
const calendarDateIn = (now, timeZone) => new Intl.DateTimeFormat("en-CA", {
|
|
17
|
+
day: "2-digit",
|
|
18
|
+
month: "2-digit",
|
|
19
|
+
timeZone,
|
|
20
|
+
year: "numeric",
|
|
21
|
+
}).format(now);
|
|
22
|
+
exports.calendarDateIn = calendarDateIn;
|
|
23
|
+
/** From seven days before the expiry up to the expiry day itself. */
|
|
24
|
+
const isCredentialExpiryDue = (expiresOn, today) => {
|
|
25
|
+
const days = (Date.parse(`${expiresOn}T00:00:00Z`) - Date.parse(`${today}T00:00:00Z`)) /
|
|
26
|
+
DAY_MS;
|
|
27
|
+
return days >= 0 && days <= exports.CREDENTIAL_EXPIRY_WARNING_DAYS;
|
|
28
|
+
};
|
|
29
|
+
exports.isCredentialExpiryDue = isCredentialExpiryDue;
|
|
30
|
+
/**
|
|
31
|
+
* Warns the shop (e-mail of the Shop-Stammdaten) that the Microsoft 365
|
|
32
|
+
* client secret expires soon. The business key holds client id and expiry
|
|
33
|
+
* date, so each secret is warned about once; a new date warns again.
|
|
34
|
+
*/
|
|
35
|
+
const warnCredentialExpiry = async (container, now = new Date()) => {
|
|
36
|
+
const { values } = await (0, settings_1.getPluginSettings)(container, plugin_features_1.emailPluginFeatures);
|
|
37
|
+
const expiresOn = values.microsoft_client_secret_expires_on;
|
|
38
|
+
const clientId = values.microsoft_client_id;
|
|
39
|
+
if (values.provider !== "microsoft365" ||
|
|
40
|
+
!(0, lib_1.isCalendarDate)(expiresOn) ||
|
|
41
|
+
typeof clientId !== "string") {
|
|
42
|
+
return "not_due";
|
|
43
|
+
}
|
|
44
|
+
const email = container.resolve(email_1.EMAIL_MODULE);
|
|
45
|
+
const timeZone = email.getDispatchConfiguration().timeZone ?? "Europe/Vienna";
|
|
46
|
+
if (!(0, exports.isCredentialExpiryDue)(expiresOn, (0, exports.calendarDateIn)(now, timeZone))) {
|
|
47
|
+
return "not_due";
|
|
48
|
+
}
|
|
49
|
+
const recipient = (await (0, shop_master_data_1.getShopMasterData)(container)).values.email;
|
|
50
|
+
if (!recipient) {
|
|
51
|
+
container
|
|
52
|
+
.resolve(utils_1.ContainerRegistrationKeys.LOGGER)
|
|
53
|
+
.warn("email: the client secret expires soon, but the Shop-Stammdaten have no e-mail to warn");
|
|
54
|
+
return "no_recipient";
|
|
55
|
+
}
|
|
56
|
+
const message = await email.upsertMessageFact({
|
|
57
|
+
kind: "system.credential_expiry.admin",
|
|
58
|
+
business_key: (0, business_keys_1.credentialExpiryBusinessKey)(clientId, expiresOn),
|
|
59
|
+
resource_type: "email_provider",
|
|
60
|
+
resource_id: clientId,
|
|
61
|
+
recipient,
|
|
62
|
+
required_facts: ["due"],
|
|
63
|
+
fact: "due",
|
|
64
|
+
template_data: {
|
|
65
|
+
provider: "microsoft365",
|
|
66
|
+
client_id: clientId,
|
|
67
|
+
expires_on: expiresOn,
|
|
68
|
+
},
|
|
69
|
+
suppression_code: null,
|
|
70
|
+
});
|
|
71
|
+
await (0, dispatch_email_message_1.dispatchEmailMessageWorkflow)(container).run({
|
|
72
|
+
input: { message_id: message.id },
|
|
73
|
+
});
|
|
74
|
+
return "dispatched";
|
|
75
|
+
};
|
|
76
|
+
exports.warnCredentialExpiry = warnCredentialExpiry;
|
|
77
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Fybi1jcmVkZW50aWFsLWV4cGlyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9lbWFpbC9hcHBsaWNhdGlvbi93YXJuLWNyZWRlbnRpYWwtZXhwaXJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUFzRTtBQUV0RSxvREFBMEQ7QUFDMUQsb0VBQWtFO0FBQ2xFLDBDQUFrRDtBQUNsRCwrQ0FBbUQ7QUFFbkQseUZBQTRGO0FBQzVGLDJEQUFzRTtBQUN0RSx3REFBeUQ7QUFFekQscUVBQXFFO0FBQ3hELFFBQUEsOEJBQThCLEdBQUcsQ0FBQyxDQUFDO0FBRWhELE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQztBQUUxQiwyQ0FBMkM7QUFDcEMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxHQUFTLEVBQUUsUUFBZ0IsRUFBVSxFQUFFLENBQ3BFLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUU7SUFDL0IsR0FBRyxFQUFFLFNBQVM7SUFDZCxLQUFLLEVBQUUsU0FBUztJQUNoQixRQUFRO0lBQ1IsSUFBSSxFQUFFLFNBQVM7Q0FDaEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztBQU5KLFFBQUEsY0FBYyxrQkFNVjtBQUVqQixxRUFBcUU7QUFDOUQsTUFBTSxxQkFBcUIsR0FBRyxDQUNuQyxTQUFpQixFQUNqQixLQUFhLEVBQ0osRUFBRTtJQUNYLE1BQU0sSUFBSSxHQUNSLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLFNBQVMsWUFBWSxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEtBQUssWUFBWSxDQUFDLENBQUM7UUFDekUsTUFBTSxDQUFDO0lBQ1QsT0FBTyxJQUFJLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxzQ0FBOEIsQ0FBQztBQUM3RCxDQUFDLENBQUM7QUFSVyxRQUFBLHFCQUFxQix5QkFRaEM7QUFPRjs7OztHQUlHO0FBQ0ksTUFBTSxvQkFBb0IsR0FBRyxLQUFLLEVBQ3ZDLFNBQTBCLEVBQzFCLE1BQVksSUFBSSxJQUFJLEVBQUUsRUFDa0IsRUFBRTtJQUMxQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLDRCQUFpQixFQUFDLFNBQVMsRUFBRSxxQ0FBbUIsQ0FBQyxDQUFDO0lBQzNFLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxrQ0FBa0MsQ0FBQztJQUM1RCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUM7SUFDNUMsSUFDRSxNQUFNLENBQUMsUUFBUSxLQUFLLGNBQWM7UUFDbEMsQ0FBQyxJQUFBLG9CQUFjLEVBQUMsU0FBUyxDQUFDO1FBQzFCLE9BQU8sUUFBUSxLQUFLLFFBQVEsRUFDNUIsQ0FBQztRQUNELE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRCxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFxQixvQkFBWSxDQUFDLENBQUM7SUFDbEUsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLHdCQUF3QixFQUFFLENBQUMsUUFBUSxJQUFJLGVBQWUsQ0FBQztJQUM5RSxJQUFJLENBQUMsSUFBQSw2QkFBcUIsRUFBQyxTQUFTLEVBQUUsSUFBQSxzQkFBYyxFQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDckUsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUVELE1BQU0sU0FBUyxHQUFHLENBQUMsTUFBTSxJQUFBLG9DQUFpQixFQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztJQUNwRSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixTQUFTO2FBQ04sT0FBTyxDQUFTLGlDQUF5QixDQUFDLE1BQU0sQ0FBQzthQUNqRCxJQUFJLENBQ0gsdUZBQXVGLENBQ3hGLENBQUM7UUFDSixPQUFPLGNBQWMsQ0FBQztJQUN4QixDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxLQUFLLENBQUMsaUJBQWlCLENBQUM7UUFDNUMsSUFBSSxFQUFFLGdDQUFnQztRQUN0QyxZQUFZLEVBQUUsSUFBQSwyQ0FBMkIsRUFBQyxRQUFRLEVBQUUsU0FBUyxDQUFDO1FBQzlELGFBQWEsRUFBRSxnQkFBZ0I7UUFDL0IsV0FBVyxFQUFFLFFBQVE7UUFDckIsU0FBUztRQUNULGNBQWMsRUFBRSxDQUFDLEtBQUssQ0FBQztRQUN2QixJQUFJLEVBQUUsS0FBSztRQUNYLGFBQWEsRUFBRTtZQUNiLFFBQVEsRUFBRSxjQUFjO1lBQ3hCLFNBQVMsRUFBRSxRQUFRO1lBQ25CLFVBQVUsRUFBRSxTQUFTO1NBQ3RCO1FBQ0QsZ0JBQWdCLEVBQUUsSUFBSTtLQUN2QixDQUFDLENBQUM7SUFDSCxNQUFNLElBQUEscURBQTRCLEVBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDO1FBQ2hELEtBQUssRUFBRSxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFO0tBQ2xDLENBQUMsQ0FBQztJQUNILE9BQU8sWUFBWSxDQUFDO0FBQ3RCLENBQUMsQ0FBQztBQWxEVyxRQUFBLG9CQUFvQix3QkFrRC9CIn0=
|