@koloseum/utils 0.2.28 → 0.3.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/dist/client.d.ts +125 -0
- package/dist/client.js +680 -0
- package/dist/formatting.d.ts +125 -0
- package/dist/formatting.js +369 -0
- package/dist/general.d.ts +54 -0
- package/dist/general.js +88 -0
- package/dist/platform.d.ts +66 -0
- package/dist/platform.js +764 -0
- package/dist/server.d.ts +77 -0
- package/dist/server.js +300 -0
- package/package.json +25 -3
- package/dist/utils.d.ts +0 -394
- package/dist/utils.js +0 -2019
package/dist/platform.js
ADDED
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
import { Transform } from "./formatting.js";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import validator from "validator";
|
|
4
|
+
/* HELPERS */
|
|
5
|
+
const { trim, escape } = validator;
|
|
6
|
+
const { KenyaAdministrativeDivisions } = (await import("kenya-administrative-divisions")).default;
|
|
7
|
+
/* CONFIG HELPERS */
|
|
8
|
+
export const Config = {
|
|
9
|
+
/**
|
|
10
|
+
* A reference of microservices available on the platform, represented as an object with each user group (i.e. `public`, `players`, `lounges`, and `backroom`) having its own array of microservices. Each microservice in a list is an object with the following properties:
|
|
11
|
+
* - `name`: The name of the microservice.
|
|
12
|
+
* - `description`: A description of the microservice.
|
|
13
|
+
* - `slug`: The slug of the microservice.
|
|
14
|
+
* - `features`: An array of features that the microservice has.
|
|
15
|
+
* - `roles`: An array of roles attached to the microservice.
|
|
16
|
+
*/
|
|
17
|
+
microservices: {
|
|
18
|
+
backroom: [
|
|
19
|
+
{
|
|
20
|
+
name: "Compliance",
|
|
21
|
+
description: "Management of compliance and regulatory adherence for Players and Lounges.",
|
|
22
|
+
slug: "compliance",
|
|
23
|
+
features: [
|
|
24
|
+
{
|
|
25
|
+
name: "Players",
|
|
26
|
+
description: "Search, review, and manage Player data.",
|
|
27
|
+
slug: "players",
|
|
28
|
+
tabs: [
|
|
29
|
+
{
|
|
30
|
+
name: "Profile",
|
|
31
|
+
description: "Review basic Player data.",
|
|
32
|
+
root: true
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "Documents",
|
|
36
|
+
description: "Review Player documents.",
|
|
37
|
+
slug: "documents"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "Data updates",
|
|
41
|
+
description: "Review Player data updates.",
|
|
42
|
+
slug: "data-updates",
|
|
43
|
+
tabs: [
|
|
44
|
+
{
|
|
45
|
+
name: "Requests",
|
|
46
|
+
description: "Review Player data update requests.",
|
|
47
|
+
root: true
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "History",
|
|
51
|
+
description: "Review Player data update history.",
|
|
52
|
+
slug: "history"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "Credits",
|
|
58
|
+
description: "Review Koloseum Credits data for the Player.",
|
|
59
|
+
slug: "credits",
|
|
60
|
+
tabs: [
|
|
61
|
+
{
|
|
62
|
+
name: "Transactions",
|
|
63
|
+
description: "Review Player transactions with Koloseum Credits.",
|
|
64
|
+
root: true
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "Transfers",
|
|
68
|
+
description: "Review Player transfers with Koloseum Credits.",
|
|
69
|
+
slug: "transfers"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "Subscriptions",
|
|
73
|
+
description: "Review Player subscriptions with Koloseum Credits.",
|
|
74
|
+
slug: "subscriptions"
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: "Misconduct",
|
|
80
|
+
description: "Review Player reports and sanctions.",
|
|
81
|
+
slug: "misconduct",
|
|
82
|
+
tabs: [
|
|
83
|
+
{
|
|
84
|
+
name: "Reports",
|
|
85
|
+
description: "Review Player reports.",
|
|
86
|
+
root: true
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "Sanctions",
|
|
90
|
+
description: "Review Player sanctions.",
|
|
91
|
+
slug: "sanctions"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "Points / KXP",
|
|
97
|
+
description: "Review Koloseum Experience Points (KXP) transactions for the Player.",
|
|
98
|
+
slug: "points"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "Lounges",
|
|
104
|
+
description: "Search, review, and manage Lounge data.",
|
|
105
|
+
slug: "lounges",
|
|
106
|
+
tabs: [
|
|
107
|
+
{
|
|
108
|
+
name: "Profile",
|
|
109
|
+
description: "Review basic Lounge data.",
|
|
110
|
+
root: true
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "Documents",
|
|
114
|
+
description: "Review Lounge documents.",
|
|
115
|
+
slug: "documents"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "Staff",
|
|
119
|
+
description: "Search, review, and manage Lounge staff data.",
|
|
120
|
+
slug: "staff"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "Branches",
|
|
124
|
+
description: "Review Lounge branches.",
|
|
125
|
+
slug: "branches",
|
|
126
|
+
tabs: [
|
|
127
|
+
{
|
|
128
|
+
name: "Profile",
|
|
129
|
+
description: "Review basic Lounge branch data.",
|
|
130
|
+
root: true
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "Amenities",
|
|
134
|
+
description: "Review Lounge branch amenities.",
|
|
135
|
+
slug: "amenities"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "Staff",
|
|
139
|
+
description: "Search, review, and manage Lounge branchstaff data.",
|
|
140
|
+
slug: "staff"
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: "Data updates",
|
|
146
|
+
description: "Review Lounge data updates.",
|
|
147
|
+
slug: "data-updates",
|
|
148
|
+
tabs: [
|
|
149
|
+
{
|
|
150
|
+
name: "Requests",
|
|
151
|
+
description: "Review Lounge data update requests.",
|
|
152
|
+
root: true
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "History",
|
|
156
|
+
description: "Review Lounge data update history.",
|
|
157
|
+
slug: "history"
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: "Credits",
|
|
163
|
+
description: "Review Koloseum Credits data for the Lounge.",
|
|
164
|
+
slug: "credits",
|
|
165
|
+
tabs: [
|
|
166
|
+
{
|
|
167
|
+
name: "Transactions",
|
|
168
|
+
description: "Review Lounge transactions with Koloseum Credits.",
|
|
169
|
+
root: true
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "Transfers",
|
|
173
|
+
description: "Review Lounge transfers with Koloseum Credits.",
|
|
174
|
+
slug: "transfers"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: "Subscriptions",
|
|
178
|
+
description: "Review Lounge subscriptions with Koloseum Credits.",
|
|
179
|
+
slug: "subscriptions"
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: "Misconduct",
|
|
185
|
+
description: "Review Lounge reports and sanctions.",
|
|
186
|
+
slug: "misconduct",
|
|
187
|
+
tabs: [
|
|
188
|
+
{
|
|
189
|
+
name: "Reports",
|
|
190
|
+
description: "Review Lounge reports.",
|
|
191
|
+
root: true
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: "Sanctions",
|
|
195
|
+
description: "Review Lounge sanctions.",
|
|
196
|
+
slug: "sanctions"
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
name: "Points / KXP",
|
|
202
|
+
description: "Review Koloseum Experience Points (KXP) transactions for the Lounge.",
|
|
203
|
+
slug: "points"
|
|
204
|
+
}
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
roles: [
|
|
209
|
+
{
|
|
210
|
+
name: "Compliance",
|
|
211
|
+
slug: "compliance",
|
|
212
|
+
root: true
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "Players",
|
|
216
|
+
slug: "players",
|
|
217
|
+
featureSlugs: ["players"]
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: "Lounges",
|
|
221
|
+
slug: "lounges",
|
|
222
|
+
featureSlugs: ["lounges"]
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: "Competitions",
|
|
228
|
+
description: "Management of competitions data and live events across Markets.",
|
|
229
|
+
slug: "competitions",
|
|
230
|
+
features: [
|
|
231
|
+
{
|
|
232
|
+
name: "Ma Esto",
|
|
233
|
+
description: "Manage football esports data for Ma Esto.",
|
|
234
|
+
slug: "fbl"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: "Savanna FGC",
|
|
238
|
+
description: "Manage fighting games esports data for Savanna FGC.",
|
|
239
|
+
slug: "fgc",
|
|
240
|
+
tabs: [
|
|
241
|
+
{
|
|
242
|
+
name: "Savanna Circuit",
|
|
243
|
+
description: "Manage competition data for the Savanna Circuit.",
|
|
244
|
+
slug: "league",
|
|
245
|
+
tabs: [
|
|
246
|
+
{
|
|
247
|
+
name: "Rankings",
|
|
248
|
+
description: "Manage rankings for any Savanna Circuit season.",
|
|
249
|
+
root: true
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "Tournaments",
|
|
253
|
+
description: "Manage tournaments for any Savanna Circuit season.",
|
|
254
|
+
slug: "tournaments",
|
|
255
|
+
tabs: [
|
|
256
|
+
{
|
|
257
|
+
name: "Events",
|
|
258
|
+
description: "Manage events for any Savanna Circuit tournament.",
|
|
259
|
+
root: true
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "Tickets",
|
|
263
|
+
description: "Manage tickets for any Savanna Circuit tournament.",
|
|
264
|
+
slug: "tickets"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
name: "Settings",
|
|
268
|
+
description: "Manage settings for any Savanna Circuit tournament.",
|
|
269
|
+
slug: "settings"
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
name: "Settings",
|
|
275
|
+
description: "Manage settings for any Savanna Circuit season.",
|
|
276
|
+
slug: "settings"
|
|
277
|
+
}
|
|
278
|
+
]
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
name: "Savanna Fight Night",
|
|
282
|
+
description: "Manage competition data for Savanna Fight Night.",
|
|
283
|
+
slug: "challenges"
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: "Hit List",
|
|
289
|
+
description: "Manage battle royale esports data for Hit List.",
|
|
290
|
+
slug: "bryl"
|
|
291
|
+
}
|
|
292
|
+
],
|
|
293
|
+
roles: [
|
|
294
|
+
{
|
|
295
|
+
name: "Competitions",
|
|
296
|
+
slug: "competitions",
|
|
297
|
+
root: true
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "Ma Esto",
|
|
301
|
+
slug: "fbl",
|
|
302
|
+
featureSlugs: ["fbl"]
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
name: "Savanna FGC",
|
|
306
|
+
slug: "fgc",
|
|
307
|
+
featureSlugs: ["fgc"]
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
name: "Hit List",
|
|
311
|
+
slug: "bryl",
|
|
312
|
+
featureSlugs: ["bryl"]
|
|
313
|
+
}
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
name: "KLSM",
|
|
318
|
+
description: "Management of game and console trades between users.",
|
|
319
|
+
slug: "commerce",
|
|
320
|
+
features: [],
|
|
321
|
+
roles: [
|
|
322
|
+
{
|
|
323
|
+
name: "Commerce",
|
|
324
|
+
slug: "commerce",
|
|
325
|
+
root: true
|
|
326
|
+
}
|
|
327
|
+
]
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "Staff",
|
|
331
|
+
description: "Management of Backroom staff authorisation.",
|
|
332
|
+
slug: "staff",
|
|
333
|
+
features: [
|
|
334
|
+
{
|
|
335
|
+
name: "Roles",
|
|
336
|
+
description: "Review and manage Backroom roles.",
|
|
337
|
+
slug: "roles"
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: "Users",
|
|
341
|
+
description: "Review and manage Backroom users.",
|
|
342
|
+
slug: "users"
|
|
343
|
+
}
|
|
344
|
+
],
|
|
345
|
+
roles: [
|
|
346
|
+
{
|
|
347
|
+
name: "Human Resources",
|
|
348
|
+
slug: "hr",
|
|
349
|
+
root: true
|
|
350
|
+
}
|
|
351
|
+
]
|
|
352
|
+
}
|
|
353
|
+
],
|
|
354
|
+
players: [
|
|
355
|
+
{
|
|
356
|
+
name: "Sessions",
|
|
357
|
+
description: "Track your gaming sessions at registered lounges.",
|
|
358
|
+
slug: "sessions",
|
|
359
|
+
features: [],
|
|
360
|
+
roles: null
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
name: "KLSM",
|
|
364
|
+
description: "Trade used games and consoles with other users at affordable prices.",
|
|
365
|
+
slug: "commerce",
|
|
366
|
+
features: [],
|
|
367
|
+
roles: null
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
name: "Savanna FGC",
|
|
371
|
+
description: "Check out the latest news and competitions from Savanna FGC.",
|
|
372
|
+
slug: "fgc",
|
|
373
|
+
features: [
|
|
374
|
+
{
|
|
375
|
+
name: "Home",
|
|
376
|
+
description: "Learn more about the Savanna Circuit.",
|
|
377
|
+
root: true
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
name: "Rules",
|
|
381
|
+
description: "Review the rules and regulations of the Savanna Circuit.",
|
|
382
|
+
slug: "rules"
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: "Tournaments",
|
|
386
|
+
description: "Review and join upcoming tournaments on the Savanna Circuit.",
|
|
387
|
+
slug: "tournaments"
|
|
388
|
+
}
|
|
389
|
+
],
|
|
390
|
+
roles: null
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
name: "Account",
|
|
394
|
+
description: "Review Player account settings and preferences.",
|
|
395
|
+
slug: "account",
|
|
396
|
+
features: [
|
|
397
|
+
{
|
|
398
|
+
name: "General",
|
|
399
|
+
description: "Review and manage your general settings.",
|
|
400
|
+
slug: "general"
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
name: "Documents",
|
|
404
|
+
description: "Review and manage your ID documents.",
|
|
405
|
+
slug: "documents"
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
name: "Personal",
|
|
409
|
+
description: "Review and manage your personal information.",
|
|
410
|
+
slug: "personal"
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
name: "Gaming & Socials",
|
|
414
|
+
description: "Review and manage your gaming and social media information.",
|
|
415
|
+
slug: "gaming-socials"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
name: "Notifications",
|
|
419
|
+
description: "Review and manage your notification preferences.",
|
|
420
|
+
slug: "notifications"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
name: "Security",
|
|
424
|
+
description: "Review and manage your security preferences.",
|
|
425
|
+
slug: "security"
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
name: "Lounges",
|
|
429
|
+
description: "Review your access to Lounges microservices.",
|
|
430
|
+
slug: "lounges"
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
name: "Backroom",
|
|
434
|
+
description: "Review your access to Backroom microservices.",
|
|
435
|
+
slug: "backroom"
|
|
436
|
+
}
|
|
437
|
+
],
|
|
438
|
+
roles: null
|
|
439
|
+
}
|
|
440
|
+
]
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
/* DUMMY DATA */
|
|
444
|
+
export const Mock = {
|
|
445
|
+
/**
|
|
446
|
+
* A generic authenticated user.
|
|
447
|
+
* @param {string} id - The user ID; defaults to a random UUID
|
|
448
|
+
* @param {Date} date - The date and time; defaults to the current date and time
|
|
449
|
+
* @param {string} phone - The phone number; defaults to a generic Kenyan phone number
|
|
450
|
+
* @param {string} identityId - A default identity ID; defaults to a random UUID
|
|
451
|
+
* @returns A generic authenticated user.
|
|
452
|
+
*/
|
|
453
|
+
authenticatedUser: (id = uuidv4(), date = new Date(), phone = "254111222333", identityId = uuidv4()) => {
|
|
454
|
+
// Convert date to ISO string
|
|
455
|
+
const time = date.toISOString();
|
|
456
|
+
// User data
|
|
457
|
+
return {
|
|
458
|
+
id,
|
|
459
|
+
aud: "authenticated",
|
|
460
|
+
role: "authenticated",
|
|
461
|
+
email: "",
|
|
462
|
+
phone,
|
|
463
|
+
phone_confirmed_at: time,
|
|
464
|
+
confirmation_sent_at: time,
|
|
465
|
+
confirmed_at: time,
|
|
466
|
+
last_sign_in_at: time,
|
|
467
|
+
app_metadata: {
|
|
468
|
+
person_data: { player_id: "KP1234567", first_name: "John", last_name: "Test", pseudonym: "JDtest" },
|
|
469
|
+
provider: "phone",
|
|
470
|
+
providers: ["phone"],
|
|
471
|
+
roles: ["player", "backroom_superuser"]
|
|
472
|
+
},
|
|
473
|
+
user_metadata: {
|
|
474
|
+
email_verified: false,
|
|
475
|
+
phone_verified: false,
|
|
476
|
+
sub: id,
|
|
477
|
+
backroom: {
|
|
478
|
+
welcome_notification_sent: true
|
|
479
|
+
},
|
|
480
|
+
players: {
|
|
481
|
+
welcome_notification_sent: true
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
identities: [
|
|
485
|
+
{
|
|
486
|
+
identity_id: identityId,
|
|
487
|
+
id,
|
|
488
|
+
user_id: id,
|
|
489
|
+
identity_data: {
|
|
490
|
+
email_verified: false,
|
|
491
|
+
phone_verified: false,
|
|
492
|
+
sub: id
|
|
493
|
+
},
|
|
494
|
+
provider: "phone",
|
|
495
|
+
last_sign_in_at: time,
|
|
496
|
+
created_at: time,
|
|
497
|
+
updated_at: time
|
|
498
|
+
}
|
|
499
|
+
],
|
|
500
|
+
created_at: time,
|
|
501
|
+
updated_at: time,
|
|
502
|
+
is_anonymous: false
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
/* RESOURCE HELPERS */
|
|
507
|
+
export const Resource = {
|
|
508
|
+
/**
|
|
509
|
+
* Returns a list of all counties in Kenya.
|
|
510
|
+
* @param {"name" | "code"} sortBy - The field to sort the counties by, i.e. `name` or `code`; defaults to `name`
|
|
511
|
+
* @returns {Promise<County[]>} A list of objects with the county `name`, `code`, and a list of `subCounties`
|
|
512
|
+
*/
|
|
513
|
+
getKenyaCounties: async (sortBy = "name") => {
|
|
514
|
+
// Create Kenya administrative divisions instance
|
|
515
|
+
const kenyaAdmin = new KenyaAdministrativeDivisions();
|
|
516
|
+
// Get all counties
|
|
517
|
+
const countiesData = await kenyaAdmin.getAll();
|
|
518
|
+
// Format counties
|
|
519
|
+
const counties = countiesData.map((county) => {
|
|
520
|
+
// Get list of sub-counties
|
|
521
|
+
const subCounties = [];
|
|
522
|
+
for (const subCounty of county.constituencies)
|
|
523
|
+
subCounties.push(subCounty.constituency_name);
|
|
524
|
+
subCounties.sort();
|
|
525
|
+
// Format county name and add to list
|
|
526
|
+
const countyName = county.county_name.split(" ");
|
|
527
|
+
let name = county.county_name;
|
|
528
|
+
if (countyName.length > 1)
|
|
529
|
+
name = countyName.map((word) => Transform.capitalise(word)).join(" ");
|
|
530
|
+
// Return county
|
|
531
|
+
return { name, code: county.county_code, subCounties };
|
|
532
|
+
});
|
|
533
|
+
// Return sorted counties
|
|
534
|
+
return counties.sort((a, b) => (sortBy === "name" ? a.name.localeCompare(b.name) : a.code - b.code));
|
|
535
|
+
},
|
|
536
|
+
/**
|
|
537
|
+
* Returns the parent URL for a given base URL.
|
|
538
|
+
* @param {string} base - The base URL
|
|
539
|
+
* @returns {string} The parent URL
|
|
540
|
+
*/
|
|
541
|
+
getParentUrl: (base) => {
|
|
542
|
+
// Validate input
|
|
543
|
+
if (typeof base !== "string")
|
|
544
|
+
return "";
|
|
545
|
+
// Return parent URL
|
|
546
|
+
return base.replace(/\/$/, "").split("/").slice(0, -1).join("/") || "/";
|
|
547
|
+
},
|
|
548
|
+
/**
|
|
549
|
+
* Returns the redirect URL for a given URI.
|
|
550
|
+
* @param {string} uri - The URI to get the redirect URL for, i.e. `microserviceGroup:path` (e.g. `players:fgc/tournaments`)
|
|
551
|
+
* @param {"development" | "production"} env - The environment to use for the redirect URL; defaults to `production`
|
|
552
|
+
* @returns {string} An object with the redirect `url`, or an `error` if any occurs
|
|
553
|
+
*/
|
|
554
|
+
getRedirectUrl: (uri, env = "production") => {
|
|
555
|
+
// Get microservice groups
|
|
556
|
+
const microserviceGroups = ["public", "players", "lounges", "backroom"];
|
|
557
|
+
// Extract microservice group and path from URI
|
|
558
|
+
let [microserviceGroup, path] = uri.split(":");
|
|
559
|
+
if (!microserviceGroup || !path)
|
|
560
|
+
return { error: { code: 400, message: "URI is invalid." } };
|
|
561
|
+
if (!microserviceGroups.includes(microserviceGroup))
|
|
562
|
+
return { error: { code: 400, message: "Microservice group is invalid." } };
|
|
563
|
+
// Initialise port number for local development
|
|
564
|
+
let port;
|
|
565
|
+
// Return redirect URL for Public microservices
|
|
566
|
+
if (microserviceGroup === "public") {
|
|
567
|
+
// Initialise subdomain for production
|
|
568
|
+
let subdomain = "";
|
|
569
|
+
// Handle Authentication microservice
|
|
570
|
+
if (path.startsWith("auth")) {
|
|
571
|
+
subdomain = "auth.";
|
|
572
|
+
port = 5173;
|
|
573
|
+
path = path.replace("auth", "");
|
|
574
|
+
}
|
|
575
|
+
// Handle Legal microservice
|
|
576
|
+
else if (path.startsWith("legal")) {
|
|
577
|
+
subdomain = "legal.";
|
|
578
|
+
port = 5174;
|
|
579
|
+
path = path.replace("legal", "");
|
|
580
|
+
}
|
|
581
|
+
// Handle Landing microservice
|
|
582
|
+
else if (path.startsWith("landing")) {
|
|
583
|
+
port = 5184;
|
|
584
|
+
path = path.replace("landing", "");
|
|
585
|
+
}
|
|
586
|
+
// Return redirect URL
|
|
587
|
+
return {
|
|
588
|
+
url: env === "production"
|
|
589
|
+
? `https://${subdomain}koloseum.ke${path || ""}`
|
|
590
|
+
: `http://127.0.0.1:${port}${path || ""}`
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
// Handle Players microservices
|
|
594
|
+
if (microserviceGroup === "players") {
|
|
595
|
+
if (path.startsWith("account")) {
|
|
596
|
+
port = 5175;
|
|
597
|
+
if (env === "development")
|
|
598
|
+
path = path.replace("account", "");
|
|
599
|
+
}
|
|
600
|
+
if (path.startsWith("fgc")) {
|
|
601
|
+
port = 5178;
|
|
602
|
+
if (env === "development")
|
|
603
|
+
path = path.replace("fgc", "");
|
|
604
|
+
}
|
|
605
|
+
if (path.startsWith("commerce")) {
|
|
606
|
+
port = 5179;
|
|
607
|
+
if (env === "development")
|
|
608
|
+
path = path.replace("commerce", "");
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
// Handle Lounges microservices
|
|
612
|
+
if (microserviceGroup === "lounges") {
|
|
613
|
+
if (path.startsWith("branches")) {
|
|
614
|
+
port = 5181;
|
|
615
|
+
if (env === "development")
|
|
616
|
+
path = path.replace("branches", "");
|
|
617
|
+
}
|
|
618
|
+
if (path.startsWith("staff")) {
|
|
619
|
+
port = 5182;
|
|
620
|
+
if (env === "development")
|
|
621
|
+
path = path.replace("staff", "");
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
// Handle Backroom microservices
|
|
625
|
+
if (microserviceGroup === "backroom") {
|
|
626
|
+
if (path.startsWith("compliance")) {
|
|
627
|
+
port = 5176;
|
|
628
|
+
if (env === "development")
|
|
629
|
+
path = path.replace("compliance", "");
|
|
630
|
+
}
|
|
631
|
+
if (path.startsWith("competitions")) {
|
|
632
|
+
port = 5177;
|
|
633
|
+
if (env === "development")
|
|
634
|
+
path = path.replace("competitions", "");
|
|
635
|
+
}
|
|
636
|
+
if (path.startsWith("commerce")) {
|
|
637
|
+
port = 5180;
|
|
638
|
+
if (env === "development")
|
|
639
|
+
path = path.replace("commerce", "");
|
|
640
|
+
}
|
|
641
|
+
if (path.startsWith("staff")) {
|
|
642
|
+
port = 5183;
|
|
643
|
+
if (env === "development")
|
|
644
|
+
path = path.replace("staff", "");
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
// Return redirect URL
|
|
648
|
+
return {
|
|
649
|
+
url: env === "production"
|
|
650
|
+
? `https://${microserviceGroup}.koloseum.ke/${path || ""}`
|
|
651
|
+
: `http://127.0.0.1:${port}${path || ""}`
|
|
652
|
+
};
|
|
653
|
+
},
|
|
654
|
+
/**
|
|
655
|
+
* Parses a resource request and returns the URL and path.
|
|
656
|
+
* @param request - The request to parse.
|
|
657
|
+
* @returns An object with the `url` and `path` of the request.
|
|
658
|
+
*/
|
|
659
|
+
parseResourceRequest: (request) => {
|
|
660
|
+
// Get the request URL and path
|
|
661
|
+
const url = new URL(request.url);
|
|
662
|
+
const path = url.pathname.split("/").pop();
|
|
663
|
+
// Return the request URL and path
|
|
664
|
+
return { url, path };
|
|
665
|
+
},
|
|
666
|
+
/**
|
|
667
|
+
* Validates address data submitted in a form and returns the validated data.
|
|
668
|
+
* @param {FormData} formData - The submitted form data
|
|
669
|
+
* @returns An object with the validated `address`, or an `error` if any has occurred
|
|
670
|
+
*/
|
|
671
|
+
validateAddress: async (formData) => {
|
|
672
|
+
// Create Kenya administrative divisions instance
|
|
673
|
+
const kenyaAdmin = new KenyaAdministrativeDivisions();
|
|
674
|
+
// Building name
|
|
675
|
+
let buildingName = formData.get("building-name");
|
|
676
|
+
if (!buildingName)
|
|
677
|
+
return { error: { code: 400, message: "Building name is required." } };
|
|
678
|
+
buildingName = Transform.sanitiseHtml(trim(escape(buildingName)));
|
|
679
|
+
// Unit number
|
|
680
|
+
let unitNumber = formData.get("unit-number") || undefined;
|
|
681
|
+
if (unitNumber) {
|
|
682
|
+
unitNumber = Transform.sanitiseHtml(trim(escape(unitNumber)));
|
|
683
|
+
if (unitNumber === "")
|
|
684
|
+
unitNumber = undefined;
|
|
685
|
+
}
|
|
686
|
+
// Street name
|
|
687
|
+
let streetName = formData.get("street-name");
|
|
688
|
+
if (!streetName)
|
|
689
|
+
return { error: { code: 400, message: "Street name is required." } };
|
|
690
|
+
streetName = Transform.sanitiseHtml(trim(escape(streetName)));
|
|
691
|
+
// P.O. box and postal code
|
|
692
|
+
let boxNumber = formData.get("box-number") || undefined;
|
|
693
|
+
let postalCode = formData.get("postal-code") || undefined;
|
|
694
|
+
if (boxNumber) {
|
|
695
|
+
boxNumber = Transform.sanitiseHtml(trim(escape(boxNumber)));
|
|
696
|
+
if (boxNumber === "")
|
|
697
|
+
boxNumber = undefined;
|
|
698
|
+
if (boxNumber && !postalCode)
|
|
699
|
+
return { error: { code: 400, message: "Postal code is required." } };
|
|
700
|
+
}
|
|
701
|
+
if (postalCode) {
|
|
702
|
+
postalCode = Transform.sanitiseHtml(trim(escape(postalCode)));
|
|
703
|
+
if (postalCode === "")
|
|
704
|
+
postalCode = undefined;
|
|
705
|
+
if (postalCode && !boxNumber)
|
|
706
|
+
return { error: { code: 400, message: "P.O. box is required." } };
|
|
707
|
+
}
|
|
708
|
+
// Town
|
|
709
|
+
let town = formData.get("town");
|
|
710
|
+
if (!town)
|
|
711
|
+
return { error: { code: 400, message: "City/town is required." } };
|
|
712
|
+
town = Transform.sanitiseHtml(trim(escape(town)));
|
|
713
|
+
// County
|
|
714
|
+
let county = undefined;
|
|
715
|
+
const countyCode = Number(formData.get("county-code"));
|
|
716
|
+
if (isNaN(countyCode))
|
|
717
|
+
return { error: { code: 400, message: "County is invalid." } };
|
|
718
|
+
if (!countyCode)
|
|
719
|
+
return { error: { code: 400, message: "County is required." } };
|
|
720
|
+
const counties = await kenyaAdmin.getAll();
|
|
721
|
+
if (!counties || counties.length === 0)
|
|
722
|
+
return { error: { code: 400, message: "County is invalid." } };
|
|
723
|
+
const countyData = counties.find(({ county_code }) => county_code === countyCode);
|
|
724
|
+
if (!countyData)
|
|
725
|
+
return { error: { code: 400, message: "County is invalid." } };
|
|
726
|
+
const { county_name, constituencies } = countyData;
|
|
727
|
+
county = county_name;
|
|
728
|
+
// Sub-county
|
|
729
|
+
let subCounty = formData.get("sub-county") || undefined;
|
|
730
|
+
if (subCounty) {
|
|
731
|
+
subCounty = Transform.sanitiseHtml(trim(escape(subCounty)));
|
|
732
|
+
if (subCounty === "")
|
|
733
|
+
subCounty = undefined;
|
|
734
|
+
else {
|
|
735
|
+
// Check if constituencies exists and is an array before mapping
|
|
736
|
+
if (!constituencies || !Array.isArray(constituencies))
|
|
737
|
+
return { error: { code: 400, message: "Sub-county data is unavailable." } };
|
|
738
|
+
// Get list of sub-counties
|
|
739
|
+
const subCounties = constituencies.map(({ constituency_name: name }) => name);
|
|
740
|
+
if (!subCounties.includes(subCounty))
|
|
741
|
+
return { error: { code: 400, message: "Sub-county is invalid." } };
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
// Additional information
|
|
745
|
+
let additionalInfo = formData.get("address-additional-info") || undefined;
|
|
746
|
+
if (additionalInfo) {
|
|
747
|
+
additionalInfo = Transform.sanitiseHtml(trim(escape(additionalInfo)));
|
|
748
|
+
if (additionalInfo === "")
|
|
749
|
+
additionalInfo = undefined;
|
|
750
|
+
}
|
|
751
|
+
// Create address object
|
|
752
|
+
const address = {
|
|
753
|
+
buildingName,
|
|
754
|
+
unitNumber,
|
|
755
|
+
streetName,
|
|
756
|
+
town,
|
|
757
|
+
subCounty,
|
|
758
|
+
county,
|
|
759
|
+
additionalInfo
|
|
760
|
+
};
|
|
761
|
+
// Return data
|
|
762
|
+
return { address };
|
|
763
|
+
}
|
|
764
|
+
};
|