mirror of
https://github.com/docmost/docmost.git
synced 2026-05-25 12:04:35 +08:00
WIP
This commit is contained in:
@@ -6,8 +6,14 @@ import {
|
|||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
IsUUID,
|
IsUUID,
|
||||||
|
Matches,
|
||||||
MaxLength,
|
MaxLength,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
|
import { Transform } from 'class-transformer';
|
||||||
|
|
||||||
|
function normalizeLabel(name: string): string {
|
||||||
|
return name.trim().replace(/\s+/g, '-').toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
export class AddLabelsDto {
|
export class AddLabelsDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@@ -19,7 +25,14 @@ export class AddLabelsDto {
|
|||||||
@ArrayMaxSize(25)
|
@ArrayMaxSize(25)
|
||||||
@IsString({ each: true })
|
@IsString({ each: true })
|
||||||
@IsNotEmpty({ each: true })
|
@IsNotEmpty({ each: true })
|
||||||
|
@Transform(({ value }) =>
|
||||||
|
Array.isArray(value) ? value.map(normalizeLabel) : value,
|
||||||
|
)
|
||||||
@MaxLength(100, { each: true })
|
@MaxLength(100, { each: true })
|
||||||
|
@Matches(/^[a-z0-9_~-]+$/, {
|
||||||
|
each: true,
|
||||||
|
message: 'Label names can only contain letters, numbers, hyphens, underscores, and tildes',
|
||||||
|
})
|
||||||
names: string[];
|
names: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ export async function up(db: Kysely<any>): Promise<void> {
|
|||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
await db.schema
|
await db.schema
|
||||||
.createIndex('labels_workspace_id_lower_name_unique')
|
.createIndex('labels_workspace_id_name_unique')
|
||||||
.on('labels')
|
.on('labels')
|
||||||
.expression(sql`workspace_id, LOWER(name)`)
|
.columns(['workspace_id', 'name'])
|
||||||
.unique()
|
.unique()
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { InjectKysely } from 'nestjs-kysely';
|
|||||||
import { KyselyDB, KyselyTransaction } from '../../types/kysely.types';
|
import { KyselyDB, KyselyTransaction } from '../../types/kysely.types';
|
||||||
import { Label } from '@docmost/db/types/entity.types';
|
import { Label } from '@docmost/db/types/entity.types';
|
||||||
import { dbOrTx } from '@docmost/db/utils';
|
import { dbOrTx } from '@docmost/db/utils';
|
||||||
import { sql } from 'kysely';
|
|
||||||
import { SpaceMemberRepo } from '@docmost/db/repos/space/space-member.repo';
|
import { SpaceMemberRepo } from '@docmost/db/repos/space/space-member.repo';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -34,7 +33,7 @@ export class LabelRepo {
|
|||||||
return db
|
return db
|
||||||
.selectFrom('labels')
|
.selectFrom('labels')
|
||||||
.selectAll()
|
.selectAll()
|
||||||
.where(sql`LOWER(name)`, '=', name.toLowerCase())
|
.where('name', '=', name.toLowerCase())
|
||||||
.where('workspaceId', '=', workspaceId)
|
.where('workspaceId', '=', workspaceId)
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
}
|
}
|
||||||
@@ -45,15 +44,13 @@ export class LabelRepo {
|
|||||||
trx?: KyselyTransaction,
|
trx?: KyselyTransaction,
|
||||||
): Promise<Label> {
|
): Promise<Label> {
|
||||||
const db = dbOrTx(this.db, trx);
|
const db = dbOrTx(this.db, trx);
|
||||||
const trimmedName = name.trim();
|
const normalizedName = name.trim().toLowerCase();
|
||||||
|
|
||||||
const result = await db
|
const result = await db
|
||||||
.insertInto('labels')
|
.insertInto('labels')
|
||||||
.values({ name: trimmedName, workspaceId })
|
.values({ name: normalizedName, workspaceId })
|
||||||
.onConflict((oc) =>
|
.onConflict((oc) =>
|
||||||
oc
|
oc.columns(['name', 'workspaceId']).doNothing(),
|
||||||
.expression(sql`workspace_id, LOWER(name)`)
|
|
||||||
.doNothing(),
|
|
||||||
)
|
)
|
||||||
.returningAll()
|
.returningAll()
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
@@ -62,7 +59,7 @@ export class LabelRepo {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.findByNameAndWorkspace(trimmedName, workspaceId, trx);
|
return this.findByNameAndWorkspace(normalizedName, workspaceId, trx);
|
||||||
}
|
}
|
||||||
|
|
||||||
async findLabelsByPageId(pageId: string): Promise<Label[]> {
|
async findLabelsByPageId(pageId: string): Promise<Label[]> {
|
||||||
|
|||||||
Reference in New Issue
Block a user