-
Notifications
You must be signed in to change notification settings - Fork 3
/
validators.ts
257 lines (232 loc) · 8.68 KB
/
validators.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/**
* SudoSOS back-end API service.
* Copyright (C) 2024 Study association GEWIS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { InvoiceState } from '../entity/invoices/invoice-status';
import { VatDeclarationPeriod } from '../entity/vat-group';
import { UserType } from '../entity/user/user';
import { Dinero } from 'dinero.js';
import DineroTransformer from '../entity/transformer/dinero-transformer';
import { Availability } from '../entity/event/event-shift-answer';
import { EventType } from '../entity/event/event';
import { ReturnFileType } from 'pdf-generator-client';
/**
* Returns whether the given object is a number
* @param number any - The object to check
* @param canBeUndefined boolean - Whether number is also allowed to be undefined
*/
export function isNumber(number: any, canBeUndefined?: boolean): boolean {
if (canBeUndefined && number === undefined) return true;
// If the object is of type number, simply return true
if (typeof number === 'number') return true;
// Parse the object to a number
const p = Number(number);
// If it is NaN, return false
if (Number.isNaN(p)) return false;
// If the length of the number is not equal to the length of the string, return false
// Otherwise, return true
return p.toString().length === number.length;
}
/**
* Returns whether a given date string is actually a date
* @param date string - The date string
* @param canBeUndefined boolean - Whether number is also allowed to be undefined
*/
export function isDate(date: any, canBeUndefined?: boolean): boolean {
if (canBeUndefined && date === undefined) return true;
return !Number.isNaN(new Date(date).getTime());
}
/**
* Converts the input to a number.
* @param input - The input which should be converted.
* @returns The parsed integer.
* @throws TypeError - If the input is not a valid integer.
*/
export function asNumber(input: any): number | undefined {
if (!isNumber(input, true)) throw new TypeError(`Input '${input}' is not a number.`);
return (input !== undefined ? Number(input) : undefined);
}
/**
* Converts the input to a Dinero object.
* @param input - The input which should be converted.
* @returns The parsed dinero object.
* @throws TypeError - If the input is not a valid integer.
*/
export function asDinero(input: any): Dinero | undefined {
const parsed = asNumber(input);
return parsed !== undefined ? DineroTransformer.Instance.from(parsed) : undefined;
}
/**
* Converts the input to a boolean
* @param input - The input which should be converted.
* @returns {true} - for 1, '1', true, 'true' (case-insensitive), otherwise false.
*/
export function asBoolean(input: any): boolean | undefined {
if (input === undefined) return undefined;
if (typeof input === 'string') {
return input.toLowerCase() === 'true' || !!+input;
}
return !!input;
}
/**
* Converts the input to a Date object.
* @param input - The input which should be converted.
* @returns The parsed Date object.
* @throws TypeError - If the input is not a valid date.
*/
export function asDate(input: any): Date | undefined {
if (!isDate(input, true)) throw new TypeError(`Input '${input}' is not a date.`);
return (input ? new Date(input) : undefined);
}
/**
* Converts the input to a InvoiceState
* @param input - The input which should be converted.
* @returns The parsed InvoiceState.
* @throws TypeError - If the input is not a valid InvoiceState
*/
export function asInvoiceState(input: any): InvoiceState | undefined {
if (!input) return undefined;
const state: InvoiceState = InvoiceState[input as keyof typeof InvoiceState];
if (state === undefined) {
throw new TypeError(`Input '${input}' is not a valid InvoiceState.`);
}
return state;
}
/**
* Converts the input to an VatDeclarationPeriod
* @param input - The input which should be converted.
* @returns VatDeclarationPeriod - The parsed VatDeclarationPeriod.
* @throws TypeError - If the input is not a valid VatDeclarationPeriod
*/
export function asVatDeclarationPeriod(input: any): VatDeclarationPeriod | undefined {
if (!input) return undefined;
if (!Object.values(VatDeclarationPeriod).includes(input)) {
throw new TypeError(`Input '${input}' is not a valid VatDeclarationPeriod.`);
}
return input;
}
/**
* Converts the input to a UserType
* @param input - The input which should be converted.
* @returns The parsed UserType as a number representation.
* @throws TypeError - If the input is not a valid UserType
*/
export function asUserType(input: any): UserType | undefined {
if (input === undefined || input === null) return undefined;
// Convert input to a number if it's a string representation of a number
if (typeof input === 'string' && !isNaN(Number(input))) {
input = Number(input);
}
// Check if input is now a number and a valid enum value
if (typeof input === 'number' && UserType[input] !== undefined) {
return input;
}
// Check if input is a string and a valid enum key
const state: UserType = UserType[input as keyof typeof UserType];
if (state === undefined) {
throw new TypeError(`Input '${input}' is not a valid UserType.`);
}
return state;
}
/**
* Converts the input to a shift availability
* @param input - The input which should be converted.
* @returns The parsed shift Availability.
* @throws TypeError - If the input is not a valid Availability
*/
export function asShiftAvailability(input: any): Availability | undefined {
if (!input) return undefined;
const state: Availability = Availability[input as keyof typeof Availability];
if (state === undefined) {
throw new TypeError(`Input '${input}' is not a valid shift Availability.`);
}
return state;
}
/**
* Converts the input to an EventType
* @param input - The input which should be converted.
* @returns The parsed EventType.
* @throws TypeError - If the input is not a valid EventType
*/
export function asEventType(input: any): EventType | undefined {
if (!input) return undefined;
const state: EventType = EventType[input as keyof typeof EventType];
if (state === undefined) {
throw new TypeError(`Input '${input}' is not a valid EventType.`);
}
return state;
}
/**
* Converts the input to a list of UserTypes
* @param input
* @throws TypeError - If the input is not a valid UserType
*/
export function asArrayOfUserTypes(input: any): UserType[] | undefined {
if (!input) return undefined;
let arr = input;
if (!Array.isArray(input)) arr = [input];
return arr.map((i: any) => asUserType(i));
}
/**
* Converts the input to a list of numbers
* @param input
*/
export function asArrayOfNumbers(input: any): number[] | undefined {
if (!input) return undefined;
if (!Array.isArray(input)) return undefined;
return input.map((i) => asNumber(i));
}
/**
* Converts the input to a list of dates
* @param input
* @throws TypeError - If array contains one or more invalid or undefined dates
*/
export function asArrayOfDates(input: any): Date[] | undefined {
if (!input) return undefined;
if (!Array.isArray(input)) input = [input];
const dates = input.map((i: any[]) => asDate(i));
if (dates.some((d: (Date | undefined)[]) => d === undefined)) throw new TypeError('Array contains invalid date');
return dates;
}
/**
* Converts the inputs to a from and till date
* @param fromDate
* @param tillDate
* @throws Error - If tillDate is before fromDate
* @throws TypeError - If any of the inputs is not a valid date
*/
export function asFromAndTillDate(fromDate: any, tillDate: any): { fromDate: Date, tillDate: Date } {
const filters = {
fromDate: asDate(fromDate),
tillDate: asDate(tillDate),
};
if (filters.fromDate >= filters.tillDate) {
throw new Error('tillDate must be after fromDate');
}
return filters;
}
/**
* Converts the input to a ReturnFileType
* @param input
*/
export function asReturnFileType(input: any): ReturnFileType {
if (!input) return undefined;
input = input.toUpperCase();
if (typeof input === 'string' && Object.values(ReturnFileType).includes(input as ReturnFileType)) {
return input as ReturnFileType;
}
throw new TypeError(`Input '${input}' is not a valid ReturnFileType.`);
}