5htp-core 0.0.8 → 0.1.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/package.json +1 -1
- package/src/client/assets/css/components/button.less +47 -44
- package/src/client/assets/css/components/card.less +43 -21
- package/src/client/assets/css/components/components.less +25 -0
- package/src/client/assets/css/components/lists.less +30 -15
- package/src/client/assets/css/components/other.less +9 -5
- package/src/client/assets/css/core.less +1 -0
- package/src/client/assets/css/layouts.less +25 -10
- package/src/client/assets/css/medias.less +3 -1
- package/src/client/assets/css/spacing.less +2 -1
- package/src/client/assets/css/text/icons.less +1 -1
- package/src/client/assets/css/text/text.less +17 -11
- package/src/client/assets/css/text/titres.less +5 -5
- package/src/client/assets/css/theme.less +15 -13
- package/src/client/components/Dialog/card.tsx +1 -1
- package/src/client/components/Dialog/index.less +4 -3
- package/src/client/components/Form/index.tsx +2 -2
- package/src/client/components/Select/index.tsx +58 -0
- package/src/client/components/button.tsx +1 -1
- package/src/client/components/chart/base.tsx +1 -1
- package/src/client/components/containers/Scrollbar/index.less +1 -1
- package/src/client/components/containers/tabs/index.tsx +2 -2
- package/src/client/components/data/progressbar/circular/index.tsx +1 -1
- package/src/client/components/data/progressbar/index.less +5 -3
- package/src/client/components/data/progressbar/index.tsx +3 -3
- package/src/client/components/dropdown/index.tsx +12 -21
- package/src/client/components/input/BaseV2/index.less +4 -3
- package/src/client/components/input/BaseV2/index.tsx +4 -2
- package/src/client/components/input/Slider/index.less +1 -1
- package/src/client/components/input/UploadImage/index.less +1 -1
- package/src/client/context/index.ts +45 -41
- package/src/client/router/component.tsx +1 -0
- package/src/client/router/index.tsx +10 -3
- package/src/client/router/request/index.ts +0 -0
- package/src/common/data/input/validate.ts +2 -2
- package/src/common/data/input/validators/basic.ts +18 -18
- package/src/common/data/input/validators/build.ts +2 -2
- package/src/common/data/number/percentage.ts +4 -2
- package/src/common/errors/index.ts +17 -13
- package/src/common/router/index.ts +1 -1
- package/src/server/app/index.ts +70 -17
- package/src/server/data/Cache.ts +10 -4
- package/src/server/data/Token.olg.ts +2 -2
- package/src/server/data/aes.ts +2 -2
- package/src/server/patch.ts +0 -11
- package/src/server/routes/auth.ts +6 -0
- package/src/server/services/auth/base.ts +20 -12
- package/src/server/services/console/bugReporter.ts +31 -27
- package/src/server/services/console/html.ts +0 -0
- package/src/server/services/console/index.ts +1 -1
- package/src/server/services/cron/index.ts +2 -2
- package/src/server/services/database/index.ts +9 -11
- package/src/server/services/email/index.ts +2 -5
- package/src/server/services/router/index.ts +2 -2
- package/src/server/services/router/request/index.ts +1 -1
- package/src/server/services/router/request/services/auth.ts +5 -5
- package/src/server/services/router/request/services/detect.ts +4 -4
- package/src/server/services/router/request/services/tracking.ts +2 -2
- package/src/server/services/router/response/index.ts +3 -3
- package/src/server/services/socket/index.ts +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
5
|
// Libs
|
|
6
|
-
import {
|
|
6
|
+
import { InputError } from '@common/errors';
|
|
7
7
|
import * as basicValidators from './basic';
|
|
8
8
|
|
|
9
9
|
// Components
|
|
@@ -39,7 +39,7 @@ export const champ = <TValeur>(
|
|
|
39
39
|
return undefined;
|
|
40
40
|
// Requis
|
|
41
41
|
else
|
|
42
|
-
throw new
|
|
42
|
+
throw new InputError("Please enter a value");
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
if (opts.valider !== undefined)
|
|
@@ -11,11 +11,13 @@ export type TVariation = {
|
|
|
11
11
|
color: string,
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export const variationStr = (value: number, reference: number,
|
|
14
|
+
export const variationStr = (value: number, reference: number, options: {
|
|
15
|
+
lowerIsBetter?: boolean
|
|
16
|
+
} = {}): TVariation => {
|
|
15
17
|
const pc = variation(value, reference);
|
|
16
18
|
const pcStr = pc.toFixed(2);
|
|
17
19
|
return {
|
|
18
20
|
txt: ((pc > 0) ? '+' + pcStr : pcStr) + '%',
|
|
19
|
-
color: (lowerIsBetter ? pc > 0 : pc < 0) ? 'ea3943' : '16c784'
|
|
21
|
+
color: (options.lowerIsBetter ? pc > 0 : pc < 0) ? 'ea3943' : '16c784'
|
|
20
22
|
}
|
|
21
23
|
}
|
|
@@ -66,13 +66,13 @@ export abstract class Erreur extends Error {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
export class
|
|
69
|
+
export class InputError extends Erreur {
|
|
70
70
|
public http = 400;
|
|
71
71
|
public title = "Bad Request";
|
|
72
72
|
public static msgDefaut = "Bad Request.";
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
export class
|
|
75
|
+
export class InputErrorSchema extends Erreur {
|
|
76
76
|
|
|
77
77
|
public http = 400;
|
|
78
78
|
public title = "Bad Request";
|
|
@@ -89,7 +89,7 @@ export class ErreurSaisieSchema extends Erreur {
|
|
|
89
89
|
|
|
90
90
|
public constructor(message: TListeErreursSaisie, details?: TDetailsErreur) {
|
|
91
91
|
|
|
92
|
-
super(
|
|
92
|
+
super( InputErrorSchema.listeToString(message), details );
|
|
93
93
|
|
|
94
94
|
this.erreursSaisie = message;
|
|
95
95
|
|
|
@@ -103,29 +103,33 @@ export class ErreurSaisieSchema extends Erreur {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
export class
|
|
106
|
+
export class AuthRequired extends Erreur {
|
|
107
107
|
public http = 401;
|
|
108
108
|
public title = "Authentication Required";
|
|
109
109
|
public static msgDefaut = "Please Login to Continue.";
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
export class
|
|
112
|
+
export class Forbidden extends Erreur {
|
|
113
113
|
public http = 403;
|
|
114
114
|
public title = "Access Denied";
|
|
115
115
|
public static msgDefaut = "You're not allowed to access to this resource.";
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
export class
|
|
118
|
+
export class NotFound extends Erreur {
|
|
119
119
|
public http = 404;
|
|
120
120
|
public title = "Not Found";
|
|
121
121
|
public static msgDefaut = "The resource you asked for was not found.";
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
export class
|
|
124
|
+
export class Anomaly extends Erreur {
|
|
125
125
|
|
|
126
126
|
public http = 500;
|
|
127
127
|
public title = "Technical Error";
|
|
128
128
|
public static msgDefaut = "A technical error has occurred. A notification has just been sent to the admin.";
|
|
129
|
+
|
|
130
|
+
public constructor(message, public data: object) {
|
|
131
|
+
super(message);
|
|
132
|
+
}
|
|
129
133
|
}
|
|
130
134
|
|
|
131
135
|
export class NotAvailable extends Erreur {
|
|
@@ -148,13 +152,13 @@ export const instancierViaCode = (
|
|
|
148
152
|
): Erreur => {
|
|
149
153
|
|
|
150
154
|
if (typeof message === 'object')
|
|
151
|
-
return new
|
|
155
|
+
return new InputErrorSchema(message, details);
|
|
152
156
|
|
|
153
157
|
switch (code) {
|
|
154
|
-
case 400: return new
|
|
155
|
-
case 401: return new
|
|
156
|
-
case 403: return new
|
|
157
|
-
case 404: return new
|
|
158
|
-
default: return new
|
|
158
|
+
case 400: return new InputError( message, details);
|
|
159
|
+
case 401: return new AuthRequired( message, details);
|
|
160
|
+
case 403: return new Forbidden( message, details);
|
|
161
|
+
case 404: return new NotFound( message, details);
|
|
162
|
+
default: return new Anomaly( message, details);
|
|
159
163
|
}
|
|
160
164
|
}
|
|
@@ -35,7 +35,7 @@ const getLayout = (routePath: string | undefined): Layout | undefined => {
|
|
|
35
35
|
if (routePath === layoutPath || routePath.startsWith( layoutPath + '/' ))
|
|
36
36
|
layout = { path: layoutPath, Component: layouts[layoutPath] };
|
|
37
37
|
}
|
|
38
|
-
layout && console.log(
|
|
38
|
+
//layout && console.log(`${routePath}: Using Layout: ${layout.path}`);
|
|
39
39
|
return layout;
|
|
40
40
|
}
|
|
41
41
|
|
package/src/server/app/index.ts
CHANGED
|
@@ -15,7 +15,7 @@ import ConfigParser, { TEnvConfig } from './config';
|
|
|
15
15
|
----------------------------------*/
|
|
16
16
|
|
|
17
17
|
type THookName = 'ready' | 'cleanup' | 'error'
|
|
18
|
-
type THook = () => void
|
|
18
|
+
type THook = () => Promise<void>;
|
|
19
19
|
|
|
20
20
|
type TServiceOptions = {
|
|
21
21
|
instanciate: boolean
|
|
@@ -91,6 +91,20 @@ export class App {
|
|
|
91
91
|
----------------------------------*/
|
|
92
92
|
|
|
93
93
|
public constructor() {
|
|
94
|
+
|
|
95
|
+
// Gestion crash
|
|
96
|
+
process.on('unhandledRejection', (error: any, promise: any) => {
|
|
97
|
+
|
|
98
|
+
console.error("Unhandled promise rejection:", error);
|
|
99
|
+
|
|
100
|
+
// Send email report
|
|
101
|
+
if (this.isLoaded('console'))
|
|
102
|
+
$.console.bugReport.server(error);
|
|
103
|
+
else
|
|
104
|
+
console.error(`Unable to send bug report: console service not loaded.`);
|
|
105
|
+
|
|
106
|
+
});
|
|
107
|
+
|
|
94
108
|
// Load config files
|
|
95
109
|
const configParser = new ConfigParser( this.path.root );
|
|
96
110
|
this.env = configParser.env();
|
|
@@ -106,21 +120,47 @@ export class App {
|
|
|
106
120
|
console.log("Configure services with", this.config);
|
|
107
121
|
}
|
|
108
122
|
|
|
109
|
-
|
|
123
|
+
// Register a service
|
|
124
|
+
public register<TServiceName extends keyof Core.Services>(
|
|
125
|
+
id: TServiceName,
|
|
126
|
+
Service: TServiceClass,
|
|
127
|
+
options: Partial<TServiceOptions> = {}
|
|
128
|
+
) {
|
|
110
129
|
|
|
111
130
|
// Pas d'export default new Service pour chaque fichier de service,
|
|
112
131
|
// dissuaded'importer ms service sn'importe où, ce qui créé des références circulaires
|
|
113
|
-
console.log(`
|
|
132
|
+
console.log(`[services] Registering service ${id} ...`);
|
|
114
133
|
const service = options.instanciate !== false ? new Service() : Service;
|
|
115
|
-
this.services[id] = service;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
service
|
|
134
|
+
this.services[id as string] = service;
|
|
135
|
+
|
|
136
|
+
if ('load' in service) {
|
|
137
|
+
|
|
138
|
+
console.log(`[services] Starting service ${id} ...`);
|
|
139
|
+
|
|
140
|
+
// Lorsque service.load est async, une propriété loading doit etre présente
|
|
141
|
+
// De façon à ce que les autres services puissent savoir quand ce service est prêt
|
|
142
|
+
if ('loading' in service) {
|
|
143
|
+
|
|
144
|
+
console.log(`[services] Waiting service ${id} to be fully loaded ...`);
|
|
145
|
+
service.loading = service.load().then(() => {
|
|
146
|
+
console.info(`[service] Service ${id} successfully started.`);
|
|
147
|
+
}).catch(e => {
|
|
148
|
+
// Bug report via email
|
|
149
|
+
console.error(`[service] Error while starting the ${id} service:`, e);
|
|
150
|
+
e.message = `Start ${id} service: ` + e.message;
|
|
151
|
+
$.console.bugReport.server(e);
|
|
152
|
+
});;
|
|
153
|
+
|
|
154
|
+
this.loading.push(service.loading);
|
|
155
|
+
|
|
156
|
+
} else
|
|
157
|
+
service.load();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Test if a service was registered
|
|
162
|
+
public isLoaded( id: keyof Core.Services ) {
|
|
163
|
+
return id in this.services;
|
|
124
164
|
}
|
|
125
165
|
|
|
126
166
|
public on( name: THookName, callback: THook ) {
|
|
@@ -128,23 +168,36 @@ export class App {
|
|
|
128
168
|
return this;
|
|
129
169
|
}
|
|
130
170
|
|
|
171
|
+
public runHook( hookName: THookName ) {
|
|
172
|
+
console.info(`[hook] Run all ${hookName} hook (${this.hooks.ready.length}).`);
|
|
173
|
+
return Promise.all(
|
|
174
|
+
this.hooks.ready.map(
|
|
175
|
+
cb => cb().catch(e => {
|
|
176
|
+
console.error(`[hook] Error while executing hook ${hookName}:`, e);
|
|
177
|
+
})
|
|
178
|
+
)
|
|
179
|
+
).then(() => {
|
|
180
|
+
console.info(`[hook] Hooks ${hookName} executed with success.`);
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
131
184
|
/*----------------------------------
|
|
132
185
|
- LAUNCH
|
|
133
186
|
----------------------------------*/
|
|
134
187
|
public async launch() {
|
|
135
188
|
|
|
136
|
-
console.info(`Waiting for services to be ready ...`);
|
|
189
|
+
console.info(`[boot] Waiting for all services to be ready ...`);
|
|
137
190
|
await Promise.all( this.loading );
|
|
138
191
|
|
|
139
|
-
console.info(`Launching application ...`);
|
|
140
|
-
await
|
|
192
|
+
console.info(`[boot] Launching application ...`);
|
|
193
|
+
await this.runHook('ready');
|
|
141
194
|
|
|
142
195
|
// NOTE: Useless ?
|
|
143
196
|
/*if (this.hmr)
|
|
144
197
|
this.activateHMR();*/
|
|
145
198
|
|
|
146
|
-
console.info(`Application is ready.`);
|
|
147
|
-
|
|
199
|
+
console.info(`[boot] Application is ready.`);
|
|
200
|
+
|
|
148
201
|
this.launched = true;
|
|
149
202
|
|
|
150
203
|
}
|
package/src/server/data/Cache.ts
CHANGED
|
@@ -14,6 +14,12 @@ import app from '@server/app';
|
|
|
14
14
|
|
|
15
15
|
// Libs
|
|
16
16
|
|
|
17
|
+
/*----------------------------------
|
|
18
|
+
- CONFIG
|
|
19
|
+
----------------------------------*/
|
|
20
|
+
|
|
21
|
+
const debug = false;
|
|
22
|
+
|
|
17
23
|
/*----------------------------------
|
|
18
24
|
- TYPES
|
|
19
25
|
----------------------------------*/
|
|
@@ -50,7 +56,7 @@ class Cache {
|
|
|
50
56
|
|
|
51
57
|
private cleanMem() {
|
|
52
58
|
|
|
53
|
-
console.log("[cache] Clean memory");
|
|
59
|
+
debug && console.log("[cache] Clean memory");
|
|
54
60
|
|
|
55
61
|
const now = Date.now();
|
|
56
62
|
for (const key in this.data) {
|
|
@@ -88,11 +94,11 @@ class Cache {
|
|
|
88
94
|
|
|
89
95
|
let retour: CacheEntry | undefined = this.data[cle];
|
|
90
96
|
|
|
91
|
-
console.log(`[cache] Get "${cle}".`);
|
|
97
|
+
debug && console.log(`[cache] Get "${cle}".`);
|
|
92
98
|
|
|
93
99
|
// Expired
|
|
94
100
|
if (retour?.expiration && retour.expiration < Date.now()){
|
|
95
|
-
console.log(`[cache] Key ${cle} expired.`);
|
|
101
|
+
debug && console.log(`[cache] Key ${cle} expired.`);
|
|
96
102
|
retour = undefined;
|
|
97
103
|
}
|
|
98
104
|
|
|
@@ -133,7 +139,7 @@ class Cache {
|
|
|
133
139
|
*/
|
|
134
140
|
public set( cle: string, val: TPrimitiveValue, expiration: TExpirationDelay = null ): void {
|
|
135
141
|
|
|
136
|
-
console.log("[cache] Updating cache " + cle);
|
|
142
|
+
debug && console.log("[cache] Updating cache " + cle);
|
|
137
143
|
this.data[ cle ] = {
|
|
138
144
|
value: val,
|
|
139
145
|
expiration: this.delayToTimestamp(expiration)
|
|
@@ -15,7 +15,7 @@ import hInterval from 'human-interval';
|
|
|
15
15
|
|
|
16
16
|
// Core
|
|
17
17
|
import Cron, { CronTask } from '@server/services/cron';
|
|
18
|
-
import {
|
|
18
|
+
import { Forbidden } from '@common/errors';
|
|
19
19
|
|
|
20
20
|
const debug = true;
|
|
21
21
|
|
|
@@ -82,7 +82,7 @@ class Tokens {
|
|
|
82
82
|
debug && console.log("Get token", token, options);
|
|
83
83
|
if (options === undefined) {
|
|
84
84
|
if (critical)
|
|
85
|
-
throw new
|
|
85
|
+
throw new Forbidden(`Invalid token.`);
|
|
86
86
|
else
|
|
87
87
|
return undefined;
|
|
88
88
|
}
|
package/src/server/data/aes.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import crypto from 'crypto';
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
|
-
import {
|
|
9
|
+
import { Forbidden } from '@common/errors';
|
|
10
10
|
|
|
11
11
|
const debug = true;
|
|
12
12
|
|
|
@@ -43,7 +43,7 @@ class AES {
|
|
|
43
43
|
|
|
44
44
|
} catch (error) {
|
|
45
45
|
|
|
46
|
-
throw new
|
|
46
|
+
throw new Forbidden("Invalid token.");
|
|
47
47
|
|
|
48
48
|
}
|
|
49
49
|
|
package/src/server/patch.ts
CHANGED
|
@@ -4,17 +4,6 @@ moduleAlias.addAliases({
|
|
|
4
4
|
'react-dom': "preact/compat",
|
|
5
5
|
})
|
|
6
6
|
|
|
7
|
-
/*----------------------------------
|
|
8
|
-
- DEBUG
|
|
9
|
-
----------------------------------*/
|
|
10
|
-
|
|
11
|
-
// Gestion crash
|
|
12
|
-
process.on('unhandledRejection', (error: any, promise: any) => {
|
|
13
|
-
|
|
14
|
-
console.error("Unhandled promise rejection:", error);
|
|
15
|
-
|
|
16
|
-
});
|
|
17
|
-
|
|
18
7
|
/*----------------------------------
|
|
19
8
|
- DATES & TIMZEONE
|
|
20
9
|
----------------------------------*/
|
|
@@ -7,7 +7,7 @@ import md5 from 'md5';
|
|
|
7
7
|
import { OAuth2Client, LoginTicket } from 'google-auth-library';
|
|
8
8
|
|
|
9
9
|
// Core libs
|
|
10
|
-
import {
|
|
10
|
+
import { Forbidden } from '@common/errors';
|
|
11
11
|
|
|
12
12
|
// App Libs
|
|
13
13
|
import { IP } from '@models';
|
|
@@ -38,7 +38,7 @@ export type AuthConfig = {
|
|
|
38
38
|
key: string,
|
|
39
39
|
expiration: string,
|
|
40
40
|
},
|
|
41
|
-
google
|
|
41
|
+
google?: {
|
|
42
42
|
web: {
|
|
43
43
|
clientId: string,
|
|
44
44
|
secret: string,
|
|
@@ -75,11 +75,13 @@ export default abstract class UserAuthBase {
|
|
|
75
75
|
public abstract beforeSignup(user: User): Promise< void >;
|
|
76
76
|
public abstract afterSignup(user: User): Promise<{ redirect: string }>;
|
|
77
77
|
|
|
78
|
-
private googleClient =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
private googleClient = app.config.auth.google
|
|
79
|
+
? new OAuth2Client(
|
|
80
|
+
app.config.auth.google.web.clientId, // Google Client ID
|
|
81
|
+
app.config.auth.google.web.secret, // Private key
|
|
82
|
+
"https://" + app.env.domain + "/auth/google/response" // Redirect url
|
|
83
|
+
)
|
|
84
|
+
: undefined;
|
|
83
85
|
|
|
84
86
|
public async load() {
|
|
85
87
|
|
|
@@ -101,6 +103,9 @@ export default abstract class UserAuthBase {
|
|
|
101
103
|
|
|
102
104
|
public async FromGoogle(request: ServerRequest): Promise<string> {
|
|
103
105
|
|
|
106
|
+
if (!this.googleClient)
|
|
107
|
+
throw new Forbidden(`Authentication method disabled.`);
|
|
108
|
+
|
|
104
109
|
// Register start time, so we can determine the signup time to display
|
|
105
110
|
request.response?.cookie('signupstart', Date.now());
|
|
106
111
|
|
|
@@ -126,8 +131,11 @@ export default abstract class UserAuthBase {
|
|
|
126
131
|
request: ServerRequest,
|
|
127
132
|
): Promise<AuthResponse> {
|
|
128
133
|
|
|
134
|
+
if (!this.googleClient)
|
|
135
|
+
throw new Forbidden(`Authentication method disabled.`);
|
|
136
|
+
|
|
129
137
|
if (codeOrToken === undefined)
|
|
130
|
-
throw new
|
|
138
|
+
throw new Forbidden("Bad code / token");
|
|
131
139
|
|
|
132
140
|
if (type === 'code') {
|
|
133
141
|
const r = await this.googleClient.getToken(codeOrToken);
|
|
@@ -146,16 +154,16 @@ export default abstract class UserAuthBase {
|
|
|
146
154
|
]
|
|
147
155
|
});
|
|
148
156
|
} catch (error) {
|
|
149
|
-
throw new
|
|
157
|
+
throw new Forbidden(`Google denied your login attempt: ` + error.message + `. If you don't think it's normal, please contact us.`);
|
|
150
158
|
}
|
|
151
159
|
|
|
152
160
|
const payload = ticket.getPayload();
|
|
153
161
|
if (payload === undefined)
|
|
154
|
-
throw new
|
|
162
|
+
throw new Forbidden("Invalid payload");
|
|
155
163
|
const { email, sub: google_id } = payload;
|
|
156
164
|
|
|
157
165
|
if (email === undefined)
|
|
158
|
-
throw new
|
|
166
|
+
throw new Forbidden("Unable to get your email address from the Google sign-in.");
|
|
159
167
|
|
|
160
168
|
return await this.Auth(email, request, true);
|
|
161
169
|
|
|
@@ -180,7 +188,7 @@ export default abstract class UserAuthBase {
|
|
|
180
188
|
|
|
181
189
|
} else if (!canPass) { // Send login email
|
|
182
190
|
|
|
183
|
-
throw new
|
|
191
|
+
throw new Forbidden("This option is not available");
|
|
184
192
|
|
|
185
193
|
// If the current IP was used to connect to another account that the current
|
|
186
194
|
ip = await request.detect.botsAndMultiaccount(user.name);
|
|
@@ -70,7 +70,7 @@ export default class BugReporter {
|
|
|
70
70
|
public async server( error: Error, request?: ServerRequest ) {
|
|
71
71
|
|
|
72
72
|
// error should be printed in the console, so they're acccessible from logs
|
|
73
|
-
console.error(error);
|
|
73
|
+
console.error(`Sending bug report for the following error:`, error);
|
|
74
74
|
|
|
75
75
|
// Prevent duplicates
|
|
76
76
|
if (!this.shouldSendReport('server', request?.user?.name, undefined, error.message))
|
|
@@ -79,7 +79,6 @@ export default class BugReporter {
|
|
|
79
79
|
// Get context
|
|
80
80
|
const now = new Date();
|
|
81
81
|
const hash = uuid();
|
|
82
|
-
const erroTitle = "Server Bug: " + error.message;
|
|
83
82
|
const { channelType, channelId } = this.console.getChannel();
|
|
84
83
|
|
|
85
84
|
// On envoi l'email avant l'insertion dans bla bdd
|
|
@@ -90,31 +89,36 @@ export default class BugReporter {
|
|
|
90
89
|
);
|
|
91
90
|
|
|
92
91
|
// Send notification
|
|
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
|
-
|
|
92
|
+
if (app.isLoaded('email'))
|
|
93
|
+
$.email.send({
|
|
94
|
+
to: app.identity.author.email,
|
|
95
|
+
subject: "Server bug: " + error.message,
|
|
96
|
+
html: `
|
|
97
|
+
<a href="${app.env.url}/admin/activity/requests/${channelId}">
|
|
98
|
+
View Request details & console
|
|
99
|
+
</a>
|
|
100
|
+
<br/>
|
|
101
|
+
${logsHtml}
|
|
102
|
+
`
|
|
103
|
+
});
|
|
104
|
+
else
|
|
105
|
+
console.error("Unable to send bug report: email service not loaded.");
|
|
106
|
+
|
|
107
|
+
/*if (app.isLoaded('sql'))
|
|
108
|
+
// Memorize
|
|
109
|
+
$.sql.insert('BugServer', {
|
|
110
|
+
// Context
|
|
111
|
+
hash: hash,
|
|
112
|
+
date: now,
|
|
113
|
+
channelType,
|
|
114
|
+
channelId,
|
|
115
|
+
// User
|
|
116
|
+
user: request?.user?.name,
|
|
117
|
+
ip: request?.ip,
|
|
118
|
+
// Error
|
|
119
|
+
stacktrace: error.stack || error.message,
|
|
120
|
+
logs: logsHtml
|
|
121
|
+
});*/
|
|
118
122
|
|
|
119
123
|
// Update error message
|
|
120
124
|
error.message = "A bug report has been sent to my personal mailbox. Sorry for the inconvenience.";
|
|
File without changes
|
|
@@ -256,7 +256,7 @@ export class Console {
|
|
|
256
256
|
let html = logs.map( log => logToHTML( log, this )).join('\n');
|
|
257
257
|
|
|
258
258
|
if (full) {
|
|
259
|
-
const consoleCss = `background: #000; padding: 20px; font-family: 'monospace'; font-size: 12px; line-height: 20px;`
|
|
259
|
+
const consoleCss = `background: #000; padding: 20px; font-family: 'Fira Mono', 'monospace', 'Monaco'; font-size: 12px; line-height: 20px;`
|
|
260
260
|
html = '<div style="' + consoleCss + '">' + html + '</div>';
|
|
261
261
|
}
|
|
262
262
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
5
|
// Core
|
|
6
|
-
import {
|
|
6
|
+
import { NotFound } from '@common/errors';
|
|
7
7
|
import app from '@server/app';
|
|
8
8
|
import context from '@server/context';
|
|
9
9
|
|
|
@@ -99,7 +99,7 @@ export class CronManager {
|
|
|
99
99
|
const tache = CronManager.taches[nom];
|
|
100
100
|
|
|
101
101
|
if (tache === undefined)
|
|
102
|
-
throw new
|
|
102
|
+
throw new NotFound("Tâche NotFound: " + nom);
|
|
103
103
|
|
|
104
104
|
await tache.run(true);
|
|
105
105
|
|
|
@@ -9,7 +9,7 @@ const safeStringify = require('fast-safe-stringify'); // remplace les référenc
|
|
|
9
9
|
|
|
10
10
|
// Core: general
|
|
11
11
|
import app, { $ } from '@server/app';
|
|
12
|
-
import {
|
|
12
|
+
import { NotFound } from '@common/errors';
|
|
13
13
|
|
|
14
14
|
// Services
|
|
15
15
|
import './connection';
|
|
@@ -113,7 +113,7 @@ export function sql<TRowData extends TObjetDonnees = {}>(strings: TemplateString
|
|
|
113
113
|
fetchStats(columns, string, periodStr, intervalStr)*/
|
|
114
114
|
|
|
115
115
|
query.mergeValues = (options: TQueryOptions = {}) =>
|
|
116
|
-
sql.query(string, options).then(queriesResult => {
|
|
116
|
+
sql.query(string, options).then( queriesResult => {
|
|
117
117
|
|
|
118
118
|
const data: TObjetDonnees = {};
|
|
119
119
|
for (const queryResult of queriesResult)
|
|
@@ -211,7 +211,8 @@ sql.query = async <TRowData extends TObjetDonnees = {}>(
|
|
|
211
211
|
time: Date.now() - startTime,
|
|
212
212
|
});
|
|
213
213
|
}
|
|
214
|
-
|
|
214
|
+
|
|
215
|
+
return rows as unknown as TRowData[];
|
|
215
216
|
|
|
216
217
|
} catch (error) {
|
|
217
218
|
|
|
@@ -251,7 +252,7 @@ sql.firstOrFail = <TRowData extends TObjetDonnees = {}>(query: string, message?:
|
|
|
251
252
|
sql.query(query, opts).then((resultatRequetes: any) => {
|
|
252
253
|
|
|
253
254
|
if (resultatRequetes.length === 0)
|
|
254
|
-
throw new
|
|
255
|
+
throw new NotFound(message);
|
|
255
256
|
|
|
256
257
|
return resultatRequetes[0];
|
|
257
258
|
|
|
@@ -359,18 +360,15 @@ sql.insert = async <TData extends TObjetDonnees>(
|
|
|
359
360
|
}).join(', ');
|
|
360
361
|
|
|
361
362
|
if (opts.upsert !== undefined)
|
|
362
|
-
query += ' ON DUPLICATE KEY UPDATE ' + opts.upsert.map(col =>
|
|
363
|
+
query += ' ON DUPLICATE KEY UPDATE ' + opts.upsert.map( col =>
|
|
363
364
|
'`' + col + '` = ' + (opts.upsertMode === 'increment' ? '`' + col + '` + ' : '') + 'VALUES(' + col + ')'
|
|
364
365
|
)
|
|
365
366
|
|
|
366
367
|
const queryResult = await sql.query(query + ';', opts);
|
|
367
368
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
data.id = queryResult.insertId;
|
|
372
|
-
return data;
|
|
373
|
-
}
|
|
369
|
+
console.log("opts.returnQuery", opts.returnQuery, "queryResult", queryResult);
|
|
370
|
+
|
|
371
|
+
return [data, queryResult.insertId, queryResult];
|
|
374
372
|
}
|
|
375
373
|
|
|
376
374
|
/*----------------------------------
|
|
@@ -135,7 +135,7 @@ export default class Email {
|
|
|
135
135
|
const template = templates[email.template];
|
|
136
136
|
|
|
137
137
|
if (template === undefined)
|
|
138
|
-
throw new Error(`Impossible de charger la template email ${email.template} depuis le cache (
|
|
138
|
+
throw new Error(`Impossible de charger la template email ${email.template} depuis le cache (NotFound).`);
|
|
139
139
|
|
|
140
140
|
const txt = template(email.data || {})
|
|
141
141
|
|
|
@@ -197,7 +197,4 @@ declare global {
|
|
|
197
197
|
email: Email;
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Register transporters
|
|
203
|
-
require("./transports/*");
|
|
200
|
+
}
|
|
@@ -22,7 +22,7 @@ import TrackingService from './request/services/tracking';
|
|
|
22
22
|
|
|
23
23
|
// Core: libs
|
|
24
24
|
import app, { $ } from '@server/app';
|
|
25
|
-
import {
|
|
25
|
+
import { NotFound } from '@common/errors';
|
|
26
26
|
|
|
27
27
|
// Core: types
|
|
28
28
|
import type { TSsrUnresolvedRoute, TRegisterPageArgs } from '@client/router';
|
|
@@ -439,7 +439,7 @@ export class Router extends BaseRouter {
|
|
|
439
439
|
return response;
|
|
440
440
|
}
|
|
441
441
|
|
|
442
|
-
throw new
|
|
442
|
+
throw new NotFound(`The requested endpoint was not found.`);
|
|
443
443
|
}
|
|
444
444
|
|
|
445
445
|
}
|