@goralys/core 1.1.3 → 1.2.1
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/index.d.ts +20 -19
- package/dist/index.js +218 -221
- package/package.json +3 -1
package/dist/index.d.ts
CHANGED
|
@@ -5,14 +5,18 @@ declare function configureGoralysClient(cfg: GoralysClientConfig): void;
|
|
|
5
5
|
declare function getGoralysClientConfig(): GoralysClientConfig;
|
|
6
6
|
|
|
7
7
|
interface StorageAdapter {
|
|
8
|
-
getItem(key: string): string | null
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
getItem(key: string): string | null;
|
|
9
|
+
getSize(): number;
|
|
10
|
+
keyAt(ids: number): string | undefined;
|
|
11
|
+
setItem(key: string, value: string): void;
|
|
12
|
+
removeItem(key: string): void;
|
|
11
13
|
}
|
|
12
14
|
declare function configureStorage(customAdapter: StorageAdapter): void;
|
|
13
|
-
declare
|
|
14
|
-
declare
|
|
15
|
-
declare
|
|
15
|
+
declare const storageGet: (key: string) => string | null;
|
|
16
|
+
declare const storageSet: (key: string, value: string) => void;
|
|
17
|
+
declare const storageSize: () => number;
|
|
18
|
+
declare const storageKeyAt: (idx: number) => string | undefined;
|
|
19
|
+
declare const storageRemove: (key: string) => void;
|
|
16
20
|
|
|
17
21
|
interface PHPDateTime {
|
|
18
22
|
date: string;
|
|
@@ -23,16 +27,17 @@ type CookieValue = string | boolean | number | null | undefined;
|
|
|
23
27
|
|
|
24
28
|
interface CookiesAdapter {
|
|
25
29
|
onChange(callback: () => void): () => void;
|
|
26
|
-
getCookies(key: string):
|
|
30
|
+
getCookies(key: string): CookieValue;
|
|
31
|
+
getAll(): Record<string, CookieValue>;
|
|
27
32
|
setCookies(key: string, value: CookieValue, path: string, maxAge: number): void;
|
|
28
|
-
removeCookies(key: string): void;
|
|
33
|
+
removeCookies(key: string, path: string): void;
|
|
29
34
|
}
|
|
30
35
|
declare function configureCookies(customAdapter: CookiesAdapter): void;
|
|
31
|
-
declare
|
|
32
|
-
declare
|
|
33
|
-
declare
|
|
34
|
-
declare
|
|
35
|
-
declare
|
|
36
|
+
declare const cookiesGet: (key: string) => CookieValue;
|
|
37
|
+
declare const cookiesGetAll: () => Record<string, CookieValue>;
|
|
38
|
+
declare const cookiesSet: (key: string, value: string, path?: string, maxAge?: number) => void;
|
|
39
|
+
declare const cookiesRemove: (key: string, path?: string) => void;
|
|
40
|
+
declare const cookiesOnChange: (callback: () => void) => (() => void);
|
|
36
41
|
|
|
37
42
|
type CheckAuthImpl = () => boolean;
|
|
38
43
|
declare function configureCheckAuth(impl: CheckAuthImpl): void;
|
|
@@ -43,10 +48,6 @@ interface GoralysCoreConfig {
|
|
|
43
48
|
storage: StorageAdapter;
|
|
44
49
|
cookies: CookiesAdapter;
|
|
45
50
|
auth: CheckAuthImpl;
|
|
46
|
-
cache: {
|
|
47
|
-
cache: () => Promise<void>;
|
|
48
|
-
empty: () => void;
|
|
49
|
-
};
|
|
50
51
|
}
|
|
51
52
|
declare function configGoralysCore(cfg: GoralysCoreConfig): void;
|
|
52
53
|
|
|
@@ -169,6 +170,7 @@ declare const LOGO_PATH: {
|
|
|
169
170
|
eye: string;
|
|
170
171
|
};
|
|
171
172
|
|
|
173
|
+
declare const COOKIES_DISMISSED_KEY = "cookie-banner-dismissed";
|
|
172
174
|
declare const PERSISTANT_COOKIES: string[];
|
|
173
175
|
declare const PERSISTANT_LOCALS: string[];
|
|
174
176
|
declare const USERNAME_KEY = "username";
|
|
@@ -271,7 +273,6 @@ declare function getLongFromShort(short: string): string;
|
|
|
271
273
|
|
|
272
274
|
declare function fetchSubjectsForRoleClient(role: UserRole): Promise<Response | null>;
|
|
273
275
|
|
|
274
|
-
declare function configureUserCacheCallbacks(cache: () => Promise<void>, empty: () => void): void;
|
|
275
276
|
declare function cacheUserDataClient(): Promise<void>;
|
|
276
277
|
declare function emptyUserCacheClient(): void;
|
|
277
278
|
declare function fetchUsersClient(): Promise<Response>;
|
|
@@ -279,4 +280,4 @@ declare function fetchVirtualUsersClient(): Promise<Response>;
|
|
|
279
280
|
declare function fetchAdminsClient(): Promise<Response>;
|
|
280
281
|
declare function fetchVirtualAdminsClient(): Promise<Response>;
|
|
281
282
|
|
|
282
|
-
export { ADMIN_CACHE_RADIX, ADMIN_SYNC_RADIX, type AuthEvent, type CheckAuthImpl, type ConfirmOptions, type CookieValue, type CookiesAdapter, type DraftModalResult, EMAIL_KEY, FULL_NAME_KEY, GoralysActionHandler, type GoralysClientConfig, HTTP_METHODS, type HttpMethod, LOGO_PATH, PERSISTANT_COOKIES, PERSISTANT_LOCALS, type PHPDateTime, PUB_ID_KEY, ROLE_KEY, SUBJECT_CACHES, SUBJECT_CACHE_RADIX, SUBJECT_SYNCS, SUBJECT_SYNC_RADIX, SUPPORT_TICKET_CACHE, SUPPORT_TICKET_SYNC, type StorageAdapter, type Subject, type SubjectStatus, SubjectStatusConfig, type SubjectsSearchField, type SupportReasons, type SupportTicket, type Toast, type ToastFn, USERNAME_KEY, USER_CACHES, USER_CACHE_RADIX, USER_ROLES, USER_SYNCS, USER_SYNC_RADIX, type User, type UserData, type UserEvent, type UserRole, type UserType, buildApiUrl, buildArray, cacheUserDataClient, configGoralysCore, configureCheckAuth, configureCookies, configureGoralysClient, configureStorage,
|
|
283
|
+
export { ADMIN_CACHE_RADIX, ADMIN_SYNC_RADIX, type AuthEvent, COOKIES_DISMISSED_KEY, type CheckAuthImpl, type ConfirmOptions, type CookieValue, type CookiesAdapter, type DraftModalResult, EMAIL_KEY, FULL_NAME_KEY, GoralysActionHandler, type GoralysClientConfig, HTTP_METHODS, type HttpMethod, LOGO_PATH, PERSISTANT_COOKIES, PERSISTANT_LOCALS, type PHPDateTime, PUB_ID_KEY, ROLE_KEY, SUBJECT_CACHES, SUBJECT_CACHE_RADIX, SUBJECT_SYNCS, SUBJECT_SYNC_RADIX, SUPPORT_TICKET_CACHE, SUPPORT_TICKET_SYNC, type StorageAdapter, type Subject, type SubjectStatus, SubjectStatusConfig, type SubjectsSearchField, type SupportReasons, type SupportTicket, type Toast, type ToastFn, USERNAME_KEY, USER_CACHES, USER_CACHE_RADIX, USER_ROLES, USER_SYNCS, USER_SYNC_RADIX, type User, type UserData, type UserEvent, type UserRole, type UserType, buildApiUrl, buildArray, cacheUserDataClient, configGoralysCore, configureCheckAuth, configureCookies, configureGoralysClient, configureStorage, cookiesGet, cookiesGetAll, cookiesOnChange, cookiesRemove, cookiesSet, emitAuthEvent, emitNavigationEvent, emitUserEvent, emptyUserCacheClient, fetchAdminsClient, fetchCsrfClient, fetchSubjectsForRoleClient, fetchUsersClient, fetchVirtualAdminsClient, fetchVirtualUsersClient, getGoralysClientConfig, getLongFromShort, getStatusHelper, getStatusLabel, goralysFetchClient, handleToastRequest, helpContent, isAuthenticated, isFoolsDay, isHTTPMethod, onAuthEvent, onNavigationEvent, onUserEvent, parsePhpDateTime, reasonsConfig, searchFields, storageGet, storageKeyAt, storageRemove, storageSet, storageSize, useAdmins, useSubjects, useSupportTickets, useUsers, useVirtualAdmins, useVirtualUsers };
|
package/dist/index.js
CHANGED
|
@@ -21,15 +21,11 @@ function getAdapter() {
|
|
|
21
21
|
}
|
|
22
22
|
return adapter;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
async function storageRemove(key) {
|
|
31
|
-
await getAdapter().removeItem(key);
|
|
32
|
-
}
|
|
24
|
+
var storageGet = (key) => getAdapter().getItem(key);
|
|
25
|
+
var storageSet = (key, value) => getAdapter().setItem(key, value);
|
|
26
|
+
var storageSize = () => getAdapter().getSize();
|
|
27
|
+
var storageKeyAt = (idx) => getAdapter().keyAt(idx);
|
|
28
|
+
var storageRemove = (key) => getAdapter().removeItem(key);
|
|
33
29
|
|
|
34
30
|
// src/lib/storage/cookies-adapter.ts
|
|
35
31
|
var adapter2 = null;
|
|
@@ -42,21 +38,11 @@ function getAdapter2() {
|
|
|
42
38
|
}
|
|
43
39
|
return adapter2;
|
|
44
40
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
function cookiesRemove(key) {
|
|
52
|
-
getAdapter2().removeCookies(key);
|
|
53
|
-
}
|
|
54
|
-
function cookiesOnChange(callback) {
|
|
55
|
-
return getAdapter2().onChange(callback);
|
|
56
|
-
}
|
|
57
|
-
function setCookiesExpire(duration) {
|
|
58
|
-
storageSet("goralys-cookies-expire", String(Date.now() + duration * 1e3)).then();
|
|
59
|
-
}
|
|
41
|
+
var cookiesGet = (key) => getAdapter2().getCookies(key);
|
|
42
|
+
var cookiesGetAll = () => getAdapter2().getAll();
|
|
43
|
+
var cookiesSet = (key, value, path = "/", maxAge = 1.5 * 60) => getAdapter2().setCookies(key, value, path, maxAge);
|
|
44
|
+
var cookiesRemove = (key, path = "/") => getAdapter2().removeCookies(key, path);
|
|
45
|
+
var cookiesOnChange = (callback) => getAdapter2().onChange(callback);
|
|
60
46
|
|
|
61
47
|
// src/lib/auth/check-auth.ts
|
|
62
48
|
var checkAuthImpl;
|
|
@@ -70,6 +56,17 @@ function isAuthenticated() {
|
|
|
70
56
|
return checkAuthImpl();
|
|
71
57
|
}
|
|
72
58
|
|
|
59
|
+
// src/config.ts
|
|
60
|
+
function configGoralysCore(cfg) {
|
|
61
|
+
configureGoralysClient(cfg.client);
|
|
62
|
+
configureCookies(cfg.cookies);
|
|
63
|
+
configureStorage(cfg.storage);
|
|
64
|
+
configureCheckAuth(cfg.auth);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/hooks/useSubjects.ts
|
|
68
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
69
|
+
|
|
73
70
|
// src/lib/auth/auth-event.ts
|
|
74
71
|
var listeners = /* @__PURE__ */ new Set();
|
|
75
72
|
function emitAuthEvent(event) {
|
|
@@ -92,191 +89,9 @@ function onNavigationEvent(listener) {
|
|
|
92
89
|
return () => listeners2.delete(listener);
|
|
93
90
|
}
|
|
94
91
|
|
|
95
|
-
// src/lib/auth/user-event.ts
|
|
96
|
-
var listeners3 = /* @__PURE__ */ new Set();
|
|
97
|
-
function emitUserEvent(event) {
|
|
98
|
-
listeners3.forEach((l) => l(event));
|
|
99
|
-
}
|
|
100
|
-
function onUserEvent(callback) {
|
|
101
|
-
listeners3.add(callback);
|
|
102
|
-
return () => {
|
|
103
|
-
listeners3.delete(callback);
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// src/lib/fetch/goralys-action-handler.ts
|
|
108
|
-
var GoralysActionHandler = class {
|
|
109
|
-
constructor() {
|
|
110
|
-
this.handle = async (r) => {
|
|
111
|
-
const data = await r.clone().json();
|
|
112
|
-
if (!data || !data.action) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const action = data.action;
|
|
116
|
-
if (action === "login-success") {
|
|
117
|
-
await this.onLogin();
|
|
118
|
-
}
|
|
119
|
-
return;
|
|
120
|
-
};
|
|
121
|
-
this.onLogin = async () => {
|
|
122
|
-
await cacheUserDataClient();
|
|
123
|
-
emitUserEvent("login");
|
|
124
|
-
return;
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
// src/lib/fetch/fetch.client.ts
|
|
130
|
-
var actionHandler = new GoralysActionHandler();
|
|
131
|
-
async function goralysFetchClient(method, input, payload, requestOptions) {
|
|
132
|
-
const { apiDomain } = getGoralysClientConfig();
|
|
133
|
-
const res = await fetch(`${apiDomain}/${input}`, {
|
|
134
|
-
credentials: "include",
|
|
135
|
-
method: method === "BREW" ? "POST" : method,
|
|
136
|
-
headers: method === "BREW" ? { "X-HTTP-Method-Override": method } : {},
|
|
137
|
-
body: payload ? payload instanceof FormData ? payload : JSON.stringify(payload) : void 0,
|
|
138
|
-
...requestOptions
|
|
139
|
-
});
|
|
140
|
-
const clone = res.clone();
|
|
141
|
-
const contentType = clone.headers.get("Content-Type");
|
|
142
|
-
if (!(contentType && contentType.toLowerCase().trim().includes("application/json")))
|
|
143
|
-
return res;
|
|
144
|
-
const data = await clone.json();
|
|
145
|
-
if (res.status === 401) {
|
|
146
|
-
try {
|
|
147
|
-
emitAuthEvent(data?.authEvent ?? "unauthenticated");
|
|
148
|
-
} catch {
|
|
149
|
-
emitAuthEvent("unauthenticated");
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
if (res.status === 418) {
|
|
153
|
-
const teapotData = await res.clone().json();
|
|
154
|
-
emitNavigationEvent({
|
|
155
|
-
type: "teapot",
|
|
156
|
-
toastType: teapotData.toastType,
|
|
157
|
-
toastTitle: teapotData.toastTitle,
|
|
158
|
-
toastMessage: teapotData.toastMessage
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
await actionHandler.handle(res);
|
|
162
|
-
return res;
|
|
163
|
-
}
|
|
164
|
-
async function fetchCsrfClient(formId) {
|
|
165
|
-
const { apiDomain } = getGoralysClientConfig();
|
|
166
|
-
const res = await fetch(`${apiDomain}/csrf`, {
|
|
167
|
-
method: "POST",
|
|
168
|
-
headers: { "Content-Type": "application/json" },
|
|
169
|
-
credentials: "include",
|
|
170
|
-
body: JSON.stringify({ form: formId })
|
|
171
|
-
});
|
|
172
|
-
if (!res.ok)
|
|
173
|
-
return null;
|
|
174
|
-
const json = await res.json();
|
|
175
|
-
return json["csrf-token"];
|
|
176
|
-
}
|
|
177
|
-
function buildQueryString(params) {
|
|
178
|
-
return Object.entries(params).filter(([, value]) => value !== null && value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
179
|
-
}
|
|
180
|
-
function buildApiUrl(endpoint, params, domain = false) {
|
|
181
|
-
const { apiDomain } = getGoralysClientConfig();
|
|
182
|
-
const queryString = buildQueryString(params);
|
|
183
|
-
return `${domain ? apiDomain + "/" : ""}${endpoint}${queryString ? `?${queryString}` : ""}`;
|
|
184
|
-
}
|
|
185
|
-
async function handleToastRequest(r, showToast, redirect = true, duration) {
|
|
186
|
-
const res = r.clone();
|
|
187
|
-
const data = await res.json();
|
|
188
|
-
if (data?.toast) {
|
|
189
|
-
showToast({ type: data.toastType, title: data.toastTitle, message: data.toastMessage }, duration);
|
|
190
|
-
if (data?.redirect && redirect) {
|
|
191
|
-
emitNavigationEvent({ type: "redirect", url: data.redirect });
|
|
192
|
-
}
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// src/lib/user/user.client.ts
|
|
199
|
-
var cacheUserClient;
|
|
200
|
-
var emptyCacheUserClient;
|
|
201
|
-
function configureUserCacheCallbacks(cache, empty) {
|
|
202
|
-
cacheUserClient = cache;
|
|
203
|
-
emptyCacheUserClient = empty;
|
|
204
|
-
}
|
|
205
|
-
async function cacheUserDataClient() {
|
|
206
|
-
if (!cacheUserClient) {
|
|
207
|
-
throw new Error("User cache not configured. Call configUserCacheCallbacks() first.");
|
|
208
|
-
}
|
|
209
|
-
return await cacheUserClient();
|
|
210
|
-
}
|
|
211
|
-
function emptyUserCacheClient() {
|
|
212
|
-
if (!emptyCacheUserClient) {
|
|
213
|
-
throw new Error("User cache not configured. Call configUserCacheCallbacks() first.");
|
|
214
|
-
}
|
|
215
|
-
return emptyCacheUserClient();
|
|
216
|
-
}
|
|
217
|
-
async function fetchUsersClient() {
|
|
218
|
-
const csrfToken = await fetchCsrfClient("get-all-users");
|
|
219
|
-
return await goralysFetchClient("GET", buildApiUrl("users/all", { "csrf-token": csrfToken }));
|
|
220
|
-
}
|
|
221
|
-
async function fetchVirtualUsersClient() {
|
|
222
|
-
const csrfToken = await fetchCsrfClient("get-virtual-users");
|
|
223
|
-
return await goralysFetchClient("GET", buildApiUrl("users/virtual", { "csrf-token": csrfToken }));
|
|
224
|
-
}
|
|
225
|
-
async function fetchAdminsClient() {
|
|
226
|
-
const csrfToken = await fetchCsrfClient("get-all-admins");
|
|
227
|
-
return await goralysFetchClient("GET", buildApiUrl("admins/all", { "csrf-token": csrfToken }));
|
|
228
|
-
}
|
|
229
|
-
async function fetchVirtualAdminsClient() {
|
|
230
|
-
const csrfToken = await fetchCsrfClient("get-virtual-admins");
|
|
231
|
-
return await goralysFetchClient("GET", buildApiUrl("admins/virtual", { "csrf-token": csrfToken }));
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// src/config.ts
|
|
235
|
-
function configGoralysCore(cfg) {
|
|
236
|
-
configureGoralysClient(cfg.client);
|
|
237
|
-
configureCookies(cfg.cookies);
|
|
238
|
-
configureStorage(cfg.storage);
|
|
239
|
-
configureCheckAuth(cfg.auth);
|
|
240
|
-
configureUserCacheCallbacks(cfg.cache.cache, cfg.cache.empty);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// src/hooks/useSubjects.ts
|
|
244
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
245
|
-
|
|
246
|
-
// src/lib/subjects/subjects.client.ts
|
|
247
|
-
async function fetchStudentSubjectsClient() {
|
|
248
|
-
const csrfToken = await fetchCsrfClient("get-student-subjects");
|
|
249
|
-
if (!csrfToken)
|
|
250
|
-
return null;
|
|
251
|
-
return await goralysFetchClient("GET", buildApiUrl("subjects/student", { "csrf-token": csrfToken }));
|
|
252
|
-
}
|
|
253
|
-
async function fetchTeacherSubjectsClient() {
|
|
254
|
-
const csrfToken = await fetchCsrfClient("get-teacher-subjects");
|
|
255
|
-
if (!csrfToken)
|
|
256
|
-
return null;
|
|
257
|
-
return await goralysFetchClient("GET", buildApiUrl("subjects/teacher", { "csrf-token": csrfToken }));
|
|
258
|
-
}
|
|
259
|
-
async function fetchAdminSubjectsClient() {
|
|
260
|
-
const csrfToken = await fetchCsrfClient("get-admin-subjects");
|
|
261
|
-
if (!csrfToken)
|
|
262
|
-
return null;
|
|
263
|
-
return await goralysFetchClient("GET", buildApiUrl("subjects/admin", { "csrf-token": csrfToken }));
|
|
264
|
-
}
|
|
265
|
-
async function fetchSubjectsForRoleClient(role) {
|
|
266
|
-
switch (role.role) {
|
|
267
|
-
case "student":
|
|
268
|
-
return await fetchStudentSubjectsClient();
|
|
269
|
-
case "teacher":
|
|
270
|
-
return await fetchTeacherSubjectsClient();
|
|
271
|
-
case "admin":
|
|
272
|
-
return await fetchAdminSubjectsClient();
|
|
273
|
-
default:
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
92
|
// src/lib/config.ts
|
|
279
|
-
var
|
|
93
|
+
var COOKIES_DISMISSED_KEY = "cookie-banner-dismissed";
|
|
94
|
+
var PERSISTANT_COOKIES = [COOKIES_DISMISSED_KEY, "rate_limit_token"];
|
|
280
95
|
var PERSISTANT_LOCALS = ["goralys-cookies-expire", "flash_toast"];
|
|
281
96
|
var USERNAME_KEY = "username";
|
|
282
97
|
var ROLE_KEY = "user-role";
|
|
@@ -516,6 +331,186 @@ Attention : les administrateurs ont acc\xE8s \xE0 toutes les fonctionnalit\xE9s
|
|
|
516
331
|
}
|
|
517
332
|
];
|
|
518
333
|
|
|
334
|
+
// src/lib/user/user.client.ts
|
|
335
|
+
async function cacheUserDataClient() {
|
|
336
|
+
const res = await goralysFetchClient("GET", "user/profile");
|
|
337
|
+
if (!res.ok) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const data = (await res.json())["data"];
|
|
341
|
+
cookiesSet(USERNAME_KEY, data.username, "/", 1.5 * 60 * 60);
|
|
342
|
+
cookiesSet(FULL_NAME_KEY, data.full_name, "/", 1.5 * 60 * 60);
|
|
343
|
+
cookiesSet(ROLE_KEY, data.role, "/", 1.5 * 60 * 60);
|
|
344
|
+
cookiesSet(PUB_ID_KEY, data.public_id, "/", 1.5 * 60 * 60);
|
|
345
|
+
if (data?.email)
|
|
346
|
+
cookiesSet(EMAIL_KEY, data.email, "/", 1.5 * 60 * 60);
|
|
347
|
+
else
|
|
348
|
+
cookiesRemove(EMAIL_KEY);
|
|
349
|
+
}
|
|
350
|
+
function emptyUserCacheClient() {
|
|
351
|
+
for (let i = 0; i < storageSize(); i++) {
|
|
352
|
+
const key = storageKeyAt(i);
|
|
353
|
+
if (!PERSISTANT_LOCALS.includes(key))
|
|
354
|
+
storageRemove(key);
|
|
355
|
+
}
|
|
356
|
+
Object.keys(cookiesGetAll()).forEach((name) => {
|
|
357
|
+
if (PERSISTANT_COOKIES.includes(name.trim()))
|
|
358
|
+
return;
|
|
359
|
+
if (name.startsWith("__next"))
|
|
360
|
+
return;
|
|
361
|
+
cookiesRemove(name);
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
async function fetchUsersClient() {
|
|
365
|
+
const csrfToken = await fetchCsrfClient("get-all-users");
|
|
366
|
+
return await goralysFetchClient("GET", buildApiUrl("users/all", { "csrf-token": csrfToken }));
|
|
367
|
+
}
|
|
368
|
+
async function fetchVirtualUsersClient() {
|
|
369
|
+
const csrfToken = await fetchCsrfClient("get-virtual-users");
|
|
370
|
+
return await goralysFetchClient("GET", buildApiUrl("users/virtual", { "csrf-token": csrfToken }));
|
|
371
|
+
}
|
|
372
|
+
async function fetchAdminsClient() {
|
|
373
|
+
const csrfToken = await fetchCsrfClient("get-all-admins");
|
|
374
|
+
return await goralysFetchClient("GET", buildApiUrl("admins/all", { "csrf-token": csrfToken }));
|
|
375
|
+
}
|
|
376
|
+
async function fetchVirtualAdminsClient() {
|
|
377
|
+
const csrfToken = await fetchCsrfClient("get-virtual-admins");
|
|
378
|
+
return await goralysFetchClient("GET", buildApiUrl("admins/virtual", { "csrf-token": csrfToken }));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// src/lib/auth/user-event.ts
|
|
382
|
+
var listeners3 = /* @__PURE__ */ new Set();
|
|
383
|
+
function emitUserEvent(event) {
|
|
384
|
+
listeners3.forEach((l) => l(event));
|
|
385
|
+
}
|
|
386
|
+
function onUserEvent(callback) {
|
|
387
|
+
listeners3.add(callback);
|
|
388
|
+
return () => {
|
|
389
|
+
listeners3.delete(callback);
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/lib/fetch/goralys-action-handler.ts
|
|
394
|
+
var GoralysActionHandler = class {
|
|
395
|
+
handle = async (r) => {
|
|
396
|
+
const data = await r.clone().json();
|
|
397
|
+
if (!data || !data.action) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const action = data.action;
|
|
401
|
+
if (action === "login-success") {
|
|
402
|
+
await this.onLogin();
|
|
403
|
+
}
|
|
404
|
+
return;
|
|
405
|
+
};
|
|
406
|
+
onLogin = async () => {
|
|
407
|
+
await cacheUserDataClient();
|
|
408
|
+
emitUserEvent("login");
|
|
409
|
+
return;
|
|
410
|
+
};
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// src/lib/fetch/fetch.client.ts
|
|
414
|
+
var actionHandler = new GoralysActionHandler();
|
|
415
|
+
async function goralysFetchClient(method, input, payload, requestOptions) {
|
|
416
|
+
const { apiDomain } = getGoralysClientConfig();
|
|
417
|
+
const res = await fetch(`${apiDomain}/${input}`, {
|
|
418
|
+
credentials: "include",
|
|
419
|
+
method: method === "BREW" ? "POST" : method,
|
|
420
|
+
headers: method === "BREW" ? { "X-HTTP-Method-Override": method } : {},
|
|
421
|
+
body: payload ? payload instanceof FormData ? payload : JSON.stringify(payload) : void 0,
|
|
422
|
+
...requestOptions
|
|
423
|
+
});
|
|
424
|
+
const clone = res.clone();
|
|
425
|
+
const contentType = clone.headers.get("Content-Type");
|
|
426
|
+
if (!(contentType && contentType.toLowerCase().trim().includes("application/json")))
|
|
427
|
+
return res;
|
|
428
|
+
const data = await clone.json();
|
|
429
|
+
if (res.status === 401) {
|
|
430
|
+
try {
|
|
431
|
+
emitAuthEvent(data?.authEvent ?? "unauthenticated");
|
|
432
|
+
} catch {
|
|
433
|
+
emitAuthEvent("unauthenticated");
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (res.status === 418) {
|
|
437
|
+
const teapotData = await res.clone().json();
|
|
438
|
+
emitNavigationEvent({
|
|
439
|
+
type: "teapot",
|
|
440
|
+
toastType: teapotData.toastType,
|
|
441
|
+
toastTitle: teapotData.toastTitle,
|
|
442
|
+
toastMessage: teapotData.toastMessage
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
await actionHandler.handle(res);
|
|
446
|
+
return res;
|
|
447
|
+
}
|
|
448
|
+
async function fetchCsrfClient(formId) {
|
|
449
|
+
const { apiDomain } = getGoralysClientConfig();
|
|
450
|
+
const res = await fetch(`${apiDomain}/csrf`, {
|
|
451
|
+
method: "POST",
|
|
452
|
+
headers: { "Content-Type": "application/json" },
|
|
453
|
+
credentials: "include",
|
|
454
|
+
body: JSON.stringify({ form: formId })
|
|
455
|
+
});
|
|
456
|
+
if (!res.ok)
|
|
457
|
+
return null;
|
|
458
|
+
const json = await res.json();
|
|
459
|
+
return json["csrf-token"];
|
|
460
|
+
}
|
|
461
|
+
function buildQueryString(params) {
|
|
462
|
+
return Object.entries(params).filter(([, value]) => value !== null && value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
463
|
+
}
|
|
464
|
+
function buildApiUrl(endpoint, params, domain = false) {
|
|
465
|
+
const { apiDomain } = getGoralysClientConfig();
|
|
466
|
+
const queryString = buildQueryString(params);
|
|
467
|
+
return `${domain ? apiDomain + "/" : ""}${endpoint}${queryString ? `?${queryString}` : ""}`;
|
|
468
|
+
}
|
|
469
|
+
async function handleToastRequest(r, showToast, redirect = true, duration) {
|
|
470
|
+
const res = r.clone();
|
|
471
|
+
const data = await res.json();
|
|
472
|
+
if (data?.toast) {
|
|
473
|
+
showToast({ type: data.toastType, title: data.toastTitle, message: data.toastMessage }, duration);
|
|
474
|
+
if (data?.redirect && redirect) {
|
|
475
|
+
emitNavigationEvent({ type: "redirect", url: data.redirect });
|
|
476
|
+
}
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// src/lib/subjects/subjects.client.ts
|
|
483
|
+
async function fetchStudentSubjectsClient() {
|
|
484
|
+
const csrfToken = await fetchCsrfClient("get-student-subjects");
|
|
485
|
+
if (!csrfToken)
|
|
486
|
+
return null;
|
|
487
|
+
return await goralysFetchClient("GET", buildApiUrl("subjects/student", { "csrf-token": csrfToken }));
|
|
488
|
+
}
|
|
489
|
+
async function fetchTeacherSubjectsClient() {
|
|
490
|
+
const csrfToken = await fetchCsrfClient("get-teacher-subjects");
|
|
491
|
+
if (!csrfToken)
|
|
492
|
+
return null;
|
|
493
|
+
return await goralysFetchClient("GET", buildApiUrl("subjects/teacher", { "csrf-token": csrfToken }));
|
|
494
|
+
}
|
|
495
|
+
async function fetchAdminSubjectsClient() {
|
|
496
|
+
const csrfToken = await fetchCsrfClient("get-admin-subjects");
|
|
497
|
+
if (!csrfToken)
|
|
498
|
+
return null;
|
|
499
|
+
return await goralysFetchClient("GET", buildApiUrl("subjects/admin", { "csrf-token": csrfToken }));
|
|
500
|
+
}
|
|
501
|
+
async function fetchSubjectsForRoleClient(role) {
|
|
502
|
+
switch (role.role) {
|
|
503
|
+
case "student":
|
|
504
|
+
return await fetchStudentSubjectsClient();
|
|
505
|
+
case "teacher":
|
|
506
|
+
return await fetchTeacherSubjectsClient();
|
|
507
|
+
case "admin":
|
|
508
|
+
return await fetchAdminSubjectsClient();
|
|
509
|
+
default:
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
519
514
|
// src/hooks/useSubjects.ts
|
|
520
515
|
function useSubjects(role, showToast) {
|
|
521
516
|
const [subjects, setSubjects] = useState(null);
|
|
@@ -543,10 +538,10 @@ function useSubjects(role, showToast) {
|
|
|
543
538
|
try {
|
|
544
539
|
const syncValue = cookiesGet(syncKey);
|
|
545
540
|
if (syncValue == "1") {
|
|
546
|
-
const raw =
|
|
541
|
+
const raw = storageGet(cacheKey);
|
|
547
542
|
if (raw === null || raw === void 0) {
|
|
548
543
|
cookiesSet(syncKey, "0");
|
|
549
|
-
|
|
544
|
+
storageRemove(cacheKey);
|
|
550
545
|
await fetchSubjects();
|
|
551
546
|
return;
|
|
552
547
|
}
|
|
@@ -563,7 +558,7 @@ function useSubjects(role, showToast) {
|
|
|
563
558
|
await handleToastRequest(res, showToastRef.current, false);
|
|
564
559
|
const data = await res?.json();
|
|
565
560
|
cookiesSet(syncKey, "1");
|
|
566
|
-
|
|
561
|
+
storageSet(cacheKey, JSON.stringify(data));
|
|
567
562
|
console.log("[useSubjects] set syncKey and cached to localStorage");
|
|
568
563
|
const result = Array.isArray(data) ? data : null;
|
|
569
564
|
setSubjects((prev) => {
|
|
@@ -575,7 +570,7 @@ function useSubjects(role, showToast) {
|
|
|
575
570
|
inFlightRef.current = null;
|
|
576
571
|
resolve();
|
|
577
572
|
}
|
|
578
|
-
}, [role]);
|
|
573
|
+
}, [role, showToastRef]);
|
|
579
574
|
useEffect(() => {
|
|
580
575
|
const onChange = () => {
|
|
581
576
|
if (inFlightRef.current)
|
|
@@ -623,10 +618,10 @@ function useSupportTickets(showToast) {
|
|
|
623
618
|
try {
|
|
624
619
|
const syncValue = cookiesGet(syncKey);
|
|
625
620
|
if (syncValue == "1") {
|
|
626
|
-
const raw =
|
|
621
|
+
const raw = storageGet(cacheKey);
|
|
627
622
|
if (raw === null || raw === void 0) {
|
|
628
623
|
cookiesSet(syncKey, "0");
|
|
629
|
-
|
|
624
|
+
storageRemove(cacheKey);
|
|
630
625
|
await fetchSupportTickets();
|
|
631
626
|
return;
|
|
632
627
|
}
|
|
@@ -643,7 +638,7 @@ function useSupportTickets(showToast) {
|
|
|
643
638
|
await handleToastRequest(res, showToastRef.current, false);
|
|
644
639
|
const data = await res?.json();
|
|
645
640
|
cookiesSet(syncKey, "1");
|
|
646
|
-
|
|
641
|
+
storageSet(cacheKey, JSON.stringify(data));
|
|
647
642
|
const result = Array.isArray(data) ? data : null;
|
|
648
643
|
setSupportTickets((prev) => {
|
|
649
644
|
if (JSON.stringify(prev) === JSON.stringify(result))
|
|
@@ -654,7 +649,7 @@ function useSupportTickets(showToast) {
|
|
|
654
649
|
inFlightRef.current = null;
|
|
655
650
|
resolve();
|
|
656
651
|
}
|
|
657
|
-
}, []);
|
|
652
|
+
}, [showToastRef]);
|
|
658
653
|
useEffect2(() => {
|
|
659
654
|
const onChange = () => {
|
|
660
655
|
if (inFlightRef.current)
|
|
@@ -700,10 +695,10 @@ function useUserCollection(fetchFn, type, showToast) {
|
|
|
700
695
|
try {
|
|
701
696
|
const syncValue = cookiesGet(syncKey);
|
|
702
697
|
if (syncValue == "1") {
|
|
703
|
-
const raw =
|
|
698
|
+
const raw = storageGet(cacheKey);
|
|
704
699
|
if (raw === null || raw === void 0) {
|
|
705
700
|
cookiesSet(syncKey, "0");
|
|
706
|
-
|
|
701
|
+
storageRemove(cacheKey);
|
|
707
702
|
await fetchUsers();
|
|
708
703
|
return;
|
|
709
704
|
}
|
|
@@ -721,7 +716,7 @@ function useUserCollection(fetchFn, type, showToast) {
|
|
|
721
716
|
const data = await res?.json();
|
|
722
717
|
if (res?.ok) {
|
|
723
718
|
cookiesSet(syncKey, "1");
|
|
724
|
-
|
|
719
|
+
storageSet(cacheKey, JSON.stringify(data));
|
|
725
720
|
}
|
|
726
721
|
const result = Array.isArray(data) ? data : null;
|
|
727
722
|
setUsers((prev) => {
|
|
@@ -881,6 +876,7 @@ var USER_ROLES = ["admin", "teacher", "student", "none"];
|
|
|
881
876
|
export {
|
|
882
877
|
ADMIN_CACHE_RADIX,
|
|
883
878
|
ADMIN_SYNC_RADIX,
|
|
879
|
+
COOKIES_DISMISSED_KEY,
|
|
884
880
|
EMAIL_KEY,
|
|
885
881
|
FULL_NAME_KEY,
|
|
886
882
|
GoralysActionHandler,
|
|
@@ -910,8 +906,8 @@ export {
|
|
|
910
906
|
configureCookies,
|
|
911
907
|
configureGoralysClient,
|
|
912
908
|
configureStorage,
|
|
913
|
-
configureUserCacheCallbacks,
|
|
914
909
|
cookiesGet,
|
|
910
|
+
cookiesGetAll,
|
|
915
911
|
cookiesOnChange,
|
|
916
912
|
cookiesRemove,
|
|
917
913
|
cookiesSet,
|
|
@@ -940,10 +936,11 @@ export {
|
|
|
940
936
|
parsePhpDateTime,
|
|
941
937
|
reasonsConfig,
|
|
942
938
|
searchFields,
|
|
943
|
-
setCookiesExpire,
|
|
944
939
|
storageGet,
|
|
940
|
+
storageKeyAt,
|
|
945
941
|
storageRemove,
|
|
946
942
|
storageSet,
|
|
943
|
+
storageSize,
|
|
947
944
|
useAdmins,
|
|
948
945
|
useSubjects,
|
|
949
946
|
useSupportTickets,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goralys/core",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"license": "LGPL-2.1-or-later",
|
|
5
5
|
"description": "Shared business logic for the Goralys web application",
|
|
6
6
|
"repository": {
|
|
@@ -28,12 +28,14 @@
|
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "tsup",
|
|
31
|
+
"typeCheck": "tsgo --noEmit",
|
|
31
32
|
"dev": "tsup --watch"
|
|
32
33
|
},
|
|
33
34
|
"peerDependencies": {
|
|
34
35
|
"react": ">=18"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
38
|
+
"@typescript/native-preview": "7.0.0-dev.20260705.1",
|
|
37
39
|
"barrelsby": "^2.8.1",
|
|
38
40
|
"esbuild-plugin-tsconfig-paths": "^1.0.2",
|
|
39
41
|
"react": "^18.0.0",
|