feat(i18n): extend content translation storage
This commit is contained in:
@@ -2,10 +2,15 @@ export type ContentTranslationFieldKind = "text" | "textarea";
|
|||||||
export type ContentTranslationEntityType =
|
export type ContentTranslationEntityType =
|
||||||
| "branding"
|
| "branding"
|
||||||
| "calendar_event"
|
| "calendar_event"
|
||||||
|
| "chat_session"
|
||||||
| "client"
|
| "client"
|
||||||
| "client_activity"
|
| "client_activity"
|
||||||
|
| "finance_transaction"
|
||||||
|
| "journal_entry"
|
||||||
| "planning_section"
|
| "planning_section"
|
||||||
|
| "proposal"
|
||||||
| "project"
|
| "project"
|
||||||
|
| "subscription"
|
||||||
| "task";
|
| "task";
|
||||||
|
|
||||||
export type ContentTranslationField = {
|
export type ContentTranslationField = {
|
||||||
@@ -48,6 +53,25 @@ export const contentTranslationRegistry = {
|
|||||||
{ name: "title", label: "Başlık", required: true, maxLength: 500 },
|
{ name: "title", label: "Başlık", required: true, maxLength: 500 },
|
||||||
{ name: "content", label: "İçerik", kind: "textarea", maxLength: 20_000 },
|
{ name: "content", label: "İçerik", kind: "textarea", maxLength: 20_000 },
|
||||||
],
|
],
|
||||||
|
finance_transaction: [
|
||||||
|
{ name: "category", label: "Kategori", maxLength: 100 },
|
||||||
|
{ name: "description", label: "Açıklama", kind: "textarea", maxLength: 1_000 },
|
||||||
|
],
|
||||||
|
journal_entry: [
|
||||||
|
{ name: "moodLabel", label: "Mod Etiketi", maxLength: 100 },
|
||||||
|
{ name: "note", label: "Not", kind: "textarea", maxLength: 5_000 },
|
||||||
|
],
|
||||||
|
chat_session: [
|
||||||
|
{ name: "title", label: "Başlık", required: true, maxLength: 200 },
|
||||||
|
],
|
||||||
|
proposal: [
|
||||||
|
{ name: "title", label: "Başlık", required: true, maxLength: 300, placeholder: "Örn. Kurumsal web sitesi teklifi" },
|
||||||
|
{ name: "description", label: "Açıklama", kind: "textarea", maxLength: 30_000, placeholder: "Kapsam, teslimatlar ve teklif notları..." },
|
||||||
|
],
|
||||||
|
subscription: [
|
||||||
|
{ name: "name", label: "Abonelik adı", required: true, maxLength: 300, placeholder: "Örn. Tasarım aracı" },
|
||||||
|
{ name: "category", label: "Kategori", maxLength: 160, placeholder: "Örn. Yazılım, altyapı, pazarlama" },
|
||||||
|
],
|
||||||
} satisfies Record<ContentTranslationEntityType, ContentTranslationField[]>;
|
} satisfies Record<ContentTranslationEntityType, ContentTranslationField[]>;
|
||||||
|
|
||||||
export function contentInputName(locale: string, field: string) {
|
export function contentInputName(locale: string, field: string) {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ export const I18N_NAMESPACES = [
|
|||||||
"status",
|
"status",
|
||||||
"validation",
|
"validation",
|
||||||
"api",
|
"api",
|
||||||
|
"analytics",
|
||||||
|
"business",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type I18nNamespace = (typeof I18N_NAMESPACES)[number];
|
export type I18nNamespace = (typeof I18N_NAMESPACES)[number];
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
||||||
|
CREATE TABLE `__new_content_translations` (
|
||||||
|
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
`entity_type` text NOT NULL,
|
||||||
|
`entity_id` text NOT NULL,
|
||||||
|
`field` text NOT NULL,
|
||||||
|
`locale` text NOT NULL,
|
||||||
|
`value` text NOT NULL,
|
||||||
|
`created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL,
|
||||||
|
`updated_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL,
|
||||||
|
CONSTRAINT "content_translations_entity_type_check" CHECK("__new_content_translations"."entity_type" in ('branding', 'calendar_event', 'chat_session', 'client', 'client_activity', 'finance_transaction', 'journal_entry', 'planning_section', 'project', 'task')),
|
||||||
|
CONSTRAINT "content_translations_field_check" CHECK(length("__new_content_translations"."field") between 1 and 64),
|
||||||
|
CONSTRAINT "content_translations_locale_check" CHECK(length("__new_content_translations"."locale") between 2 and 12)
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
INSERT INTO `__new_content_translations`("id", "entity_type", "entity_id", "field", "locale", "value", "created_at", "updated_at") SELECT "id", "entity_type", "entity_id", "field", "locale", "value", "created_at", "updated_at" FROM `content_translations`;--> statement-breakpoint
|
||||||
|
DROP TABLE `content_translations`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `__new_content_translations` RENAME TO `content_translations`;--> statement-breakpoint
|
||||||
|
PRAGMA foreign_keys=ON;--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `content_translations_entity_field_locale_unique` ON `content_translations` (`entity_type`,`entity_id`,`field`,`locale`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `content_translations_locale_idx` ON `content_translations` (`locale`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `content_translations_entity_locale_idx` ON `content_translations` (`entity_type`,`entity_id`,`locale`);--> statement-breakpoint
|
||||||
|
ALTER TABLE `chat_messages` ADD `source_locale` text;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
||||||
|
CREATE TABLE `__new_content_translations` (
|
||||||
|
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
`entity_type` text NOT NULL,
|
||||||
|
`entity_id` text NOT NULL,
|
||||||
|
`field` text NOT NULL,
|
||||||
|
`locale` text NOT NULL,
|
||||||
|
`value` text NOT NULL,
|
||||||
|
`created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL,
|
||||||
|
`updated_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL,
|
||||||
|
CONSTRAINT "content_translations_entity_type_check" CHECK("__new_content_translations"."entity_type" in ('branding', 'calendar_event', 'chat_session', 'client', 'client_activity', 'finance_transaction', 'journal_entry', 'planning_section', 'proposal', 'project', 'subscription', 'task')),
|
||||||
|
CONSTRAINT "content_translations_field_check" CHECK(length("__new_content_translations"."field") between 1 and 64),
|
||||||
|
CONSTRAINT "content_translations_locale_check" CHECK(length("__new_content_translations"."locale") between 2 and 12)
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
INSERT INTO `__new_content_translations`("id", "entity_type", "entity_id", "field", "locale", "value", "created_at", "updated_at") SELECT "id", "entity_type", "entity_id", "field", "locale", "value", "created_at", "updated_at" FROM `content_translations`;--> statement-breakpoint
|
||||||
|
DROP TABLE `content_translations`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `__new_content_translations` RENAME TO `content_translations`;--> statement-breakpoint
|
||||||
|
PRAGMA foreign_keys=ON;--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `content_translations_entity_field_locale_unique` ON `content_translations` (`entity_type`,`entity_id`,`field`,`locale`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `content_translations_locale_idx` ON `content_translations` (`locale`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `content_translations_entity_locale_idx` ON `content_translations` (`entity_type`,`entity_id`,`locale`);
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -71,6 +71,20 @@
|
|||||||
"when": 1784533970134,
|
"when": 1784533970134,
|
||||||
"tag": "0009_loose_sersi",
|
"tag": "0009_loose_sersi",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 10,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1784625110660,
|
||||||
|
"tag": "0010_lovely_smasher",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 11,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1784626279393,
|
||||||
|
"tag": "0011_tricky_mordo",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -373,6 +373,7 @@ export const chatMessages = sqliteTable(
|
|||||||
.$type<string[]>()
|
.$type<string[]>()
|
||||||
.default([])
|
.default([])
|
||||||
.notNull(),
|
.notNull(),
|
||||||
|
sourceLocale: text("source_locale"),
|
||||||
createdAt: integer("created_at", { mode: "timestamp_ms" }).default(nowMs).notNull(),
|
createdAt: integer("created_at", { mode: "timestamp_ms" }).default(nowMs).notNull(),
|
||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
|
|||||||
@@ -13,10 +13,15 @@ export type TextDirection = "ltr" | "rtl";
|
|||||||
export type TranslationEntityType =
|
export type TranslationEntityType =
|
||||||
| "branding"
|
| "branding"
|
||||||
| "calendar_event"
|
| "calendar_event"
|
||||||
|
| "chat_session"
|
||||||
| "client"
|
| "client"
|
||||||
| "client_activity"
|
| "client_activity"
|
||||||
|
| "finance_transaction"
|
||||||
|
| "journal_entry"
|
||||||
| "planning_section"
|
| "planning_section"
|
||||||
|
| "proposal"
|
||||||
| "project"
|
| "project"
|
||||||
|
| "subscription"
|
||||||
| "task";
|
| "task";
|
||||||
|
|
||||||
const nowMs = sql`(cast(unixepoch('subsecond') * 1000 as integer))`;
|
const nowMs = sql`(cast(unixepoch('subsecond') * 1000 as integer))`;
|
||||||
@@ -115,7 +120,7 @@ export const contentTranslations = sqliteTable(
|
|||||||
index("content_translations_entity_locale_idx").on(table.entityType, table.entityId, table.locale),
|
index("content_translations_entity_locale_idx").on(table.entityType, table.entityId, table.locale),
|
||||||
check(
|
check(
|
||||||
"content_translations_entity_type_check",
|
"content_translations_entity_type_check",
|
||||||
sql`${table.entityType} in ('branding', 'calendar_event', 'client', 'client_activity', 'planning_section', 'project', 'task')`,
|
sql`${table.entityType} in ('branding', 'calendar_event', 'chat_session', 'client', 'client_activity', 'finance_transaction', 'journal_entry', 'planning_section', 'proposal', 'project', 'subscription', 'task')`,
|
||||||
),
|
),
|
||||||
check("content_translations_field_check", sql`length(${table.field}) between 1 and 64`),
|
check("content_translations_field_check", sql`length(${table.field}) between 1 and 64`),
|
||||||
check("content_translations_locale_check", sql`length(${table.locale}) between 2 and 12`),
|
check("content_translations_locale_check", sql`length(${table.locale}) between 2 and 12`),
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ export const chatMessageCreateSchema = z.object({
|
|||||||
role: z.enum(chatMessageRoles),
|
role: z.enum(chatMessageRoles),
|
||||||
content: z.string().trim().min(1).max(100_000),
|
content: z.string().trim().min(1).max(100_000),
|
||||||
contextJournalEntryIds: z.array(resourceIdSchema).max(100).default([]),
|
contextJournalEntryIds: z.array(resourceIdSchema).max(100).default([]),
|
||||||
|
sourceLocale: z.string().trim().min(2).max(12).nullable().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const proposalCreateSchema = z.object({
|
export const proposalCreateSchema = z.object({
|
||||||
|
|||||||
+92
-23
@@ -44,7 +44,7 @@ import type { ContentTranslationInput } from "../../lib/i18n/content";
|
|||||||
|
|
||||||
export class DomainService {
|
export class DomainService {
|
||||||
readonly repositories: DomainRepositories;
|
readonly repositories: DomainRepositories;
|
||||||
private readonly contentTranslations: ContentTranslationService;
|
public readonly contentTranslations: ContentTranslationService;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly db: DomainDatabase,
|
private readonly db: DomainDatabase,
|
||||||
@@ -283,9 +283,16 @@ export class DomainService {
|
|||||||
|
|
||||||
createFinanceTransaction(actor: DomainActor, input: unknown) {
|
createFinanceTransaction(actor: DomainActor, input: unknown) {
|
||||||
const scope = requireOwnerScope(actor);
|
const scope = requireOwnerScope(actor);
|
||||||
const value = parseDomainInput(financeTransactionCreateSchema, input);
|
const translations = this.getContentTranslations(input);
|
||||||
|
const defaultLocale = this.contentTranslations.getLocalizationContext(actor).defaultLocale;
|
||||||
|
const value = parseDomainInput(
|
||||||
|
financeTransactionCreateSchema,
|
||||||
|
translations ? projectBaseFromTranslations("finance_transaction", input as Record<string, unknown>, translations, defaultLocale) : input,
|
||||||
|
);
|
||||||
this.assertTaskRelations(scope, value);
|
this.assertTaskRelations(scope, value);
|
||||||
return this.repositories.finance.create(scope, { ...value, id: value.id ?? this.id() });
|
const transaction = this.repositories.finance.create(scope, { ...value, id: value.id ?? this.id() });
|
||||||
|
this.contentTranslations.upsertEntityTranslations("finance_transaction", transaction.id, translations);
|
||||||
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
listFinanceTransactions(actor: DomainActor) {
|
listFinanceTransactions(actor: DomainActor) {
|
||||||
@@ -295,21 +302,42 @@ export class DomainService {
|
|||||||
updateFinanceTransaction(actor: DomainActor, transactionId: string, input: unknown) {
|
updateFinanceTransaction(actor: DomainActor, transactionId: string, input: unknown) {
|
||||||
const scope = requireOwnerScope(actor);
|
const scope = requireOwnerScope(actor);
|
||||||
const current = this.repositories.finance.get(scope, transactionId) ?? this.throwNotFound("Finans kaydı");
|
const current = this.repositories.finance.get(scope, transactionId) ?? this.throwNotFound("Finans kaydı");
|
||||||
const value = parseDomainInput(financeTransactionUpdateSchema, input);
|
const translations = this.getContentTranslations(input);
|
||||||
|
const defaultLocale = this.contentTranslations.getLocalizationContext(actor).defaultLocale;
|
||||||
|
const value = parseDomainInput(
|
||||||
|
financeTransactionUpdateSchema,
|
||||||
|
translations ? projectBaseFromTranslations("finance_transaction", input as Record<string, unknown>, translations, defaultLocale) : input,
|
||||||
|
);
|
||||||
this.assertTaskRelations(scope, { ...current, ...value });
|
this.assertTaskRelations(scope, { ...current, ...value });
|
||||||
return this.repositories.finance.update(scope, transactionId, value) ?? this.throwNotFound("Finans kaydı");
|
const transaction = this.repositories.finance.update(scope, transactionId, value) ?? this.throwNotFound("Finans kaydı");
|
||||||
|
this.contentTranslations.upsertEntityTranslations("finance_transaction", transaction.id, translations);
|
||||||
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteFinanceTransaction(actor: DomainActor, transactionId: string) {
|
deleteFinanceTransaction(actor: DomainActor, transactionId: string) {
|
||||||
return this.repositories.finance.remove(requireOwnerScope(actor), transactionId) ?? this.throwNotFound("Finans kaydı");
|
const transaction = this.repositories.finance.remove(requireOwnerScope(actor), transactionId) ?? this.throwNotFound("Finans kaydı");
|
||||||
|
this.contentTranslations.deleteEntityTranslations("finance_transaction", transactionId);
|
||||||
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveJournalEntry(actor: DomainActor, input: unknown) {
|
saveJournalEntry(actor: DomainActor, input: unknown) {
|
||||||
const scope = requireOwnerScope(actor);
|
const scope = requireOwnerScope(actor);
|
||||||
const value = parseDomainInput(journalEntrySchema, input);
|
const translations = this.getContentTranslations(input);
|
||||||
const existing = this.repositories.journal.getByDate(scope, value.entryDate);
|
const defaultLocale = this.contentTranslations.getLocalizationContext(actor).defaultLocale;
|
||||||
if (existing) return this.repositories.journal.updateByDate(scope, value.entryDate, value);
|
const value = parseDomainInput(
|
||||||
return this.repositories.journal.create(scope, { ...value, id: value.id ?? this.id() });
|
journalEntrySchema,
|
||||||
|
translations ? projectBaseFromTranslations("journal_entry", input as Record<string, unknown>, translations, defaultLocale) : input,
|
||||||
|
);
|
||||||
|
let entry = this.repositories.journal.getByDate(scope, value.entryDate);
|
||||||
|
if (entry) {
|
||||||
|
entry = this.repositories.journal.updateByDate(scope, value.entryDate, value);
|
||||||
|
} else {
|
||||||
|
entry = this.repositories.journal.create(scope, { ...value, id: value.id ?? this.id() });
|
||||||
|
}
|
||||||
|
if (entry) {
|
||||||
|
this.contentTranslations.upsertEntityTranslations("journal_entry", entry.id, translations);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
listJournalEntries(actor: DomainActor) {
|
listJournalEntries(actor: DomainActor) {
|
||||||
@@ -318,16 +346,25 @@ export class DomainService {
|
|||||||
|
|
||||||
updateJournalEntry(actor: DomainActor, entryId: string, input: unknown) {
|
updateJournalEntry(actor: DomainActor, entryId: string, input: unknown) {
|
||||||
const scope = requireOwnerScope(actor);
|
const scope = requireOwnerScope(actor);
|
||||||
const value = parseDomainInput(journalEntrySchema.omit({ id: true }), input);
|
const translations = this.getContentTranslations(input);
|
||||||
|
const defaultLocale = this.contentTranslations.getLocalizationContext(actor).defaultLocale;
|
||||||
|
const value = parseDomainInput(
|
||||||
|
journalEntrySchema.omit({ id: true }),
|
||||||
|
translations ? projectBaseFromTranslations("journal_entry", input as Record<string, unknown>, translations, defaultLocale) : input,
|
||||||
|
);
|
||||||
const conflicting = this.repositories.journal.getByDate(scope, value.entryDate);
|
const conflicting = this.repositories.journal.getByDate(scope, value.entryDate);
|
||||||
if (conflicting && conflicting.id !== entryId) {
|
if (conflicting && conflicting.id !== entryId) {
|
||||||
throw conflict("Bu tarih için zaten bir günlük kaydı var.");
|
throw conflict("Bu tarih için zaten bir günlük kaydı var.");
|
||||||
}
|
}
|
||||||
return this.repositories.journal.update(scope, entryId, value) ?? this.throwNotFound("Günlük kaydı");
|
const entry = this.repositories.journal.update(scope, entryId, value) ?? this.throwNotFound("Günlük kaydı");
|
||||||
|
this.contentTranslations.upsertEntityTranslations("journal_entry", entry.id, translations);
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteJournalEntry(actor: DomainActor, entryId: string) {
|
deleteJournalEntry(actor: DomainActor, entryId: string) {
|
||||||
return this.repositories.journal.remove(requireOwnerScope(actor), entryId) ?? this.throwNotFound("Günlük kaydı");
|
const entry = this.repositories.journal.remove(requireOwnerScope(actor), entryId) ?? this.throwNotFound("Günlük kaydı");
|
||||||
|
this.contentTranslations.deleteEntityTranslations("journal_entry", entryId);
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
addPlanningSection(actor: DomainActor, input: unknown) {
|
addPlanningSection(actor: DomainActor, input: unknown) {
|
||||||
@@ -579,9 +616,16 @@ export class DomainService {
|
|||||||
|
|
||||||
createProposal(actor: DomainActor, input: unknown) {
|
createProposal(actor: DomainActor, input: unknown) {
|
||||||
const scope = requireOwnerScope(actor);
|
const scope = requireOwnerScope(actor);
|
||||||
const value = parseDomainInput(proposalCreateSchema, input);
|
const { translations, ...rawInput } = input as Record<string, unknown>;
|
||||||
|
const defaultLocale = this.contentTranslations.getLocalizationContext(actor).defaultLocale;
|
||||||
|
const value = parseDomainInput(
|
||||||
|
proposalCreateSchema,
|
||||||
|
translations ? projectBaseFromTranslations("proposal", rawInput, translations as ContentTranslationInput, defaultLocale) : input,
|
||||||
|
);
|
||||||
this.assertTaskRelations(scope, value);
|
this.assertTaskRelations(scope, value);
|
||||||
return this.repositories.business.createProposal(scope, { ...value, id: value.id ?? this.id() });
|
const proposal = this.repositories.business.createProposal(scope, { ...value, id: value.id ?? this.id() });
|
||||||
|
this.contentTranslations.upsertEntityTranslations("proposal", proposal.id, translations as ContentTranslationInput | undefined);
|
||||||
|
return proposal;
|
||||||
}
|
}
|
||||||
|
|
||||||
listProposals(actor: DomainActor) {
|
listProposals(actor: DomainActor) {
|
||||||
@@ -597,15 +641,24 @@ export class DomainService {
|
|||||||
const scope = requireOwnerScope(actor);
|
const scope = requireOwnerScope(actor);
|
||||||
const current = this.repositories.business.getProposal(scope, proposalId)
|
const current = this.repositories.business.getProposal(scope, proposalId)
|
||||||
?? this.throwNotFound("Teklif");
|
?? this.throwNotFound("Teklif");
|
||||||
const value = parseDomainInput(proposalUpdateSchema, input);
|
const { translations, ...rawInput } = input as Record<string, unknown>;
|
||||||
|
const defaultLocale = this.contentTranslations.getLocalizationContext(actor).defaultLocale;
|
||||||
|
const value = parseDomainInput(
|
||||||
|
proposalUpdateSchema,
|
||||||
|
translations ? projectBaseFromTranslations("proposal", rawInput, translations as ContentTranslationInput, defaultLocale) : input,
|
||||||
|
);
|
||||||
this.assertTaskRelations(scope, { ...current, ...value });
|
this.assertTaskRelations(scope, { ...current, ...value });
|
||||||
return this.repositories.business.updateProposal(scope, proposalId, value)
|
const proposal = this.repositories.business.updateProposal(scope, proposalId, value)
|
||||||
?? this.throwNotFound("Teklif");
|
?? this.throwNotFound("Teklif");
|
||||||
|
this.contentTranslations.upsertEntityTranslations("proposal", proposal.id, translations as ContentTranslationInput | undefined);
|
||||||
|
return proposal;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteProposal(actor: DomainActor, proposalId: string) {
|
deleteProposal(actor: DomainActor, proposalId: string) {
|
||||||
return this.repositories.business.removeProposal(requireOwnerScope(actor), proposalId)
|
const proposal = this.repositories.business.removeProposal(requireOwnerScope(actor), proposalId)
|
||||||
?? this.throwNotFound("Teklif");
|
?? this.throwNotFound("Teklif");
|
||||||
|
this.contentTranslations.deleteEntityTranslations("proposal", proposalId);
|
||||||
|
return proposal;
|
||||||
}
|
}
|
||||||
|
|
||||||
createContract(actor: DomainActor, input: unknown) {
|
createContract(actor: DomainActor, input: unknown) {
|
||||||
@@ -672,8 +725,15 @@ export class DomainService {
|
|||||||
|
|
||||||
createSubscription(actor: DomainActor, input: unknown) {
|
createSubscription(actor: DomainActor, input: unknown) {
|
||||||
const scope = requireOwnerScope(actor);
|
const scope = requireOwnerScope(actor);
|
||||||
const value = parseDomainInput(subscriptionCreateSchema, input);
|
const { translations, ...rawInput } = input as Record<string, unknown>;
|
||||||
return this.repositories.business.createSubscription(scope, { ...value, id: value.id ?? this.id() });
|
const defaultLocale = this.contentTranslations.getLocalizationContext(actor).defaultLocale;
|
||||||
|
const value = parseDomainInput(
|
||||||
|
subscriptionCreateSchema,
|
||||||
|
translations ? projectBaseFromTranslations("subscription", rawInput, translations as ContentTranslationInput, defaultLocale) : input,
|
||||||
|
);
|
||||||
|
const subscription = this.repositories.business.createSubscription(scope, { ...value, id: value.id ?? this.id() });
|
||||||
|
this.contentTranslations.upsertEntityTranslations("subscription", subscription.id, translations as ContentTranslationInput | undefined);
|
||||||
|
return subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
listSubscriptions(actor: DomainActor) {
|
listSubscriptions(actor: DomainActor) {
|
||||||
@@ -687,17 +747,26 @@ export class DomainService {
|
|||||||
|
|
||||||
updateSubscription(actor: DomainActor, subscriptionId: string, input: unknown) {
|
updateSubscription(actor: DomainActor, subscriptionId: string, input: unknown) {
|
||||||
const scope = requireOwnerScope(actor);
|
const scope = requireOwnerScope(actor);
|
||||||
const value = parseDomainInput(subscriptionUpdateSchema, input);
|
const { translations, ...rawInput } = input as Record<string, unknown>;
|
||||||
|
const defaultLocale = this.contentTranslations.getLocalizationContext(actor).defaultLocale;
|
||||||
|
const value = parseDomainInput(
|
||||||
|
subscriptionUpdateSchema,
|
||||||
|
translations ? projectBaseFromTranslations("subscription", rawInput, translations as ContentTranslationInput, defaultLocale) : input,
|
||||||
|
);
|
||||||
if (!this.repositories.business.getSubscription(scope, subscriptionId)) {
|
if (!this.repositories.business.getSubscription(scope, subscriptionId)) {
|
||||||
throw notFound("Abonelik");
|
throw notFound("Abonelik");
|
||||||
}
|
}
|
||||||
return this.repositories.business.updateSubscription(scope, subscriptionId, value)
|
const subscription = this.repositories.business.updateSubscription(scope, subscriptionId, value)
|
||||||
?? this.throwNotFound("Abonelik");
|
?? this.throwNotFound("Abonelik");
|
||||||
|
this.contentTranslations.upsertEntityTranslations("subscription", subscription.id, translations as ContentTranslationInput | undefined);
|
||||||
|
return subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteSubscription(actor: DomainActor, subscriptionId: string) {
|
deleteSubscription(actor: DomainActor, subscriptionId: string) {
|
||||||
return this.repositories.business.removeSubscription(requireOwnerScope(actor), subscriptionId)
|
const subscription = this.repositories.business.removeSubscription(requireOwnerScope(actor), subscriptionId)
|
||||||
?? this.throwNotFound("Abonelik");
|
?? this.throwNotFound("Abonelik");
|
||||||
|
this.contentTranslations.deleteEntityTranslations("subscription", subscriptionId);
|
||||||
|
return subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
private requireOwnedClient(scope: OwnerScope, clientId: string) {
|
private requireOwnedClient(scope: OwnerScope, clientId: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user