mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
fix(freight-permissions): split company stamp from per-officer teeter permission
This commit is contained in:
@@ -15,21 +15,21 @@ export class StampSettingsController {
|
|||||||
constructor(private readonly service: StampSettingsService) {}
|
constructor(private readonly service: StampSettingsService) {}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@BookingStaff([FREIGHT_PERMS.settings.invoiceStamp.view, FREIGHT_PERMS.admin])
|
@BookingStaff([FREIGHT_PERMS.settings.stamp.view, FREIGHT_PERMS.admin])
|
||||||
@ApiOperation({ summary: "Current company stamp used on invoice/receipt PDFs" })
|
@ApiOperation({ summary: "Current company stamp used on invoice/receipt PDFs" })
|
||||||
get() {
|
get() {
|
||||||
return this.service.getView();
|
return this.service.getView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put()
|
@Put()
|
||||||
@BookingStaff([FREIGHT_PERMS.settings.invoiceStamp.manage, FREIGHT_PERMS.admin])
|
@BookingStaff([FREIGHT_PERMS.settings.stamp.manage, FREIGHT_PERMS.admin])
|
||||||
@ApiOperation({ summary: "Replace the company stamp" })
|
@ApiOperation({ summary: "Replace the company stamp" })
|
||||||
update(@Body() dto: UpdateStampSettingDto, @CurrentUser() user: TCurrentUser) {
|
update(@Body() dto: UpdateStampSettingDto, @CurrentUser() user: TCurrentUser) {
|
||||||
return this.service.setStamp(dto.stampImageBase64, user?.id ?? null);
|
return this.service.setStamp(dto.stampImageBase64, user?.id ?? null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete()
|
@Delete()
|
||||||
@BookingStaff([FREIGHT_PERMS.settings.invoiceStamp.manage, FREIGHT_PERMS.admin])
|
@BookingStaff([FREIGHT_PERMS.settings.stamp.manage, FREIGHT_PERMS.admin])
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Clear the company stamp (invoices fall back to the plain seal)",
|
summary: "Clear the company stamp (invoices fall back to the plain seal)",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1190,22 +1190,28 @@ export const CONFIG_SETTINGS_PERMISSIONS: FreightPermissionSeed[] = [
|
|||||||
perm(
|
perm(
|
||||||
"b4b00002-0001-4000-8000-000000000001",
|
"b4b00002-0001-4000-8000-000000000001",
|
||||||
"edr_freight_app:settings:stamp:view",
|
"edr_freight_app:settings:stamp:view",
|
||||||
"View stamp settings",
|
"View the company stamp",
|
||||||
),
|
),
|
||||||
perm(
|
perm(
|
||||||
"b4b00002-0001-4000-8000-000000000002",
|
"b4b00002-0001-4000-8000-000000000002",
|
||||||
"edr_freight_app:settings:stamp:manage",
|
"edr_freight_app:settings:stamp:manage",
|
||||||
"Manage stamp settings",
|
"Manage the company stamp",
|
||||||
),
|
),
|
||||||
|
// The per-officer approval teeter (ማህተም) — an individual's own stamp +
|
||||||
|
// signature, not the company seal. It used to ride on settings:stamp:*, which
|
||||||
|
// now gates the ONE company stamp; this key was split out when the two were
|
||||||
|
// untangled. `settings:invoice_stamp:*` retired at the same time: it gated the
|
||||||
|
// company stamp before the fold and is deliberately left orphaned in any DB
|
||||||
|
// that already seeded it (the seeder upserts by key and never deletes).
|
||||||
perm(
|
perm(
|
||||||
"b4b00003-0001-4000-8000-000000000001",
|
"b4b00003-0001-4000-8000-000000000001",
|
||||||
"edr_freight_app:settings:invoice_stamp:view",
|
"edr_freight_app:settings:teeter:view",
|
||||||
"View invoice stamp settings",
|
"View own approval teeter and signature",
|
||||||
),
|
),
|
||||||
perm(
|
perm(
|
||||||
"b4b00003-0001-4000-8000-000000000002",
|
"b4b00003-0001-4000-8000-000000000002",
|
||||||
"edr_freight_app:settings:invoice_stamp:manage",
|
"edr_freight_app:settings:teeter:manage",
|
||||||
"Manage invoice stamp settings",
|
"Manage own approval teeter and signature",
|
||||||
),
|
),
|
||||||
perm(
|
perm(
|
||||||
"b4c00001-0001-4000-8000-000000000001",
|
"b4c00001-0001-4000-8000-000000000001",
|
||||||
@@ -1907,15 +1913,18 @@ export const FREIGHT_PERMS = {
|
|||||||
view: "edr_freight_app:settings:dropdown:view",
|
view: "edr_freight_app:settings:dropdown:view",
|
||||||
manage: "edr_freight_app:settings:dropdown:manage",
|
manage: "edr_freight_app:settings:dropdown:manage",
|
||||||
},
|
},
|
||||||
|
// The ONE company stamp/seal, applied to every generated document
|
||||||
|
// (invoices, receipts, warehouse papers, the EDR side of contracts).
|
||||||
stamp: {
|
stamp: {
|
||||||
view: "edr_freight_app:settings:stamp:view",
|
view: "edr_freight_app:settings:stamp:view",
|
||||||
manage: "edr_freight_app:settings:stamp:manage",
|
manage: "edr_freight_app:settings:stamp:manage",
|
||||||
},
|
},
|
||||||
// Company stamp/seal image stamped onto invoice/receipt PDFs — separate
|
// The per-officer approval teeter (ማህተም) + signature — genuinely per-person,
|
||||||
// from `stamp` above, which is the per-employee approval-record teeter.
|
// and NOT the company seal above. Retired: `invoiceStamp`, which used to
|
||||||
invoiceStamp: {
|
// gate the company stamp before the two were untangled.
|
||||||
view: "edr_freight_app:settings:invoice_stamp:view",
|
teeter: {
|
||||||
manage: "edr_freight_app:settings:invoice_stamp:manage",
|
view: "edr_freight_app:settings:teeter:view",
|
||||||
|
manage: "edr_freight_app:settings:teeter:manage",
|
||||||
},
|
},
|
||||||
exchangeRate: {
|
exchangeRate: {
|
||||||
view: "edr_freight_app:settings:exchange_rate:view",
|
view: "edr_freight_app:settings:exchange_rate:view",
|
||||||
|
|||||||
@@ -796,7 +796,7 @@ const App = () => {
|
|||||||
path="stamp-settings"
|
path="stamp-settings"
|
||||||
element={
|
element={
|
||||||
<RequirePermission
|
<RequirePermission
|
||||||
permission={FREIGHT_PERMS.settings.invoiceStamp.view}
|
permission={FREIGHT_PERMS.settings.stamp.view}
|
||||||
>
|
>
|
||||||
<CompanyStampSettingsPage />
|
<CompanyStampSettingsPage />
|
||||||
</RequirePermission>
|
</RequirePermission>
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ export const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[]
|
|||||||
label: "Company stamp",
|
label: "Company stamp",
|
||||||
href: "/dashboard/stamp-settings",
|
href: "/dashboard/stamp-settings",
|
||||||
icon: <Stamp />,
|
icon: <Stamp />,
|
||||||
permission: FREIGHT_PERMS.settings.invoiceStamp.view,
|
permission: FREIGHT_PERMS.settings.stamp.view,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Contract templates",
|
label: "Contract templates",
|
||||||
|
|||||||
@@ -328,15 +328,18 @@ export const FREIGHT_PERMS = {
|
|||||||
view: "edr_freight_app:settings:dropdown:view",
|
view: "edr_freight_app:settings:dropdown:view",
|
||||||
manage: "edr_freight_app:settings:dropdown:manage",
|
manage: "edr_freight_app:settings:dropdown:manage",
|
||||||
},
|
},
|
||||||
|
// The ONE company stamp/seal, applied to every generated document
|
||||||
|
// (invoices, receipts, warehouse papers, the EDR side of contracts).
|
||||||
stamp: {
|
stamp: {
|
||||||
view: "edr_freight_app:settings:stamp:view",
|
view: "edr_freight_app:settings:stamp:view",
|
||||||
manage: "edr_freight_app:settings:stamp:manage",
|
manage: "edr_freight_app:settings:stamp:manage",
|
||||||
},
|
},
|
||||||
// Company stamp/seal image stamped onto invoice/receipt PDFs — separate
|
// The per-officer approval teeter (ማህተም) + signature — genuinely per-person,
|
||||||
// from `stamp` above, which is the per-employee approval-record teeter.
|
// and NOT the company seal above. Retired: `invoiceStamp`, which used to
|
||||||
invoiceStamp: {
|
// gate the company stamp before the two were untangled.
|
||||||
view: "edr_freight_app:settings:invoice_stamp:view",
|
teeter: {
|
||||||
manage: "edr_freight_app:settings:invoice_stamp:manage",
|
view: "edr_freight_app:settings:teeter:view",
|
||||||
|
manage: "edr_freight_app:settings:teeter:manage",
|
||||||
},
|
},
|
||||||
exchangeRate: {
|
exchangeRate: {
|
||||||
view: "edr_freight_app:settings:exchange_rate:view",
|
view: "edr_freight_app:settings:exchange_rate:view",
|
||||||
|
|||||||
@@ -147,13 +147,17 @@ export function UserManagementRoutes(): ReactElement {
|
|||||||
(am/en) and genuinely per-person. It used to sit at
|
(am/en) and genuinely per-person. It used to sit at
|
||||||
/dashboard/stamp-settings under Settings, next to the
|
/dashboard/stamp-settings under Settings, next to the
|
||||||
single global company stamp, which read as duplication.
|
single global company stamp, which read as duplication.
|
||||||
Permission gate unchanged from that route.
|
|
||||||
|
Gated by settings:teeter:*, split out of settings:stamp:*
|
||||||
|
when the two were untangled — settings:stamp:* now means
|
||||||
|
the company stamp, so anyone who held it for the teeter
|
||||||
|
needs the new key granted.
|
||||||
*/}
|
*/}
|
||||||
<Route
|
<Route
|
||||||
path="user-management/teeter-and-signature"
|
path="user-management/teeter-and-signature"
|
||||||
element={
|
element={
|
||||||
<RequirePermission
|
<RequirePermission
|
||||||
permission={FREIGHT_PERMS.settings.stamp.view}
|
permission={FREIGHT_PERMS.settings.teeter.view}
|
||||||
>
|
>
|
||||||
<UploadTeeterAndSignature />
|
<UploadTeeterAndSignature />
|
||||||
</RequirePermission>
|
</RequirePermission>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import { Injectable, Logger, NestMiddleware } from "@nestjs/common";
|
import { Injectable, NestMiddleware } from "@nestjs/common";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
RequestLogContext,
|
RequestLogContext,
|
||||||
@@ -58,8 +58,6 @@ const userId = (req: LoggedRequest): string | undefined => {
|
|||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RequestLogMiddleware implements NestMiddleware {
|
export class RequestLogMiddleware implements NestMiddleware {
|
||||||
private readonly logger = new Logger("HTTP");
|
|
||||||
|
|
||||||
use(req: LoggedRequest, res: LoggedResponse, next: () => void): void {
|
use(req: LoggedRequest, res: LoggedResponse, next: () => void): void {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
const requestId = header(req, "x-request-id") ?? randomUUID();
|
const requestId = header(req, "x-request-id") ?? randomUUID();
|
||||||
@@ -85,8 +83,6 @@ export class RequestLogMiddleware implements NestMiddleware {
|
|||||||
const status = res.statusCode;
|
const status = res.statusCode;
|
||||||
const durationMs = Date.now() - start;
|
const durationMs = Date.now() - start;
|
||||||
|
|
||||||
this.logger.log(`${req.method} ${url} ${status} ${durationMs}ms`);
|
|
||||||
|
|
||||||
const line = {
|
const line = {
|
||||||
...ctx,
|
...ctx,
|
||||||
// Fields the Nest console prefix used to carry. They are IN the JSON
|
// Fields the Nest console prefix used to carry. They are IN the JSON
|
||||||
|
|||||||
Reference in New Issue
Block a user