Skip to content

Commit 10af22f

Browse files
committed
[add] test cases of Hackathon controller
[fix] some detail bugs of User, Hackathon & Staff
1 parent e5b9bbc commit 10af22f

File tree

8 files changed

+254
-62
lines changed

8 files changed

+254
-62
lines changed

source/controller/Hackathon.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import {
1111
OnNull,
1212
OnUndefined,
1313
Param,
14-
Patch,
1514
Post,
15+
Put,
1616
QueryParams
1717
} from 'routing-controllers';
1818
import { ResponseSchema } from 'routing-controllers-openapi';
@@ -21,6 +21,7 @@ import {
2121
dataSource,
2222
Hackathon,
2323
HackathonFilter,
24+
HackathonInput,
2425
HackathonListChunk,
2526
StaffType,
2627
User
@@ -37,7 +38,7 @@ const store = dataSource.getRepository(Hackathon);
3738
export class HackathonController {
3839
static async ensureAdmin(userId: number, hackathonName: string) {
3940
if (
40-
!(await StaffController.isAdmin(userId, hackathonName)) ||
41+
!(await StaffController.isAdmin(userId, hackathonName)) &&
4142
!(await PlatformAdminController.isAdmin(userId))
4243
)
4344
throw new ForbiddenError();
@@ -53,13 +54,13 @@ export class HackathonController {
5354
throw new ForbiddenError();
5455
}
5556

56-
@Patch('/:name')
57+
@Put('/:name')
5758
@Authorized()
5859
@ResponseSchema(Hackathon)
5960
async updateOne(
6061
@CurrentUser() updatedBy: User,
6162
@Param('name') name: string,
62-
@Body() newData: Hackathon
63+
@Body() newData: HackathonInput
6364
) {
6465
const old = await store.findOne({
6566
where: { name },
@@ -105,10 +106,8 @@ export class HackathonController {
105106
@CurrentUser() deletedBy: User,
106107
@Param('name') name: string
107108
) {
108-
const old = await store.findOne({
109-
where: { name },
110-
relations: ['createdBy']
111-
});
109+
const old = await store.findOneBy({ name });
110+
112111
if (!old) throw new NotFoundError();
113112

114113
await HackathonController.ensureAdmin(deletedBy.id, name);
@@ -125,7 +124,7 @@ export class HackathonController {
125124
@ResponseSchema(Hackathon)
126125
async createOne(
127126
@CurrentUser() createdBy: User,
128-
@Body() hackathon: Hackathon
127+
@Body() hackathon: HackathonInput
129128
) {
130129
const saved = await store.save({ ...hackathon, createdBy });
131130

source/controller/Staff.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export class StaffController {
161161
});
162162
const [list, count] = await store.findAndCount({
163163
where,
164-
relations: ['user'],
164+
relations: ['hackathon', 'user'],
165165
skip: pageSize * (pageIndex - 1),
166166
take: pageSize
167167
});

source/controller/User.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export class UserController {
112112
});
113113
await ActivityLogController.logUpdate(updatedBy, 'User', id);
114114

115-
return saved;
115+
return UserController.sign(saved);
116116
}
117117

118118
@Get('/:id')

source/model/Hackathon.ts

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { Column, Entity, Index, ManyToOne, VirtualColumn } from 'typeorm';
1313

1414
import { BaseFilter, InputData, ListChunk, Media } from './Base';
15-
import { UserBase } from './User';
15+
import { UserBase, UserInputData } from './User';
1616

1717
export enum HackathonStatus {
1818
Planning = 'planning',
@@ -23,94 +23,68 @@ export enum HackathonStatus {
2323

2424
@Entity()
2525
export class Hackathon extends UserBase {
26-
@IsString()
2726
@Column()
2827
@Index({ unique: true })
2928
name: string;
3029

31-
@IsString()
3230
@Column({ unique: true })
3331
displayName: string;
3432

35-
@IsString()
3633
@Column()
3734
ribbon: string;
3835

39-
@IsString({ each: true })
4036
@Column('simple-json')
4137
tags: string[];
4238

43-
@IsString()
4439
@Column()
4540
summary: string;
4641

47-
@IsString()
4842
@Column('text')
4943
detail: string;
5044

51-
@IsString()
5245
@Column()
5346
location: string;
5447

55-
@Type(() => Media)
56-
@ValidateNested({ each: true })
5748
@Column('simple-json')
5849
banners: Media[];
5950

60-
@IsEnum(HackathonStatus)
61-
@IsOptional()
6251
@Column({
6352
type: 'simple-enum',
6453
enum: HackathonStatus,
6554
default: HackathonStatus.Planning
6655
})
6756
status?: HackathonStatus = HackathonStatus.Planning;
6857

69-
@IsBoolean()
70-
@IsOptional()
7158
@Column('boolean', { default: false })
7259
readOnly?: boolean = false;
7360

74-
@IsBoolean()
75-
@IsOptional()
7661
@Column('boolean', { default: true })
7762
autoApprove?: boolean = true;
7863

79-
@IsInt()
80-
@Min(0)
81-
@IsOptional()
8264
@Column({ nullable: true })
8365
maxEnrollment?: number;
8466

85-
@IsInt()
86-
@Min(0)
8767
@VirtualColumn({
8868
query: alias =>
8969
`SELECT COUNT(*) FROM "enrollment" WHERE "enrollment"."hackathonId" = ${alias}.id`
9070
})
9171
enrollment: number;
9272

93-
@IsDateString()
9473
@Column('date')
9574
eventStartedAt: string;
9675

97-
@IsDateString()
9876
@Column('date')
9977
eventEndedAt: string;
10078

101-
@IsDateString()
10279
@Column('date')
10380
enrollmentStartedAt: string;
10481

105-
@IsDateString()
10682
@Column('date')
10783
enrollmentEndedAt: string;
10884

109-
@IsDateString()
11085
@Column('date')
11186
judgeStartedAt: string;
11287

113-
@IsDateString()
11488
@Column('date')
11589
judgeEndedAt: string;
11690

@@ -129,14 +103,77 @@ export abstract class HackathonBase extends UserBase {
129103
hackathon: Hackathon;
130104
}
131105

106+
export class HackathonInput implements UserInputData<Hackathon> {
107+
@IsString()
108+
name: string;
109+
110+
@IsString()
111+
displayName: string;
112+
113+
@IsString()
114+
ribbon: string;
115+
116+
@IsString({ each: true })
117+
tags: string[];
118+
119+
@IsString()
120+
summary: string;
121+
122+
@IsString()
123+
detail: string;
124+
125+
@IsString()
126+
location: string;
127+
128+
@Type(() => Media)
129+
@ValidateNested({ each: true })
130+
banners: Media[];
131+
132+
@IsEnum(HackathonStatus)
133+
@IsOptional()
134+
status?: HackathonStatus = HackathonStatus.Planning;
135+
136+
@IsBoolean()
137+
@IsOptional()
138+
readOnly?: boolean = false;
139+
140+
@IsBoolean()
141+
@IsOptional()
142+
autoApprove?: boolean = true;
143+
144+
@IsInt()
145+
@Min(0)
146+
@IsOptional()
147+
maxEnrollment?: number;
148+
149+
@IsInt()
150+
@Min(0)
151+
@IsOptional()
152+
enrollment: number;
153+
154+
@IsDateString()
155+
eventStartedAt: string;
156+
157+
@IsDateString()
158+
eventEndedAt: string;
159+
160+
@IsDateString()
161+
enrollmentStartedAt: string;
162+
163+
@IsDateString()
164+
enrollmentEndedAt: string;
165+
166+
@IsDateString()
167+
judgeStartedAt: string;
168+
169+
@IsDateString()
170+
judgeEndedAt: string;
171+
}
172+
132173
export class HackathonFilter
133174
extends BaseFilter
134175
implements Partial<InputData<Hackathon>>
135176
{
136-
@IsString()
137-
@IsOptional()
138-
name?: string;
139-
140177
@IsEnum(HackathonStatus)
141178
@IsOptional()
142179
status?: HackathonStatus;

source/utility.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FindOptionsWhere, Like } from 'typeorm';
1+
import { FindOptionsWhere, ILike } from 'typeorm';
22

33
import { Base } from './model';
44

@@ -18,5 +18,5 @@ export const searchConditionOf = <T extends Base>(
1818
filter?: FindOptionsWhere<T>
1919
) =>
2020
keywords
21-
? keys.map(key => ({ [key]: Like(`%${keywords}%`), ...filter }))
21+
? keys.map(key => ({ [key]: ILike(`%${keywords}%`), ...filter }))
2222
: filter;

0 commit comments

Comments
 (0)