@open-mercato/core 0.4.2-canary-bdaa640a68 → 0.4.2-canary-3b5064ce72
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/dist/generated/entities/notification/index.js +57 -0
- package/dist/generated/entities/notification/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +5 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/api_docs/frontend/docs/api/page.js +3 -2
- package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/page.js +1 -1
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +4 -0
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +2 -0
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/auth/api/admin/nav.js +4 -3
- package/dist/modules/auth/api/admin/nav.js.map +2 -2
- package/dist/modules/auth/api/login.js +25 -6
- package/dist/modules/auth/api/login.js.map +2 -2
- package/dist/modules/auth/api/profile/route.js +157 -0
- package/dist/modules/auth/api/profile/route.js.map +7 -0
- package/dist/modules/auth/api/reset/confirm.js +25 -2
- package/dist/modules/auth/api/reset/confirm.js.map +2 -2
- package/dist/modules/auth/api/reset.js +23 -0
- package/dist/modules/auth/api/reset.js.map +2 -2
- package/dist/modules/auth/api/sidebar/preferences/route.js +14 -9
- package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +4 -2
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/auth/profile/page.js +141 -0
- package/dist/modules/auth/backend/auth/profile/page.js.map +7 -0
- package/dist/modules/auth/backend/auth/profile/page.meta.js +13 -0
- package/dist/modules/auth/backend/auth/profile/page.meta.js.map +7 -0
- package/dist/modules/auth/backend/roles/[id]/edit/page.js +4 -1
- package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +3 -3
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +18 -3
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +15 -2
- package/dist/modules/auth/backend/users/create/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +3 -3
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/cli.js +25 -11
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +59 -2
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/validators.js +6 -3
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/auth/frontend/login.js +112 -3
- package/dist/modules/auth/frontend/login.js.map +2 -2
- package/dist/modules/auth/frontend/reset/[token]/page.js +20 -10
- package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +42 -8
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/notifications.js +112 -0
- package/dist/modules/auth/notifications.js.map +7 -0
- package/dist/modules/auth/services/authService.js +24 -3
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/business_rules/api/execute/route.js +7 -1
- package/dist/modules/business_rules/api/execute/route.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +4 -0
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +3 -0
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/business_rules/cli.js +2 -1
- package/dist/modules/business_rules/cli.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +33 -3
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/business_rules/notifications.js +28 -0
- package/dist/modules/business_rules/notifications.js.map +7 -0
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +37 -0
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +7 -0
- package/dist/modules/catalog/components/PriceKindSettings.js +2 -0
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +2 -0
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/notifications.js +28 -0
- package/dist/modules/catalog/notifications.js.map +7 -0
- package/dist/modules/catalog/subscribers/low-stock-notification.js +38 -0
- package/dist/modules/catalog/subscribers/low-stock-notification.js.map +7 -0
- package/dist/modules/configs/cli.js +6 -0
- package/dist/modules/configs/cli.js.map +2 -2
- package/dist/modules/configs/components/CachePanel.js +4 -4
- package/dist/modules/configs/components/CachePanel.js.map +2 -2
- package/dist/modules/configs/lib/system-status.js +48 -1
- package/dist/modules/configs/lib/system-status.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +18 -0
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +3 -0
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +2 -0
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +3 -0
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +3 -0
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +3 -0
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +31 -0
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/customers/notifications.js +48 -0
- package/dist/modules/customers/notifications.js.map +7 -0
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js +2 -1
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.js +2 -1
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.js +2 -1
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js +2 -1
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js.map +2 -2
- package/dist/modules/dashboards/cli.js +44 -5
- package/dist/modules/dashboards/cli.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +16 -11
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +3 -3
- package/dist/modules/dashboards/lib/role-widgets.js +58 -0
- package/dist/modules/dashboards/lib/role-widgets.js.map +7 -0
- package/dist/modules/dashboards/services/widgetDataService.js +139 -3
- package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryTable.js +2 -0
- package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
- package/dist/modules/directory/api/get/tenants/lookup.js +70 -0
- package/dist/modules/directory/api/get/tenants/lookup.js.map +7 -0
- package/dist/modules/directory/backend/directory/organizations/page.js +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/entities/components/SystemEntitiesTable.js +1 -1
- package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
- package/dist/modules/entities/components/UserEntitiesTable.js +2 -2
- package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +3 -3
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/OverridesTable.js +1 -1
- package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
- package/dist/modules/notifications/acl.js +11 -0
- package/dist/modules/notifications/acl.js.map +7 -0
- package/dist/modules/notifications/api/[id]/action/route.js +74 -0
- package/dist/modules/notifications/api/[id]/action/route.js.map +7 -0
- package/dist/modules/notifications/api/[id]/dismiss/route.js +15 -0
- package/dist/modules/notifications/api/[id]/dismiss/route.js.map +7 -0
- package/dist/modules/notifications/api/[id]/read/route.js +15 -0
- package/dist/modules/notifications/api/[id]/read/route.js.map +7 -0
- package/dist/modules/notifications/api/[id]/restore/route.js +53 -0
- package/dist/modules/notifications/api/[id]/restore/route.js.map +7 -0
- package/dist/modules/notifications/api/batch/route.js +17 -0
- package/dist/modules/notifications/api/batch/route.js.map +7 -0
- package/dist/modules/notifications/api/feature/route.js +17 -0
- package/dist/modules/notifications/api/feature/route.js.map +7 -0
- package/dist/modules/notifications/api/mark-all-read/route.js +35 -0
- package/dist/modules/notifications/api/mark-all-read/route.js.map +7 -0
- package/dist/modules/notifications/api/openapi.js +76 -0
- package/dist/modules/notifications/api/openapi.js.map +7 -0
- package/dist/modules/notifications/api/role/route.js +17 -0
- package/dist/modules/notifications/api/role/route.js.map +7 -0
- package/dist/modules/notifications/api/route.js +85 -0
- package/dist/modules/notifications/api/route.js.map +7 -0
- package/dist/modules/notifications/api/settings/route.js +155 -0
- package/dist/modules/notifications/api/settings/route.js.map +7 -0
- package/dist/modules/notifications/api/unread-count/route.js +38 -0
- package/dist/modules/notifications/api/unread-count/route.js.map +7 -0
- package/dist/modules/notifications/backend/config/notifications/page.js +10 -0
- package/dist/modules/notifications/backend/config/notifications/page.js.map +7 -0
- package/dist/modules/notifications/backend/config/notifications/page.meta.js +24 -0
- package/dist/modules/notifications/backend/config/notifications/page.meta.js.map +7 -0
- package/dist/modules/notifications/cli.js +16 -0
- package/dist/modules/notifications/cli.js.map +7 -0
- package/dist/modules/notifications/data/entities.js +112 -0
- package/dist/modules/notifications/data/entities.js.map +7 -0
- package/dist/modules/notifications/data/validators.js +98 -0
- package/dist/modules/notifications/data/validators.js.map +7 -0
- package/dist/modules/notifications/di.js +13 -0
- package/dist/modules/notifications/di.js.map +7 -0
- package/dist/modules/notifications/emails/NotificationEmail.js +58 -0
- package/dist/modules/notifications/emails/NotificationEmail.js.map +7 -0
- package/dist/modules/notifications/frontend/NotificationInboxPageClient.js +44 -0
- package/dist/modules/notifications/frontend/NotificationInboxPageClient.js.map +7 -0
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +220 -0
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +7 -0
- package/dist/modules/notifications/index.js +14 -0
- package/dist/modules/notifications/index.js.map +7 -0
- package/dist/modules/notifications/lib/deliveryConfig.js +107 -0
- package/dist/modules/notifications/lib/deliveryConfig.js.map +7 -0
- package/dist/modules/notifications/lib/deliveryStrategies.js +14 -0
- package/dist/modules/notifications/lib/deliveryStrategies.js.map +7 -0
- package/dist/modules/notifications/lib/events.js +12 -0
- package/dist/modules/notifications/lib/events.js.map +7 -0
- package/dist/modules/notifications/lib/notificationBuilder.js +66 -0
- package/dist/modules/notifications/lib/notificationBuilder.js.map +7 -0
- package/dist/modules/notifications/lib/notificationFactory.js +54 -0
- package/dist/modules/notifications/lib/notificationFactory.js.map +7 -0
- package/dist/modules/notifications/lib/notificationMapper.js +34 -0
- package/dist/modules/notifications/lib/notificationMapper.js.map +7 -0
- package/dist/modules/notifications/lib/notificationRecipients.js +35 -0
- package/dist/modules/notifications/lib/notificationRecipients.js.map +7 -0
- package/dist/modules/notifications/lib/notificationService.js +279 -0
- package/dist/modules/notifications/lib/notificationService.js.map +7 -0
- package/dist/modules/notifications/lib/routeHelpers.js +101 -0
- package/dist/modules/notifications/lib/routeHelpers.js.map +7 -0
- package/dist/modules/notifications/lib/safeHref.js +24 -0
- package/dist/modules/notifications/lib/safeHref.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260123000001.js +70 -0
- package/dist/modules/notifications/migrations/Migration20260123000001.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260126150000.js +37 -0
- package/dist/modules/notifications/migrations/Migration20260126150000.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260129082610.js +13 -0
- package/dist/modules/notifications/migrations/Migration20260129082610.js.map +7 -0
- package/dist/modules/notifications/subscribers/deliver-notification.js +165 -0
- package/dist/modules/notifications/subscribers/deliver-notification.js.map +7 -0
- package/dist/modules/notifications/workers/create-notification.worker.js +70 -0
- package/dist/modules/notifications/workers/create-notification.worker.js.map +7 -0
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/query_index/cli.js +63 -7
- package/dist/modules/query_index/cli.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +7 -1
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +2 -0
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +2 -0
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +53 -0
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +26 -0
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/TaxRatesSettings.js +2 -2
- package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +2 -0
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +2 -0
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +2 -1
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +2 -0
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/notifications.client.js +51 -0
- package/dist/modules/sales/notifications.client.js.map +7 -0
- package/dist/modules/sales/notifications.js +88 -0
- package/dist/modules/sales/notifications.js.map +7 -0
- package/dist/modules/sales/subscribers/quote-expiring-notification.js +38 -0
- package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +7 -0
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +137 -0
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +7 -0
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +137 -0
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +7 -0
- package/dist/modules/sales/widgets/notifications/index.js +7 -0
- package/dist/modules/sales/widgets/notifications/index.js.map +7 -0
- package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js +60 -0
- package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js.map +7 -0
- package/dist/modules/staff/backend/staff/team-members/page.js +1 -1
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/commands/leave-requests.js +79 -0
- package/dist/modules/staff/commands/leave-requests.js.map +2 -2
- package/dist/modules/staff/notifications.js +75 -0
- package/dist/modules/staff/notifications.js.map +7 -0
- package/dist/modules/workflows/backend/definitions/page.js +5 -0
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +3 -0
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +3 -0
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/cli.js +12 -12
- package/dist/modules/workflows/cli.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +14 -6
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/notifications.js +28 -0
- package/dist/modules/workflows/notifications.js.map +7 -0
- package/dist/modules/workflows/subscribers/task-assigned-notification.js +38 -0
- package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +7 -0
- package/generated/entities/notification/index.ts +27 -0
- package/generated/entities.ids.generated.ts +5 -1
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +2 -2
- package/src/modules/api_docs/frontend/docs/api/page.tsx +3 -2
- package/src/modules/api_keys/backend/api-keys/page.tsx +1 -1
- package/src/modules/attachments/components/AttachmentLibrary.tsx +4 -0
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +2 -0
- package/src/modules/auth/README.md +1 -1
- package/src/modules/auth/__tests__/cli-setup-acl.test.ts +1 -1
- package/src/modules/auth/api/__tests__/login.test.ts +2 -0
- package/src/modules/auth/api/admin/nav.ts +10 -6
- package/src/modules/auth/api/login.ts +26 -7
- package/src/modules/auth/api/profile/route.ts +163 -0
- package/src/modules/auth/api/reset/confirm.ts +25 -2
- package/src/modules/auth/api/reset.ts +23 -0
- package/src/modules/auth/api/sidebar/preferences/route.ts +21 -12
- package/src/modules/auth/api/users/route.ts +5 -2
- package/src/modules/auth/backend/auth/profile/page.meta.ts +9 -0
- package/src/modules/auth/backend/auth/profile/page.tsx +174 -0
- package/src/modules/auth/backend/roles/[id]/edit/page.tsx +4 -1
- package/src/modules/auth/backend/roles/page.tsx +3 -3
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +22 -3
- package/src/modules/auth/backend/users/create/page.tsx +19 -2
- package/src/modules/auth/backend/users/page.tsx +3 -3
- package/src/modules/auth/cli.ts +38 -11
- package/src/modules/auth/commands/users.ts +73 -2
- package/src/modules/auth/data/validators.ts +6 -2
- package/src/modules/auth/frontend/login.tsx +134 -5
- package/src/modules/auth/frontend/reset/[token]/page.tsx +24 -11
- package/src/modules/auth/i18n/de.json +48 -1
- package/src/modules/auth/i18n/en.json +48 -1
- package/src/modules/auth/i18n/es.json +48 -1
- package/src/modules/auth/i18n/pl.json +48 -1
- package/src/modules/auth/lib/setup-app.ts +58 -9
- package/src/modules/auth/notifications.ts +109 -0
- package/src/modules/auth/services/authService.ts +27 -4
- package/src/modules/business_rules/api/execute/route.ts +8 -1
- package/src/modules/business_rules/backend/rules/page.tsx +4 -0
- package/src/modules/business_rules/backend/sets/page.tsx +3 -0
- package/src/modules/business_rules/cli.ts +2 -1
- package/src/modules/business_rules/i18n/en.json +3 -1
- package/src/modules/business_rules/lib/__tests__/rule-engine.test.ts +51 -0
- package/src/modules/business_rules/lib/rule-engine.ts +57 -3
- package/src/modules/business_rules/notifications.ts +25 -0
- package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +50 -0
- package/src/modules/catalog/components/PriceKindSettings.tsx +2 -0
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -2
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +2 -0
- package/src/modules/catalog/i18n/en.json +3 -1
- package/src/modules/catalog/notifications.ts +25 -0
- package/src/modules/catalog/subscribers/low-stock-notification.ts +52 -0
- package/src/modules/configs/cli.ts +6 -0
- package/src/modules/configs/components/CachePanel.tsx +4 -4
- package/src/modules/configs/i18n/en.json +12 -2
- package/src/modules/configs/i18n/pl.json +12 -2
- package/src/modules/configs/lib/system-status.ts +48 -1
- package/src/modules/configs/lib/system-status.types.ts +1 -0
- package/src/modules/configs/lib/upgrade-actions.ts +18 -0
- package/src/modules/currencies/backend/currencies/page.tsx +3 -0
- package/src/modules/currencies/backend/exchange-rates/page.tsx +2 -0
- package/src/modules/customers/backend/customers/companies/page.tsx +3 -0
- package/src/modules/customers/backend/customers/deals/page.tsx +3 -0
- package/src/modules/customers/backend/customers/people/page.tsx +3 -0
- package/src/modules/customers/commands/deals.ts +39 -0
- package/src/modules/customers/components/CustomerTodosTable.tsx +1 -0
- package/src/modules/customers/i18n/en.json +5 -1
- package/src/modules/customers/notifications.ts +44 -0
- package/src/modules/customers/widgets/dashboard/customer-todos/widget.ts +2 -2
- package/src/modules/customers/widgets/dashboard/new-customers/widget.ts +2 -2
- package/src/modules/customers/widgets/dashboard/new-deals/widget.ts +2 -2
- package/src/modules/customers/widgets/dashboard/next-interactions/widget.ts +2 -2
- package/src/modules/dashboards/cli.ts +55 -5
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +22 -11
- package/src/modules/dashboards/lib/role-widgets.ts +80 -0
- package/src/modules/dashboards/services/widgetDataService.ts +164 -4
- package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/orders-kpi/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/top-customers/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/top-products/widget.ts +2 -2
- package/src/modules/dictionaries/components/DictionaryTable.tsx +2 -0
- package/src/modules/directory/api/get/tenants/lookup.ts +75 -0
- package/src/modules/directory/backend/directory/organizations/page.tsx +2 -2
- package/src/modules/directory/backend/directory/tenants/page.tsx +2 -2
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +2 -2
- package/src/modules/entities/components/SystemEntitiesTable.tsx +1 -1
- package/src/modules/entities/components/UserEntitiesTable.tsx +2 -2
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +3 -4
- package/src/modules/feature_toggles/components/OverridesTable.tsx +1 -1
- package/src/modules/notifications/__tests__/deliver-notification.test.ts +195 -0
- package/src/modules/notifications/__tests__/deliveryStrategies.test.ts +19 -0
- package/src/modules/notifications/__tests__/notificationService.test.ts +208 -0
- package/src/modules/notifications/acl.ts +7 -0
- package/src/modules/notifications/api/[id]/action/route.ts +75 -0
- package/src/modules/notifications/api/[id]/dismiss/route.ts +12 -0
- package/src/modules/notifications/api/[id]/read/route.ts +12 -0
- package/src/modules/notifications/api/[id]/restore/route.ts +53 -0
- package/src/modules/notifications/api/batch/route.ts +14 -0
- package/src/modules/notifications/api/feature/route.ts +14 -0
- package/src/modules/notifications/api/mark-all-read/route.ts +34 -0
- package/src/modules/notifications/api/openapi.ts +76 -0
- package/src/modules/notifications/api/role/route.ts +14 -0
- package/src/modules/notifications/api/route.ts +92 -0
- package/src/modules/notifications/api/settings/route.ts +157 -0
- package/src/modules/notifications/api/unread-count/route.ts +38 -0
- package/src/modules/notifications/backend/config/notifications/page.meta.ts +22 -0
- package/src/modules/notifications/backend/config/notifications/page.tsx +12 -0
- package/src/modules/notifications/cli.ts +18 -0
- package/src/modules/notifications/data/entities.ts +99 -0
- package/src/modules/notifications/data/validators.ts +115 -0
- package/src/modules/notifications/di.ts +11 -0
- package/src/modules/notifications/emails/NotificationEmail.tsx +98 -0
- package/src/modules/notifications/frontend/NotificationInboxPageClient.tsx +42 -0
- package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +233 -0
- package/src/modules/notifications/i18n/de.json +50 -0
- package/src/modules/notifications/i18n/en.json +50 -0
- package/src/modules/notifications/i18n/es.json +50 -0
- package/src/modules/notifications/i18n/pl.json +50 -0
- package/src/modules/notifications/index.ts +12 -0
- package/src/modules/notifications/lib/deliveryConfig.ts +153 -0
- package/src/modules/notifications/lib/deliveryStrategies.ts +50 -0
- package/src/modules/notifications/lib/events.ts +48 -0
- package/src/modules/notifications/lib/notificationBuilder.ts +121 -0
- package/src/modules/notifications/lib/notificationFactory.ts +76 -0
- package/src/modules/notifications/lib/notificationMapper.ts +33 -0
- package/src/modules/notifications/lib/notificationRecipients.ts +83 -0
- package/src/modules/notifications/lib/notificationService.ts +414 -0
- package/src/modules/notifications/lib/routeHelpers.ts +151 -0
- package/src/modules/notifications/lib/safeHref.ts +29 -0
- package/src/modules/notifications/migrations/.snapshot-open-mercato.json +336 -0
- package/src/modules/notifications/migrations/Migration20260123000001.ts +73 -0
- package/src/modules/notifications/migrations/Migration20260126150000.ts +39 -0
- package/src/modules/notifications/migrations/Migration20260129082610.ts +13 -0
- package/src/modules/notifications/subscribers/deliver-notification.ts +204 -0
- package/src/modules/notifications/workers/create-notification.worker.ts +122 -0
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +2 -2
- package/src/modules/query_index/cli.ts +82 -13
- package/src/modules/query_index/components/QueryIndexesTable.tsx +8 -2
- package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -2
- package/src/modules/resources/backend/resources/resources/page.tsx +2 -2
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +2 -0
- package/src/modules/sales/backend/sales/channels/page.tsx +2 -0
- package/src/modules/sales/commands/documents.ts +65 -0
- package/src/modules/sales/commands/payments.ts +33 -0
- package/src/modules/sales/components/AdjustmentKindSettings.tsx +2 -2
- package/src/modules/sales/components/PaymentMethodsSettings.tsx +2 -2
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +2 -2
- package/src/modules/sales/components/TaxRatesSettings.tsx +2 -2
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +2 -0
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +2 -0
- package/src/modules/sales/components/documents/PaymentsSection.tsx +2 -1
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +2 -0
- package/src/modules/sales/i18n/de.json +20 -0
- package/src/modules/sales/i18n/en.json +25 -1
- package/src/modules/sales/i18n/es.json +20 -0
- package/src/modules/sales/i18n/pl.json +20 -0
- package/src/modules/sales/notifications.client.ts +65 -0
- package/src/modules/sales/notifications.ts +82 -0
- package/src/modules/sales/subscribers/quote-expiring-notification.ts +53 -0
- package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +156 -0
- package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +156 -0
- package/src/modules/sales/widgets/notifications/index.ts +2 -0
- package/src/modules/sales/widgets/notifications/useSalesDocumentTotals.ts +81 -0
- package/src/modules/staff/backend/staff/team-members/page.tsx +1 -1
- package/src/modules/staff/backend/staff/team-roles/page.tsx +2 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +2 -2
- package/src/modules/staff/backend/staff/teams/page.tsx +2 -2
- package/src/modules/staff/commands/leave-requests.ts +94 -0
- package/src/modules/staff/i18n/de.json +4 -0
- package/src/modules/staff/i18n/en.json +9 -1
- package/src/modules/staff/i18n/es.json +4 -0
- package/src/modules/staff/i18n/pl.json +4 -0
- package/src/modules/staff/notifications.ts +71 -0
- package/src/modules/workflows/backend/definitions/page.tsx +5 -0
- package/src/modules/workflows/backend/instances/page.tsx +4 -1
- package/src/modules/workflows/backend/tasks/page.tsx +4 -1
- package/src/modules/workflows/cli.ts +12 -12
- package/src/modules/workflows/i18n/en.json +3 -1
- package/src/modules/workflows/lib/transition-handler.ts +18 -6
- package/src/modules/workflows/notifications.ts +25 -0
- package/src/modules/workflows/subscribers/task-assigned-notification.ts +53 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { resolveNotificationService } from "../../notifications/lib/notificationService.js";
|
|
2
|
+
import { buildNotificationFromType } from "../../notifications/lib/notificationBuilder.js";
|
|
3
|
+
import { notificationTypes } from "../notifications.js";
|
|
4
|
+
const metadata = {
|
|
5
|
+
event: "workflows.task.assigned",
|
|
6
|
+
persistent: true,
|
|
7
|
+
id: "workflows:task-assigned-notification"
|
|
8
|
+
};
|
|
9
|
+
async function handle(payload, ctx) {
|
|
10
|
+
if (!payload.assignedUserId) return;
|
|
11
|
+
try {
|
|
12
|
+
const notificationService = resolveNotificationService(ctx);
|
|
13
|
+
const typeDef = notificationTypes.find((type) => type.type === "workflows.task.assigned");
|
|
14
|
+
if (!typeDef) return;
|
|
15
|
+
const notificationInput = buildNotificationFromType(typeDef, {
|
|
16
|
+
recipientUserId: payload.assignedUserId,
|
|
17
|
+
bodyVariables: {
|
|
18
|
+
taskName: payload.taskName,
|
|
19
|
+
workflowName: payload.workflowName,
|
|
20
|
+
dueDate: payload.dueDate ?? ""
|
|
21
|
+
},
|
|
22
|
+
sourceEntityType: "workflows:user_task",
|
|
23
|
+
sourceEntityId: payload.taskId,
|
|
24
|
+
linkHref: `/backend/workflows/tasks/${payload.taskId}`
|
|
25
|
+
});
|
|
26
|
+
await notificationService.create(notificationInput, {
|
|
27
|
+
tenantId: payload.tenantId,
|
|
28
|
+
organizationId: payload.organizationId ?? null
|
|
29
|
+
});
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error("[workflows:task-assigned-notification] Failed to create notification:", err);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
handle as default,
|
|
36
|
+
metadata
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=task-assigned-notification.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/workflows/subscribers/task-assigned-notification.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { resolveNotificationService } from '../../notifications/lib/notificationService'\nimport { buildNotificationFromType } from '../../notifications/lib/notificationBuilder'\nimport { notificationTypes } from '../notifications'\n\nexport const metadata = {\n event: 'workflows.task.assigned',\n persistent: true,\n id: 'workflows:task-assigned-notification',\n}\n\ntype TaskAssignedPayload = {\n taskId: string\n taskName: string\n workflowName: string\n assignedUserId: string\n dueDate?: string | null\n tenantId: string\n organizationId?: string | null\n}\n\ntype ResolverContext = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport default async function handle(payload: TaskAssignedPayload, ctx: ResolverContext) {\n if (!payload.assignedUserId) return\n\n try {\n const notificationService = resolveNotificationService(ctx)\n const typeDef = notificationTypes.find((type) => type.type === 'workflows.task.assigned')\n if (!typeDef) return\n\n const notificationInput = buildNotificationFromType(typeDef, {\n recipientUserId: payload.assignedUserId,\n bodyVariables: {\n taskName: payload.taskName,\n workflowName: payload.workflowName,\n dueDate: payload.dueDate ?? '',\n },\n sourceEntityType: 'workflows:user_task',\n sourceEntityId: payload.taskId,\n linkHref: `/backend/workflows/tasks/${payload.taskId}`,\n })\n\n await notificationService.create(notificationInput, {\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n })\n } catch (err) {\n console.error('[workflows:task-assigned-notification] Failed to create notification:', err)\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,kCAAkC;AAC3C,SAAS,iCAAiC;AAC1C,SAAS,yBAAyB;AAE3B,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAgBA,eAAO,OAA8B,SAA8B,KAAsB;AACvF,MAAI,CAAC,QAAQ,eAAgB;AAE7B,MAAI;AACF,UAAM,sBAAsB,2BAA2B,GAAG;AAC1D,UAAM,UAAU,kBAAkB,KAAK,CAAC,SAAS,KAAK,SAAS,yBAAyB;AACxF,QAAI,CAAC,QAAS;AAEd,UAAM,oBAAoB,0BAA0B,SAAS;AAAA,MAC3D,iBAAiB,QAAQ;AAAA,MACzB,eAAe;AAAA,QACb,UAAU,QAAQ;AAAA,QAClB,cAAc,QAAQ;AAAA,QACtB,SAAS,QAAQ,WAAW;AAAA,MAC9B;AAAA,MACA,kBAAkB;AAAA,MAClB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,4BAA4B,QAAQ,MAAM;AAAA,IACtD,CAAC;AAED,UAAM,oBAAoB,OAAO,mBAAmB;AAAA,MAClD,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ,kBAAkB;AAAA,IAC5C,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,YAAQ,MAAM,yEAAyE,GAAG;AAAA,EAC5F;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const id = 'id'
|
|
2
|
+
export const recipient_user_id = 'recipient_user_id'
|
|
3
|
+
export const type = 'type'
|
|
4
|
+
export const title_key = 'title_key'
|
|
5
|
+
export const body_key = 'body_key'
|
|
6
|
+
export const title_variables = 'title_variables'
|
|
7
|
+
export const body_variables = 'body_variables'
|
|
8
|
+
export const title = 'title'
|
|
9
|
+
export const body = 'body'
|
|
10
|
+
export const icon = 'icon'
|
|
11
|
+
export const severity = 'severity'
|
|
12
|
+
export const status = 'status'
|
|
13
|
+
export const action_data = 'action_data'
|
|
14
|
+
export const action_result = 'action_result'
|
|
15
|
+
export const action_taken = 'action_taken'
|
|
16
|
+
export const source_module = 'source_module'
|
|
17
|
+
export const source_entity_type = 'source_entity_type'
|
|
18
|
+
export const source_entity_id = 'source_entity_id'
|
|
19
|
+
export const link_href = 'link_href'
|
|
20
|
+
export const group_key = 'group_key'
|
|
21
|
+
export const created_at = 'created_at'
|
|
22
|
+
export const read_at = 'read_at'
|
|
23
|
+
export const actioned_at = 'actioned_at'
|
|
24
|
+
export const dismissed_at = 'dismissed_at'
|
|
25
|
+
export const expires_at = 'expires_at'
|
|
26
|
+
export const tenant_id = 'tenant_id'
|
|
27
|
+
export const organization_id = 'organization_id'
|
|
@@ -21,7 +21,8 @@ export const M = {
|
|
|
21
21
|
"currencies": "currencies",
|
|
22
22
|
"planner": "planner",
|
|
23
23
|
"resources": "resources",
|
|
24
|
-
"staff": "staff"
|
|
24
|
+
"staff": "staff",
|
|
25
|
+
"notifications": "notifications"
|
|
25
26
|
} as const
|
|
26
27
|
export const E = {
|
|
27
28
|
"dashboards": {
|
|
@@ -182,6 +183,9 @@ export const E = {
|
|
|
182
183
|
"staff_team_member_comment": "staff:staff_team_member_comment",
|
|
183
184
|
"staff_team_member_job_history": "staff:staff_team_member_job_history",
|
|
184
185
|
"staff_team_role": "staff:staff_team_role"
|
|
186
|
+
},
|
|
187
|
+
"notifications": {
|
|
188
|
+
"notification": "notifications:notification"
|
|
185
189
|
}
|
|
186
190
|
} as const
|
|
187
191
|
export type KnownModuleId = keyof typeof M
|
|
@@ -53,6 +53,7 @@ import * as feature_toggle_override from './entities/feature_toggle_override/ind
|
|
|
53
53
|
import * as indexer_error_log from './entities/indexer_error_log/index'
|
|
54
54
|
import * as indexer_status_log from './entities/indexer_status_log/index'
|
|
55
55
|
import * as module_config from './entities/module_config/index'
|
|
56
|
+
import * as notification from './entities/notification/index'
|
|
56
57
|
import * as organization from './entities/organization/index'
|
|
57
58
|
import * as password_reset from './entities/password_reset/index'
|
|
58
59
|
import * as perspective from './entities/perspective/index'
|
|
@@ -172,6 +173,7 @@ export const entityFieldsRegistry: Record<string, Record<string, string>> = {
|
|
|
172
173
|
indexer_error_log,
|
|
173
174
|
indexer_status_log,
|
|
174
175
|
module_config,
|
|
176
|
+
notification,
|
|
175
177
|
organization,
|
|
176
178
|
password_reset,
|
|
177
179
|
perspective,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.4.2-canary-
|
|
3
|
+
"version": "0.4.2-canary-3b5064ce72",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -207,7 +207,7 @@
|
|
|
207
207
|
}
|
|
208
208
|
},
|
|
209
209
|
"dependencies": {
|
|
210
|
-
"@open-mercato/shared": "0.4.2-canary-
|
|
210
|
+
"@open-mercato/shared": "0.4.2-canary-3b5064ce72",
|
|
211
211
|
"@xyflow/react": "^12.6.0",
|
|
212
212
|
"date-fns": "^4.1.0",
|
|
213
213
|
"date-fns-tz": "^3.2.0"
|
|
@@ -2,6 +2,7 @@ import ApiDocsExplorer from './Explorer'
|
|
|
2
2
|
import { getModules } from '@open-mercato/shared/lib/i18n/server'
|
|
3
3
|
import { buildOpenApiDocument } from '@open-mercato/shared/lib/openapi'
|
|
4
4
|
import { resolveApiDocsBaseUrl } from '@open-mercato/core/modules/api_docs/lib/resources'
|
|
5
|
+
import { APP_VERSION } from '@open-mercato/shared/lib/version'
|
|
5
6
|
|
|
6
7
|
type ExplorerOperation = {
|
|
7
8
|
id: string
|
|
@@ -54,7 +55,7 @@ export default async function ApiDocsViewerPage() {
|
|
|
54
55
|
const modules = getModules()
|
|
55
56
|
const doc = buildOpenApiDocument(modules, {
|
|
56
57
|
title: 'Open Mercato API',
|
|
57
|
-
version:
|
|
58
|
+
version: APP_VERSION,
|
|
58
59
|
description: 'Auto-generated OpenAPI definition for all enabled modules.',
|
|
59
60
|
servers: [{ url: baseUrl, description: 'Default environment' }],
|
|
60
61
|
baseUrlForExamples: baseUrl,
|
|
@@ -67,7 +68,7 @@ export default async function ApiDocsViewerPage() {
|
|
|
67
68
|
return (
|
|
68
69
|
<ApiDocsExplorer
|
|
69
70
|
title={doc.info?.title ?? 'Open Mercato API'}
|
|
70
|
-
version={doc.info?.version ??
|
|
71
|
+
version={doc.info?.version ?? APP_VERSION}
|
|
71
72
|
description={doc.info?.description}
|
|
72
73
|
operations={operations}
|
|
73
74
|
tagOrder={tagOrder}
|
|
@@ -175,7 +175,7 @@ export default function ApiKeysListPage() {
|
|
|
175
175
|
perspective={{ tableId: 'api_keys.list' }}
|
|
176
176
|
rowActions={(row) => (
|
|
177
177
|
<RowActions items={[
|
|
178
|
-
{ label: t('common.delete'), destructive: true, onSelect: () => { void handleDelete(row) } },
|
|
178
|
+
{ id: 'delete', label: t('common.delete'), destructive: true, onSelect: () => { void handleDelete(row) } },
|
|
179
179
|
]} />
|
|
180
180
|
)}
|
|
181
181
|
pagination={{ page, pageSize: 20, total, totalPages, onPageChange: setPage }}
|
|
@@ -1056,6 +1056,7 @@ export function AttachmentLibrary() {
|
|
|
1056
1056
|
<RowActions
|
|
1057
1057
|
items={[
|
|
1058
1058
|
{
|
|
1059
|
+
id: 'open',
|
|
1059
1060
|
label: t('attachments.library.actions.open', 'Open'),
|
|
1060
1061
|
onSelect: () => {
|
|
1061
1062
|
if (!row.url) return
|
|
@@ -1063,10 +1064,12 @@ export function AttachmentLibrary() {
|
|
|
1063
1064
|
},
|
|
1064
1065
|
},
|
|
1065
1066
|
{
|
|
1067
|
+
id: 'edit',
|
|
1066
1068
|
label: t('attachments.library.actions.edit', 'Edit metadata'),
|
|
1067
1069
|
onSelect: () => openMetadataDialog(row),
|
|
1068
1070
|
},
|
|
1069
1071
|
{
|
|
1072
|
+
id: 'copy-url',
|
|
1070
1073
|
label: t('attachments.library.actions.copyUrl', 'Copy URL'),
|
|
1071
1074
|
onSelect: () => {
|
|
1072
1075
|
if (!row.url) {
|
|
@@ -1091,6 +1094,7 @@ export function AttachmentLibrary() {
|
|
|
1091
1094
|
},
|
|
1092
1095
|
},
|
|
1093
1096
|
{
|
|
1097
|
+
id: 'delete',
|
|
1094
1098
|
label: t('attachments.library.actions.delete', 'Delete'),
|
|
1095
1099
|
destructive: true,
|
|
1096
1100
|
onSelect: () => openDeleteDialog(row),
|
|
@@ -305,10 +305,12 @@ export function AttachmentPartitionSettings() {
|
|
|
305
305
|
<RowActions
|
|
306
306
|
items={[
|
|
307
307
|
{
|
|
308
|
+
id: 'edit',
|
|
308
309
|
label: t('attachments.partitions.actions.edit', 'Edit'),
|
|
309
310
|
onSelect: () => openDialog({ mode: 'edit', entry }),
|
|
310
311
|
},
|
|
311
312
|
{
|
|
313
|
+
id: 'delete',
|
|
312
314
|
label: t('attachments.partitions.actions.delete', 'Delete'),
|
|
313
315
|
destructive: true,
|
|
314
316
|
onSelect: () => { void handleDelete(entry) },
|
|
@@ -8,7 +8,7 @@ Features:
|
|
|
8
8
|
- `mercato auth add-user --email <e> --password <p> --organizationId <id> [--roles r1,r2]`
|
|
9
9
|
- `mercato auth seed-roles`
|
|
10
10
|
- `mercato auth add-org --name <org>`
|
|
11
|
-
- `mercato auth setup --orgName <org> --email <e> --password <p> [--roles superadmin,admin]`
|
|
11
|
+
- `mercato auth setup --orgName <org> --email <e> --password <p> [--roles superadmin,admin] [--skip-password-policy]`
|
|
12
12
|
|
|
13
13
|
DB entities used (defined in root schema):
|
|
14
14
|
- `users` with: `email`, `password_hash`, `is_confirmed`, `last_login_at`, `organization_id`, timestamps.
|
|
@@ -46,7 +46,7 @@ describe('auth CLI setup seeds ACLs', () => {
|
|
|
46
46
|
findOneOrFail.mockImplementation(async (_: any, where: any) => ({ id: 'role-' + where.name, name: where.name }))
|
|
47
47
|
|
|
48
48
|
// Act
|
|
49
|
-
await setup.run(['--orgName', 'Acme', '--email', 'root@acme.com', '--password', 'secret'])
|
|
49
|
+
await setup.run(['--orgName', 'Acme', '--email', 'root@acme.com', '--password', 'secret', '--skip-password-policy'])
|
|
50
50
|
|
|
51
51
|
// Assert: persistAndFlush was called to create three RoleAcl rows with expected flags/features
|
|
52
52
|
const calls = persistAndFlush.mock.calls.map((c) => c[0])
|
|
@@ -15,6 +15,8 @@ jest.mock('@open-mercato/shared/lib/di/container', () => ({
|
|
|
15
15
|
createRequestContainer: async () => ({
|
|
16
16
|
resolve: (_: string) => ({
|
|
17
17
|
findUserByEmail: async (email: string) => ({ id: 1, email, passwordHash: 'hash', tenantId: tenantId, organizationId: orgId }),
|
|
18
|
+
findUsersByEmail: async (email: string) => ([{ id: 1, email, passwordHash: 'hash', tenantId: tenantId, organizationId: orgId }]),
|
|
19
|
+
findUserByEmailAndTenant: async (email: string) => ({ id: 1, email, passwordHash: 'hash', tenantId: tenantId, organizationId: orgId }),
|
|
18
20
|
verifyPassword: async () => true,
|
|
19
21
|
getUserRoles: async (_user: any, _tenant: string | null | undefined) => ['admin'],
|
|
20
22
|
updateLastLoginAt: async () => undefined,
|
|
@@ -297,12 +297,16 @@ export async function GET(req: Request) {
|
|
|
297
297
|
const groupsWithRole = rolePreference ? applySidebarPreference(groups, rolePreference) : groups
|
|
298
298
|
const baseForUser = adoptSidebarDefaults(groupsWithRole)
|
|
299
299
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
300
|
+
// For API key auth, use userId (the actual user) if available; otherwise skip user preferences
|
|
301
|
+
const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub
|
|
302
|
+
const preference = effectiveUserId
|
|
303
|
+
? await loadSidebarPreference(em, {
|
|
304
|
+
userId: effectiveUserId,
|
|
305
|
+
tenantId: auth.tenantId ?? null,
|
|
306
|
+
organizationId: auth.orgId ?? null,
|
|
307
|
+
locale,
|
|
308
|
+
})
|
|
309
|
+
: null
|
|
306
310
|
|
|
307
311
|
const withPreference = applySidebarPreference(baseForUser, preference)
|
|
308
312
|
|
|
@@ -17,15 +17,33 @@ export async function POST(req: Request) {
|
|
|
17
17
|
const email = String(form.get('email') ?? '')
|
|
18
18
|
const password = String(form.get('password') ?? '')
|
|
19
19
|
const remember = parseBooleanToken(form.get('remember')?.toString()) === true
|
|
20
|
+
const tenantIdRaw = String(form.get('tenantId') ?? form.get('tenant') ?? '').trim()
|
|
20
21
|
const requireRoleRaw = (String(form.get('requireRole') ?? form.get('role') ?? '')).trim()
|
|
21
22
|
const requiredRoles = requireRoleRaw ? requireRoleRaw.split(',').map((s) => s.trim()).filter(Boolean) : []
|
|
22
|
-
const parsed = userLoginSchema.pick({ email: true, password: true }).safeParse({
|
|
23
|
+
const parsed = userLoginSchema.pick({ email: true, password: true, tenantId: true }).safeParse({
|
|
24
|
+
email,
|
|
25
|
+
password,
|
|
26
|
+
tenantId: tenantIdRaw || undefined,
|
|
27
|
+
})
|
|
23
28
|
if (!parsed.success) {
|
|
24
29
|
return NextResponse.json({ ok: false, error: translate('auth.login.errors.invalidCredentials', 'Invalid credentials') }, { status: 400 })
|
|
25
30
|
}
|
|
26
31
|
const container = await createRequestContainer()
|
|
27
32
|
const auth = (container.resolve('authService') as AuthService)
|
|
28
|
-
const
|
|
33
|
+
const tenantId = parsed.data.tenantId ?? null
|
|
34
|
+
let user = null
|
|
35
|
+
if (tenantId) {
|
|
36
|
+
user = await auth.findUserByEmailAndTenant(parsed.data.email, tenantId)
|
|
37
|
+
} else {
|
|
38
|
+
const users = await auth.findUsersByEmail(parsed.data.email)
|
|
39
|
+
if (users.length > 1) {
|
|
40
|
+
return NextResponse.json({
|
|
41
|
+
ok: false,
|
|
42
|
+
error: translate('auth.login.errors.tenantRequired', 'Use the login link provided with your tenant activation to continue.'),
|
|
43
|
+
}, { status: 400 })
|
|
44
|
+
}
|
|
45
|
+
user = users[0] ?? null
|
|
46
|
+
}
|
|
29
47
|
if (!user || !user.passwordHash) {
|
|
30
48
|
return NextResponse.json({ ok: false, error: translate('auth.login.errors.invalidCredentials', 'Invalid email or password') }, { status: 401 })
|
|
31
49
|
}
|
|
@@ -35,26 +53,27 @@ export async function POST(req: Request) {
|
|
|
35
53
|
}
|
|
36
54
|
// Optional role requirement
|
|
37
55
|
if (requiredRoles.length) {
|
|
38
|
-
const userRoleNames = await auth.getUserRoles(user, user.tenantId ? String(user.tenantId) : null)
|
|
56
|
+
const userRoleNames = await auth.getUserRoles(user, tenantId ?? (user.tenantId ? String(user.tenantId) : null))
|
|
39
57
|
const authorized = requiredRoles.some(r => userRoleNames.includes(r))
|
|
40
58
|
if (!authorized) {
|
|
41
59
|
return NextResponse.json({ ok: false, error: translate('auth.login.errors.permissionDenied', 'Not authorized for this area') }, { status: 403 })
|
|
42
60
|
}
|
|
43
61
|
}
|
|
44
62
|
await auth.updateLastLoginAt(user)
|
|
45
|
-
const
|
|
63
|
+
const resolvedTenantId = tenantId ?? (user.tenantId ? String(user.tenantId) : null)
|
|
64
|
+
const userRoleNames = await auth.getUserRoles(user, resolvedTenantId)
|
|
46
65
|
try {
|
|
47
66
|
const eventBus = (container.resolve('eventBus') as EventBus)
|
|
48
67
|
void eventBus.emitEvent('query_index.coverage.warmup', {
|
|
49
|
-
tenantId:
|
|
68
|
+
tenantId: resolvedTenantId,
|
|
50
69
|
}).catch(() => undefined)
|
|
51
70
|
} catch {
|
|
52
71
|
// optional warmup
|
|
53
72
|
}
|
|
54
73
|
const token = signJwt({
|
|
55
74
|
sub: String(user.id),
|
|
56
|
-
tenantId:
|
|
57
|
-
orgId: user.organizationId ? String(user.organizationId) : null,
|
|
75
|
+
tenantId: resolvedTenantId,
|
|
76
|
+
orgId: user.organizationId ? String(user.organizationId) : null,
|
|
58
77
|
email: user.email,
|
|
59
78
|
roles: userRoleNames
|
|
60
79
|
})
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
4
|
+
import type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
|
|
5
|
+
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
6
|
+
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
7
|
+
import { signJwt } from '@open-mercato/shared/lib/auth/jwt'
|
|
8
|
+
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
9
|
+
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
10
|
+
import { AuthService } from '@open-mercato/core/modules/auth/services/authService'
|
|
11
|
+
import { User } from '@open-mercato/core/modules/auth/data/entities'
|
|
12
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
13
|
+
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
14
|
+
import { buildPasswordSchema } from '@open-mercato/shared/lib/auth/passwordPolicy'
|
|
15
|
+
|
|
16
|
+
const profileResponseSchema = z.object({
|
|
17
|
+
email: z.string().email(),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const passwordSchema = buildPasswordSchema()
|
|
21
|
+
|
|
22
|
+
const updateSchema = z.object({
|
|
23
|
+
email: z.string().email().optional(),
|
|
24
|
+
password: passwordSchema.optional(),
|
|
25
|
+
}).refine((data) => Boolean(data.email || data.password), {
|
|
26
|
+
message: 'Provide an email or password.',
|
|
27
|
+
path: ['email'],
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const profileUpdateResponseSchema = z.object({
|
|
31
|
+
ok: z.literal(true),
|
|
32
|
+
email: z.string().email(),
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
export const metadata = {
|
|
36
|
+
GET: { requireAuth: true },
|
|
37
|
+
PUT: { requireAuth: true },
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildCommandContext(container: Awaited<ReturnType<typeof createRequestContainer>>, auth: NonNullable<Awaited<ReturnType<typeof getAuthFromRequest>>>, req: Request): CommandRuntimeContext {
|
|
41
|
+
return {
|
|
42
|
+
container,
|
|
43
|
+
auth,
|
|
44
|
+
organizationScope: null,
|
|
45
|
+
selectedOrganizationId: auth.orgId ?? null,
|
|
46
|
+
organizationIds: auth.orgId ? [auth.orgId] : null,
|
|
47
|
+
request: req,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function GET(req: Request) {
|
|
52
|
+
const { translate } = await resolveTranslations()
|
|
53
|
+
const auth = await getAuthFromRequest(req)
|
|
54
|
+
if (!auth?.sub) {
|
|
55
|
+
return NextResponse.json({ error: translate('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const container = await createRequestContainer()
|
|
59
|
+
const em = (container.resolve('em') as EntityManager)
|
|
60
|
+
const user = await findOneWithDecryption(
|
|
61
|
+
em,
|
|
62
|
+
User,
|
|
63
|
+
{ id: auth.sub, deletedAt: null },
|
|
64
|
+
undefined,
|
|
65
|
+
{ tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null },
|
|
66
|
+
)
|
|
67
|
+
if (!user) {
|
|
68
|
+
return NextResponse.json({ error: translate('auth.users.form.errors.notFound', 'User not found') }, { status: 404 })
|
|
69
|
+
}
|
|
70
|
+
return NextResponse.json({ email: String(user.email) })
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error('auth.profile.load failed', err)
|
|
73
|
+
return NextResponse.json({ error: translate('auth.profile.form.errors.load', 'Failed to load profile.') }, { status: 400 })
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function PUT(req: Request) {
|
|
78
|
+
const { translate } = await resolveTranslations()
|
|
79
|
+
const auth = await getAuthFromRequest(req)
|
|
80
|
+
if (!auth?.sub) {
|
|
81
|
+
return NextResponse.json({ error: translate('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const body = await req.json().catch(() => ({}))
|
|
85
|
+
const parsed = updateSchema.safeParse(body)
|
|
86
|
+
if (!parsed.success) {
|
|
87
|
+
return NextResponse.json(
|
|
88
|
+
{
|
|
89
|
+
error: translate('auth.profile.form.errors.invalid', 'Invalid profile update.'),
|
|
90
|
+
issues: parsed.error.issues,
|
|
91
|
+
},
|
|
92
|
+
{ status: 400 },
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
const container = await createRequestContainer()
|
|
96
|
+
const commandBus = (container.resolve('commandBus') as CommandBus)
|
|
97
|
+
const ctx = buildCommandContext(container, auth, req)
|
|
98
|
+
const { result } = await commandBus.execute<{ id: string; email?: string; password?: string }, User>(
|
|
99
|
+
'auth.users.update',
|
|
100
|
+
{
|
|
101
|
+
input: {
|
|
102
|
+
id: auth.sub,
|
|
103
|
+
email: parsed.data.email,
|
|
104
|
+
password: parsed.data.password,
|
|
105
|
+
},
|
|
106
|
+
ctx,
|
|
107
|
+
},
|
|
108
|
+
)
|
|
109
|
+
const authService = container.resolve('authService') as AuthService
|
|
110
|
+
const roles = await authService.getUserRoles(result, result.tenantId ? String(result.tenantId) : null)
|
|
111
|
+
const jwt = signJwt({
|
|
112
|
+
sub: String(result.id),
|
|
113
|
+
tenantId: result.tenantId ? String(result.tenantId) : null,
|
|
114
|
+
orgId: result.organizationId ? String(result.organizationId) : null,
|
|
115
|
+
email: result.email,
|
|
116
|
+
roles,
|
|
117
|
+
})
|
|
118
|
+
const res = NextResponse.json({ ok: true, email: String(result.email) })
|
|
119
|
+
res.cookies.set('auth_token', jwt, {
|
|
120
|
+
httpOnly: true,
|
|
121
|
+
path: '/',
|
|
122
|
+
sameSite: 'lax',
|
|
123
|
+
secure: process.env.NODE_ENV === 'production',
|
|
124
|
+
maxAge: 60 * 60 * 8,
|
|
125
|
+
})
|
|
126
|
+
return res
|
|
127
|
+
} catch (err) {
|
|
128
|
+
if (err instanceof CrudHttpError) {
|
|
129
|
+
return NextResponse.json(err.body, { status: err.status })
|
|
130
|
+
}
|
|
131
|
+
console.error('auth.profile.update failed', err)
|
|
132
|
+
return NextResponse.json({ error: translate('auth.profile.form.errors.save', 'Failed to update profile.') }, { status: 400 })
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const openApi: OpenApiRouteDoc = {
|
|
137
|
+
tag: 'Authentication & Accounts',
|
|
138
|
+
summary: 'Profile settings',
|
|
139
|
+
methods: {
|
|
140
|
+
GET: {
|
|
141
|
+
summary: 'Get current profile',
|
|
142
|
+
description: 'Returns the email address for the signed-in user.',
|
|
143
|
+
responses: [
|
|
144
|
+
{ status: 200, description: 'Profile payload', schema: profileResponseSchema },
|
|
145
|
+
{ status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },
|
|
146
|
+
{ status: 404, description: 'User not found', schema: z.object({ error: z.string() }) },
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
PUT: {
|
|
150
|
+
summary: 'Update current profile',
|
|
151
|
+
description: 'Updates the email address or password for the signed-in user.',
|
|
152
|
+
requestBody: {
|
|
153
|
+
contentType: 'application/json',
|
|
154
|
+
schema: updateSchema,
|
|
155
|
+
},
|
|
156
|
+
responses: [
|
|
157
|
+
{ status: 200, description: 'Profile updated', schema: profileUpdateResponseSchema },
|
|
158
|
+
{ status: 400, description: 'Invalid payload', schema: z.object({ error: z.string() }) },
|
|
159
|
+
{ status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
}
|
|
@@ -3,6 +3,9 @@ import { NextResponse } from 'next/server'
|
|
|
3
3
|
import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
4
4
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
5
5
|
import { AuthService } from '@open-mercato/core/modules/auth/services/authService'
|
|
6
|
+
import { buildNotificationFromType } from '@open-mercato/core/modules/notifications/lib/notificationBuilder'
|
|
7
|
+
import { resolveNotificationService } from '@open-mercato/core/modules/notifications/lib/notificationService'
|
|
8
|
+
import notificationTypes from '@open-mercato/core/modules/auth/notifications'
|
|
6
9
|
import { z } from 'zod'
|
|
7
10
|
|
|
8
11
|
// validation via confirmPasswordResetSchema
|
|
@@ -15,8 +18,28 @@ export async function POST(req: Request) {
|
|
|
15
18
|
if (!parsed.success) return NextResponse.json({ ok: false, error: 'Invalid request' }, { status: 400 })
|
|
16
19
|
const c = await createRequestContainer()
|
|
17
20
|
const auth = c.resolve<AuthService>('authService')
|
|
18
|
-
const
|
|
19
|
-
if (!
|
|
21
|
+
const user = await auth.confirmPasswordReset(parsed.data.token, parsed.data.password)
|
|
22
|
+
if (!user) return NextResponse.json({ ok: false, error: 'Invalid or expired token' }, { status: 400 })
|
|
23
|
+
try {
|
|
24
|
+
const tenantId = user.tenantId ? String(user.tenantId) : null
|
|
25
|
+
if (tenantId) {
|
|
26
|
+
const notificationService = resolveNotificationService(c)
|
|
27
|
+
const typeDef = notificationTypes.find((type) => type.type === 'auth.password_reset.completed')
|
|
28
|
+
if (typeDef) {
|
|
29
|
+
const notificationInput = buildNotificationFromType(typeDef, {
|
|
30
|
+
recipientUserId: String(user.id),
|
|
31
|
+
sourceEntityType: 'auth:user',
|
|
32
|
+
sourceEntityId: String(user.id),
|
|
33
|
+
})
|
|
34
|
+
await notificationService.create(notificationInput, {
|
|
35
|
+
tenantId,
|
|
36
|
+
organizationId: user.organizationId ? String(user.organizationId) : null,
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} catch (err) {
|
|
41
|
+
console.error('[auth.reset.confirm] Failed to create notification:', err)
|
|
42
|
+
}
|
|
20
43
|
return NextResponse.json({ ok: true, redirect: '/login' })
|
|
21
44
|
}
|
|
22
45
|
|
|
@@ -6,6 +6,9 @@ import { AuthService } from '@open-mercato/core/modules/auth/services/authServic
|
|
|
6
6
|
import { sendEmail } from '@open-mercato/shared/lib/email/send'
|
|
7
7
|
import ResetPasswordEmail from '@open-mercato/core/modules/auth/emails/ResetPasswordEmail'
|
|
8
8
|
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
9
|
+
import { buildNotificationFromType } from '@open-mercato/core/modules/notifications/lib/notificationBuilder'
|
|
10
|
+
import { resolveNotificationService } from '@open-mercato/core/modules/notifications/lib/notificationService'
|
|
11
|
+
import notificationTypes from '@open-mercato/core/modules/auth/notifications'
|
|
9
12
|
import { z } from 'zod'
|
|
10
13
|
|
|
11
14
|
// validation via requestPasswordResetSchema
|
|
@@ -35,6 +38,26 @@ export async function POST(req: Request) {
|
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
await sendEmail({ to: user.email, subject, react: ResetPasswordEmail({ resetUrl, copy }) })
|
|
41
|
+
try {
|
|
42
|
+
const tenantId = user.tenantId ? String(user.tenantId) : null
|
|
43
|
+
if (tenantId) {
|
|
44
|
+
const notificationService = resolveNotificationService(c)
|
|
45
|
+
const typeDef = notificationTypes.find((type) => type.type === 'auth.password_reset.requested')
|
|
46
|
+
if (typeDef) {
|
|
47
|
+
const notificationInput = buildNotificationFromType(typeDef, {
|
|
48
|
+
recipientUserId: String(user.id),
|
|
49
|
+
sourceEntityType: 'auth:user',
|
|
50
|
+
sourceEntityId: String(user.id),
|
|
51
|
+
})
|
|
52
|
+
await notificationService.create(notificationInput, {
|
|
53
|
+
tenantId,
|
|
54
|
+
organizationId: user.organizationId ? String(user.organizationId) : null,
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.error('[auth.reset] Failed to create notification:', err)
|
|
60
|
+
}
|
|
38
61
|
return NextResponse.json({ ok: true })
|
|
39
62
|
}
|
|
40
63
|
|
|
@@ -64,12 +64,16 @@ export async function GET(req: Request) {
|
|
|
64
64
|
{ tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null },
|
|
65
65
|
) ?? false
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
// For API key auth, use userId (the actual user) if available
|
|
68
|
+
const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub
|
|
69
|
+
const settings = effectiveUserId
|
|
70
|
+
? await loadSidebarPreference(em, {
|
|
71
|
+
userId: effectiveUserId,
|
|
72
|
+
tenantId: auth.tenantId ?? null,
|
|
73
|
+
organizationId: auth.orgId ?? null,
|
|
74
|
+
locale,
|
|
75
|
+
})
|
|
76
|
+
: null
|
|
73
77
|
|
|
74
78
|
let rolesPayload: Array<{ id: string; name: string; hasPreference: boolean }> = []
|
|
75
79
|
if (canApplyToRoles) {
|
|
@@ -92,11 +96,11 @@ export async function GET(req: Request) {
|
|
|
92
96
|
return NextResponse.json({
|
|
93
97
|
locale,
|
|
94
98
|
settings: {
|
|
95
|
-
version: settings
|
|
96
|
-
groupOrder: settings
|
|
97
|
-
groupLabels: settings
|
|
98
|
-
itemLabels: settings
|
|
99
|
-
hiddenItems: settings
|
|
99
|
+
version: settings?.version ?? SIDEBAR_PREFERENCES_VERSION,
|
|
100
|
+
groupOrder: settings?.groupOrder ?? [],
|
|
101
|
+
groupLabels: settings?.groupLabels ?? {},
|
|
102
|
+
itemLabels: settings?.itemLabels ?? {},
|
|
103
|
+
hiddenItems: settings?.hiddenItems ?? [],
|
|
100
104
|
},
|
|
101
105
|
canApplyToRoles,
|
|
102
106
|
roles: rolesPayload,
|
|
@@ -106,6 +110,11 @@ export async function GET(req: Request) {
|
|
|
106
110
|
export async function PUT(req: Request) {
|
|
107
111
|
const auth = await getAuthFromRequest(req)
|
|
108
112
|
if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
113
|
+
// For API key auth, use userId (the actual user) if available
|
|
114
|
+
const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub
|
|
115
|
+
if (!effectiveUserId) {
|
|
116
|
+
return NextResponse.json({ error: 'Cannot save preferences: no user associated with this API key' }, { status: 403 })
|
|
117
|
+
}
|
|
109
118
|
|
|
110
119
|
let parsedBody: unknown
|
|
111
120
|
try {
|
|
@@ -182,7 +191,7 @@ export async function PUT(req: Request) {
|
|
|
182
191
|
}
|
|
183
192
|
|
|
184
193
|
const settings = await saveSidebarPreference(em, {
|
|
185
|
-
userId:
|
|
194
|
+
userId: effectiveUserId,
|
|
186
195
|
tenantId: auth.tenantId ?? null,
|
|
187
196
|
organizationId: auth.orgId ?? null,
|
|
188
197
|
locale,
|