1 parent
f0f36c4f48
commit
40d579cdb9
30 files changed
+115
-14
No files matched your search
@@ -12,6 +12,7 @@ export class IssueWithUsersDto {
|
||||
assignee: UserDto | null;
|
||||
reporter: UserDto;
|
||||
projectId: string;
|
||||
dueDate: Date | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -8,6 +8,7 @@ export class IssueDto {
|
||||
assigneeId: string | null;
|
||||
reporterId: string;
|
||||
projectId: string;
|
||||
dueDate: Date | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ export class IssueApplicationMapper {
|
||||
assigneeId: issue.assignee,
|
||||
reporterId: issue.reporter,
|
||||
projectId: issue.projectId,
|
||||
dueDate: issue.dueDate,
|
||||
createdAt: issue.createdAt,
|
||||
updatedAt: issue.updatedAt,
|
||||
};
|
||||
@@ -39,6 +40,7 @@ export class IssueApplicationMapper {
|
||||
assignee: issue.assignee ? (usersById.get(issue.assignee) ?? null) : null,
|
||||
reporter,
|
||||
projectId: issue.projectId,
|
||||
dueDate: issue.dueDate,
|
||||
createdAt: issue.createdAt,
|
||||
updatedAt: issue.updatedAt,
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@ const buildIssue = (overrides: Partial<{ assignee: string | null; reporter: stri
|
||||
assignee: 'assignee' in overrides ? (overrides.assignee ?? null) : 'user-2',
|
||||
reporter: overrides.reporter ?? 'user-1',
|
||||
projectId: 'project-1',
|
||||
dueDate: null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
@@ -7,5 +7,6 @@ export class CreateIssueCommand {
|
||||
public readonly content?: string,
|
||||
public readonly priority?: number,
|
||||
public readonly assignee?: string,
|
||||
public readonly dueDate?: Date,
|
||||
) {}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ describe('CreateIssueUseCase', () => {
|
||||
assignee: issue.assignee,
|
||||
reporter: issue.reporter,
|
||||
projectId: issue.projectId,
|
||||
dueDate: issue.dueDate,
|
||||
createdAt: issue.createdAt,
|
||||
updatedAt: issue.updatedAt,
|
||||
}),
|
||||
@@ -104,6 +105,7 @@ describe('CreateIssueUseCase', () => {
|
||||
assignee: issue.assignee,
|
||||
reporter: issue.reporter,
|
||||
projectId: issue.projectId,
|
||||
dueDate: issue.dueDate,
|
||||
createdAt: issue.createdAt,
|
||||
updatedAt: issue.updatedAt,
|
||||
}),
|
||||
|
||||
@@ -31,6 +31,7 @@ export class CreateIssueUseCase {
|
||||
assignee: command.assignee,
|
||||
reporter: command.reporter,
|
||||
projectId: command.projectId,
|
||||
dueDate: command.dueDate,
|
||||
});
|
||||
|
||||
const issue = await this.issueRepository.create(draft);
|
||||
|
||||
@@ -17,6 +17,7 @@ const buildIssue = () =>
|
||||
assignee: null,
|
||||
reporter: 'user-1',
|
||||
projectId: 'project-1',
|
||||
dueDate: null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
+1
@@ -18,6 +18,7 @@ const buildIssue = () =>
|
||||
assignee: 'user-2',
|
||||
reporter: 'user-1',
|
||||
projectId: 'project-1',
|
||||
dueDate: null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
@@ -18,6 +18,7 @@ const buildIssue = () =>
|
||||
assignee: 'user-2',
|
||||
reporter: 'user-1',
|
||||
projectId: 'project-1',
|
||||
dueDate: null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ const buildIssue = (id: number) =>
|
||||
assignee: null,
|
||||
reporter: 'user-1',
|
||||
projectId: 'project-1',
|
||||
dueDate: null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
@@ -7,5 +7,6 @@ export class UpdateIssueCommand {
|
||||
public readonly status?: string,
|
||||
public readonly priority?: number,
|
||||
public readonly assignee?: string | null,
|
||||
public readonly dueDate?: Date | null,
|
||||
) {}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ const buildIssue = () =>
|
||||
assignee: null,
|
||||
reporter: 'user-1',
|
||||
projectId: 'project-1',
|
||||
dueDate: null,
|
||||
createdAt: new Date('2026-01-01T00:00:00.000Z'),
|
||||
updatedAt: new Date('2026-01-01T00:00:00.000Z'),
|
||||
});
|
||||
|
||||
@@ -53,6 +53,10 @@ export class UpdateIssueUseCase {
|
||||
}
|
||||
}
|
||||
|
||||
if (command.dueDate !== undefined) {
|
||||
issue.updateDueDate(command.dueDate);
|
||||
}
|
||||
|
||||
await this.issueRepository.update(issue);
|
||||
const dto = await this.issueUserExpander.expand(issue);
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ describe('Issue', () => {
|
||||
assignee: 'user-3',
|
||||
reporter: 'user-1',
|
||||
projectId: 'project-1',
|
||||
dueDate: null,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
@@ -94,6 +95,7 @@ describe('Issue', () => {
|
||||
assignee: null,
|
||||
reporter: 'user-1',
|
||||
projectId: 'project-1',
|
||||
dueDate: null,
|
||||
createdAt: new Date('2026-01-01T00:00:00.000Z'),
|
||||
updatedAt: new Date('2026-01-01T00:00:00.000Z'),
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@ interface IssueProps {
|
||||
assignee: string | null;
|
||||
reporter: string;
|
||||
projectId: string;
|
||||
dueDate: Date | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -40,6 +41,7 @@ export class Issue {
|
||||
assignee?: string | null;
|
||||
reporter: string;
|
||||
projectId: string;
|
||||
dueDate?: Date | null;
|
||||
}): Issue {
|
||||
const issue = new Issue({
|
||||
id: null,
|
||||
@@ -51,6 +53,7 @@ export class Issue {
|
||||
assignee: params.assignee ?? null,
|
||||
reporter: params.reporter,
|
||||
projectId: params.projectId,
|
||||
dueDate: params.dueDate ?? null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
@@ -71,6 +74,7 @@ export class Issue {
|
||||
assignee: string | null;
|
||||
reporter: string;
|
||||
projectId: string;
|
||||
dueDate: Date | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}): Issue {
|
||||
@@ -84,6 +88,7 @@ export class Issue {
|
||||
assignee: props.assignee,
|
||||
reporter: props.reporter,
|
||||
projectId: props.projectId,
|
||||
dueDate: props.dueDate,
|
||||
createdAt: props.createdAt,
|
||||
updatedAt: props.updatedAt,
|
||||
});
|
||||
@@ -125,6 +130,10 @@ export class Issue {
|
||||
return this.props.projectId;
|
||||
}
|
||||
|
||||
get dueDate(): Date | null {
|
||||
return this.props.dueDate;
|
||||
}
|
||||
|
||||
get createdAt(): Date {
|
||||
return this.props.createdAt;
|
||||
}
|
||||
@@ -163,6 +172,11 @@ export class Issue {
|
||||
this.touch();
|
||||
}
|
||||
|
||||
updateDueDate(dueDate: Date | null): void {
|
||||
this.props.dueDate = dueDate;
|
||||
this.touch();
|
||||
}
|
||||
|
||||
private touch(): void {
|
||||
this.props.updatedAt = new Date();
|
||||
this.addDomainEvent(new IssueUpdatedEvent(this.key));
|
||||
|
||||
@@ -13,6 +13,7 @@ describe('IssuePrismaMapper', () => {
|
||||
assigneeId: 'user-2',
|
||||
reporterId: 'user-1',
|
||||
projectId: 'project-1',
|
||||
dueDate: null,
|
||||
createdAt: new Date('2026-01-01T00:00:00.000Z'),
|
||||
updatedAt: new Date('2026-01-02T00:00:00.000Z'),
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ export class IssuePrismaMapper {
|
||||
assignee: record.assigneeId,
|
||||
reporter: record.reporterId,
|
||||
projectId: record.projectId,
|
||||
dueDate: record.dueDate,
|
||||
createdAt: record.createdAt,
|
||||
updatedAt: record.updatedAt,
|
||||
});
|
||||
@@ -29,6 +30,7 @@ export class IssuePrismaMapper {
|
||||
assigneeId: issue.assignee,
|
||||
reporterId: issue.reporter,
|
||||
projectId: issue.projectId,
|
||||
dueDate: issue.dueDate,
|
||||
createdAt: issue.createdAt,
|
||||
updatedAt: issue.updatedAt,
|
||||
};
|
||||
@@ -41,6 +43,7 @@ export class IssuePrismaMapper {
|
||||
status: issue.status,
|
||||
priority: issue.priority,
|
||||
assigneeId: issue.assignee,
|
||||
dueDate: issue.dueDate,
|
||||
updatedAt: issue.updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ export class IssueController {
|
||||
dto.content,
|
||||
dto.priority,
|
||||
dto.assignee,
|
||||
dto.dueDate !== undefined ? new Date(dto.dueDate) : undefined,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -132,7 +133,16 @@ export class IssueController {
|
||||
) {
|
||||
return this.handleErrors(() =>
|
||||
this.updateIssueUseCase.execute(
|
||||
new UpdateIssueCommand(id, session.user.id, dto.title, dto.content, dto.status, dto.priority, dto.assignee),
|
||||
new UpdateIssueCommand(
|
||||
id,
|
||||
session.user.id,
|
||||
dto.title,
|
||||
dto.content,
|
||||
dto.status,
|
||||
dto.priority,
|
||||
dto.assignee,
|
||||
dto.dueDate === undefined ? undefined : dto.dueDate === null ? null : new Date(dto.dueDate),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IsInt, IsNotEmpty, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
|
||||
import { IsDateString, IsInt, IsNotEmpty, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
|
||||
|
||||
export class CreateIssueRequestDto {
|
||||
@IsString()
|
||||
@@ -27,4 +27,8 @@ export class CreateIssueRequestDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
assignee?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
dueDate?: string;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IsIn, IsInt, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
|
||||
import { IsDateString, IsIn, IsInt, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
|
||||
import { ISSUE_STATUSES } from '../../domain/value-objects/issue-status.vo.js';
|
||||
|
||||
export class UpdateIssueRequestDto {
|
||||
@@ -24,4 +24,8 @@ export class UpdateIssueRequestDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
assignee?: string | null;
|
||||
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
dueDate?: string | null;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Field, InputType, Int } from '@nestjs/graphql';
|
||||
import { IsInt, IsNotEmpty, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
|
||||
import { IsDate, IsInt, IsNotEmpty, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
|
||||
|
||||
@InputType()
|
||||
export class CreateIssueInput {
|
||||
@@ -35,4 +35,9 @@ export class CreateIssueInput {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
assignee?: string;
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
dueDate?: Date;
|
||||
}
|
||||
@@ -36,6 +36,9 @@ export class IssueDetailType {
|
||||
@Field()
|
||||
projectId: string;
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
dueDate: Date | null;
|
||||
|
||||
@Field(() => Date)
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ export class IssueType {
|
||||
@Field()
|
||||
projectId: string;
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
dueDate: Date | null;
|
||||
|
||||
@Field(() => Date)
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Field, InputType, Int } from '@nestjs/graphql';
|
||||
import { IsIn, IsInt, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
|
||||
import { IsDate, IsIn, IsInt, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
|
||||
import { ISSUE_STATUSES } from '../../domain/value-objects/issue-status.vo.js';
|
||||
|
||||
@InputType()
|
||||
@@ -31,4 +31,9 @@ export class UpdateIssueInput {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
assignee?: string | null;
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
dueDate?: Date | null;
|
||||
}
|
||||
@@ -66,6 +66,7 @@ export class IssueResolver {
|
||||
input.content,
|
||||
input.priority,
|
||||
input.assignee,
|
||||
input.dueDate,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -87,6 +88,7 @@ export class IssueResolver {
|
||||
input.status,
|
||||
input.priority,
|
||||
input.assignee,
|
||||
input.dueDate,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user