@olinfo/quizms-firebase 4.0.0-canary.20251130
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/bin/bin.js +4 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +36 -0
- package/dist/cli.js.map +1 -0
- package/dist/entry.d.ts +4 -0
- package/dist/entry.js +19 -0
- package/dist/entry.js.map +1 -0
- package/dist/functions.d.ts +14 -0
- package/dist/functions.js +104 -0
- package/dist/functions.js.map +1 -0
- package/dist/package.json.js +5 -0
- package/dist/package.json.js.map +1 -0
- package/dist/src/cli/definalize.js +23 -0
- package/dist/src/cli/definalize.js.map +1 -0
- package/dist/src/cli/export.js +54 -0
- package/dist/src/cli/export.js.map +1 -0
- package/dist/src/cli/files/firestore-indexes.json.js +10 -0
- package/dist/src/cli/files/firestore-indexes.json.js.map +1 -0
- package/dist/src/cli/files/firestore.rules.js +191 -0
- package/dist/src/cli/files/firestore.rules.js.map +1 -0
- package/dist/src/cli/files/storage.rules.js +35 -0
- package/dist/src/cli/files/storage.rules.js.map +1 -0
- package/dist/src/cli/import.js +140 -0
- package/dist/src/cli/import.js.map +1 -0
- package/dist/src/cli/init.js +140 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/update-scores.js +37 -0
- package/dist/src/cli/update-scores.js.map +1 -0
- package/dist/src/cli/utils/collection.js +55 -0
- package/dist/src/cli/utils/collection.js.map +1 -0
- package/dist/src/cli/utils/converters-admin.js +41 -0
- package/dist/src/cli/utils/converters-admin.js.map +1 -0
- package/dist/src/cli/utils/initialize.js +31 -0
- package/dist/src/cli/utils/initialize.js.map +1 -0
- package/dist/src/cli/utils/rest-api.js +23 -0
- package/dist/src/cli/utils/rest-api.js.map +1 -0
- package/dist/src/cli/utils/storage.js +41 -0
- package/dist/src/cli/utils/storage.js.map +1 -0
- package/dist/src/cli/utils/users.js +30 -0
- package/dist/src/cli/utils/users.js.map +1 -0
- package/dist/src/models/user.js +12 -0
- package/dist/src/models/user.js.map +1 -0
- package/dist/src/vite/entry.js +33 -0
- package/dist/src/vite/entry.js.map +1 -0
- package/dist/src/vite/preset.js +30 -0
- package/dist/src/vite/preset.js.map +1 -0
- package/dist/src/web/admin/announcements.js +85 -0
- package/dist/src/web/admin/announcements.js.map +1 -0
- package/dist/src/web/admin/contest-settings.js +16 -0
- package/dist/src/web/admin/contest-settings.js.map +1 -0
- package/dist/src/web/admin/context.js +11 -0
- package/dist/src/web/admin/context.js.map +1 -0
- package/dist/src/web/admin/dashboard.js +85 -0
- package/dist/src/web/admin/dashboard.js.map +1 -0
- package/dist/src/web/admin/export.js +59 -0
- package/dist/src/web/admin/export.js.map +1 -0
- package/dist/src/web/admin/layout.js +38 -0
- package/dist/src/web/admin/layout.js.map +1 -0
- package/dist/src/web/admin/provider.js +30 -0
- package/dist/src/web/admin/provider.js.map +1 -0
- package/dist/src/web/admin/school-table.js +79 -0
- package/dist/src/web/admin/school-table.js.map +1 -0
- package/dist/src/web/common/api.js +43 -0
- package/dist/src/web/common/api.js.map +1 -0
- package/dist/src/web/common/base-login.js +26 -0
- package/dist/src/web/common/base-login.js.map +1 -0
- package/dist/src/web/common/converters.js +57 -0
- package/dist/src/web/common/converters.js.map +1 -0
- package/dist/src/web/common/query.js +16 -0
- package/dist/src/web/common/query.js.map +1 -0
- package/dist/src/web/common/token-login.js +40 -0
- package/dist/src/web/common/token-login.js.map +1 -0
- package/dist/src/web/entry/admin.js +27 -0
- package/dist/src/web/entry/admin.js.map +1 -0
- package/dist/src/web/entry/student-statement.js +28 -0
- package/dist/src/web/entry/student-statement.js.map +1 -0
- package/dist/src/web/entry/student.js +126 -0
- package/dist/src/web/entry/student.js.map +1 -0
- package/dist/src/web/entry/teacher.js +88 -0
- package/dist/src/web/entry/teacher.js.map +1 -0
- package/dist/src/web/hooks/auth.js +26 -0
- package/dist/src/web/hooks/auth.js.map +1 -0
- package/dist/src/web/hooks/collection.js +68 -0
- package/dist/src/web/hooks/collection.js.map +1 -0
- package/dist/src/web/hooks/count.js +22 -0
- package/dist/src/web/hooks/count.js.map +1 -0
- package/dist/src/web/hooks/document.js +61 -0
- package/dist/src/web/hooks/document.js.map +1 -0
- package/dist/src/web/hooks/subscription.js +42 -0
- package/dist/src/web/hooks/subscription.js.map +1 -0
- package/dist/vite.d.ts +4 -0
- package/dist/vite.js +7 -0
- package/dist/vite.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"school-table.js","sources":["../../../../src/web/admin/school-table.tsx"],"sourcesContent":["import { Suspense, useMemo } from \"react\";\n\nimport { AgGrid, Loading } from \"@olinfo/quizms/components\";\nimport type { Participation, Student } from \"@olinfo/quizms/models\";\nimport type { CellEditRequestEvent, ColDef, ICellRendererParams } from \"ag-grid-community\";\n\nimport { participationConverter } from \"~/web/common/converters\";\nimport { useCollection } from \"~/web/hooks\";\nimport { useCount } from \"~/web/hooks/count\";\n\nimport { useAdmin } from \"./context\";\n\nexport function SchoolTable() {\n const { contest } = useAdmin();\n\n const [participations, setParticipation] = useCollection(\n \"participations\",\n participationConverter,\n {\n constraints: { contestId: contest.id },\n subscribe: true,\n },\n );\n\n const colDefs = useMemo(() => columnDefinition(), []);\n\n const onCellEditRequest = async (ev: CellEditRequestEvent) => {\n const participation = ev.data as Participation;\n if (ev.colDef.field === \"finalized\") {\n await setParticipation({ ...participation, finalized: ev.newValue });\n }\n ev.api.refreshCells({ force: true });\n };\n\n return (\n <Suspense fallback={<Loading />}>\n <div className=\"relative grow p-2\">\n <div className=\"absolute inset-0\">\n <AgGrid\n rowData={participations}\n getRowId={(row) => (row.data as Participation).id}\n columnDefs={colDefs}\n onCellEditRequest={onCellEditRequest}\n />\n </div>\n </div>\n </Suspense>\n );\n}\n\nfunction columnDefinition(): ColDef[] {\n return [\n {\n field: \"schoolId\",\n headerName: \"ID\",\n width: 150,\n filter: true,\n },\n {\n field: \"name\",\n headerName: \"Nome\",\n minWidth: 200,\n flex: 1,\n filter: true,\n },\n {\n field: \"count\",\n headerName: \"Studenti\",\n width: 100,\n sortable: false,\n cellRenderer: ({ data }: ICellRendererParams<Participation>) => {\n if (!data) return;\n return (\n <Suspense>\n <Count participationId={data.id} />\n </Suspense>\n );\n },\n },\n {\n field: \"finalized\",\n headerName: \"Finalizzato\",\n width: 100,\n filter: true,\n cellDataType: \"boolean\",\n editable: true,\n },\n ];\n}\n\nfunction Count({ participationId }: { participationId: string }) {\n return useCount<Student>(`participations/${participationId}/students`, {\n constraints: { disabled: false },\n });\n}\n"],"names":["SchoolTable","contest","useAdmin","participations","setParticipation","useCollection","participationConverter","colDefs","useMemo","columnDefinition","jsx","Suspense","Loading","AgGrid","row","ev","participation","data","Count","participationId","useCount"],"mappings":";;;;;;;;;;;;;AAYO,SAASA,IAAc;AAC5B,QAAM,EAAE,SAAAC,EAAA,IAAYC,EAAA,GAEd,CAACC,GAAgBC,CAAgB,IAAIC;AAAA,IACzC;AAAA,IACAC;AAAA,IACA;AAAA,MACE,aAAa,EAAE,WAAWL,EAAQ,GAAA;AAAA,MAClC,WAAW;AAAA,IAAA;AAAA,EACb,GAGIM,IAAUC,EAAQ,MAAMC,EAAA,GAAoB,CAAA,CAAE;AAUpD,SACE,gBAAAC,EAACC,GAAA,EAAS,UAAU,gBAAAD,EAACE,GAAA,CAAA,CAAQ,GAC3B,UAAA,gBAAAF,EAAC,OAAA,EAAI,WAAU,qBACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,oBACb,UAAA,gBAAAA;AAAA,IAACG;AAAA,IAAA;AAAA,MACC,SAASV;AAAA,MACT,UAAU,CAACW,MAASA,EAAI,KAAuB;AAAA,MAC/C,YAAYP;AAAA,MACZ,mBAhBgB,OAAOQ,MAA6B;AAC5D,cAAMC,IAAgBD,EAAG;AACzB,QAAIA,EAAG,OAAO,UAAU,eACtB,MAAMX,EAAiB,EAAE,GAAGY,GAAe,WAAWD,EAAG,UAAU,GAErEA,EAAG,IAAI,aAAa,EAAE,OAAO,IAAM;AAAA,MACrC;AAAA,IAUU;AAAA,EAAA,EACF,CACF,GACF,GACF;AAEJ;AAEA,SAASN,IAA6B;AACpC,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,IAAA;AAAA,IAEV;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,MAAM;AAAA,MACN,QAAQ;AAAA,IAAA;AAAA,IAEV;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc,CAAC,EAAE,MAAAQ,QAA+C;AAC9D,YAAKA;AACL,mCACGN,GAAA,EACC,UAAA,gBAAAD,EAACQ,KAAM,iBAAiBD,EAAK,IAAI,EAAA,CACnC;AAAA,MAEJ;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,UAAU;AAAA,IAAA;AAAA,EACZ;AAEJ;AAEA,SAASC,EAAM,EAAE,iBAAAC,KAAgD;AAC/D,SAAOC,EAAkB,kBAAkBD,CAAe,aAAa;AAAA,IACrE,aAAa,EAAE,UAAU,GAAA;AAAA,EAAM,CAChC;AACH;"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { validate as c } from "@olinfo/quizms/utils";
|
|
2
|
+
import { getFunctions as g, httpsCallable as f } from "firebase/functions";
|
|
3
|
+
import n from "zod";
|
|
4
|
+
const d = n.discriminatedUnion("success", [
|
|
5
|
+
n.object({ success: n.literal(!0), data: n.any() }),
|
|
6
|
+
n.object({ success: n.literal(!1), errorCode: n.string(), error: n.string() })
|
|
7
|
+
]);
|
|
8
|
+
async function r(t, i, a, s) {
|
|
9
|
+
const p = g(t.app, "europe-west6"), u = f(p, "api");
|
|
10
|
+
let o;
|
|
11
|
+
try {
|
|
12
|
+
o = await u({ action: i, ...a });
|
|
13
|
+
} catch (l) {
|
|
14
|
+
throw new Error("Server non raggiungibile", { cause: l });
|
|
15
|
+
}
|
|
16
|
+
const e = c(d, o.data);
|
|
17
|
+
if (!e.success)
|
|
18
|
+
throw new Error(e.error);
|
|
19
|
+
return c(n.object(s), e.data);
|
|
20
|
+
}
|
|
21
|
+
function y(t, i, a) {
|
|
22
|
+
return r(t, `${i}Login`, a, { token: n.string() });
|
|
23
|
+
}
|
|
24
|
+
function P(t, i) {
|
|
25
|
+
return r(t, "studentLogin", i, { token: n.string() });
|
|
26
|
+
}
|
|
27
|
+
async function S(t, i) {
|
|
28
|
+
await r(t, "teacherStartParticipation", { participationId: i }, {});
|
|
29
|
+
}
|
|
30
|
+
async function j(t, i) {
|
|
31
|
+
await r(t, "teacherStopParticipation", { participationId: i }, {});
|
|
32
|
+
}
|
|
33
|
+
async function z(t, i) {
|
|
34
|
+
await r(t, "teacherFinalizeParticipation", { participationId: i }, {});
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
z as finalizeParticipation,
|
|
38
|
+
y as login,
|
|
39
|
+
S as startParticipation,
|
|
40
|
+
j as stopParticipation,
|
|
41
|
+
P as studentLogin
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sources":["../../../../src/web/common/api.ts"],"sourcesContent":["import type { Student } from \"@olinfo/quizms/models\";\nimport { validate } from \"@olinfo/quizms/utils\";\nimport type { Firestore } from \"firebase/firestore\";\nimport { getFunctions, type HttpsCallableResult, httpsCallable } from \"firebase/functions\";\nimport z, { type ZodObject, type ZodRawShape } from \"zod\";\n\nconst responseSchema = z.discriminatedUnion(\"success\", [\n z.object({ success: z.literal(true), data: z.any() }),\n z.object({ success: z.literal(false), errorCode: z.string(), error: z.string() }),\n]);\n\nasync function api<Shape extends ZodRawShape>(\n db: Firestore,\n action: string,\n body: any,\n shape: Shape,\n): Promise<z.infer<ZodObject<Shape>>> {\n const region = \"europe-west6\"; // TODO\n const functions = getFunctions(db.app, region);\n const apiCallable = httpsCallable(functions, \"api\");\n\n let resp: HttpsCallableResult;\n try {\n resp = await apiCallable({ action, ...body });\n } catch (err: any) {\n throw new Error(\"Server non raggiungibile\", { cause: err });\n }\n\n const data = validate(responseSchema, resp.data);\n if (!data.success) {\n throw new Error(data.error);\n }\n return validate(z.object(shape), data.data);\n}\n\nexport function login(db: Firestore, role: string, body: { username: string; password: string }) {\n return api(db, `${role}Login`, body, { token: z.string() });\n}\n\nexport function studentLogin(\n db: Firestore,\n body: {\n contestId: string;\n token: string;\n userData: Student[\"userData\"];\n },\n) {\n return api(db, \"studentLogin\", body, { token: z.string() });\n}\n\nexport async function startParticipation(db: Firestore, participationId: string) {\n await api(db, \"teacherStartParticipation\", { participationId }, {});\n}\n\nexport async function stopParticipation(db: Firestore, participationId: string) {\n await api(db, \"teacherStopParticipation\", { participationId }, {});\n}\n\nexport async function finalizeParticipation(db: Firestore, participationId: string) {\n await api(db, \"teacherFinalizeParticipation\", { participationId }, {});\n}\n"],"names":["responseSchema","z","api","db","action","body","shape","functions","getFunctions","apiCallable","httpsCallable","resp","err","data","validate","login","role","studentLogin","startParticipation","participationId","stopParticipation","finalizeParticipation"],"mappings":";;;AAMA,MAAMA,IAAiBC,EAAE,mBAAmB,WAAW;AAAA,EACrDA,EAAE,OAAO,EAAE,SAASA,EAAE,QAAQ,EAAI,GAAG,MAAMA,EAAE,IAAA,EAAI,CAAG;AAAA,EACpDA,EAAE,OAAO,EAAE,SAASA,EAAE,QAAQ,EAAK,GAAG,WAAWA,EAAE,UAAU,OAAOA,EAAE,OAAA,GAAU;AAClF,CAAC;AAED,eAAeC,EACbC,GACAC,GACAC,GACAC,GACoC;AAEpC,QAAMC,IAAYC,EAAaL,EAAG,KADnB,cAC8B,GACvCM,IAAcC,EAAcH,GAAW,KAAK;AAElD,MAAII;AACJ,MAAI;AACF,IAAAA,IAAO,MAAMF,EAAY,EAAE,QAAAL,GAAQ,GAAGC,GAAM;AAAA,EAC9C,SAASO,GAAU;AACjB,UAAM,IAAI,MAAM,4BAA4B,EAAE,OAAOA,GAAK;AAAA,EAC5D;AAEA,QAAMC,IAAOC,EAASd,GAAgBW,EAAK,IAAI;AAC/C,MAAI,CAACE,EAAK;AACR,UAAM,IAAI,MAAMA,EAAK,KAAK;AAE5B,SAAOC,EAASb,EAAE,OAAOK,CAAK,GAAGO,EAAK,IAAI;AAC5C;AAEO,SAASE,EAAMZ,GAAea,GAAcX,GAA8C;AAC/F,SAAOH,EAAIC,GAAI,GAAGa,CAAI,SAASX,GAAM,EAAE,OAAOJ,EAAE,OAAA,EAAO,CAAG;AAC5D;AAEO,SAASgB,EACdd,GACAE,GAKA;AACA,SAAOH,EAAIC,GAAI,gBAAgBE,GAAM,EAAE,OAAOJ,EAAE,OAAA,GAAU;AAC5D;AAEA,eAAsBiB,EAAmBf,GAAegB,GAAyB;AAC/E,QAAMjB,EAAIC,GAAI,6BAA6B,EAAE,iBAAAgB,EAAA,GAAmB,CAAA,CAAE;AACpE;AAEA,eAAsBC,EAAkBjB,GAAegB,GAAyB;AAC9E,QAAMjB,EAAIC,GAAI,4BAA4B,EAAE,iBAAAgB,EAAA,GAAmB,CAAA,CAAE;AACnE;AAEA,eAAsBE,EAAsBlB,GAAegB,GAAyB;AAClF,QAAMjB,EAAIC,GAAI,gCAAgC,EAAE,iBAAAgB,EAAA,GAAmB,CAAA,CAAE;AACvE;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as s, use as a, useMemo as p, useCallback as u, Suspense as c } from "react";
|
|
3
|
+
import { ErrorBoundary as m, Loading as l } from "@olinfo/quizms/components";
|
|
4
|
+
import { initializeApp as d } from "firebase/app";
|
|
5
|
+
import { initializeAuth as f, debugErrorMap as b, browserSessionPersistence as g, getAuth as h } from "firebase/auth";
|
|
6
|
+
import { getFirestore as x } from "firebase/firestore";
|
|
7
|
+
import w from "virtual:quizms-firebase-config";
|
|
8
|
+
function z({ children: i }) {
|
|
9
|
+
const r = p(() => {
|
|
10
|
+
const o = d(w);
|
|
11
|
+
return f(o, { persistence: g, errorMap: b }), x(o);
|
|
12
|
+
}, []), n = u(async () => {
|
|
13
|
+
await h(r.app).signOut(), window.location.reload();
|
|
14
|
+
}, [r]);
|
|
15
|
+
return /* @__PURE__ */ e(t.Provider, { value: r, children: /* @__PURE__ */ e(m, { onReset: n, children: /* @__PURE__ */ e(c, { fallback: /* @__PURE__ */ e(l, {}), children: i }) }) });
|
|
16
|
+
}
|
|
17
|
+
const t = s(void 0);
|
|
18
|
+
t.displayName = "FirebaseContext";
|
|
19
|
+
function E() {
|
|
20
|
+
return a(t);
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
z as FirebaseLogin,
|
|
24
|
+
E as useDb
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=base-login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-login.js","sources":["../../../../src/web/common/base-login.tsx"],"sourcesContent":["import { createContext, type ReactNode, Suspense, use, useCallback, useMemo } from \"react\";\n\nimport { ErrorBoundary, Loading } from \"@olinfo/quizms/components\";\nimport { initializeApp } from \"firebase/app\";\nimport { browserSessionPersistence, debugErrorMap, getAuth, initializeAuth } from \"firebase/auth\";\nimport { type Firestore, getFirestore } from \"firebase/firestore\";\n\n// @ts-expect-error\nimport config from \"virtual:quizms-firebase-config\";\n\ntype Props = {\n children: ReactNode;\n};\n\nexport function FirebaseLogin({ children }: Props) {\n const db = useMemo(() => {\n const app = initializeApp(config);\n initializeAuth(app, { persistence: browserSessionPersistence, errorMap: debugErrorMap });\n return getFirestore(app);\n }, []);\n\n const onReset = useCallback(async () => {\n const auth = getAuth(db.app);\n await auth.signOut();\n window.location.reload();\n }, [db]);\n\n return (\n <FirebaseContext.Provider value={db}>\n <ErrorBoundary onReset={onReset}>\n <Suspense fallback={<Loading />}>{children}</Suspense>\n </ErrorBoundary>\n </FirebaseContext.Provider>\n );\n}\n\nconst FirebaseContext = createContext<Firestore | undefined>(undefined);\nFirebaseContext.displayName = \"FirebaseContext\";\n\nexport function useDb() {\n return use(FirebaseContext)!;\n}\n"],"names":["FirebaseLogin","children","db","useMemo","app","initializeApp","config","initializeAuth","browserSessionPersistence","debugErrorMap","getFirestore","onReset","useCallback","getAuth","FirebaseContext","jsx","ErrorBoundary","Suspense","Loading","createContext","useDb","use"],"mappings":";;;;;;;AAcO,SAASA,EAAc,EAAE,UAAAC,KAAmB;AACjD,QAAMC,IAAKC,EAAQ,MAAM;AACvB,UAAMC,IAAMC,EAAcC,CAAM;AAChC,WAAAC,EAAeH,GAAK,EAAE,aAAaI,GAA2B,UAAUC,GAAe,GAChFC,EAAaN,CAAG;AAAA,EACzB,GAAG,CAAA,CAAE,GAECO,IAAUC,EAAY,YAAY;AAEtC,UADaC,EAAQX,EAAG,GAAG,EAChB,QAAA,GACX,OAAO,SAAS,OAAA;AAAA,EAClB,GAAG,CAACA,CAAE,CAAC;AAEP,2BACGY,EAAgB,UAAhB,EAAyB,OAAOZ,GAC/B,UAAA,gBAAAa,EAACC,GAAA,EAAc,SAAAL,GACb,UAAA,gBAAAI,EAACE,KAAS,UAAU,gBAAAF,EAACG,KAAQ,GAAK,UAAAjB,EAAA,CAAS,GAC7C,GACF;AAEJ;AAEA,MAAMa,IAAkBK,EAAqC,MAAS;AACtEL,EAAgB,cAAc;AAEvB,SAASM,IAAQ;AACtB,SAAOC,EAAIP,CAAe;AAC5B;"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { announcementSchema as u, contestSchema as d, participationSchema as c, studentRestoreSchema as m, variantSchema as v, studentSchema as D } from "@olinfo/quizms/models";
|
|
2
|
+
import { validate as F } from "@olinfo/quizms/utils";
|
|
3
|
+
import { serverTimestamp as f, Timestamp as s } from "firebase/firestore";
|
|
4
|
+
import { cloneDeepWith as S, omit as Z, isDate as l, isString as C, mapValues as T } from "lodash-es";
|
|
5
|
+
import n, { ZodDate as b, ZodObject as A, ZodRecord as R, ZodArray as U, ZodOptional as j, ZodDefault as y, ZodUnion as O, ZodDiscriminatedUnion as g } from "zod";
|
|
6
|
+
function i(t) {
|
|
7
|
+
return S(Z(t, "id"), (r) => {
|
|
8
|
+
if (l(r))
|
|
9
|
+
return s.fromDate(r);
|
|
10
|
+
if (C(r))
|
|
11
|
+
return r.trim();
|
|
12
|
+
if (r === void 0)
|
|
13
|
+
return null;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function e(t) {
|
|
17
|
+
return t instanceof b ? n.instanceof(s).transform((r) => r.toDate()).pipe(t) : t instanceof A ? n.object(T(t.shape, (r) => e(r))) : t instanceof R ? n.record(e(t.element)) : t instanceof U ? e(t.element).array() : t instanceof j ? n.preprocess((r) => r ?? void 0, e(t.unwrap()).optional()) : t instanceof y ? e(t.removeDefault()).pipe(t) : t instanceof O ? n.union(t.options.map((r) => e(r))) : t instanceof g ? n.discriminatedUnion(
|
|
18
|
+
t.discriminator,
|
|
19
|
+
t.options.map((r) => e(r))
|
|
20
|
+
) : t;
|
|
21
|
+
}
|
|
22
|
+
function a(t, r) {
|
|
23
|
+
const p = { ...r.data({ serverTimestamps: "estimate" }), id: r.id };
|
|
24
|
+
return F(e(t), p);
|
|
25
|
+
}
|
|
26
|
+
function o(t) {
|
|
27
|
+
return {
|
|
28
|
+
toFirestore: (r) => i(r),
|
|
29
|
+
fromFirestore: (r) => a(t, r)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const k = o(d), q = o(c), B = o(m), E = o(v), G = {
|
|
33
|
+
toFirestore(t) {
|
|
34
|
+
return {
|
|
35
|
+
...i(t),
|
|
36
|
+
createdAt: f()
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
fromFirestore: (t) => a(u, t)
|
|
40
|
+
}, H = {
|
|
41
|
+
toFirestore(t) {
|
|
42
|
+
return {
|
|
43
|
+
...i(t),
|
|
44
|
+
updatedAt: f()
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
fromFirestore: (t) => a(D, t)
|
|
48
|
+
};
|
|
49
|
+
export {
|
|
50
|
+
G as announcementConverter,
|
|
51
|
+
k as contestConverter,
|
|
52
|
+
q as participationConverter,
|
|
53
|
+
H as studentConverter,
|
|
54
|
+
B as studentRestoreConvert,
|
|
55
|
+
E as variantConverter
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=converters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converters.js","sources":["../../../../src/web/common/converters.ts"],"sourcesContent":["import {\n type Announcement,\n announcementSchema,\n contestSchema,\n participationSchema,\n type Student,\n studentRestoreSchema,\n studentSchema,\n variantSchema,\n} from \"@olinfo/quizms/models\";\nimport { validate } from \"@olinfo/quizms/utils\";\nimport {\n type DocumentSnapshot,\n type FirestoreDataConverter,\n serverTimestamp,\n Timestamp,\n} from \"firebase/firestore\";\nimport { cloneDeepWith, isDate, isString, mapValues, omit } from \"lodash-es\";\nimport z, {\n ZodArray,\n ZodDate,\n ZodDefault,\n ZodDiscriminatedUnion,\n ZodObject,\n ZodOptional,\n ZodRecord,\n type ZodType,\n type ZodTypeAny,\n ZodUnion,\n} from \"zod\";\n\nfunction convertToFirestore(data: Record<string, any>) {\n return cloneDeepWith(omit(data, \"id\"), (value) => {\n if (isDate(value)) {\n return Timestamp.fromDate(value);\n }\n if (isString(value)) {\n return value.trim();\n }\n if (value === undefined) {\n return null;\n }\n });\n}\n\nfunction toFirebaseSchema(schema: ZodTypeAny): ZodTypeAny {\n if (schema instanceof ZodDate) {\n return z\n .instanceof(Timestamp)\n .transform((ts) => ts.toDate())\n .pipe(schema);\n }\n if (schema instanceof ZodObject) {\n return z.object(mapValues(schema.shape, (field) => toFirebaseSchema(field)));\n }\n if (schema instanceof ZodRecord) {\n return z.record(toFirebaseSchema(schema.element));\n }\n if (schema instanceof ZodArray) {\n return toFirebaseSchema(schema.element).array();\n }\n if (schema instanceof ZodOptional) {\n return z.preprocess((val) => val ?? undefined, toFirebaseSchema(schema.unwrap()).optional());\n }\n if (schema instanceof ZodDefault) {\n return toFirebaseSchema(schema.removeDefault()).pipe(schema);\n }\n if (schema instanceof ZodUnion) {\n return z.union(schema.options.map((option: ZodTypeAny) => toFirebaseSchema(option)));\n }\n if (schema instanceof ZodDiscriminatedUnion) {\n return z.discriminatedUnion(\n schema.discriminator,\n schema.options.map((option: ZodTypeAny) => toFirebaseSchema(option)),\n );\n }\n return schema;\n}\n\nfunction parse<T>(schema: ZodType<T, any, any>, snapshot: DocumentSnapshot): T {\n const data = { ...snapshot.data({ serverTimestamps: \"estimate\" }), id: snapshot.id };\n return validate(toFirebaseSchema(schema), data);\n}\n\nfunction converter<T extends object>(schema: ZodType<T, any, any>): FirestoreDataConverter<T> {\n return {\n toFirestore: (data) => convertToFirestore(data),\n fromFirestore: (snapshot) => parse(schema, snapshot),\n };\n}\n\nexport const contestConverter = converter(contestSchema);\nexport const participationConverter = converter(participationSchema);\nexport const studentRestoreConvert = converter(studentRestoreSchema);\nexport const variantConverter = converter(variantSchema);\n\nexport const announcementConverter: FirestoreDataConverter<Announcement> = {\n toFirestore(data) {\n return {\n ...convertToFirestore(data),\n createdAt: serverTimestamp(),\n };\n },\n fromFirestore: (snapshot) => parse(announcementSchema, snapshot),\n};\n\nexport const studentConverter: FirestoreDataConverter<Student> = {\n toFirestore(data) {\n return {\n ...convertToFirestore(data),\n updatedAt: serverTimestamp(),\n };\n },\n fromFirestore: (snapshot) => parse(studentSchema, snapshot),\n};\n"],"names":["convertToFirestore","data","cloneDeepWith","omit","value","isDate","Timestamp","isString","toFirebaseSchema","schema","ZodDate","z","ts","ZodObject","mapValues","field","ZodRecord","ZodArray","ZodOptional","val","ZodDefault","ZodUnion","option","ZodDiscriminatedUnion","parse","snapshot","validate","converter","contestConverter","contestSchema","participationConverter","participationSchema","studentRestoreConvert","studentRestoreSchema","variantConverter","variantSchema","announcementConverter","serverTimestamp","announcementSchema","studentConverter","studentSchema"],"mappings":";;;;;AA+BA,SAASA,EAAmBC,GAA2B;AACrD,SAAOC,EAAcC,EAAKF,GAAM,IAAI,GAAG,CAACG,MAAU;AAChD,QAAIC,EAAOD,CAAK;AACd,aAAOE,EAAU,SAASF,CAAK;AAEjC,QAAIG,EAASH,CAAK;AAChB,aAAOA,EAAM,KAAA;AAEf,QAAIA,MAAU;AACZ,aAAO;AAAA,EAEX,CAAC;AACH;AAEA,SAASI,EAAiBC,GAAgC;AACxD,SAAIA,aAAkBC,IACbC,EACJ,WAAWL,CAAS,EACpB,UAAU,CAACM,MAAOA,EAAG,OAAA,CAAQ,EAC7B,KAAKH,CAAM,IAEZA,aAAkBI,IACbF,EAAE,OAAOG,EAAUL,EAAO,OAAO,CAACM,MAAUP,EAAiBO,CAAK,CAAC,CAAC,IAEzEN,aAAkBO,IACbL,EAAE,OAAOH,EAAiBC,EAAO,OAAO,CAAC,IAE9CA,aAAkBQ,IACbT,EAAiBC,EAAO,OAAO,EAAE,MAAA,IAEtCA,aAAkBS,IACbP,EAAE,WAAW,CAACQ,MAAQA,KAAO,QAAWX,EAAiBC,EAAO,QAAQ,EAAE,SAAA,CAAU,IAEzFA,aAAkBW,IACbZ,EAAiBC,EAAO,cAAA,CAAe,EAAE,KAAKA,CAAM,IAEzDA,aAAkBY,IACbV,EAAE,MAAMF,EAAO,QAAQ,IAAI,CAACa,MAAuBd,EAAiBc,CAAM,CAAC,CAAC,IAEjFb,aAAkBc,IACbZ,EAAE;AAAA,IACPF,EAAO;AAAA,IACPA,EAAO,QAAQ,IAAI,CAACa,MAAuBd,EAAiBc,CAAM,CAAC;AAAA,EAAA,IAGhEb;AACT;AAEA,SAASe,EAASf,GAA8BgB,GAA+B;AAC7E,QAAMxB,IAAO,EAAE,GAAGwB,EAAS,KAAK,EAAE,kBAAkB,YAAY,GAAG,IAAIA,EAAS,GAAA;AAChF,SAAOC,EAASlB,EAAiBC,CAAM,GAAGR,CAAI;AAChD;AAEA,SAAS0B,EAA4BlB,GAAyD;AAC5F,SAAO;AAAA,IACL,aAAa,CAACR,MAASD,EAAmBC,CAAI;AAAA,IAC9C,eAAe,CAACwB,MAAaD,EAAMf,GAAQgB,CAAQ;AAAA,EAAA;AAEvD;AAEO,MAAMG,IAAmBD,EAAUE,CAAa,GAC1CC,IAAyBH,EAAUI,CAAmB,GACtDC,IAAwBL,EAAUM,CAAoB,GACtDC,IAAmBP,EAAUQ,CAAa,GAE1CC,IAA8D;AAAA,EACzE,YAAYnC,GAAM;AAChB,WAAO;AAAA,MACL,GAAGD,EAAmBC,CAAI;AAAA,MAC1B,WAAWoC,EAAA;AAAA,IAAgB;AAAA,EAE/B;AAAA,EACA,eAAe,CAACZ,MAAaD,EAAMc,GAAoBb,CAAQ;AACjE,GAEac,IAAoD;AAAA,EAC/D,YAAYtC,GAAM;AAChB,WAAO;AAAA,MACL,GAAGD,EAAmBC,CAAI;AAAA,MAC1B,WAAWoC,EAAA;AAAA,IAAgB;AAAA,EAE/B;AAAA,EACA,eAAe,CAACZ,MAAaD,EAAMgB,GAAef,CAAQ;AAC5D;"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { collectionGroup as A, collection as s, query as t, where as i, orderBy as f, limit as u, startAfter as d } from "firebase/firestore";
|
|
2
|
+
function m(c, n, l, e) {
|
|
3
|
+
let r = (e?.group ? A : s)(
|
|
4
|
+
c,
|
|
5
|
+
n
|
|
6
|
+
).withConverter(l);
|
|
7
|
+
for (const [y, a] of Object.entries(e?.constraints ?? {}))
|
|
8
|
+
r = t(r, i(y, Array.isArray(a) ? "in" : "==", a));
|
|
9
|
+
for (const [y, a] of Object.entries(e?.arrayConstraints ?? {}))
|
|
10
|
+
r = t(r, i(y, Array.isArray(a) ? "array-contains-any" : "array-contains", a));
|
|
11
|
+
return e?.orderBy && (r = Array.isArray(e.orderBy) ? t(r, f(...e.orderBy)) : t(r, f(e.orderBy))), e?.limit && (r = t(r, u(e.limit))), e?.startAfter && (r = t(r, d(e.startAfter))), r;
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
m as default
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sources":["../../../../src/web/common/query.ts"],"sourcesContent":["import {\n query as _query,\n type CollectionReference,\n collection,\n collectionGroup,\n type DocumentReference,\n type DocumentSnapshot,\n type Firestore,\n type FirestoreDataConverter,\n limit,\n orderBy,\n type Query,\n startAfter,\n where,\n} from \"firebase/firestore\";\n\nexport type Constraints<T> = { [P in keyof T]?: T[P] | T[P][] };\nexport type ArrayConstraints<T> = {\n [P in keyof T]?: T[P] extends (infer E)[] ? E | E[] : never;\n};\n\nexport type QueryOption<T> = {\n constraints?: Constraints<T>;\n arrayConstraints?: ArrayConstraints<T>;\n orderBy?: (keyof T & string) | [keyof T & string, \"asc\" | \"desc\"];\n limit?: number;\n startAfter?: T | DocumentSnapshot<T>;\n group?: boolean;\n};\n\nexport default function query<T>(\n db: Firestore | DocumentReference | CollectionReference,\n path: string,\n converter: FirestoreDataConverter<T>,\n options?: QueryOption<T>,\n) {\n let q: Query<T> = (options?.group ? collectionGroup : collection)(\n db as Firestore,\n path,\n ).withConverter(converter);\n for (const [k, v] of Object.entries(options?.constraints ?? {})) {\n q = _query(q, where(k, Array.isArray(v) ? \"in\" : \"==\", v));\n }\n for (const [k, v] of Object.entries(options?.arrayConstraints ?? {})) {\n q = _query(q, where(k, Array.isArray(v) ? \"array-contains-any\" : \"array-contains\", v));\n }\n\n if (options?.orderBy) {\n q = Array.isArray(options.orderBy)\n ? _query(q, orderBy(...options.orderBy))\n : _query(q, orderBy(options.orderBy));\n }\n if (options?.limit) q = _query(q, limit(options.limit));\n if (options?.startAfter) q = _query(q, startAfter(options.startAfter));\n\n return q;\n}\n"],"names":["query","db","path","converter","options","q","collectionGroup","collection","k","v","_query","where","orderBy","limit","startAfter"],"mappings":";AA8BA,SAAwBA,EACtBC,GACAC,GACAC,GACAC,GACA;AACA,MAAIC,KAAeD,GAAS,QAAQE,IAAkBC;AAAA,IACpDN;AAAA,IACAC;AAAA,EAAA,EACA,cAAcC,CAAS;AACzB,aAAW,CAACK,GAAGC,CAAC,KAAK,OAAO,QAAQL,GAAS,eAAe,CAAA,CAAE;AAC5D,IAAAC,IAAIK,EAAOL,GAAGM,EAAMH,GAAG,MAAM,QAAQC,CAAC,IAAI,OAAO,MAAMA,CAAC,CAAC;AAE3D,aAAW,CAACD,GAAGC,CAAC,KAAK,OAAO,QAAQL,GAAS,oBAAoB,CAAA,CAAE;AACjE,IAAAC,IAAIK,EAAOL,GAAGM,EAAMH,GAAG,MAAM,QAAQC,CAAC,IAAI,uBAAuB,kBAAkBA,CAAC,CAAC;AAGvF,SAAIL,GAAS,YACXC,IAAI,MAAM,QAAQD,EAAQ,OAAO,IAC7BM,EAAOL,GAAGO,EAAQ,GAAGR,EAAQ,OAAO,CAAC,IACrCM,EAAOL,GAAGO,EAAQR,EAAQ,OAAO,CAAC,IAEpCA,GAAS,UAAOC,IAAIK,EAAOL,GAAGQ,EAAMT,EAAQ,KAAK,CAAC,IAClDA,GAAS,eAAYC,IAAIK,EAAOL,GAAGS,EAAWV,EAAQ,UAAU,CAAC,IAE9DC;AACT;"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsxs as n, Fragment as f, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect as p } from "react";
|
|
3
|
+
import { useMetadata as h } from "@olinfo/quizms/components";
|
|
4
|
+
import { Navbar as b, NavbarBrand as w, Form as g, UsernameField as x, CurrentPasswordField as N, SubmitButton as S } from "@olinfo/react-components";
|
|
5
|
+
import { getAuth as v, signInWithCustomToken as A } from "firebase/auth";
|
|
6
|
+
import { useSearch as F } from "wouter";
|
|
7
|
+
import { useAuth as P } from "../hooks/auth.js";
|
|
8
|
+
import "firebase/firestore";
|
|
9
|
+
import "lodash-es";
|
|
10
|
+
import "react-error-boundary";
|
|
11
|
+
import "swr";
|
|
12
|
+
import { useDb as k } from "./base-login.js";
|
|
13
|
+
import { login as C } from "./api.js";
|
|
14
|
+
function q({ allowedRole: r, children: i }) {
|
|
15
|
+
const a = k(), o = new URLSearchParams(F()), m = h();
|
|
16
|
+
p(() => {
|
|
17
|
+
const t = new URL(window.location.href);
|
|
18
|
+
t.searchParams.delete("username"), t.searchParams.delete("password"), window.history.replaceState(void 0, "", t.href);
|
|
19
|
+
}, []);
|
|
20
|
+
const c = {
|
|
21
|
+
username: o.get("username") ?? "",
|
|
22
|
+
password: o.get("password") ?? ""
|
|
23
|
+
}, d = async (t) => {
|
|
24
|
+
const { token: l } = await C(a, r, t), u = v(a.app);
|
|
25
|
+
await A(u, l);
|
|
26
|
+
}, s = P(r);
|
|
27
|
+
return s ? i(s) : /* @__PURE__ */ n(f, { children: [
|
|
28
|
+
/* @__PURE__ */ e(b, { color: "bg-base-300 text-base-content", children: /* @__PURE__ */ e(w, { children: /* @__PURE__ */ e("div", { className: "flex items-center h-full font-bold", children: m.title }) }) }),
|
|
29
|
+
/* @__PURE__ */ n(g, { defaultValue: c, onSubmit: d, className: "p-4 pb-8", children: [
|
|
30
|
+
/* @__PURE__ */ e("h1", { className: "mb-2 text-xl font-bold", children: "Accedi alla gestione gara" }),
|
|
31
|
+
/* @__PURE__ */ e(x, { field: "username" }),
|
|
32
|
+
/* @__PURE__ */ e(N, { field: "password" }),
|
|
33
|
+
/* @__PURE__ */ e(S, { children: "Accedi" })
|
|
34
|
+
] })
|
|
35
|
+
] });
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
q as default
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=token-login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-login.js","sources":["../../../../src/web/common/token-login.tsx"],"sourcesContent":["import { type ReactNode, useEffect } from \"react\";\n\nimport { useMetadata } from \"@olinfo/quizms/components\";\nimport {\n CurrentPasswordField,\n Form,\n Navbar,\n NavbarBrand,\n SubmitButton,\n UsernameField,\n} from \"@olinfo/react-components\";\nimport { getAuth, signInWithCustomToken, type User } from \"firebase/auth\";\nimport { useSearch } from \"wouter\";\n\nimport { useAuth } from \"~/web/hooks\";\n\nimport { login } from \"./api\";\nimport { useDb } from \"./base-login\";\n\ntype Props = {\n allowedRole: \"teacher\" | \"admin\";\n children: (auth: { user: User; claims: Record<string, string> }) => ReactNode;\n};\n\nexport default function TokenLogin({ allowedRole, children }: Props) {\n const db = useDb();\n const params = new URLSearchParams(useSearch());\n const metadata = useMetadata();\n\n useEffect(() => {\n const url = new URL(window.location.href);\n url.searchParams.delete(\"username\");\n url.searchParams.delete(\"password\");\n window.history.replaceState(undefined, \"\", url.href);\n }, []);\n\n const defaultCredential = {\n username: params.get(\"username\") ?? \"\",\n password: params.get(\"password\") ?? \"\",\n };\n\n const signIn = async (credential: { username: string; password: string }) => {\n const { token } = await login(db, allowedRole, credential);\n\n const auth = getAuth(db.app);\n await signInWithCustomToken(auth, token);\n };\n\n const auth = useAuth(allowedRole);\n if (auth) {\n return children(auth);\n }\n\n return (\n <>\n <Navbar color=\"bg-base-300 text-base-content\">\n <NavbarBrand>\n <div className=\"flex items-center h-full font-bold\">{metadata.title}</div>\n </NavbarBrand>\n </Navbar>\n <Form defaultValue={defaultCredential} onSubmit={signIn} className=\"p-4 pb-8\">\n <h1 className=\"mb-2 text-xl font-bold\">Accedi alla gestione gara</h1>\n <UsernameField field=\"username\" />\n <CurrentPasswordField field=\"password\" />\n <SubmitButton>Accedi</SubmitButton>\n </Form>\n </>\n );\n}\n"],"names":["TokenLogin","allowedRole","children","db","useDb","params","useSearch","metadata","useMetadata","useEffect","url","defaultCredential","signIn","credential","token","login","auth","getAuth","signInWithCustomToken","useAuth","jsxs","Fragment","jsx","Navbar","NavbarBrand","Form","UsernameField","CurrentPasswordField","SubmitButton"],"mappings":";;;;;;;;;;;;;AAwBA,SAAwBA,EAAW,EAAE,aAAAC,GAAa,UAAAC,KAAmB;AACnE,QAAMC,IAAKC,EAAA,GACLC,IAAS,IAAI,gBAAgBC,GAAW,GACxCC,IAAWC,EAAA;AAEjB,EAAAC,EAAU,MAAM;AACd,UAAMC,IAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AACxC,IAAAA,EAAI,aAAa,OAAO,UAAU,GAClCA,EAAI,aAAa,OAAO,UAAU,GAClC,OAAO,QAAQ,aAAa,QAAW,IAAIA,EAAI,IAAI;AAAA,EACrD,GAAG,CAAA,CAAE;AAEL,QAAMC,IAAoB;AAAA,IACxB,UAAUN,EAAO,IAAI,UAAU,KAAK;AAAA,IACpC,UAAUA,EAAO,IAAI,UAAU,KAAK;AAAA,EAAA,GAGhCO,IAAS,OAAOC,MAAuD;AAC3E,UAAM,EAAE,OAAAC,EAAA,IAAU,MAAMC,EAAMZ,GAAIF,GAAaY,CAAU,GAEnDG,IAAOC,EAAQd,EAAG,GAAG;AAC3B,UAAMe,EAAsBF,GAAMF,CAAK;AAAA,EACzC,GAEME,IAAOG,EAAQlB,CAAW;AAChC,SAAIe,IACKd,EAASc,CAAI,IAIpB,gBAAAI,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAC,EAACC,GAAA,EAAO,OAAM,iCACZ,UAAA,gBAAAD,EAACE,GAAA,EACC,UAAA,gBAAAF,EAAC,OAAA,EAAI,WAAU,sCAAsC,UAAAf,EAAS,MAAA,CAAM,EAAA,CACtE,GACF;AAAA,sBACCkB,GAAA,EAAK,cAAcd,GAAmB,UAAUC,GAAQ,WAAU,YACjE,UAAA;AAAA,MAAA,gBAAAU,EAAC,MAAA,EAAG,WAAU,0BAAyB,UAAA,6BAAyB;AAAA,MAChE,gBAAAA,EAACI,GAAA,EAAc,OAAM,WAAA,CAAW;AAAA,MAChC,gBAAAJ,EAACK,GAAA,EAAqB,OAAM,WAAA,CAAW;AAAA,MACvC,gBAAAL,EAACM,KAAa,UAAA,SAAA,CAAM;AAAA,IAAA,EAAA,CACtB;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback as s } from "react";
|
|
3
|
+
import { signOut as a, getAuth as p } from "firebase/auth";
|
|
4
|
+
import { AdminProvider as c } from "../admin/provider.js";
|
|
5
|
+
import { useDb as u } from "../common/base-login.js";
|
|
6
|
+
import { contestConverter as l } from "../common/converters.js";
|
|
7
|
+
import d from "../common/token-login.js";
|
|
8
|
+
import "lodash-es";
|
|
9
|
+
import "react-error-boundary";
|
|
10
|
+
import "swr";
|
|
11
|
+
import { useCollection as f } from "../hooks/collection.js";
|
|
12
|
+
import "firebase/firestore";
|
|
13
|
+
function I() {
|
|
14
|
+
return /* @__PURE__ */ t(d, { allowedRole: "admin", children: (o) => /* @__PURE__ */ t(b, { user: o.user }) });
|
|
15
|
+
}
|
|
16
|
+
function b({ user: o }) {
|
|
17
|
+
const r = u(), n = o.displayName ?? "Utente anonimo", [e, i] = f("contests", l, {
|
|
18
|
+
subscribe: !0
|
|
19
|
+
}), m = s(async () => {
|
|
20
|
+
await a(p(r.app)), window.location.reload();
|
|
21
|
+
}, [r]);
|
|
22
|
+
return /* @__PURE__ */ t(c, { name: n, contests: e, setContest: i, logout: m });
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
I as default
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.js","sources":["../../../../src/web/entry/admin.tsx"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport { getAuth, signOut, type User } from \"firebase/auth\";\n\nimport { AdminProvider } from \"~/web/admin/provider\";\nimport { useDb } from \"~/web/common/base-login\";\nimport { contestConverter } from \"~/web/common/converters\";\nimport TokenLogin from \"~/web/common/token-login\";\nimport { useCollection } from \"~/web/hooks\";\n\nexport default function AdminEntry() {\n return <TokenLogin allowedRole=\"admin\">{(auth) => <AdminInner user={auth.user} />}</TokenLogin>;\n}\n\nfunction AdminInner({ user }: { user: User }) {\n const db = useDb();\n const name = user.displayName ?? \"Utente anonimo\";\n\n const [contests, setContest] = useCollection(\"contests\", contestConverter, {\n subscribe: true,\n });\n\n const logout = useCallback(async () => {\n await signOut(getAuth(db.app));\n window.location.reload();\n }, [db]);\n\n return <AdminProvider name={name} contests={contests} setContest={setContest} logout={logout} />;\n}\n"],"names":["AdminEntry","jsx","TokenLogin","auth","AdminInner","user","db","useDb","name","contests","setContest","useCollection","contestConverter","logout","useCallback","signOut","getAuth","AdminProvider"],"mappings":";;;;;;;;;;;;AAUA,SAAwBA,IAAa;AACnC,SAAO,gBAAAC,EAACC,GAAA,EAAW,aAAY,SAAS,UAAA,CAACC,MAAS,gBAAAF,EAACG,GAAA,EAAW,MAAMD,EAAK,KAAA,CAAM,EAAA,CAAG;AACpF;AAEA,SAASC,EAAW,EAAE,MAAAC,KAAwB;AAC5C,QAAMC,IAAKC,EAAA,GACLC,IAAOH,EAAK,eAAe,kBAE3B,CAACI,GAAUC,CAAU,IAAIC,EAAc,YAAYC,GAAkB;AAAA,IACzE,WAAW;AAAA,EAAA,CACZ,GAEKC,IAASC,EAAY,YAAY;AACrC,UAAMC,EAAQC,EAAQV,EAAG,GAAG,CAAC,GAC7B,OAAO,SAAS,OAAA;AAAA,EAClB,GAAG,CAACA,CAAE,CAAC;AAEP,SAAO,gBAAAL,EAACgB,GAAA,EAAc,MAAAT,GAAY,UAAAC,GAAoB,YAAAC,GAAwB,QAAAG,GAAgB;AAChG;"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as s } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback as a } from "react";
|
|
3
|
+
import { useStudent as i, RemoteStatement as u } from "@olinfo/quizms/student";
|
|
4
|
+
import { getStorage as c, ref as f, getDownloadURL as l } from "firebase/storage";
|
|
5
|
+
import { useDb as p } from "../common/base-login.js";
|
|
6
|
+
function x() {
|
|
7
|
+
const r = p(), { student: t } = i(), e = c(r.app), o = a(
|
|
8
|
+
(n) => {
|
|
9
|
+
const m = f(
|
|
10
|
+
e,
|
|
11
|
+
`statements/${t.contestId}/${t.variant}/${n}`
|
|
12
|
+
);
|
|
13
|
+
return l(m);
|
|
14
|
+
},
|
|
15
|
+
[e, t]
|
|
16
|
+
);
|
|
17
|
+
return /* @__PURE__ */ s(
|
|
18
|
+
u,
|
|
19
|
+
{
|
|
20
|
+
statementUrl: () => o("statement.txt"),
|
|
21
|
+
moduleUrl: o
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
x as FirebaseStatement
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=student-statement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"student-statement.js","sources":["../../../../src/web/entry/student-statement.tsx"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport { RemoteStatement, useStudent } from \"@olinfo/quizms/student\";\nimport { getDownloadURL, getStorage, ref } from \"firebase/storage\";\n\nimport { useDb } from \"~/web/common/base-login\";\n\nexport function FirebaseStatement() {\n const db = useDb();\n const { student } = useStudent();\n\n const storage = getStorage(db.app);\n\n const getFileUrl = useCallback(\n (fileName: string) => {\n const statementRef = ref(\n storage,\n `statements/${student.contestId}/${student.variant}/${fileName}`,\n );\n return getDownloadURL(statementRef);\n },\n [storage, student],\n );\n\n return (\n <RemoteStatement\n statementUrl={() => getFileUrl(\"statement.txt\")}\n // TODO\n // stylesheetUrl={() => getFileUrl(\"statement.css\")}\n moduleUrl={getFileUrl}\n />\n );\n}\n"],"names":["FirebaseStatement","db","useDb","student","useStudent","storage","getStorage","getFileUrl","useCallback","fileName","statementRef","ref","getDownloadURL","jsx","RemoteStatement"],"mappings":";;;;;AAOO,SAASA,IAAoB;AAClC,QAAMC,IAAKC,EAAA,GACL,EAAE,SAAAC,EAAA,IAAYC,EAAA,GAEdC,IAAUC,EAAWL,EAAG,GAAG,GAE3BM,IAAaC;AAAA,IACjB,CAACC,MAAqB;AACpB,YAAMC,IAAeC;AAAA,QACnBN;AAAA,QACA,cAAcF,EAAQ,SAAS,IAAIA,EAAQ,OAAO,IAAIM,CAAQ;AAAA,MAAA;AAEhE,aAAOG,EAAeF,CAAY;AAAA,IACpC;AAAA,IACA,CAACL,GAASF,CAAO;AAAA,EAAA;AAGnB,SACE,gBAAAU;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,cAAc,MAAMP,EAAW,eAAe;AAAA,MAG9C,WAAWA;AAAA,IAAA;AAAA,EAAA;AAGjB;"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { jsx as t, jsxs as l, Fragment as b } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo as g, useEffect as w, useCallback as x } from "react";
|
|
3
|
+
import { Loading as C, useMetadata as I, StudentFormField as y } from "@olinfo/quizms/components";
|
|
4
|
+
import { StudentProvider as F } from "@olinfo/quizms/student";
|
|
5
|
+
import { Navbar as k, NavbarBrand as N, Form as j, SelectField as D, TextField as O, SubmitButton as A } from "@olinfo/react-components";
|
|
6
|
+
import { signOut as S, getAuth as p, signInWithCustomToken as E } from "firebase/auth";
|
|
7
|
+
import { waitForPendingWrites as h } from "firebase/firestore";
|
|
8
|
+
import { isEqual as R } from "lodash-es";
|
|
9
|
+
import { studentLogin as P } from "../common/api.js";
|
|
10
|
+
import { useDb as f } from "../common/base-login.js";
|
|
11
|
+
import { contestConverter as z, studentRestoreConvert as B, studentConverter as L, participationConverter as M } from "../common/converters.js";
|
|
12
|
+
import { useAuth as T } from "../hooks/auth.js";
|
|
13
|
+
import { useCollection as W } from "../hooks/collection.js";
|
|
14
|
+
import { useDocumentOptional as q, useDocument as v } from "../hooks/document.js";
|
|
15
|
+
import { FirebaseStatement as G } from "./student-statement.js";
|
|
16
|
+
function ct() {
|
|
17
|
+
const n = T("student"), [o] = W("contests", z, {
|
|
18
|
+
subscribe: !0
|
|
19
|
+
}), r = g(
|
|
20
|
+
() => o.filter(
|
|
21
|
+
(e) => window.location.hostname === "localhost" || !e.allowedOrigins || e.allowedOrigins.includes(window.location.host)
|
|
22
|
+
),
|
|
23
|
+
[o]
|
|
24
|
+
);
|
|
25
|
+
return n ? /* @__PURE__ */ t($, { uid: n.user.uid, children: /* @__PURE__ */ t(
|
|
26
|
+
H,
|
|
27
|
+
{
|
|
28
|
+
contests: r,
|
|
29
|
+
participationId: n.claims.participationId,
|
|
30
|
+
studentId: n.claims.studentId
|
|
31
|
+
}
|
|
32
|
+
) }) : /* @__PURE__ */ t(V, { contests: r });
|
|
33
|
+
}
|
|
34
|
+
function V({ contests: n }) {
|
|
35
|
+
const o = f(), r = I(), e = x(
|
|
36
|
+
async ({ contestId: s, token: a, ...i }) => {
|
|
37
|
+
const m = await P(o, {
|
|
38
|
+
contestId: s,
|
|
39
|
+
token: a,
|
|
40
|
+
userData: {
|
|
41
|
+
...i,
|
|
42
|
+
birthDate: i.birthDate ? new Date(i.birthDate) : void 0
|
|
43
|
+
}
|
|
44
|
+
}), d = p(o.app);
|
|
45
|
+
await E(d, m.token);
|
|
46
|
+
},
|
|
47
|
+
[o]
|
|
48
|
+
), c = g(
|
|
49
|
+
() => ({
|
|
50
|
+
contestId: Object.keys(n).length === 1 ? Object.keys(n)[0] : void 0
|
|
51
|
+
}),
|
|
52
|
+
[n]
|
|
53
|
+
);
|
|
54
|
+
return /* @__PURE__ */ l(b, { children: [
|
|
55
|
+
/* @__PURE__ */ t(k, { color: "bg-base-300 text-base-content", children: /* @__PURE__ */ t(N, { children: /* @__PURE__ */ t("div", { className: "flex items-center h-full font-bold", children: r.title }) }) }),
|
|
56
|
+
/* @__PURE__ */ l(j, { defaultValue: c, onSubmit: e, className: "p-4 pb-8", children: [
|
|
57
|
+
/* @__PURE__ */ t("h1", { className: "mb-2 text-xl font-bold", children: "Accedi alla gara" }),
|
|
58
|
+
/* @__PURE__ */ t(
|
|
59
|
+
D,
|
|
60
|
+
{
|
|
61
|
+
field: "contestId",
|
|
62
|
+
label: "Gara",
|
|
63
|
+
options: Object.fromEntries(n.map((s) => [s.id, s.name])),
|
|
64
|
+
placeholder: "Seleziona una gara"
|
|
65
|
+
}
|
|
66
|
+
),
|
|
67
|
+
({ contestId: s }) => {
|
|
68
|
+
const a = n.find((i) => i.id === s);
|
|
69
|
+
if (a)
|
|
70
|
+
return /* @__PURE__ */ l(b, { children: [
|
|
71
|
+
a.userData.map((i) => /* @__PURE__ */ t(y, { field: i }, i.name)),
|
|
72
|
+
/* @__PURE__ */ t(O, { field: "token", label: "Codice prova", placeholder: "aaaaa-bbbbb-ccccc" }),
|
|
73
|
+
/* @__PURE__ */ t(A, { children: "Inizia la prova" })
|
|
74
|
+
] });
|
|
75
|
+
}
|
|
76
|
+
] })
|
|
77
|
+
] });
|
|
78
|
+
}
|
|
79
|
+
function $({ uid: n, children: o }) {
|
|
80
|
+
const r = f(), [e] = q("studentRestore", n, B, {
|
|
81
|
+
subscribe: !0
|
|
82
|
+
});
|
|
83
|
+
return w(() => {
|
|
84
|
+
e?.status === "revoked" && S(p(r.app)).then(() => window.location.reload());
|
|
85
|
+
}, [r, e]), !e || e.status === "approved" ? o : e.status === "revoked" ? /* @__PURE__ */ t(C, {}) : /* @__PURE__ */ l("div", { className: "flex flex-col justify-center items-center grow text-center m-4", children: [
|
|
86
|
+
/* @__PURE__ */ t("p", { children: "Il tuo account è già presente su un'altro dispositivo. Per trasferire l'accesso al dispositivo corrente comunica al tuo insegnante il codice seguente:" }),
|
|
87
|
+
/* @__PURE__ */ t("div", { className: "flex justify-center pt-3", children: /* @__PURE__ */ t("span", { className: "pt-1 font-mono text-3xl", children: String(e?.approvalCode).padStart(3, "0") }) })
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
function H({
|
|
91
|
+
contests: n,
|
|
92
|
+
participationId: o,
|
|
93
|
+
studentId: r
|
|
94
|
+
}) {
|
|
95
|
+
const e = f(), [c, s] = v(
|
|
96
|
+
`participations/${o}/students`,
|
|
97
|
+
r,
|
|
98
|
+
L,
|
|
99
|
+
{ subscribe: !0 }
|
|
100
|
+
), [a] = v("participations", o, M, {
|
|
101
|
+
subscribe: !0
|
|
102
|
+
}), i = n.find((u) => u.id === c.contestId), m = async () => {
|
|
103
|
+
await h(e);
|
|
104
|
+
}, d = async () => {
|
|
105
|
+
await h(e), await S(p(e.app)), window.location.reload();
|
|
106
|
+
};
|
|
107
|
+
return /* @__PURE__ */ t(
|
|
108
|
+
F,
|
|
109
|
+
{
|
|
110
|
+
contest: i,
|
|
111
|
+
participation: a,
|
|
112
|
+
student: c,
|
|
113
|
+
setStudent: async (u) => {
|
|
114
|
+
R(c, u) || await s({ ...u });
|
|
115
|
+
},
|
|
116
|
+
logout: d,
|
|
117
|
+
reset: d,
|
|
118
|
+
onSubmit: m,
|
|
119
|
+
children: /* @__PURE__ */ t(G, {})
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
export {
|
|
124
|
+
ct as default
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=student.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"student.js","sources":["../../../../src/web/entry/student.tsx"],"sourcesContent":["import { type ReactNode, useCallback, useEffect, useMemo } from \"react\";\n\nimport { Loading, StudentFormField, useMetadata } from \"@olinfo/quizms/components\";\nimport type { Contest, Student } from \"@olinfo/quizms/models\";\nimport { StudentProvider } from \"@olinfo/quizms/student\";\nimport {\n Form,\n Navbar,\n NavbarBrand,\n SelectField,\n SubmitButton,\n TextField,\n} from \"@olinfo/react-components\";\nimport { getAuth, signInWithCustomToken, signOut } from \"firebase/auth\";\nimport { waitForPendingWrites } from \"firebase/firestore\";\nimport { isEqual } from \"lodash-es\";\n\nimport { studentLogin } from \"~/web/common/api\";\nimport { useDb } from \"~/web/common/base-login\";\nimport {\n contestConverter,\n participationConverter,\n studentConverter,\n studentRestoreConvert,\n} from \"~/web/common/converters\";\nimport { useAuth, useCollection, useDocument, useDocumentOptional } from \"~/web/hooks\";\n\nimport { FirebaseStatement } from \"./student-statement\";\n\nexport default function StudentEntry() {\n const auth = useAuth(\"student\");\n\n const [contests] = useCollection(\"contests\", contestConverter, {\n subscribe: true,\n });\n\n const filteredContests = useMemo(\n () =>\n contests.filter(\n (contest) =>\n window.location.hostname === \"localhost\" ||\n !contest.allowedOrigins ||\n contest.allowedOrigins.includes(window.location.host),\n ),\n [contests],\n );\n\n if (auth) {\n return (\n <StudentRestoring uid={auth.user.uid}>\n <StudentInner\n contests={filteredContests}\n participationId={auth.claims.participationId}\n studentId={auth.claims.studentId}\n />\n </StudentRestoring>\n );\n }\n\n return <StudentForm contests={filteredContests} />;\n}\n\ntype FormStudent = {\n contestId: string;\n token: string;\n} & Student[\"userData\"];\n\nfunction StudentForm({ contests }: { contests: Contest[] }) {\n const db = useDb();\n const metadata = useMetadata();\n\n const submit = useCallback(\n async ({ contestId, token, ...userData }: FormStudent) => {\n const data = await studentLogin(db, {\n contestId,\n token,\n userData: {\n ...userData,\n birthDate: userData.birthDate ? new Date(userData.birthDate) : undefined,\n },\n });\n\n const auth = getAuth(db.app);\n await signInWithCustomToken(auth, data.token);\n },\n [db],\n );\n\n const defaultValue = useMemo(\n () => ({\n contestId: Object.keys(contests).length === 1 ? Object.keys(contests)[0] : undefined,\n }),\n [contests],\n );\n\n return (\n <>\n <Navbar color=\"bg-base-300 text-base-content\">\n <NavbarBrand>\n <div className=\"flex items-center h-full font-bold\">{metadata.title}</div>\n </NavbarBrand>\n </Navbar>\n <Form defaultValue={defaultValue} onSubmit={submit} className=\"p-4 pb-8\">\n <h1 className=\"mb-2 text-xl font-bold\">Accedi alla gara</h1>\n <SelectField\n field=\"contestId\"\n label=\"Gara\"\n options={Object.fromEntries(contests.map((c) => [c.id, c.name]))}\n placeholder=\"Seleziona una gara\"\n />\n {({ contestId }) => {\n const contest = contests.find((c) => c.id === contestId);\n if (!contest) return;\n return (\n <>\n {contest.userData.map((field) => (\n <StudentFormField key={field.name} field={field} />\n ))}\n <TextField field=\"token\" label=\"Codice prova\" placeholder=\"aaaaa-bbbbb-ccccc\" />\n <SubmitButton>Inizia la prova</SubmitButton>\n </>\n );\n }}\n </Form>\n </>\n );\n}\n\nfunction StudentRestoring({ uid, children }: { uid: string; children: ReactNode }) {\n const db = useDb();\n\n const [studentRestore] = useDocumentOptional(\"studentRestore\", uid, studentRestoreConvert, {\n subscribe: true,\n });\n\n useEffect(() => {\n if (studentRestore?.status === \"revoked\") {\n void signOut(getAuth(db.app)).then(() => window.location.reload());\n }\n }, [db, studentRestore]);\n\n if (!studentRestore || studentRestore.status === \"approved\") {\n return children;\n }\n\n if (studentRestore.status === \"revoked\") {\n return <Loading />;\n }\n\n return (\n <div className=\"flex flex-col justify-center items-center grow text-center m-4\">\n <p>\n Il tuo account è già presente su un'altro dispositivo. Per trasferire l'accesso al\n dispositivo corrente comunica al tuo insegnante il codice seguente:\n </p>\n <div className=\"flex justify-center pt-3\">\n <span className=\"pt-1 font-mono text-3xl\">\n {String(studentRestore?.approvalCode).padStart(3, \"0\")}\n </span>\n </div>\n </div>\n );\n}\n\nfunction StudentInner({\n contests,\n participationId,\n studentId,\n}: {\n contests: Contest[];\n participationId: string;\n studentId: string;\n}) {\n const db = useDb();\n\n const [student, setStudent] = useDocument(\n `participations/${participationId}/students`,\n studentId,\n studentConverter,\n { subscribe: true },\n );\n const [participation] = useDocument(\"participations\", participationId, participationConverter, {\n subscribe: true,\n });\n\n const contest = contests.find((c) => c.id === student.contestId)!;\n\n const onSubmit = async () => {\n await waitForPendingWrites(db);\n };\n\n const logout = async () => {\n await waitForPendingWrites(db);\n await signOut(getAuth(db.app));\n window.location.reload();\n };\n\n const setStudentAndSubmission = async (newStudent: Student) => {\n if (!isEqual(student, newStudent)) {\n await setStudent({ ...newStudent });\n }\n };\n\n return (\n <StudentProvider\n contest={contest}\n participation={participation}\n student={student}\n setStudent={setStudentAndSubmission}\n logout={logout}\n reset={logout}\n onSubmit={onSubmit}>\n <FirebaseStatement />\n </StudentProvider>\n );\n}\n"],"names":["StudentEntry","auth","useAuth","contests","useCollection","contestConverter","filteredContests","useMemo","contest","jsx","StudentRestoring","StudentInner","StudentForm","db","useDb","metadata","useMetadata","submit","useCallback","contestId","token","userData","data","studentLogin","getAuth","signInWithCustomToken","defaultValue","jsxs","Fragment","Navbar","NavbarBrand","Form","SelectField","c","field","StudentFormField","TextField","SubmitButton","uid","children","studentRestore","useDocumentOptional","studentRestoreConvert","useEffect","signOut","Loading","participationId","studentId","student","setStudent","useDocument","studentConverter","participation","participationConverter","onSubmit","waitForPendingWrites","logout","StudentProvider","newStudent","isEqual","FirebaseStatement"],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { jsx as p } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback as b } from "react";
|
|
3
|
+
import { TeacherProvider as v } from "@olinfo/quizms/teacher";
|
|
4
|
+
import { signOut as g, getAuth as h } from "firebase/auth";
|
|
5
|
+
import { writeBatch as d, doc as u, serverTimestamp as w } from "firebase/firestore";
|
|
6
|
+
import { getStorage as P, getBytes as y, ref as C } from "firebase/storage";
|
|
7
|
+
import { finalizeParticipation as R, stopParticipation as S, startParticipation as k } from "../common/api.js";
|
|
8
|
+
import { useDb as f } from "../common/base-login.js";
|
|
9
|
+
import { studentRestoreConvert as A, studentConverter as I, variantConverter as T, contestConverter as B, participationConverter as l } from "../common/converters.js";
|
|
10
|
+
import $ from "../common/token-login.js";
|
|
11
|
+
import "lodash-es";
|
|
12
|
+
import "react-error-boundary";
|
|
13
|
+
import "swr";
|
|
14
|
+
import { useCollection as c } from "../hooks/collection.js";
|
|
15
|
+
import { useDocument as j } from "../hooks/document.js";
|
|
16
|
+
import { FirebaseStatement as x } from "./student-statement.js";
|
|
17
|
+
function tt() {
|
|
18
|
+
return /* @__PURE__ */ p($, { allowedRole: "teacher", children: ({ claims: o }) => /* @__PURE__ */ p(z, { schoolId: o.schoolId }) });
|
|
19
|
+
}
|
|
20
|
+
function z({ schoolId: o }) {
|
|
21
|
+
const t = f(), [i] = c("participations", l, {
|
|
22
|
+
constraints: { schoolId: o },
|
|
23
|
+
subscribe: !0
|
|
24
|
+
}), [n] = c("contests", B, {
|
|
25
|
+
subscribe: !0
|
|
26
|
+
}), [s] = c("variants", T), a = b(async () => {
|
|
27
|
+
await g(h(t.app)), window.location.reload();
|
|
28
|
+
}, [t]);
|
|
29
|
+
return /* @__PURE__ */ p(
|
|
30
|
+
v,
|
|
31
|
+
{
|
|
32
|
+
participations: i,
|
|
33
|
+
contests: n,
|
|
34
|
+
startParticipation: (...e) => k(t, ...e),
|
|
35
|
+
stopParticipation: (...e) => S(t, ...e),
|
|
36
|
+
finalizeParticipation: (...e) => R(t, ...e),
|
|
37
|
+
variants: s,
|
|
38
|
+
logout: a,
|
|
39
|
+
statementComponent: () => /* @__PURE__ */ p(x, {}),
|
|
40
|
+
getPdfStatements: (e, r) => D(t, e, r),
|
|
41
|
+
useAnnouncements: E,
|
|
42
|
+
useStudents: O,
|
|
43
|
+
useStudentRestores: F
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
async function D(o, t, i) {
|
|
48
|
+
const n = P(o.app), s = await Promise.all(
|
|
49
|
+
i.map(
|
|
50
|
+
async (a) => [a, await y(C(n, `statements/${t}/${a}/statement.pdf`))]
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
return Object.fromEntries(s);
|
|
54
|
+
}
|
|
55
|
+
function E(o) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
function O(o) {
|
|
59
|
+
return c(`participations/${o}/students`, I, {
|
|
60
|
+
orderBy: "createdAt",
|
|
61
|
+
subscribe: !0
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function F(o) {
|
|
65
|
+
const t = f(), [i] = j("participations", o, l, {
|
|
66
|
+
subscribe: !0
|
|
67
|
+
}), [n] = c("studentRestore", A, {
|
|
68
|
+
constraints: { participationId: o, token: i.token, status: "pending" },
|
|
69
|
+
orderBy: "createdAt",
|
|
70
|
+
subscribe: !0
|
|
71
|
+
}), s = async (e) => {
|
|
72
|
+
const r = d(t);
|
|
73
|
+
for (const m of n)
|
|
74
|
+
m.studentId === e && r.update(u(t, "studentRestore", m.id), { status: "revoked" });
|
|
75
|
+
await r.commit();
|
|
76
|
+
};
|
|
77
|
+
return [n, async (e) => {
|
|
78
|
+
const r = d(t);
|
|
79
|
+
r.update(u(t, `/participations/${o}/students`, e.studentId), {
|
|
80
|
+
uid: e.id,
|
|
81
|
+
updatedAt: w()
|
|
82
|
+
}), r.delete(u(t, "studentRestore", e.id)), await r.commit(), await s(e.studentId);
|
|
83
|
+
}, s];
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
tt as default
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=teacher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teacher.js","sources":["../../../../src/web/entry/teacher.tsx"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport type { StudentRestore } from \"@olinfo/quizms/models\";\nimport { TeacherProvider } from \"@olinfo/quizms/teacher\";\nimport { getAuth, signOut } from \"firebase/auth\";\nimport { doc, type Firestore, serverTimestamp, writeBatch } from \"firebase/firestore\";\nimport { getBytes, getStorage, ref } from \"firebase/storage\";\n\nimport { finalizeParticipation, startParticipation, stopParticipation } from \"~/web/common/api\";\nimport { useDb } from \"~/web/common/base-login\";\nimport {\n contestConverter,\n participationConverter,\n studentConverter,\n studentRestoreConvert,\n variantConverter,\n} from \"~/web/common/converters\";\nimport TokenLogin from \"~/web/common/token-login\";\nimport { useCollection, useDocument } from \"~/web/hooks\";\n\nimport { FirebaseStatement } from \"./student-statement\";\n\nexport default function TeacherEntry() {\n return (\n <TokenLogin allowedRole=\"teacher\">\n {({ claims }) => <TeacherInner schoolId={claims.schoolId} />}\n </TokenLogin>\n );\n}\n\nfunction TeacherInner({ schoolId }: { schoolId: string }) {\n const db = useDb();\n\n const [participations] = useCollection(\"participations\", participationConverter, {\n constraints: { schoolId: schoolId },\n subscribe: true,\n });\n const [contests] = useCollection(\"contests\", contestConverter, {\n subscribe: true,\n });\n const [variants] = useCollection(\"variants\", variantConverter);\n\n const logout = useCallback(async () => {\n await signOut(getAuth(db.app));\n window.location.reload();\n }, [db]);\n\n return (\n <TeacherProvider\n participations={participations}\n contests={contests}\n startParticipation={(...args) => startParticipation(db, ...args)}\n stopParticipation={(...args) => stopParticipation(db, ...args)}\n finalizeParticipation={(...args) => finalizeParticipation(db, ...args)}\n variants={variants}\n logout={logout}\n statementComponent={() => <FirebaseStatement />}\n getPdfStatements={(contestId, variantIds) => getPdfStatements(db, contestId, variantIds)}\n useAnnouncements={useAnnouncements}\n useStudents={useStudents}\n useStudentRestores={useStudentRestores}\n />\n );\n}\n\nasync function getPdfStatements(\n db: Firestore,\n contestId: string,\n variantIds: string[],\n): Promise<Record<string, ArrayBuffer>> {\n const storage = getStorage(db.app);\n\n const files = await Promise.all(\n variantIds.map(\n async (id) =>\n [id, await getBytes(ref(storage, `statements/${contestId}/${id}/statement.pdf`))] as const,\n ),\n );\n return Object.fromEntries(files);\n}\n\nfunction useAnnouncements(_participationId: string) {\n return [];\n}\n\nfunction useStudents(participationId: string) {\n return useCollection(`participations/${participationId}/students`, studentConverter, {\n orderBy: \"createdAt\",\n subscribe: true,\n });\n}\n\nfunction useStudentRestores(\n participationId: string,\n): readonly [\n StudentRestore[],\n (request: StudentRestore) => Promise<void>,\n (studentId: string) => Promise<void>,\n] {\n const db = useDb();\n\n const [participation] = useDocument(\"participations\", participationId, participationConverter, {\n subscribe: true,\n });\n\n const [studentRestores] = useCollection(\"studentRestore\", studentRestoreConvert, {\n constraints: { participationId, token: participation.token, status: \"pending\" },\n orderBy: \"createdAt\",\n subscribe: true,\n });\n\n const reject = async (studentId: string) => {\n const batch = writeBatch(db);\n\n for (const studentRestore of studentRestores) {\n if (studentRestore.studentId === studentId) {\n batch.update(doc(db, \"studentRestore\", studentRestore.id), { status: \"revoked\" });\n }\n }\n\n await batch.commit();\n };\n\n const approve = async (request: StudentRestore) => {\n const batch = writeBatch(db);\n batch.update(doc(db, `/participations/${participationId}/students`, request.studentId), {\n uid: request.id,\n updatedAt: serverTimestamp(),\n });\n batch.delete(doc(db, \"studentRestore\", request.id));\n await batch.commit();\n\n await reject(request.studentId);\n };\n\n return [studentRestores, approve, reject];\n}\n"],"names":["TeacherEntry","jsx","TokenLogin","claims","TeacherInner","schoolId","db","useDb","participations","useCollection","participationConverter","contests","contestConverter","variants","variantConverter","logout","useCallback","signOut","getAuth","TeacherProvider","args","startParticipation","stopParticipation","finalizeParticipation","FirebaseStatement","contestId","variantIds","getPdfStatements","useAnnouncements","useStudents","useStudentRestores","storage","getStorage","files","id","getBytes","ref","_participationId","participationId","studentConverter","participation","useDocument","studentRestores","studentRestoreConvert","reject","studentId","batch","writeBatch","studentRestore","doc","request","serverTimestamp"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getAuth as m, onAuthStateChanged as c } from "firebase/auth";
|
|
2
|
+
import { noop as p } from "lodash-es";
|
|
3
|
+
import { useErrorBoundary as f } from "react-error-boundary";
|
|
4
|
+
import d from "swr";
|
|
5
|
+
import { useDb as l } from "../common/base-login.js";
|
|
6
|
+
import { useSubscription as h } from "./subscription.js";
|
|
7
|
+
function w(t) {
|
|
8
|
+
const { showBoundary: n } = f(), u = l(), s = m(u.app), r = h("firebase/auth", (i) => {
|
|
9
|
+
const a = c(s, {
|
|
10
|
+
next: (e) => i(e),
|
|
11
|
+
error: (e) => n(e),
|
|
12
|
+
complete: p
|
|
13
|
+
});
|
|
14
|
+
return () => a();
|
|
15
|
+
}), { data: o } = d(`firebase/auth/role/${r?.uid}`, () => b(r), {
|
|
16
|
+
suspense: !0
|
|
17
|
+
});
|
|
18
|
+
return !r || !o || t !== o.role ? null : { user: r, claims: o };
|
|
19
|
+
}
|
|
20
|
+
async function b(t) {
|
|
21
|
+
return t ? (await t.getIdTokenResult()).claims : void 0;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
w as useAuth
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sources":["../../../../src/web/hooks/auth.ts"],"sourcesContent":["import { getAuth, onAuthStateChanged, type User } from \"firebase/auth\";\nimport { noop } from \"lodash-es\";\nimport { useErrorBoundary } from \"react-error-boundary\";\nimport useSWR from \"swr\";\n\nimport { useDb } from \"~/web/common/base-login\";\n\nimport { useSubscription } from \"./subscription\";\n\nexport function useAuth(expectedRole: string) {\n const { showBoundary } = useErrorBoundary();\n const db = useDb();\n const auth = getAuth(db.app);\n\n const user = useSubscription<User | null>(\"firebase/auth\", (set) => {\n const unsubscribe = onAuthStateChanged(auth, {\n next: (user) => set(user),\n error: (err) => showBoundary(err),\n complete: noop,\n });\n return () => unsubscribe();\n });\n\n const { data: claims } = useSWR(`firebase/auth/role/${user?.uid}`, () => getClaims(user), {\n suspense: true,\n });\n\n if (!user || !claims || expectedRole !== claims.role) return null;\n return { user, claims };\n}\n\nasync function getClaims(user: User | null) {\n if (!user) return;\n\n const idToken = await user.getIdTokenResult();\n return idToken.claims as Record<string, string>;\n}\n"],"names":["useAuth","expectedRole","showBoundary","useErrorBoundary","db","useDb","auth","getAuth","user","useSubscription","set","unsubscribe","onAuthStateChanged","err","noop","claims","useSWR","getClaims"],"mappings":";;;;;;AASO,SAASA,EAAQC,GAAsB;AAC5C,QAAM,EAAE,cAAAC,EAAA,IAAiBC,EAAA,GACnBC,IAAKC,EAAA,GACLC,IAAOC,EAAQH,EAAG,GAAG,GAErBI,IAAOC,EAA6B,iBAAiB,CAACC,MAAQ;AAClE,UAAMC,IAAcC,EAAmBN,GAAM;AAAA,MAC3C,MAAM,CAACE,MAASE,EAAIF,CAAI;AAAA,MACxB,OAAO,CAACK,MAAQX,EAAaW,CAAG;AAAA,MAChC,UAAUC;AAAA,IAAA,CACX;AACD,WAAO,MAAMH,EAAA;AAAA,EACf,CAAC,GAEK,EAAE,MAAMI,EAAA,IAAWC,EAAO,sBAAsBR,GAAM,GAAG,IAAI,MAAMS,EAAUT,CAAI,GAAG;AAAA,IACxF,UAAU;AAAA,EAAA,CACX;AAED,SAAI,CAACA,KAAQ,CAACO,KAAUd,MAAiBc,EAAO,OAAa,OACtD,EAAE,MAAAP,GAAM,QAAAO,EAAA;AACjB;AAEA,eAAeE,EAAUT,GAAmB;AAC1C,SAAKA,KAEW,MAAMA,EAAK,iBAAA,GACZ,SAHJ;AAIb;"}
|