tonightpass 0.0.108 → 0.0.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +73 -10
- package/dist/index.d.ts +73 -10
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/rest/dtos/index.ts +1 -0
- package/src/rest/dtos/locations/create-location.dto.ts +68 -0
- package/src/rest/dtos/locations/index.ts +2 -0
- package/src/rest/dtos/locations/update-location.dto.ts +37 -0
- package/src/rest/dtos/organizations/events/create-organization-event.dto.ts +52 -5
- package/src/rest/dtos/organizations/events/tickets/create-organization-event-ticket.dto.ts +12 -1
- package/src/rest/dtos/organizations/events/tickets/update-organization-event-ticket.dto.ts +69 -2
- package/src/rest/dtos/organizations/events/update-organization-event.dto.ts +87 -2
- package/src/rest/dtos/users/create-user.dto.ts +6 -0
- package/src/rest/dtos/users/sign-in-user.dto.ts +7 -0
- package/src/rest/types/index.ts +4 -0
- package/src/rest/types/locations/index.ts +8 -0
- package/src/rest/types/organizations/events/index.ts +6 -4
- package/tests/dtos/index.ts +157 -0
- package/tests/index.ts +2 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Type } from "class-transformer";
|
|
2
|
+
import {
|
|
3
|
+
IsArray,
|
|
4
|
+
IsNotEmpty,
|
|
5
|
+
IsNumber,
|
|
6
|
+
IsOptional,
|
|
7
|
+
IsString,
|
|
8
|
+
Length,
|
|
9
|
+
ValidateNested,
|
|
10
|
+
} from "class-validator";
|
|
11
|
+
|
|
12
|
+
import { GeoPoint, Location } from "../../types";
|
|
13
|
+
|
|
14
|
+
export class GeoPointDto implements GeoPoint {
|
|
15
|
+
@IsString()
|
|
16
|
+
@IsNotEmpty()
|
|
17
|
+
type: "Point";
|
|
18
|
+
|
|
19
|
+
@IsArray()
|
|
20
|
+
@IsNotEmpty()
|
|
21
|
+
@Length(2, 2)
|
|
22
|
+
@IsNumber({}, { each: true })
|
|
23
|
+
coordinates: [number, number];
|
|
24
|
+
|
|
25
|
+
constructor() {
|
|
26
|
+
this.type = "Point";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@ValidateNested()
|
|
30
|
+
public validate(): boolean {
|
|
31
|
+
const [longitude, latitude] = this.coordinates;
|
|
32
|
+
return (
|
|
33
|
+
latitude >= -90 && latitude <= 90 && longitude >= -180 && longitude <= 180
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class CreateLocationDto implements Location {
|
|
39
|
+
@IsOptional()
|
|
40
|
+
@IsString()
|
|
41
|
+
@Length(1, 128)
|
|
42
|
+
name?: string;
|
|
43
|
+
|
|
44
|
+
@IsString()
|
|
45
|
+
@IsNotEmpty()
|
|
46
|
+
@Length(1, 256)
|
|
47
|
+
address: string;
|
|
48
|
+
|
|
49
|
+
@IsString()
|
|
50
|
+
@IsNotEmpty()
|
|
51
|
+
@Length(1, 32)
|
|
52
|
+
zipCode: string;
|
|
53
|
+
|
|
54
|
+
@IsString()
|
|
55
|
+
@IsNotEmpty()
|
|
56
|
+
@Length(1, 128)
|
|
57
|
+
city: string;
|
|
58
|
+
|
|
59
|
+
@IsString()
|
|
60
|
+
@IsNotEmpty()
|
|
61
|
+
@Length(1, 128)
|
|
62
|
+
country: string;
|
|
63
|
+
|
|
64
|
+
@ValidateNested()
|
|
65
|
+
@Type(() => GeoPointDto)
|
|
66
|
+
@IsNotEmpty()
|
|
67
|
+
geometry: GeoPointDto;
|
|
68
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Type } from "class-transformer";
|
|
2
|
+
import { IsOptional, IsString, Length, ValidateNested } from "class-validator";
|
|
3
|
+
|
|
4
|
+
import { GeoPointDto } from "./create-location.dto";
|
|
5
|
+
import { Location } from "../../types";
|
|
6
|
+
|
|
7
|
+
export class UpdateLocationDto implements Partial<Location> {
|
|
8
|
+
@IsOptional()
|
|
9
|
+
@IsString()
|
|
10
|
+
@Length(1, 128)
|
|
11
|
+
name?: string;
|
|
12
|
+
|
|
13
|
+
@IsOptional()
|
|
14
|
+
@IsString()
|
|
15
|
+
@Length(1, 256)
|
|
16
|
+
address?: string;
|
|
17
|
+
|
|
18
|
+
@IsOptional()
|
|
19
|
+
@IsString()
|
|
20
|
+
@Length(1, 32)
|
|
21
|
+
zipCode?: string;
|
|
22
|
+
|
|
23
|
+
@IsOptional()
|
|
24
|
+
@IsString()
|
|
25
|
+
@Length(1, 128)
|
|
26
|
+
city?: string;
|
|
27
|
+
|
|
28
|
+
@IsOptional()
|
|
29
|
+
@IsString()
|
|
30
|
+
@Length(1, 128)
|
|
31
|
+
country?: string;
|
|
32
|
+
|
|
33
|
+
@IsOptional()
|
|
34
|
+
@ValidateNested()
|
|
35
|
+
@Type(() => GeoPointDto)
|
|
36
|
+
geometry?: GeoPointDto;
|
|
37
|
+
}
|
|
@@ -1,23 +1,46 @@
|
|
|
1
|
+
import { Type } from "class-transformer";
|
|
1
2
|
import {
|
|
3
|
+
IsArray,
|
|
2
4
|
IsDateString,
|
|
3
5
|
IsEnum,
|
|
4
6
|
IsLowercase,
|
|
7
|
+
IsNotEmpty,
|
|
8
|
+
IsObject,
|
|
5
9
|
IsOptional,
|
|
6
10
|
IsString,
|
|
11
|
+
IsUrl,
|
|
7
12
|
Length,
|
|
8
13
|
Matches,
|
|
14
|
+
ValidateNested,
|
|
9
15
|
} from "class-validator";
|
|
10
16
|
|
|
11
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
CreateOrganizationEventTicketDto,
|
|
19
|
+
CreateOrganizationEventTicketInput,
|
|
20
|
+
} from "./tickets";
|
|
12
21
|
import { REGEX } from "../../../../constants";
|
|
13
22
|
import {
|
|
14
|
-
Location,
|
|
15
23
|
OrganizationEventType,
|
|
16
24
|
OrganizationEventVisibilityType,
|
|
25
|
+
OrganizationEvent,
|
|
26
|
+
ExcludeBase,
|
|
17
27
|
} from "../../../types";
|
|
28
|
+
import { CreateLocationDto } from "../../locations/create-location.dto";
|
|
18
29
|
|
|
19
|
-
export
|
|
30
|
+
export type CreateOrganizationEventInput = Omit<
|
|
31
|
+
ExcludeBase<OrganizationEvent>,
|
|
32
|
+
"slug" | "styles" | "tickets" | "organization"
|
|
33
|
+
> & {
|
|
34
|
+
slug?: string;
|
|
35
|
+
styles: string[];
|
|
36
|
+
tickets: CreateOrganizationEventTicketInput[];
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export class CreateOrganizationEventDto
|
|
40
|
+
implements CreateOrganizationEventInput
|
|
41
|
+
{
|
|
20
42
|
@IsString()
|
|
43
|
+
@IsNotEmpty()
|
|
21
44
|
@Length(1, 64)
|
|
22
45
|
title: string;
|
|
23
46
|
|
|
@@ -29,24 +52,48 @@ export class CreateOrganizationEventDto {
|
|
|
29
52
|
slug?: string;
|
|
30
53
|
|
|
31
54
|
@IsString()
|
|
55
|
+
@IsNotEmpty()
|
|
32
56
|
@Length(16, 2048)
|
|
33
57
|
description: string;
|
|
34
58
|
|
|
35
59
|
@IsEnum(OrganizationEventType)
|
|
60
|
+
@IsNotEmpty()
|
|
36
61
|
type: OrganizationEventType;
|
|
37
62
|
|
|
38
63
|
@IsEnum(OrganizationEventVisibilityType)
|
|
64
|
+
@IsNotEmpty()
|
|
39
65
|
visibility: OrganizationEventVisibilityType;
|
|
40
66
|
|
|
67
|
+
@IsArray()
|
|
68
|
+
@IsUrl({}, { each: true })
|
|
41
69
|
flyers: string[];
|
|
70
|
+
|
|
71
|
+
@IsArray()
|
|
72
|
+
@IsUrl({}, { each: true })
|
|
42
73
|
trailers: string[];
|
|
43
|
-
|
|
74
|
+
|
|
75
|
+
@IsObject()
|
|
76
|
+
@ValidateNested()
|
|
77
|
+
@Type(() => CreateLocationDto)
|
|
78
|
+
@IsNotEmpty()
|
|
79
|
+
location: CreateLocationDto;
|
|
80
|
+
|
|
81
|
+
@IsArray()
|
|
82
|
+
@ValidateNested({ each: true })
|
|
83
|
+
@Type(() => CreateOrganizationEventTicketDto)
|
|
84
|
+
@IsNotEmpty()
|
|
44
85
|
tickets: CreateOrganizationEventTicketDto[];
|
|
45
|
-
|
|
86
|
+
|
|
87
|
+
@IsArray()
|
|
88
|
+
@IsString({ each: true })
|
|
89
|
+
@IsNotEmpty()
|
|
90
|
+
styles: string[]; // Array of style IDs
|
|
46
91
|
|
|
47
92
|
@IsDateString()
|
|
93
|
+
@IsNotEmpty()
|
|
48
94
|
startAt: Date;
|
|
49
95
|
|
|
50
96
|
@IsDateString()
|
|
97
|
+
@IsNotEmpty()
|
|
51
98
|
endAt: Date;
|
|
52
99
|
}
|
|
@@ -13,9 +13,20 @@ import {
|
|
|
13
13
|
Currency,
|
|
14
14
|
OrganizationEventTicketCategory,
|
|
15
15
|
OrganizationEventTicketType,
|
|
16
|
+
OrganizationEventTicket,
|
|
17
|
+
ExcludeBase,
|
|
16
18
|
} from "../../../../types";
|
|
17
19
|
|
|
18
|
-
export
|
|
20
|
+
export type CreateOrganizationEventTicketInput = Omit<
|
|
21
|
+
ExcludeBase<OrganizationEventTicket>,
|
|
22
|
+
"price" | "product" | "event" | "fee"
|
|
23
|
+
> & {
|
|
24
|
+
price: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export class CreateOrganizationEventTicketDto
|
|
28
|
+
implements CreateOrganizationEventTicketInput
|
|
29
|
+
{
|
|
19
30
|
@IsString()
|
|
20
31
|
@Length(1, 128)
|
|
21
32
|
name: string;
|
|
@@ -1,3 +1,70 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
IsBoolean,
|
|
3
|
+
IsDateString,
|
|
4
|
+
IsEnum,
|
|
5
|
+
IsNumber,
|
|
6
|
+
IsOptional,
|
|
7
|
+
IsString,
|
|
8
|
+
Length,
|
|
9
|
+
Min,
|
|
10
|
+
} from "class-validator";
|
|
2
11
|
|
|
3
|
-
|
|
12
|
+
import { CreateOrganizationEventTicketInput } from "./create-organization-event-ticket.dto";
|
|
13
|
+
import {
|
|
14
|
+
Currency,
|
|
15
|
+
DeepPartial,
|
|
16
|
+
OrganizationEventTicketCategory,
|
|
17
|
+
OrganizationEventTicketType,
|
|
18
|
+
} from "../../../../types";
|
|
19
|
+
|
|
20
|
+
export class UpdateOrganizationEventTicketDto
|
|
21
|
+
implements DeepPartial<CreateOrganizationEventTicketInput>
|
|
22
|
+
{
|
|
23
|
+
@IsString()
|
|
24
|
+
@Length(1, 128)
|
|
25
|
+
@IsOptional()
|
|
26
|
+
name?: string;
|
|
27
|
+
|
|
28
|
+
@IsString()
|
|
29
|
+
@Length(1, 1024)
|
|
30
|
+
@IsOptional()
|
|
31
|
+
description?: string;
|
|
32
|
+
|
|
33
|
+
@IsNumber()
|
|
34
|
+
@Min(0)
|
|
35
|
+
@IsOptional()
|
|
36
|
+
price?: number;
|
|
37
|
+
|
|
38
|
+
@IsNumber()
|
|
39
|
+
@Min(0)
|
|
40
|
+
@IsOptional()
|
|
41
|
+
quantity?: number;
|
|
42
|
+
|
|
43
|
+
@IsEnum(OrganizationEventTicketType)
|
|
44
|
+
@IsOptional()
|
|
45
|
+
type?: OrganizationEventTicketType;
|
|
46
|
+
|
|
47
|
+
@IsEnum(OrganizationEventTicketCategory)
|
|
48
|
+
@IsOptional()
|
|
49
|
+
category?: OrganizationEventTicketCategory;
|
|
50
|
+
|
|
51
|
+
@IsEnum(Currency)
|
|
52
|
+
@IsOptional()
|
|
53
|
+
currency?: Currency;
|
|
54
|
+
|
|
55
|
+
@IsBoolean()
|
|
56
|
+
@IsOptional()
|
|
57
|
+
isVisible?: boolean;
|
|
58
|
+
|
|
59
|
+
@IsBoolean()
|
|
60
|
+
@IsOptional()
|
|
61
|
+
isFeesIncluded?: boolean;
|
|
62
|
+
|
|
63
|
+
@IsDateString()
|
|
64
|
+
@IsOptional()
|
|
65
|
+
startAt?: Date;
|
|
66
|
+
|
|
67
|
+
@IsDateString()
|
|
68
|
+
@IsOptional()
|
|
69
|
+
endAt?: Date;
|
|
70
|
+
}
|
|
@@ -1,3 +1,88 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Type } from "class-transformer";
|
|
2
|
+
import {
|
|
3
|
+
IsArray,
|
|
4
|
+
IsDateString,
|
|
5
|
+
IsEnum,
|
|
6
|
+
IsLowercase,
|
|
7
|
+
IsObject,
|
|
8
|
+
IsOptional,
|
|
9
|
+
IsString,
|
|
10
|
+
IsUrl,
|
|
11
|
+
Length,
|
|
12
|
+
Matches,
|
|
13
|
+
ValidateNested,
|
|
14
|
+
} from "class-validator";
|
|
2
15
|
|
|
3
|
-
|
|
16
|
+
import { CreateOrganizationEventInput } from "./create-organization-event.dto";
|
|
17
|
+
import { UpdateOrganizationEventTicketDto } from "./tickets";
|
|
18
|
+
import { REGEX } from "../../../../constants";
|
|
19
|
+
import {
|
|
20
|
+
DeepPartial,
|
|
21
|
+
OrganizationEventType,
|
|
22
|
+
OrganizationEventVisibilityType,
|
|
23
|
+
} from "../../../types";
|
|
24
|
+
import { UpdateLocationDto } from "../../locations/update-location.dto";
|
|
25
|
+
|
|
26
|
+
export class UpdateOrganizationEventDto
|
|
27
|
+
implements DeepPartial<CreateOrganizationEventInput>
|
|
28
|
+
{
|
|
29
|
+
@IsOptional()
|
|
30
|
+
@IsString()
|
|
31
|
+
@Length(1, 64)
|
|
32
|
+
title?: string;
|
|
33
|
+
|
|
34
|
+
@IsOptional()
|
|
35
|
+
@IsString()
|
|
36
|
+
@IsLowercase()
|
|
37
|
+
@Length(3, 48)
|
|
38
|
+
@Matches(REGEX.SLUG)
|
|
39
|
+
slug?: string;
|
|
40
|
+
|
|
41
|
+
@IsOptional()
|
|
42
|
+
@IsString()
|
|
43
|
+
@Length(16, 2048)
|
|
44
|
+
description?: string;
|
|
45
|
+
|
|
46
|
+
@IsOptional()
|
|
47
|
+
@IsEnum(OrganizationEventType)
|
|
48
|
+
type?: OrganizationEventType;
|
|
49
|
+
|
|
50
|
+
@IsOptional()
|
|
51
|
+
@IsEnum(OrganizationEventVisibilityType)
|
|
52
|
+
visibility?: OrganizationEventVisibilityType;
|
|
53
|
+
|
|
54
|
+
@IsOptional()
|
|
55
|
+
@IsArray()
|
|
56
|
+
@IsUrl({}, { each: true })
|
|
57
|
+
flyers?: string[];
|
|
58
|
+
|
|
59
|
+
@IsOptional()
|
|
60
|
+
@IsArray()
|
|
61
|
+
@IsUrl({}, { each: true })
|
|
62
|
+
trailers?: string[];
|
|
63
|
+
|
|
64
|
+
@IsOptional()
|
|
65
|
+
@IsObject()
|
|
66
|
+
@ValidateNested()
|
|
67
|
+
@Type(() => UpdateLocationDto)
|
|
68
|
+
location?: UpdateLocationDto;
|
|
69
|
+
|
|
70
|
+
@IsOptional()
|
|
71
|
+
@IsArray()
|
|
72
|
+
@ValidateNested({ each: true })
|
|
73
|
+
@Type(() => UpdateOrganizationEventTicketDto)
|
|
74
|
+
tickets?: UpdateOrganizationEventTicketDto[];
|
|
75
|
+
|
|
76
|
+
@IsOptional()
|
|
77
|
+
@IsArray()
|
|
78
|
+
@IsString({ each: true })
|
|
79
|
+
styles?: string[];
|
|
80
|
+
|
|
81
|
+
@IsOptional()
|
|
82
|
+
@IsDateString()
|
|
83
|
+
startAt?: Date;
|
|
84
|
+
|
|
85
|
+
@IsOptional()
|
|
86
|
+
@IsDateString()
|
|
87
|
+
endAt?: Date;
|
|
88
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Type } from "class-transformer";
|
|
1
2
|
import {
|
|
2
3
|
IsDateString,
|
|
3
4
|
IsEmail,
|
|
@@ -9,14 +10,19 @@ import {
|
|
|
9
10
|
IsUrl,
|
|
10
11
|
Length,
|
|
11
12
|
Matches,
|
|
13
|
+
ValidateNested,
|
|
12
14
|
} from "class-validator";
|
|
13
15
|
|
|
14
16
|
import { REGEX } from "../../../constants";
|
|
15
17
|
import { UserIdentifier, UserIdentityGender } from "../../types";
|
|
16
18
|
|
|
17
19
|
export class CreateUserDto {
|
|
20
|
+
@ValidateNested()
|
|
21
|
+
@Type(() => CreateUserIdentifierDto)
|
|
18
22
|
identifier: CreateUserIdentifierDto;
|
|
19
23
|
|
|
24
|
+
@ValidateNested()
|
|
25
|
+
@Type(() => CreateUserIdentityDto)
|
|
20
26
|
identity: CreateUserIdentityDto;
|
|
21
27
|
|
|
22
28
|
@IsString()
|
package/src/rest/types/index.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a GeoJSON point with specific geographic coordinates.
|
|
3
|
+
*
|
|
4
|
+
* @see https://geojson.org/geojson-spec.html#point
|
|
5
|
+
*
|
|
6
|
+
* @property {"Point"} type - The type of the geometry, which is always "Point" for a GeoJSON point.
|
|
7
|
+
* @property {[number, number]} coordinates - The coordinates of the point, represented as [longitude, latitude].
|
|
8
|
+
*/
|
|
1
9
|
export type GeoPoint = {
|
|
2
10
|
type: "Point";
|
|
3
11
|
coordinates: [number, number];
|
|
@@ -35,10 +35,6 @@ export type OrganizationEvent = Base & {
|
|
|
35
35
|
endAt: Date;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
export type OrganizationEventWithDistance = OrganizationEvent & {
|
|
39
|
-
distance: number;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
38
|
export enum OrganizationEventType {
|
|
43
39
|
Clubbing = "clubbing",
|
|
44
40
|
Concert = "concert",
|
|
@@ -108,6 +104,12 @@ export type OrganizationEventEndpoints =
|
|
|
108
104
|
OrganizationEvent,
|
|
109
105
|
CreateOrganizationEventDto
|
|
110
106
|
>
|
|
107
|
+
| Endpoint<
|
|
108
|
+
"POST",
|
|
109
|
+
"/organizations/:organizationSlug/events/:eventSlug/views",
|
|
110
|
+
boolean,
|
|
111
|
+
null
|
|
112
|
+
>
|
|
111
113
|
| Endpoint<
|
|
112
114
|
"PUT",
|
|
113
115
|
"/organizations/:organizationSlug/events/:eventSlug",
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import { plainToInstance } from "class-transformer";
|
|
3
|
+
import { validate, ValidationError } from "class-validator";
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
CreateUserDto,
|
|
8
|
+
CreateOrganizationEventTicketDto,
|
|
9
|
+
} from "../../src/rest/dtos";
|
|
10
|
+
import {
|
|
11
|
+
UserIdentityGender,
|
|
12
|
+
OrganizationEventTicketType,
|
|
13
|
+
OrganizationEventTicketCategory,
|
|
14
|
+
Currency,
|
|
15
|
+
} from "../../src/rest/types";
|
|
16
|
+
|
|
17
|
+
function printValidationErrors(errors: ValidationError[]): string[] {
|
|
18
|
+
const formatError = (error: ValidationError, prefix = ""): string[] => {
|
|
19
|
+
let messages: string[] = [];
|
|
20
|
+
if (error.constraints) {
|
|
21
|
+
Object.entries(error.constraints).forEach(([key, value]) => {
|
|
22
|
+
messages.push(`${prefix}${error.property} - ${key}: ${value}`);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (error.children) {
|
|
26
|
+
error.children.forEach((child: ValidationError) => {
|
|
27
|
+
messages = messages.concat(
|
|
28
|
+
formatError(child, `${prefix}${error.property}.`),
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return messages;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return errors.flatMap((error) => formatError(error));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function dtoTests() {
|
|
39
|
+
test("CreateUserDto validation", async (t) => {
|
|
40
|
+
await t.test("should fail with invalid email", async () => {
|
|
41
|
+
const dto = plainToInstance(CreateUserDto, {
|
|
42
|
+
identifier: {
|
|
43
|
+
email: "invalid-email",
|
|
44
|
+
username: "validuser123",
|
|
45
|
+
},
|
|
46
|
+
identity: {
|
|
47
|
+
firstName: "John",
|
|
48
|
+
lastName: "Doe",
|
|
49
|
+
gender: UserIdentityGender.Male,
|
|
50
|
+
birthDate: new Date().toISOString(),
|
|
51
|
+
},
|
|
52
|
+
password: "ValidPass123!",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const identifierErrors = await validate(dto.identifier);
|
|
56
|
+
const hasEmailError = identifierErrors.some(
|
|
57
|
+
(error) => error.property === "email" && error.constraints?.isEmail,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
assert(hasEmailError, "Expected validation error for invalid email");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await t.test("should fail with invalid password", async () => {
|
|
64
|
+
const dto = plainToInstance(CreateUserDto, {
|
|
65
|
+
identifier: {
|
|
66
|
+
email: "test@example.com",
|
|
67
|
+
username: "validuser123",
|
|
68
|
+
},
|
|
69
|
+
identity: {
|
|
70
|
+
firstName: "John",
|
|
71
|
+
lastName: "Doe",
|
|
72
|
+
gender: UserIdentityGender.Male,
|
|
73
|
+
birthDate: new Date().toISOString(),
|
|
74
|
+
},
|
|
75
|
+
password: "weak",
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const errors = await validate(dto, {
|
|
79
|
+
skipMissingProperties: false,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const hasPasswordError = errors.some(
|
|
83
|
+
(error) => error.property === "password" && error.constraints?.matches,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
assert(hasPasswordError, "Expected validation error for weak password");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await t.test("should pass with valid DTO", async () => {
|
|
90
|
+
const dto = plainToInstance(CreateUserDto, {
|
|
91
|
+
identifier: {
|
|
92
|
+
email: "test@example.com",
|
|
93
|
+
username: "validuser123",
|
|
94
|
+
},
|
|
95
|
+
identity: {
|
|
96
|
+
firstName: "John",
|
|
97
|
+
lastName: "Doe",
|
|
98
|
+
gender: UserIdentityGender.Male,
|
|
99
|
+
birthDate: new Date().toISOString(),
|
|
100
|
+
},
|
|
101
|
+
password: "ValidPass123!",
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const error = await validate(dto.identifier);
|
|
105
|
+
const identityError = await validate(dto.identity);
|
|
106
|
+
const mainError = await validate(dto, {
|
|
107
|
+
whitelist: true,
|
|
108
|
+
forbidNonWhitelisted: true,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const totalErrors =
|
|
112
|
+
error.length + identityError.length + mainError.length;
|
|
113
|
+
assert.strictEqual(totalErrors, 0, "Expected no validation errors");
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("CreateOrganizationEventTicketDto validation", async (t) => {
|
|
118
|
+
await t.test("should pass with valid DTO", async () => {
|
|
119
|
+
const dto = plainToInstance(CreateOrganizationEventTicketDto, {
|
|
120
|
+
name: "VIP Ticket",
|
|
121
|
+
description:
|
|
122
|
+
"Access to VIP area, minimum length should be at least 16 chars",
|
|
123
|
+
price: 100,
|
|
124
|
+
quantity: 100,
|
|
125
|
+
type: OrganizationEventTicketType.ETicket,
|
|
126
|
+
category: OrganizationEventTicketCategory.Entry,
|
|
127
|
+
currency: Currency.EUR,
|
|
128
|
+
isVisible: true,
|
|
129
|
+
isFeesIncluded: true,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const errors = await validate(dto);
|
|
133
|
+
assert.strictEqual(errors.length, 0, "Expected no validation errors");
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await t.test("should fail with invalid price", async () => {
|
|
137
|
+
const dto = plainToInstance(CreateOrganizationEventTicketDto, {
|
|
138
|
+
name: "VIP Ticket",
|
|
139
|
+
description:
|
|
140
|
+
"Access to VIP area, minimum length should be at least 16 chars",
|
|
141
|
+
price: -10,
|
|
142
|
+
quantity: 100,
|
|
143
|
+
type: OrganizationEventTicketType.ETicket,
|
|
144
|
+
category: OrganizationEventTicketCategory.Entry,
|
|
145
|
+
currency: Currency.EUR,
|
|
146
|
+
isVisible: true,
|
|
147
|
+
isFeesIncluded: true,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const errors = await validate(dto);
|
|
151
|
+
const hasPriceError = printValidationErrors(errors).some(
|
|
152
|
+
(error) => error.includes("price") && error.includes("min"),
|
|
153
|
+
);
|
|
154
|
+
assert(hasPriceError, "Expected validation error for negative price");
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
package/tests/index.ts
CHANGED
|
@@ -5,11 +5,12 @@ import test from "node:test";
|
|
|
5
5
|
|
|
6
6
|
import { authTests } from "./auth";
|
|
7
7
|
import { careersTests } from "./careers";
|
|
8
|
+
import { dtoTests } from "./dtos";
|
|
8
9
|
import { regexTests } from "./regex";
|
|
9
10
|
import { usersTests } from "./users";
|
|
10
11
|
import { TonightPass } from "../src/tonightpass";
|
|
11
12
|
|
|
12
|
-
const sdkTests = [authTests, careersTests, regexTests, usersTests];
|
|
13
|
+
const sdkTests = [authTests, careersTests, dtoTests, regexTests, usersTests];
|
|
13
14
|
|
|
14
15
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
15
16
|
// @ts-expect-error
|