5htp-core 0.1.2 → 0.2.0
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/changelog.md +5 -0
- package/doc/TODO.md +71 -0
- package/package.json +5 -4
- package/src/client/{App.tsx → app/component.tsx} +15 -8
- package/src/client/app/index.ts +128 -0
- package/src/client/app/service.ts +34 -0
- package/src/client/app.tsconfig.json +0 -4
- package/src/client/assets/css/medias.less +14 -0
- package/src/client/components/Card/index.tsx +2 -2
- package/src/client/components/Dialog/Manager.tsx +39 -12
- package/src/client/components/Form/index.tsx +1 -1
- package/src/client/components/button.tsx +2 -2
- package/src/client/components/containers/Popover/index.tsx +1 -1
- package/src/client/components/data/spintext/index.tsx +1 -1
- package/src/client/components/dropdown/index.tsx +1 -1
- package/src/client/components/index.ts +8 -0
- package/src/client/components/input/BaseV2/index.tsx +1 -1
- package/src/client/components/input/UploadImage/index.tsx +1 -1
- package/src/client/hooks/index.ts +5 -0
- package/src/client/hooks/useState/index.tsx +2 -2
- package/src/client/hooks.ts +22 -0
- package/src/client/index.ts +5 -0
- package/src/client/pages/_layout/landing/index.tsx +0 -2
- package/src/client/pages/_messages/400.tsx +2 -2
- package/src/client/pages/_messages/401.tsx +2 -2
- package/src/client/pages/_messages/403.tsx +2 -2
- package/src/client/pages/_messages/404.tsx +2 -2
- package/src/client/pages/_messages/500.tsx +2 -2
- package/src/client/pages/bug.tsx +1 -1
- package/src/client/pages/useHeader.tsx +1 -1
- package/src/client/{context/captcha.ts → services/captcha/index.ts} +0 -0
- package/src/client/services/metrics/index.ts +37 -0
- package/src/client/{router → services/router/components}/Link.tsx +1 -1
- package/src/client/services/router/components/Page.tsx +59 -0
- package/src/client/{router/component.tsx → services/router/components/router.tsx} +43 -74
- package/src/client/services/router/index.tsx +448 -0
- package/src/client/services/router/request/api.ts +229 -0
- package/src/client/{router → services/router}/request/history.ts +0 -0
- package/src/client/services/router/request/index.ts +52 -0
- package/src/client/services/router/response/index.tsx +107 -0
- package/src/client/services/router/response/page.ts +95 -0
- package/src/client/{context/socket.ts → services/socket/index.ts} +2 -2
- package/src/client/utils/dom.ts +1 -1
- package/src/common/app/index.ts +9 -0
- package/src/common/data/chaines/index.ts +9 -6
- package/src/common/data/input/validate.ts +3 -166
- package/src/common/data/objets.ts +25 -0
- package/src/common/data/tableaux.ts +8 -0
- package/src/common/errors/index.ts +3 -1
- package/src/common/router/index.ts +67 -88
- package/src/common/router/layouts.ts +50 -0
- package/src/common/router/register.ts +62 -0
- package/src/common/router/request/api.ts +72 -0
- package/src/common/router/request/index.ts +31 -0
- package/src/common/router/{response.ts → response/index.ts} +9 -13
- package/src/common/router/response/page.ts +40 -56
- package/src/common/validation/index.ts +3 -0
- package/src/common/validation/schema.ts +184 -0
- package/src/common/validation/validator.ts +88 -0
- package/src/common/validation/validators.ts +313 -0
- package/src/server/app/config.ts +9 -27
- package/src/server/app/index.ts +81 -124
- package/src/server/app/service.ts +98 -0
- package/src/server/app.tsconfig.json +0 -8
- package/src/server/error/index.ts +13 -0
- package/src/server/index.ts +5 -0
- package/src/server/patch.ts +0 -6
- package/src/server/{data/Cache.ts → services/cache/index.ts} +79 -47
- package/src/server/services/console/bugReporter.ts +26 -16
- package/src/server/services/console/index.ts +59 -51
- package/src/server/services/cron/index.ts +12 -26
- package/src/server/services/database/bucket.ts +40 -0
- package/src/server/services/database/connection.ts +206 -75
- package/src/server/services/database/datatypes.ts +63 -40
- package/src/server/services/database/index.ts +295 -272
- package/src/server/services/database/metas.ts +246 -135
- package/src/server/services/database/stats.ts +151 -126
- package/src/server/services/email/index.ts +28 -52
- package/src/server/services/{router/request/services → metrics}/detect.ts +8 -10
- package/src/server/services/{router/request/services/tracking.ts → metrics/index.ts} +68 -45
- package/src/server/services/{http → router/http}/index.ts +28 -70
- package/src/server/services/{http → router/http}/multipart.ts +0 -0
- package/src/server/services/{http → router/http}/session.ts.old +0 -0
- package/src/server/services/router/index.ts +273 -203
- package/src/server/services/router/request/api.ts +73 -0
- package/src/server/services/router/request/index.ts +16 -97
- package/src/server/services/router/request/service.ts +21 -0
- package/src/server/services/router/response/index.ts +125 -64
- package/src/server/services/router/response/{filter → mask}/Filter.ts +0 -0
- package/src/server/services/router/response/{filter → mask}/index.ts +0 -2
- package/src/server/services/router/response/{filter → mask}/selecteurs.ts +0 -0
- package/src/server/services/router/response/page/document.tsx +194 -0
- package/src/server/services/router/response/page/index.tsx +157 -0
- package/src/server/{libs/pages → services/router/response/page}/schemaGenerator.ts +0 -0
- package/src/server/services/router/service.ts +48 -0
- package/src/server/services/schema/index.ts +47 -0
- package/src/server/services/schema/request.ts +55 -0
- package/src/server/services/schema/router.ts +33 -0
- package/src/server/services/socket/index.ts +38 -43
- package/src/server/services/socket/scope.ts +6 -4
- package/src/server/services/users/index.ts +203 -0
- package/src/server/services/{auth/base.ts → users/old.ts} +28 -112
- package/src/server/services/users/router/index.ts +72 -0
- package/src/server/services/users/router/request.ts +49 -0
- package/src/types/aliases.d.ts +43 -2
- package/templates/composant.tsx +1 -1
- package/templates/modal.tsx +1 -1
- package/templates/page.tsx +1 -1
- package/tsconfig.common.json +0 -4
- package/src/client/context/api.ts +0 -92
- package/src/client/context/index.ts +0 -246
- package/src/client/index.tsx +0 -129
- package/src/client/router/index.ts +0 -286
- package/src/client/router/request/index.ts +0 -106
- package/src/client/router/response/index.ts +0 -38
- package/src/client/router/route.ts +0 -75
- package/src/common/data/input/validators/basic.ts +0 -299
- package/src/common/data/input/validators/build.ts +0 -63
- package/src/common/router/request.ts +0 -83
- package/src/server/data/ApiClient.ts +0 -119
- package/src/server/data/input.ts +0 -41
- package/src/server/libs/pages/document.static.tsx +0 -41
- package/src/server/libs/pages/document.tsx +0 -203
- package/src/server/libs/pages/render.tsx +0 -90
- package/src/server/routes/auth.ts +0 -151
- package/src/server/services/redis/index.ts +0 -71
- package/src/server/services/router/request/services/auth.ts +0 -177
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Core
|
|
6
|
+
import { Erreur, TListeErreursSaisie, InputErrorSchema } from '@common/errors';
|
|
7
|
+
|
|
8
|
+
// Specific
|
|
9
|
+
import { default as Validator, EXCLUDE_VALUE } from './validator';
|
|
10
|
+
|
|
11
|
+
/*----------------------------------
|
|
12
|
+
- TYPES
|
|
13
|
+
----------------------------------*/
|
|
14
|
+
|
|
15
|
+
export type TSchemaFields = { [fieldName: string]: Schema<{}> | Validator<any> }
|
|
16
|
+
|
|
17
|
+
type TOptsValider = {
|
|
18
|
+
critique?: boolean,
|
|
19
|
+
validationComplete?: boolean,
|
|
20
|
+
avecDependances?: boolean,
|
|
21
|
+
corriger?: boolean,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type TValidationResult<TFields extends TSchemaFields> = {
|
|
25
|
+
values: TValidatedData<TFields>,
|
|
26
|
+
nbErreurs: number,
|
|
27
|
+
erreurs: TListeErreursSaisie
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type TValidatedData<TFields extends TSchemaFields> = {
|
|
31
|
+
[name in keyof TFields]: ReturnType<TFields[name]["validate"]>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/*----------------------------------
|
|
35
|
+
- CONST
|
|
36
|
+
----------------------------------*/
|
|
37
|
+
|
|
38
|
+
const debug = true;
|
|
39
|
+
|
|
40
|
+
const LogPrefix = '[schema][validator]';
|
|
41
|
+
|
|
42
|
+
/*----------------------------------
|
|
43
|
+
- CLASS
|
|
44
|
+
----------------------------------*/
|
|
45
|
+
export default class Schema<TFields extends TSchemaFields> {
|
|
46
|
+
|
|
47
|
+
public constructor(
|
|
48
|
+
public fields: TFields
|
|
49
|
+
) {
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public validate<TDonnees extends TObjetDonnees>(
|
|
54
|
+
|
|
55
|
+
dataToValidate: Partial<TDonnees>,
|
|
56
|
+
allData: TDonnees,
|
|
57
|
+
output: TObjetDonnees = {},
|
|
58
|
+
|
|
59
|
+
opts: TOptsValider = {},
|
|
60
|
+
chemin: string[] = []
|
|
61
|
+
|
|
62
|
+
): TValidationResult<TFields> {
|
|
63
|
+
|
|
64
|
+
opts = {
|
|
65
|
+
critique: false,
|
|
66
|
+
validationComplete: false,
|
|
67
|
+
avecDependances: true,
|
|
68
|
+
corriger: false,
|
|
69
|
+
...opts,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const clesAvalider = Object.keys(opts.validationComplete === true ? this.fields : dataToValidate);
|
|
73
|
+
|
|
74
|
+
let outputSchema = output;
|
|
75
|
+
for (const branche of chemin)
|
|
76
|
+
outputSchema = outputSchema[branche];
|
|
77
|
+
|
|
78
|
+
// Validation de chacune d'entre elles
|
|
79
|
+
let erreurs: TListeErreursSaisie = {};
|
|
80
|
+
let nbErreurs = 0;
|
|
81
|
+
for (const champ of clesAvalider) {
|
|
82
|
+
|
|
83
|
+
// La donnée est répertoriée dans le schema
|
|
84
|
+
const field = this.fields[champ];
|
|
85
|
+
if (field === undefined) {
|
|
86
|
+
debug && console.warn(LogPrefix, '[' + champ + ']', 'Exclusion (pas présent dans le schéma)');
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const cheminA = [...chemin, champ]
|
|
91
|
+
const cheminAstr = cheminA.join('.')
|
|
92
|
+
|
|
93
|
+
// Sous-schema
|
|
94
|
+
if (field instanceof Schema) {
|
|
95
|
+
|
|
96
|
+
// Initialise la structure pour permettre l'assignement d'outputSchema
|
|
97
|
+
if (outputSchema[champ] === undefined)
|
|
98
|
+
outputSchema[champ] = {}
|
|
99
|
+
|
|
100
|
+
// The corresponding data should be an object
|
|
101
|
+
const schemadata = dataToValidate[champ];
|
|
102
|
+
if (typeof schemadata !== 'object') {
|
|
103
|
+
erreurs[ cheminAstr ] = [`Should be an object`];
|
|
104
|
+
nbErreurs++;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Validate the data
|
|
109
|
+
const validationSchema = field.validate(
|
|
110
|
+
|
|
111
|
+
schemadata,
|
|
112
|
+
allData,
|
|
113
|
+
output,
|
|
114
|
+
|
|
115
|
+
opts,
|
|
116
|
+
cheminA
|
|
117
|
+
);
|
|
118
|
+
erreurs = { ...erreurs, ...validationSchema.erreurs };
|
|
119
|
+
nbErreurs += validationSchema.nbErreurs;
|
|
120
|
+
|
|
121
|
+
// Pas besoin d'assigner, car output est passé en référence
|
|
122
|
+
//output[champ] = validationSchema.values;
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
// I don't remind what is options.activer about
|
|
126
|
+
/*} else if (field.activer !== undefined && field.activer(allData) === false) {
|
|
127
|
+
|
|
128
|
+
delete outputSchema[champ];*/
|
|
129
|
+
|
|
130
|
+
// Validator
|
|
131
|
+
} else {
|
|
132
|
+
|
|
133
|
+
// Champ composé de plusieurs values
|
|
134
|
+
const valOrigine = field.options.as === undefined
|
|
135
|
+
? dataToValidate[champ]
|
|
136
|
+
// Le champ regroupe plusieurs values (ex: Periode)
|
|
137
|
+
: field.options.as.map((nomVal: string) => dataToValidate[nomVal])
|
|
138
|
+
|
|
139
|
+
// Validation
|
|
140
|
+
try {
|
|
141
|
+
|
|
142
|
+
const val = field.validate(valOrigine, allData, output, opts.corriger);
|
|
143
|
+
|
|
144
|
+
// Exclusion seulement si explicitement demandé
|
|
145
|
+
// IMPORTANT: Conserver les values undefined
|
|
146
|
+
// La présence d'un valeur undefined peut être utile, par exemple, pour indiquer qu'on souhaite supprimer une donnée
|
|
147
|
+
// Exemple: undefinec = suppression fichier | Absende donnée = conservation fihcier actuel
|
|
148
|
+
if (val === EXCLUDE_VALUE)
|
|
149
|
+
debug && console.log(LogPrefix, '[' + cheminA + '] Exclusion demandée');
|
|
150
|
+
else
|
|
151
|
+
outputSchema[champ] = val;
|
|
152
|
+
|
|
153
|
+
debug && console.log(LogPrefix, '[' + cheminA + ']', valOrigine, '=>', val);
|
|
154
|
+
|
|
155
|
+
} catch (error) {
|
|
156
|
+
|
|
157
|
+
debug && console.warn(LogPrefix, '[' + cheminA + ']', valOrigine, '|| Erreur:', error);
|
|
158
|
+
|
|
159
|
+
if (error instanceof Erreur) {
|
|
160
|
+
|
|
161
|
+
// Référencement erreur
|
|
162
|
+
erreurs[cheminAstr] = [error.message]
|
|
163
|
+
nbErreurs++;
|
|
164
|
+
|
|
165
|
+
} else
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (nbErreurs !== 0 && opts.critique === true) {
|
|
172
|
+
throw new InputErrorSchema(erreurs);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
debug && console.log(LogPrefix, '', dataToValidate, '=>', output);
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
values: output as TValidatedData<TFields>,
|
|
179
|
+
erreurs,
|
|
180
|
+
nbErreurs,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import type { ComponentChild } from 'preact'
|
|
7
|
+
|
|
8
|
+
// Core
|
|
9
|
+
import { InputError } from '@common/errors';
|
|
10
|
+
|
|
11
|
+
/*----------------------------------
|
|
12
|
+
- TYPES
|
|
13
|
+
----------------------------------*/
|
|
14
|
+
|
|
15
|
+
export type TValidator<TValue> = {
|
|
16
|
+
|
|
17
|
+
rendu?: TFieldRenderer,
|
|
18
|
+
|
|
19
|
+
// I don't remind what is options.activer about
|
|
20
|
+
activer?: (donnees: TObjetDonnees) => boolean,
|
|
21
|
+
onglet?: string, // Sert juste d'identifiant secondaire. Ex: nom onglet correspondant
|
|
22
|
+
|
|
23
|
+
// Restrict to a specific set of values
|
|
24
|
+
in?: TValue[],
|
|
25
|
+
|
|
26
|
+
// Executé après le validateur propre au type
|
|
27
|
+
dependances?: string[],
|
|
28
|
+
opt?: true,
|
|
29
|
+
defaut?: TValue,
|
|
30
|
+
as?: string[], // Mapping personnalisé
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type TFieldRenderer = (props: any) => ComponentChild;
|
|
35
|
+
|
|
36
|
+
type TNonEmptyValue = Exclude<any, undefined | '' | null>
|
|
37
|
+
|
|
38
|
+
type TValidationArgs<TValue, TAllValues extends {}> = [
|
|
39
|
+
// For the value given as input in the validation function,
|
|
40
|
+
// Only the empty values were escluded
|
|
41
|
+
val: TNonEmptyValue,
|
|
42
|
+
input: TAllValues,
|
|
43
|
+
output: Partial<TAllValues>,
|
|
44
|
+
corriger?: boolean
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
type TValidationFunction<TValue, TAllValues extends {} = {}> = (
|
|
48
|
+
...args: TValidationArgs<TValue, TAllValues>
|
|
49
|
+
) => TValue | typeof EXCLUDE_VALUE | undefined;
|
|
50
|
+
|
|
51
|
+
/*----------------------------------
|
|
52
|
+
- CONST
|
|
53
|
+
----------------------------------*/
|
|
54
|
+
|
|
55
|
+
export const EXCLUDE_VALUE = "action:exclure" as const;
|
|
56
|
+
|
|
57
|
+
/*----------------------------------
|
|
58
|
+
- CLASS
|
|
59
|
+
----------------------------------*/
|
|
60
|
+
export default class Validator<TValue> {
|
|
61
|
+
|
|
62
|
+
public constructor(
|
|
63
|
+
public type: string,
|
|
64
|
+
public validateType: TValidationFunction<TValue>,
|
|
65
|
+
public options: TValidator<TValue>
|
|
66
|
+
) {
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public isEmpty = (val: any) => val === undefined || val === '' || val === null
|
|
71
|
+
|
|
72
|
+
public validate(...[ val, input, output, correct ]: TValidationArgs<TValue, {}>) {
|
|
73
|
+
|
|
74
|
+
// Required value
|
|
75
|
+
if (this.isEmpty(val)) {
|
|
76
|
+
// Optionnel, on skip
|
|
77
|
+
if (this.options.opt === true)
|
|
78
|
+
return undefined;
|
|
79
|
+
// Requis
|
|
80
|
+
else
|
|
81
|
+
throw new InputError("Please enter a value");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Validate type
|
|
85
|
+
return this.validateType(val, input, output, correct);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import {
|
|
7
|
+
trim,
|
|
8
|
+
isISO8601, toDate,
|
|
9
|
+
isEmail, normalizeEmail,
|
|
10
|
+
isURL
|
|
11
|
+
} from 'validator';
|
|
12
|
+
|
|
13
|
+
// Core
|
|
14
|
+
import { InputError } from '@common/errors';
|
|
15
|
+
import File from '@common/data/file';
|
|
16
|
+
import NormalizedFile from '@common/data/file';
|
|
17
|
+
|
|
18
|
+
// Speciific
|
|
19
|
+
import Validator, { TValidator } from './validator'
|
|
20
|
+
|
|
21
|
+
// Components
|
|
22
|
+
import NumberInput from '@client/components/input/Number';
|
|
23
|
+
import Dropdown from '@client/components/dropdown.old';
|
|
24
|
+
|
|
25
|
+
/*----------------------------------
|
|
26
|
+
- TYPES
|
|
27
|
+
----------------------------------*/
|
|
28
|
+
|
|
29
|
+
export type TFileValidator = TValidator<NormalizedFile> & {
|
|
30
|
+
type?: (keyof typeof raccourcisMime) | string[], // Raccourci, ou liste de mimetype
|
|
31
|
+
taille?: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/*----------------------------------
|
|
35
|
+
- CONST
|
|
36
|
+
----------------------------------*/
|
|
37
|
+
|
|
38
|
+
const raccourcisMime = {
|
|
39
|
+
image: ['image/jpeg', 'image/png']
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/*----------------------------------
|
|
43
|
+
- CLASS
|
|
44
|
+
----------------------------------*/
|
|
45
|
+
export default class SchemaValidator {
|
|
46
|
+
|
|
47
|
+
/*----------------------------------
|
|
48
|
+
- CONTENEURS
|
|
49
|
+
----------------------------------*/
|
|
50
|
+
public object = ({ ...opts }: TValidator<object> & {} = {}) =>
|
|
51
|
+
new Validator<object>('object', (val, input, output) => {
|
|
52
|
+
|
|
53
|
+
// TODO: executer seulement coté serveur
|
|
54
|
+
/*if (typeof val === 'string' && val.startsWith('{'))
|
|
55
|
+
try {
|
|
56
|
+
val = JSON.parse(val);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error('Unable to convert the given string into an object.');
|
|
59
|
+
}*/
|
|
60
|
+
|
|
61
|
+
if (typeof val !== 'object' || val.constructor !== Object)
|
|
62
|
+
throw new InputError("This value must be an object.");
|
|
63
|
+
|
|
64
|
+
return val;
|
|
65
|
+
}, opts)
|
|
66
|
+
|
|
67
|
+
public array = (subtype?: Validator<any[]>, { choice, ...opts }: TValidator<any[]> & {
|
|
68
|
+
choice?: any[]
|
|
69
|
+
} = {}) => {
|
|
70
|
+
|
|
71
|
+
if (subtype !== undefined)
|
|
72
|
+
subtype.options.in = choice;
|
|
73
|
+
|
|
74
|
+
return new Validator<any[]>('array', (items, input, output, corriger) => {
|
|
75
|
+
|
|
76
|
+
//console.log('VALIDER ARRAY', items, input);
|
|
77
|
+
|
|
78
|
+
if (!Array.isArray(items))
|
|
79
|
+
throw new InputError("This value must be an array.");
|
|
80
|
+
|
|
81
|
+
// Verif items
|
|
82
|
+
if (subtype !== undefined) {
|
|
83
|
+
if (false/*subtype instanceof Schema*/) {
|
|
84
|
+
|
|
85
|
+
console.log('TODO: VALIDER VIA SOUS SCHEMA');
|
|
86
|
+
|
|
87
|
+
} else {
|
|
88
|
+
|
|
89
|
+
for (let i = 0; i < items.length; i++)
|
|
90
|
+
items[i] = subtype.validate( items[i], items, items, corriger );
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return items;
|
|
96
|
+
}, {
|
|
97
|
+
...opts,
|
|
98
|
+
in: choice,
|
|
99
|
+
//multiple: true, // Sélection multiple
|
|
100
|
+
//subtype
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public choice = (values: any[], opts: TValidator<any> & {} = {}) =>
|
|
105
|
+
new Validator<any>('object', (val, input, output) => {
|
|
106
|
+
|
|
107
|
+
if (!values.includes(val))
|
|
108
|
+
throw new InputError("Invalid value. Must be: " + values.join(', '));
|
|
109
|
+
|
|
110
|
+
return val;
|
|
111
|
+
|
|
112
|
+
}, opts)
|
|
113
|
+
|
|
114
|
+
/*----------------------------------
|
|
115
|
+
- CHAINES
|
|
116
|
+
----------------------------------*/
|
|
117
|
+
public string = ({ min, max, ...opts }: TValidator<string> & { min?: number, max?: number } = {}) =>
|
|
118
|
+
new Validator<string>('string', (val, input, output, corriger?: boolean) => {
|
|
119
|
+
|
|
120
|
+
if (val === '')
|
|
121
|
+
return undefined;
|
|
122
|
+
else if (typeof val === 'number')
|
|
123
|
+
return val.toString();
|
|
124
|
+
else if (typeof val !== 'string')
|
|
125
|
+
throw new InputError("This value must be a string.");
|
|
126
|
+
|
|
127
|
+
// Espaces blancs
|
|
128
|
+
val = trim(val);
|
|
129
|
+
|
|
130
|
+
// Taille min
|
|
131
|
+
if (min !== undefined && val.length < min)
|
|
132
|
+
throw new InputError(`Must be at least ` + min + ' characters');
|
|
133
|
+
|
|
134
|
+
// Taille max
|
|
135
|
+
if (max !== undefined && val.length > max)
|
|
136
|
+
if (corriger)
|
|
137
|
+
val = val.substring(0, max);
|
|
138
|
+
else
|
|
139
|
+
throw new InputError(`Must be up to ` + max + ' characters');
|
|
140
|
+
|
|
141
|
+
return val;
|
|
142
|
+
|
|
143
|
+
}, opts)
|
|
144
|
+
|
|
145
|
+
public url = (opts: TValidator<string> & {} = {}) =>
|
|
146
|
+
new Validator<string>('url', (inputVal, input, output, corriger?) => {
|
|
147
|
+
|
|
148
|
+
let val = this.string(opts).validate(inputVal, input, output, corriger);
|
|
149
|
+
|
|
150
|
+
if (!isURL(val, {
|
|
151
|
+
// https://www.npmjs.com/package/validator
|
|
152
|
+
}))
|
|
153
|
+
throw new InputError(`Please provide a valid URL.`);
|
|
154
|
+
|
|
155
|
+
return val;
|
|
156
|
+
}, opts)
|
|
157
|
+
|
|
158
|
+
public email = (opts: TValidator<string> & {} = {}) =>
|
|
159
|
+
new Validator<string>('email', (inputVal, input, output, corriger?: boolean) => {
|
|
160
|
+
|
|
161
|
+
let val = this.string(opts).validate(inputVal, input, output, corriger);
|
|
162
|
+
|
|
163
|
+
if (!isEmail(val))
|
|
164
|
+
throw new InputError("Please enter a valid email address.");
|
|
165
|
+
|
|
166
|
+
const retour = normalizeEmail(val);
|
|
167
|
+
|
|
168
|
+
return retour;
|
|
169
|
+
}, opts)
|
|
170
|
+
|
|
171
|
+
/*----------------------------------
|
|
172
|
+
- NOMBRES
|
|
173
|
+
----------------------------------*/
|
|
174
|
+
// On ne spread pas min et max afin quils soient passés dans les props du composant
|
|
175
|
+
public number = (withDecimals: boolean) => ({ ...opts }: TValidator<number> & {
|
|
176
|
+
min?: number,
|
|
177
|
+
max?: number,
|
|
178
|
+
} = {}) => new Validator<number>('number', (val, input, output, corriger?: boolean) => {
|
|
179
|
+
|
|
180
|
+
// Vérifications suivantes inutiles si des values spécifiques ont été fournies
|
|
181
|
+
if (opts.in === undefined) {
|
|
182
|
+
|
|
183
|
+
// Tente conversion chaine en nombre
|
|
184
|
+
if (typeof val === 'string')
|
|
185
|
+
val = withDecimals ? parseFloat(val) : parseInt(val);
|
|
186
|
+
|
|
187
|
+
if (opts.min === undefined)
|
|
188
|
+
opts.min = 0;
|
|
189
|
+
|
|
190
|
+
// Type de donnée
|
|
191
|
+
if (Number.isNaN(val) || typeof val !== 'number') {
|
|
192
|
+
if (corriger)
|
|
193
|
+
val = opts.min;
|
|
194
|
+
else
|
|
195
|
+
throw new InputError("This value must be a number.");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Minimum
|
|
199
|
+
if (val < opts.min)
|
|
200
|
+
if (corriger)
|
|
201
|
+
val = opts.min;
|
|
202
|
+
else
|
|
203
|
+
throw new InputError(`Must be at least ` + opts.min);
|
|
204
|
+
|
|
205
|
+
// Maximum
|
|
206
|
+
if (opts.max !== undefined && val > opts.max)
|
|
207
|
+
if (corriger)
|
|
208
|
+
val = opts.max;
|
|
209
|
+
else
|
|
210
|
+
throw new InputError(`Must be up to ` + opts.max);
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return val;
|
|
215
|
+
}, {
|
|
216
|
+
// Force une valeur par défaut si requis
|
|
217
|
+
defaut: opts.opt ? undefined : (opts.min || 0),
|
|
218
|
+
rendu: NumberInput,
|
|
219
|
+
...opts,
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
public int = this.number(false)
|
|
223
|
+
|
|
224
|
+
public float = this.number(true)
|
|
225
|
+
|
|
226
|
+
public bool = (opts: TValidator<boolean> & {} = {}) =>
|
|
227
|
+
new Validator<boolean>('bool', (val, input, output) => {
|
|
228
|
+
|
|
229
|
+
if (typeof val !== 'boolean' && !['true', 'false'].includes(val))
|
|
230
|
+
throw new InputError("This value must be a boolean.");
|
|
231
|
+
|
|
232
|
+
val = !!val;
|
|
233
|
+
|
|
234
|
+
return val;
|
|
235
|
+
}, {
|
|
236
|
+
defaut: false,
|
|
237
|
+
...opts
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
/*----------------------------------
|
|
241
|
+
- AUTRES
|
|
242
|
+
----------------------------------*/
|
|
243
|
+
public date = (opts: TValidator<Date> & {
|
|
244
|
+
|
|
245
|
+
} = {}) => new Validator<Date>('date', (val, input, output) => {
|
|
246
|
+
|
|
247
|
+
const chaine = typeof val == 'string';
|
|
248
|
+
|
|
249
|
+
// Chaine = format iso
|
|
250
|
+
if (chaine) {
|
|
251
|
+
|
|
252
|
+
if (!isISO8601(val))
|
|
253
|
+
throw new InputError("This value must be a date.");
|
|
254
|
+
|
|
255
|
+
val = toDate(val);
|
|
256
|
+
|
|
257
|
+
} else if (!(val instanceof Date))
|
|
258
|
+
throw new InputError("This value must be a date.");
|
|
259
|
+
|
|
260
|
+
return val;
|
|
261
|
+
|
|
262
|
+
}, {
|
|
263
|
+
//defaut: new Date,
|
|
264
|
+
...opts,
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
/*----------------------------------
|
|
268
|
+
- FICHIER
|
|
269
|
+
----------------------------------*/
|
|
270
|
+
protected validateFile = (
|
|
271
|
+
{ type, taille, ...opts }: TFileValidator = {},
|
|
272
|
+
val: any,
|
|
273
|
+
input: TObjetDonnees,
|
|
274
|
+
output: TObjetDonnees
|
|
275
|
+
): File | undefined => {
|
|
276
|
+
|
|
277
|
+
console.log('VALIDER FICHIER', type, val);
|
|
278
|
+
|
|
279
|
+
if (!(val instanceof NormalizedFile))
|
|
280
|
+
throw new InputError(`Must be a File (${typeof val} received)`);
|
|
281
|
+
|
|
282
|
+
// MIME
|
|
283
|
+
if (type !== undefined) {
|
|
284
|
+
|
|
285
|
+
let mimetypes: string[];
|
|
286
|
+
|
|
287
|
+
// Raccourcis
|
|
288
|
+
if (typeof type === 'string') {
|
|
289
|
+
if (type in raccourcisMime)
|
|
290
|
+
mimetypes = raccourcisMime[type as keyof typeof raccourcisMime]
|
|
291
|
+
else
|
|
292
|
+
throw new Error(`Aucune liste de mimetype référencée pour le type de fichier « ${type} »`);
|
|
293
|
+
} else
|
|
294
|
+
mimetypes = type;
|
|
295
|
+
|
|
296
|
+
// Vérification
|
|
297
|
+
const mimeFichier = val.type;
|
|
298
|
+
if (!mimetypes.includes(mimeFichier))
|
|
299
|
+
throw new InputError('Only the following formats are allowed: ' + mimetypes.join(', ') + '. The file you gave is ' + mimeFichier + '.');
|
|
300
|
+
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Taille
|
|
304
|
+
if (taille) {
|
|
305
|
+
const tailleFichier = val.size / 1024 / 1024; // Mo
|
|
306
|
+
if (tailleFichier > taille)
|
|
307
|
+
throw new InputError(`Le fichier ne doit pas faire plus de ${taille} Mo (taille reçue: ${tailleFichier} Mo)`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return val;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
}
|
package/src/server/app/config.ts
CHANGED
|
@@ -16,28 +16,20 @@ import yaml from 'yaml';
|
|
|
16
16
|
----------------------------------*/
|
|
17
17
|
|
|
18
18
|
declare global {
|
|
19
|
-
namespace
|
|
20
|
-
namespace Config {
|
|
19
|
+
namespace Config {
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
type EnvName = TEnvConfig["name"];
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
23
|
+
type Env = TEnvConfig;
|
|
24
|
+
type Identity = AppIdentityConfig;
|
|
25
|
+
interface Services {}
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
export type TEnvName = TEnvConfig["name"];
|
|
32
30
|
export type TEnvConfig = {
|
|
33
|
-
|
|
34
31
|
name: 'local' | 'server',
|
|
35
32
|
profile: 'dev' | 'prod',
|
|
36
|
-
level: 'silly' | 'info' | 'warn' | 'error',
|
|
37
|
-
|
|
38
|
-
localIP: string,
|
|
39
|
-
domain: string,
|
|
40
|
-
url: string,
|
|
41
33
|
}
|
|
42
34
|
|
|
43
35
|
type AppIdentityConfig = {
|
|
@@ -65,8 +57,8 @@ type AppIdentityConfig = {
|
|
|
65
57
|
}
|
|
66
58
|
|
|
67
59
|
export type AppConfig = {
|
|
68
|
-
env:
|
|
69
|
-
identity:
|
|
60
|
+
env: Config.Env,
|
|
61
|
+
identity: Config.Identity,
|
|
70
62
|
}
|
|
71
63
|
|
|
72
64
|
/*----------------------------------
|
|
@@ -90,23 +82,13 @@ export default class ConfigParser {
|
|
|
90
82
|
public env(): TEnvConfig {
|
|
91
83
|
// We assume that when we run 5htp dev, we're in local
|
|
92
84
|
// Otherwise, we're in production environment (docker)
|
|
93
|
-
console.log("Using environment:", process.env.NODE_ENV);
|
|
85
|
+
console.log("[app] Using environment:", process.env.NODE_ENV);
|
|
94
86
|
return process.env.NODE_ENV === 'development' ? {
|
|
95
87
|
name: 'local',
|
|
96
|
-
profile: 'dev'
|
|
97
|
-
level: 'silly',
|
|
98
|
-
|
|
99
|
-
localIP: '86.76.176.80',
|
|
100
|
-
domain: 'localhost:3010',
|
|
101
|
-
url: 'http://localhost:3010',
|
|
88
|
+
profile: 'dev'
|
|
102
89
|
} : {
|
|
103
90
|
name: 'server',
|
|
104
91
|
profile: 'prod',
|
|
105
|
-
level: 'silly',
|
|
106
|
-
|
|
107
|
-
localIP: '86.76.176.80',
|
|
108
|
-
domain: 'megacharger.io',
|
|
109
|
-
url: 'https://megacharger.io',
|
|
110
92
|
}
|
|
111
93
|
}
|
|
112
94
|
|