forked from jappel/leistungsbilanz-ts
Add print cover fields and office profile
- Project settings gain siteAddress, workStage, projectLead and projectEditor (project.update-settings schema version 3, migration 0009); versions 2 and 1 stay executable and keep the current cover values. Snapshot schema 6 carries the fields; older versions upgrade with null. - Global office profile (office name/address) next to the document logo: table document_branding_settings, PUT /api/document-branding/office, editable from the print view toolbar. - Cover page reads all fields; empty values show the "[ergänzen]" marker. The Planstände editor column shows the project editor. - Shared logo constants moved to a dependency-free module so the Next.js bundler can import them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
94688d7a8c
commit
bf58296ba5
35 changed files with 3571 additions and 106 deletions
77
tests/document-branding.repository.test.ts
Normal file
77
tests/document-branding.repository.test.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import path from "node:path";
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
||||
import { createDatabaseContext } from "../src/db/database-context.js";
|
||||
import { DocumentBrandingRepository } from "../src/db/repositories/document-branding.repository.js";
|
||||
import { officeProfileFields } from "../src/shared/constants/project-cover.js";
|
||||
import { updateOfficeProfileSchema } from "../src/shared/validation/document-branding.schemas.js";
|
||||
|
||||
function createRepository() {
|
||||
const context = createDatabaseContext(":memory:");
|
||||
migrate(context.db, {
|
||||
migrationsFolder: path.resolve("src", "db", "migrations"),
|
||||
});
|
||||
return { context, repository: new DocumentBrandingRepository(context.db) };
|
||||
}
|
||||
|
||||
describe("document branding repository", () => {
|
||||
it("stores, replaces and removes the office profile", () => {
|
||||
const { context, repository } = createRepository();
|
||||
try {
|
||||
assert.deepEqual(repository.getSettings(officeProfileFields), {
|
||||
officeName: null,
|
||||
officeAddress: null,
|
||||
});
|
||||
repository.setSettings(
|
||||
updateOfficeProfileSchema.parse({
|
||||
officeName: " kbp köhler beraten + planen GmbH ",
|
||||
officeAddress: "Straße 1\n12345 Ort",
|
||||
})
|
||||
);
|
||||
assert.deepEqual(repository.getSettings(officeProfileFields), {
|
||||
officeName: "kbp köhler beraten + planen GmbH",
|
||||
officeAddress: "Straße 1\n12345 Ort",
|
||||
});
|
||||
repository.setSettings(
|
||||
updateOfficeProfileSchema.parse({ officeName: "Büro", officeAddress: "" })
|
||||
);
|
||||
assert.deepEqual(repository.getSettings(officeProfileFields), {
|
||||
officeName: "Büro",
|
||||
officeAddress: null,
|
||||
});
|
||||
assert.equal(
|
||||
updateOfficeProfileSchema.safeParse({ officeName: "x".repeat(201), officeAddress: null })
|
||||
.success,
|
||||
false
|
||||
);
|
||||
} finally {
|
||||
context.close();
|
||||
}
|
||||
});
|
||||
|
||||
it("replaces and deletes the logo", () => {
|
||||
const { context, repository } = createRepository();
|
||||
try {
|
||||
repository.upsert({
|
||||
key: "logo",
|
||||
mimeType: "image/png",
|
||||
fileName: "a.png",
|
||||
data: Buffer.from([1, 2, 3]),
|
||||
});
|
||||
repository.upsert({
|
||||
key: "logo",
|
||||
mimeType: "image/svg+xml",
|
||||
fileName: "b.svg",
|
||||
data: Buffer.from("<svg/>"),
|
||||
});
|
||||
const logo = repository.get("logo");
|
||||
assert.equal(logo?.mimeType, "image/svg+xml");
|
||||
assert.equal(logo?.data.toString(), "<svg/>");
|
||||
assert.equal(repository.delete("logo"), true);
|
||||
assert.equal(repository.get("logo"), undefined);
|
||||
} finally {
|
||||
context.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue