5htp-core 0.2.4-3 → 0.2.5
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/text/text.less +0 -26
- package/src/client/components/Amount.tsx +1 -1
- package/src/client/pages/_layout/index.less +6 -0
- package/src/client/pages/_layout/index.tsx +43 -0
- package/src/client/pages/_messages/400.tsx +8 -9
- package/src/client/pages/_messages/401.tsx +20 -3
- package/src/client/pages/_messages/403.tsx +6 -6
- package/src/client/pages/_messages/404.tsx +7 -7
- package/src/client/pages/_messages/500.tsx +6 -6
- package/src/client/services/router/index.tsx +5 -1
- package/src/common/errors/index.ts +1 -1
- package/src/common/router/layouts.ts +22 -23
- package/src/server/services/console/index.ts +86 -4
- package/src/server/services/database/connection.ts +43 -19
- package/src/server/services/router/index.ts +13 -5
- package/src/client/pages/_layout/base.less +0 -13
- package/src/client/pages/_layout/landing/index.less +0 -5
- package/src/client/pages/_layout/landing/index.tsx +0 -55
- package/src/client/pages/_messages/403.svg +0 -1835
- package/src/client/pages/_messages/404.svg +0 -205
- package/src/client/pages/_messages/500.svg +0 -396
- package/src/server/services/console/bugReporter.ts +0 -250
|
@@ -8,6 +8,7 @@ import mysql from 'mysql2/promise';
|
|
|
8
8
|
// Core: general
|
|
9
9
|
import Application from '@server/app';
|
|
10
10
|
import Service from '@server/app/service';
|
|
11
|
+
import { Anomaly } from '@common/errors';
|
|
11
12
|
|
|
12
13
|
// Core: specific
|
|
13
14
|
import { SqlError } from './debug';
|
|
@@ -26,14 +27,19 @@ const LogPrefix = '[database][connection]';
|
|
|
26
27
|
- SERVICE CONFIG
|
|
27
28
|
----------------------------------*/
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
type ConnectionConfig = {
|
|
31
|
+
name: string,
|
|
32
|
+
databases: string[],
|
|
31
33
|
host: string,
|
|
32
34
|
port: number,
|
|
33
35
|
login: string,
|
|
34
36
|
password: string,
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
export type DatabaseServiceConfig = {
|
|
40
|
+
connections: ConnectionConfig[]
|
|
41
|
+
}
|
|
42
|
+
|
|
37
43
|
export type THooks = {
|
|
38
44
|
|
|
39
45
|
}
|
|
@@ -63,10 +69,11 @@ type TSelectQueryResult = any;
|
|
|
63
69
|
/*----------------------------------
|
|
64
70
|
- SERVICES
|
|
65
71
|
----------------------------------*/
|
|
66
|
-
export default class
|
|
72
|
+
export default class DatabaseManager extends Service<DatabaseServiceConfig, THooks, Application> {
|
|
67
73
|
|
|
68
74
|
private initialized = false;
|
|
69
75
|
public connection!: mysql.Pool;
|
|
76
|
+
public connectionConfig?: ConnectionConfig;
|
|
70
77
|
|
|
71
78
|
public tables: TDatabasesList = {};
|
|
72
79
|
public metas = new MetadataParser(this);
|
|
@@ -84,35 +91,49 @@ export default class DatabaseConnection extends Service<DatabaseServiceConfig, T
|
|
|
84
91
|
|
|
85
92
|
this.initialized = false;
|
|
86
93
|
|
|
87
|
-
|
|
94
|
+
// Try to connect to one of the databases
|
|
95
|
+
const connectionErrors: string[] = []
|
|
96
|
+
for (const connectionConfig of this.config.connections){
|
|
97
|
+
try {
|
|
98
|
+
this.connection = await this.connect(connectionConfig);
|
|
99
|
+
this.connectionConfig = connectionConfig;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.warn(LogPrefix, `Failed to connect to ${connectionConfig.name}: ` + error);
|
|
102
|
+
connectionErrors.push(connectionConfig.name + ': ' + error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Coudnt connect to any database
|
|
107
|
+
if (this.connectionConfig === undefined)
|
|
108
|
+
throw new Anomaly(`Couldnt connect to any database.`, { connectionErrors });
|
|
88
109
|
|
|
89
|
-
|
|
110
|
+
// Disconnect from the database when the app is terminated
|
|
111
|
+
this.app.on('cleanup', () => this.disconnect());
|
|
90
112
|
|
|
91
|
-
|
|
113
|
+
// Load tables metas
|
|
114
|
+
this.tables = await this.metas.load( this.connectionConfig.databases );
|
|
92
115
|
|
|
116
|
+
// Ready to make queries
|
|
93
117
|
this.initialized = true;
|
|
94
|
-
|
|
95
118
|
}
|
|
96
119
|
|
|
97
|
-
public async
|
|
120
|
+
public async disconnect() {
|
|
98
121
|
return this.connection.end();
|
|
99
122
|
}
|
|
100
123
|
|
|
101
124
|
/*----------------------------------
|
|
102
125
|
- INIT
|
|
103
126
|
----------------------------------*/
|
|
104
|
-
public async connect() {
|
|
105
|
-
|
|
106
|
-
console.info(LogPrefix, `Connecting to databases ...`);
|
|
107
|
-
|
|
127
|
+
public async connect({ name, databases, host, login, password, port }: ConnectionConfig) {
|
|
128
|
+
console.info(LogPrefix, `Trying to connect to ${name} ...`);
|
|
108
129
|
return await mysql.createPool({
|
|
109
130
|
|
|
110
131
|
// Identification
|
|
111
|
-
host:
|
|
112
|
-
port:
|
|
113
|
-
user:
|
|
114
|
-
password:
|
|
115
|
-
database:
|
|
132
|
+
host: host,
|
|
133
|
+
port: port,
|
|
134
|
+
user: login,
|
|
135
|
+
password: password,
|
|
136
|
+
database: databases[0],
|
|
116
137
|
|
|
117
138
|
// Pool
|
|
118
139
|
waitForConnections: true,
|
|
@@ -137,7 +158,7 @@ export default class DatabaseConnection extends Service<DatabaseServiceConfig, T
|
|
|
137
158
|
//console.info(LogPrefix, 'queryFormat', query);
|
|
138
159
|
return query;
|
|
139
160
|
}
|
|
140
|
-
})
|
|
161
|
+
})
|
|
141
162
|
}
|
|
142
163
|
|
|
143
164
|
private typeCast( field: mysql.Field, next: Function ) {
|
|
@@ -216,13 +237,16 @@ export default class DatabaseConnection extends Service<DatabaseServiceConfig, T
|
|
|
216
237
|
|
|
217
238
|
public getTable( path: string ): TMetasTable {
|
|
218
239
|
|
|
240
|
+
if (this.connectionConfig === undefined)
|
|
241
|
+
throw new Error(`No connection has been initialised.`);
|
|
242
|
+
|
|
219
243
|
// Parse path
|
|
220
244
|
let db: string, table: string;
|
|
221
245
|
if (path.includes('.'))
|
|
222
246
|
([db, table] = path.split('.'));
|
|
223
247
|
else {
|
|
224
248
|
// Only the table = use the main database (first of the list in the config)
|
|
225
|
-
db = this.
|
|
249
|
+
db = this.connectionConfig.databases[0];
|
|
226
250
|
table = path;
|
|
227
251
|
}
|
|
228
252
|
|
|
@@ -27,7 +27,7 @@ import BaseRouter, {
|
|
|
27
27
|
TRouteOptions, defaultOptions
|
|
28
28
|
} from '@common/router';
|
|
29
29
|
import { buildRegex, getRegisterPageArgs } from '@common/router/register';
|
|
30
|
-
import { layoutsList } from '@common/router/layouts';
|
|
30
|
+
import { layoutsList, getLayout } from '@common/router/layouts';
|
|
31
31
|
import { TFetcherList, TFetcher } from '@common/router/request/api';
|
|
32
32
|
import type { TFrontRenderer } from '@common/router/response/page';
|
|
33
33
|
import type { TSsrUnresolvedRoute, TRegisterPageArgs } from '@client/services/router';
|
|
@@ -147,7 +147,6 @@ export default class ServerRouter<
|
|
|
147
147
|
// Since route registering requires all services to be ready,
|
|
148
148
|
// We load routes only when all services are ready
|
|
149
149
|
this.app.on('ready', async () => {
|
|
150
|
-
|
|
151
150
|
// Use require to avoid circular references
|
|
152
151
|
this.registerRoutes([
|
|
153
152
|
...require("metas:@/server/routes/**/*.ts"),
|
|
@@ -228,9 +227,13 @@ export default class ServerRouter<
|
|
|
228
227
|
options: TRoute["options"],
|
|
229
228
|
renderer: TFrontRenderer<{}, { message: string }>
|
|
230
229
|
) {
|
|
230
|
+
|
|
231
|
+
// Automatic layout form the nearest _layout folder
|
|
232
|
+
const layout = getLayout('Error ' + code, options);
|
|
233
|
+
|
|
231
234
|
this.errors[code] = {
|
|
232
235
|
code,
|
|
233
|
-
controller: (context: TRouterContext<this>) => new Page(null, renderer, context),
|
|
236
|
+
controller: (context: TRouterContext<this>) => new Page(null, renderer, context, layout),
|
|
234
237
|
options
|
|
235
238
|
};
|
|
236
239
|
}
|
|
@@ -503,7 +506,7 @@ declare type Routes = {
|
|
|
503
506
|
return response;
|
|
504
507
|
}
|
|
505
508
|
|
|
506
|
-
throw new NotFound(
|
|
509
|
+
throw new NotFound();
|
|
507
510
|
}
|
|
508
511
|
|
|
509
512
|
private async resolveApiBatch( fetchers: TFetcherList, request: ServerRequest<this> ) {
|
|
@@ -542,9 +545,14 @@ declare type Routes = {
|
|
|
542
545
|
// Rapport / debug
|
|
543
546
|
if (code === 500) {
|
|
544
547
|
|
|
548
|
+
// Report error
|
|
545
549
|
await this.app.runHook('error', e, request);
|
|
546
550
|
|
|
547
|
-
//
|
|
551
|
+
// Don't exose technical errors to users
|
|
552
|
+
if (this.app.env.profile === 'prod')
|
|
553
|
+
e.message = "We encountered an internal error, and our team has just been notified. Sorry for the inconvenience.";
|
|
554
|
+
|
|
555
|
+
// Pour déboguer les erreurs HTTP
|
|
548
556
|
} else if (this.app.env.profile === "dev")
|
|
549
557
|
console.warn(e);
|
|
550
558
|
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/*----------------------------------
|
|
2
|
-
- DEPENDANCES
|
|
3
|
-
----------------------------------*/
|
|
4
|
-
|
|
5
|
-
// Npm
|
|
6
|
-
import React from 'react';
|
|
7
|
-
|
|
8
|
-
// Core
|
|
9
|
-
|
|
10
|
-
// Core components
|
|
11
|
-
import Button, { Props as ButtonProps } from '@client/components/button';
|
|
12
|
-
import useHeader from '@client/pages/useHeader';
|
|
13
|
-
|
|
14
|
-
/*----------------------------------
|
|
15
|
-
- CONTROLEUR
|
|
16
|
-
----------------------------------*/
|
|
17
|
-
import './index.less';
|
|
18
|
-
export default ({ headline, subtitle, cta, preview }: {
|
|
19
|
-
|
|
20
|
-
headline: string,
|
|
21
|
-
subtitle: string,
|
|
22
|
-
cta: ButtonProps,
|
|
23
|
-
preview: [string, string]
|
|
24
|
-
|
|
25
|
-
}) => {
|
|
26
|
-
|
|
27
|
-
useHeader({
|
|
28
|
-
title: headline,
|
|
29
|
-
subtitle: subtitle,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
/*----------------------------------
|
|
33
|
-
- RENDER
|
|
34
|
-
----------------------------------*/
|
|
35
|
-
return (
|
|
36
|
-
<div id="landing">
|
|
37
|
-
|
|
38
|
-
<header>
|
|
39
|
-
<div class="text card">
|
|
40
|
-
<h1>{headline}</h1>
|
|
41
|
-
<p>
|
|
42
|
-
{subtitle}
|
|
43
|
-
</p>
|
|
44
|
-
<Button type="guide" {...cta} />
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
<figure>
|
|
48
|
-
<img class="image" src={preview[0]} />
|
|
49
|
-
<legend>{preview[1]}</legend>
|
|
50
|
-
</figure>
|
|
51
|
-
</header>
|
|
52
|
-
|
|
53
|
-
</div>
|
|
54
|
-
)
|
|
55
|
-
}
|