@olinfo/quizms-firebase 4.0.1 → 4.1.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.
Files changed (68) hide show
  1. package/dist/functions.d.ts +2 -11
  2. package/dist/functions.js +2 -2
  3. package/dist/package.json.js +1 -1
  4. package/dist/src/cli/files/functions-index.js +4 -4
  5. package/dist/src/cli/files/functions-index.js.map +1 -1
  6. package/dist/src/cli/import.js +85 -96
  7. package/dist/src/cli/import.js.map +1 -1
  8. package/dist/src/cli/init.js +8 -8
  9. package/dist/src/cli/init.js.map +1 -1
  10. package/dist/src/cli/update-scores.js +21 -32
  11. package/dist/src/cli/update-scores.js.map +1 -1
  12. package/dist/src/cli/utils/collection.js +20 -18
  13. package/dist/src/cli/utils/collection.js.map +1 -1
  14. package/dist/src/cli/utils/converters-admin.js +31 -32
  15. package/dist/src/cli/utils/converters-admin.js.map +1 -1
  16. package/dist/src/cli/utils/region-finder.js +6 -5
  17. package/dist/src/cli/utils/region-finder.js.map +1 -1
  18. package/dist/src/cli/utils/storage.js +26 -35
  19. package/dist/src/cli/utils/storage.js.map +1 -1
  20. package/dist/src/cli/utils/users.js +13 -12
  21. package/dist/src/cli/utils/users.js.map +1 -1
  22. package/dist/src/functions/api/admin.js +25 -10
  23. package/dist/src/functions/api/admin.js.map +1 -1
  24. package/dist/src/functions/api/index.js +26 -37
  25. package/dist/src/functions/api/index.js.map +1 -1
  26. package/dist/src/functions/api/queries.js +24 -25
  27. package/dist/src/functions/api/queries.js.map +1 -1
  28. package/dist/src/functions/api/student.js +62 -72
  29. package/dist/src/functions/api/student.js.map +1 -1
  30. package/dist/src/functions/api/teacher.js +104 -111
  31. package/dist/src/functions/api/teacher.js.map +1 -1
  32. package/dist/src/functions/api/trpc.js +18 -0
  33. package/dist/src/functions/api/trpc.js.map +1 -0
  34. package/dist/src/functions/submissions.js +1 -1
  35. package/dist/src/functions/submissions.js.map +1 -1
  36. package/dist/src/models/user.js +2 -2
  37. package/dist/src/models/user.js.map +1 -1
  38. package/dist/src/models/website.js +1 -1
  39. package/dist/src/models/website.js.map +1 -1
  40. package/dist/src/vite/preset.js +3 -4
  41. package/dist/src/vite/preset.js.map +1 -1
  42. package/dist/src/web/admin/announcements.js +9 -10
  43. package/dist/src/web/admin/announcements.js.map +1 -1
  44. package/dist/src/web/admin/school-table.js +7 -8
  45. package/dist/src/web/admin/school-table.js.map +1 -1
  46. package/dist/src/web/common/api.js +32 -35
  47. package/dist/src/web/common/api.js.map +1 -1
  48. package/dist/src/web/common/converters.js +35 -36
  49. package/dist/src/web/common/converters.js.map +1 -1
  50. package/dist/src/web/common/token-login.js +11 -11
  51. package/dist/src/web/common/token-login.js.map +1 -1
  52. package/dist/src/web/entry/admin.js +5 -7
  53. package/dist/src/web/entry/admin.js.map +1 -1
  54. package/dist/src/web/entry/student-restoring.js +18 -20
  55. package/dist/src/web/entry/student-restoring.js.map +1 -1
  56. package/dist/src/web/entry/student.js +70 -76
  57. package/dist/src/web/entry/student.js.map +1 -1
  58. package/dist/src/web/entry/teacher.js +68 -68
  59. package/dist/src/web/entry/teacher.js.map +1 -1
  60. package/dist/src/web/hooks/collection.js +29 -30
  61. package/dist/src/web/hooks/collection.js.map +1 -1
  62. package/dist/src/web/hooks/document.js +35 -36
  63. package/dist/src/web/hooks/document.js.map +1 -1
  64. package/dist/src/web/hooks/subscription.js +26 -22
  65. package/dist/src/web/hooks/subscription.js.map +1 -1
  66. package/package.json +29 -25
  67. package/dist/src/functions/api/schema.js +0 -42
  68. package/dist/src/functions/api/schema.js.map +0 -1
@@ -1,37 +1,39 @@
1
- import { confirm as h } from "@inquirer/prompts";
1
+ import { styleText as h } from "node:util";
2
+ import { confirm as g } from "@inquirer/prompts";
2
3
  import { fatal as s, info as $, success as b } from "@olinfo/quizms/utils-node";
3
- import { SingleBar as C } from "cli-progress";
4
- import { upperFirst as x, partition as y } from "lodash-es";
5
- import g from "picocolors";
4
+ import { SingleBar as x } from "cli-progress";
5
+ import { upperFirst as y, partition as C } from "lodash-es";
6
6
  async function E(o, t, m, w, r) {
7
- const c = /* @__PURE__ */ new Set();
7
+ const l = /* @__PURE__ */ new Set();
8
8
  for (const e of m)
9
- c.has(e.id) && s(`Cannot import multiple ${t} with the same id: ${e.id}`), c.add(e.id);
9
+ l.has(e.id) && s(`Cannot import multiple ${t} with the same id: ${e.id}`), l.add(e.id);
10
10
  if (r.delete) {
11
- await h({
12
- message: `You are about to delete all ${g.bold(
11
+ await g({
12
+ message: `You are about to delete all ${h(
13
+ "bold",
13
14
  t
14
15
  )}. Any previous data will be lost, this operation cannot be undone. Are you really sure?`,
15
16
  default: !1
16
17
  }) || s("Command aborted.");
17
18
  const a = o.collection(t);
18
- await o.recursiveDelete(a), $(`${x(t)} deleted!`);
19
+ await o.recursiveDelete(a), $(`${y(t)} deleted!`);
19
20
  }
20
- const l = /* @__PURE__ */ new Set();
21
+ const c = /* @__PURE__ */ new Set();
21
22
  for (const e of await o.collection(t).listDocuments())
22
- l.add(e.id);
23
- const [f, p] = y(m, (e) => l.has(e.id));
23
+ c.add(e.id);
24
+ const [f, u] = C(m, (e) => c.has(e.id));
24
25
  f.length > 0 && !r.skipExisting && !r.force && s(
25
26
  `Documents already exist in \`${t}\`. Use \`--force\` to overwrite or \`--skip-existing\` to ignore.`
26
27
  );
27
- const i = r.skipExisting ? p : [...f, ...p];
28
- r.force && f.length > 0 && (await h({
29
- message: `You are about to import the ${g.bold(
28
+ const i = r.skipExisting ? u : [...f, ...u];
29
+ r.force && f.length > 0 && (await g({
30
+ message: `You are about to import the ${h(
31
+ "bold",
30
32
  t
31
33
  )}. ${f.length} document will be overwritten, the previous data will be lost. Are you really sure?`,
32
34
  default: !1
33
35
  }) || s("Command aborted."));
34
- const d = new C({
36
+ const d = new x({
35
37
  format: " {bar} {percentage}% | {value}/{total}",
36
38
  barCompleteChar: "█",
37
39
  barIncompleteChar: "▂"
@@ -41,8 +43,8 @@ async function E(o, t, m, w, r) {
41
43
  d.update(e);
42
44
  const a = o.batch();
43
45
  for (const n of i.slice(e, e + 400)) {
44
- const u = o.doc(`${t}/${n.id}`).withConverter(w);
45
- r.force ? a.set(u, n) : a.create(u, n);
46
+ const p = o.doc(`${t}/${n.id}`).withConverter(w);
47
+ r.force ? a.set(p, n) : a.create(p, n);
46
48
  }
47
49
  try {
48
50
  await a.commit();
@@ -1 +1 @@
1
- {"version":3,"file":"collection.js","sources":["../../../../src/cli/utils/collection.ts"],"sourcesContent":["import { confirm } from \"@inquirer/prompts\";\nimport { fatal, info, success } from \"@olinfo/quizms/utils-node\";\nimport { SingleBar } from \"cli-progress\";\nimport type { Firestore, FirestoreDataConverter } from \"firebase-admin/firestore\";\nimport { partition, upperFirst } from \"lodash-es\";\nimport pc from \"picocolors\";\n\ntype ImportOptions = {\n delete?: true;\n skipExisting?: true;\n force?: true;\n};\n\nexport async function importCollection<T extends { id: string }>(\n db: Firestore,\n collection: string,\n data: T[],\n converter: FirestoreDataConverter<T>,\n options: ImportOptions,\n) {\n const newIds = new Set<string>();\n for (const doc of data) {\n if (newIds.has(doc.id)) {\n fatal(`Cannot import multiple ${collection} with the same id: ${doc.id}`);\n }\n newIds.add(doc.id);\n }\n\n if (options.delete) {\n const confirmed = await confirm({\n message: `You are about to delete all ${pc.bold(\n collection,\n )}. Any previous data will be lost, this operation cannot be undone. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n\n const ref = db.collection(collection);\n await db.recursiveDelete(ref);\n info(`${upperFirst(collection)} deleted!`);\n }\n\n const existingIds = new Set<string>();\n for (const doc of await db.collection(collection).listDocuments()) {\n existingIds.add(doc.id);\n }\n const [existing, nonExisting] = partition(data, (doc) => existingIds.has(doc.id));\n if (existing.length > 0 && !options.skipExisting && !options.force) {\n fatal(\n `Documents already exist in \\`${collection}\\`. Use \\`--force\\` to overwrite or \\`--skip-existing\\` to ignore.`,\n );\n }\n\n const docsToImport = options.skipExisting ? nonExisting : [...existing, ...nonExisting];\n\n if (options.force && existing.length > 0) {\n const confirmed = await confirm({\n message: `You are about to import the ${pc.bold(\n collection,\n )}. ${existing.length} document will be overwritten, the previous data will be lost. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n }\n\n const bar = new SingleBar({\n format: \" {bar} {percentage}% | {value}/{total}\",\n barCompleteChar: \"\\u2588\",\n barIncompleteChar: \"\\u2582\",\n });\n bar.start(docsToImport.length, 0);\n\n for (let i = 0; i < docsToImport.length; i += 400) {\n bar.update(i);\n const batch = db.batch();\n for (const record of docsToImport.slice(i, i + 400)) {\n const ref = db.doc(`${collection}/${record.id}`).withConverter(converter);\n if (options.force) {\n batch.set(ref, record);\n } else {\n batch.create(ref, record);\n }\n }\n try {\n await batch.commit();\n } catch (err) {\n fatal(`Cannot import ${collection}: ${err}`);\n }\n }\n\n bar.update(docsToImport.length);\n bar.stop();\n success(`${docsToImport.length} ${collection} imported!`);\n}\n"],"names":["importCollection","db","collection","data","converter","options","newIds","doc","fatal","confirm","pc","ref","info","upperFirst","existingIds","existing","nonExisting","partition","docsToImport","bar","SingleBar","i","batch","record","err","success"],"mappings":";;;;;AAaA,eAAsBA,EACpBC,GACAC,GACAC,GACAC,GACAC,GACA;AACA,QAAMC,wBAAa,IAAA;AACnB,aAAWC,KAAOJ;AAChB,IAAIG,EAAO,IAAIC,EAAI,EAAE,KACnBC,EAAM,0BAA0BN,CAAU,sBAAsBK,EAAI,EAAE,EAAE,GAE1ED,EAAO,IAAIC,EAAI,EAAE;AAGnB,MAAIF,EAAQ,QAAQ;AAOlB,IANkB,MAAMI,EAAQ;AAAA,MAC9B,SAAS,+BAA+BC,EAAG;AAAA,QACzCR;AAAA,MAAA,CACD;AAAA,MACD,SAAS;AAAA,IAAA,CACV,KAECM,EAAM,kBAAkB;AAG1B,UAAMG,IAAMV,EAAG,WAAWC,CAAU;AACpC,UAAMD,EAAG,gBAAgBU,CAAG,GAC5BC,EAAK,GAAGC,EAAWX,CAAU,CAAC,WAAW;AAAA,EAC3C;AAEA,QAAMY,wBAAkB,IAAA;AACxB,aAAWP,KAAO,MAAMN,EAAG,WAAWC,CAAU,EAAE;AAChD,IAAAY,EAAY,IAAIP,EAAI,EAAE;AAExB,QAAM,CAACQ,GAAUC,CAAW,IAAIC,EAAUd,GAAM,CAACI,MAAQO,EAAY,IAAIP,EAAI,EAAE,CAAC;AAChF,EAAIQ,EAAS,SAAS,KAAK,CAACV,EAAQ,gBAAgB,CAACA,EAAQ,SAC3DG;AAAA,IACE,gCAAgCN,CAAU;AAAA,EAAA;AAI9C,QAAMgB,IAAeb,EAAQ,eAAeW,IAAc,CAAC,GAAGD,GAAU,GAAGC,CAAW;AAEtF,EAAIX,EAAQ,SAASU,EAAS,SAAS,MACnB,MAAMN,EAAQ;AAAA,IAC9B,SAAS,+BAA+BC,EAAG;AAAA,MACzCR;AAAA,IAAA,CACD,KAAKa,EAAS,MAAM;AAAA,IACrB,SAAS;AAAA,EAAA,CACV,KAECP,EAAM,kBAAkB;AAI5B,QAAMW,IAAM,IAAIC,EAAU;AAAA,IACxB,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,EAAA,CACpB;AACD,EAAAD,EAAI,MAAMD,EAAa,QAAQ,CAAC;AAEhC,WAASG,IAAI,GAAGA,IAAIH,EAAa,QAAQG,KAAK,KAAK;AACjD,IAAAF,EAAI,OAAOE,CAAC;AACZ,UAAMC,IAAQrB,EAAG,MAAA;AACjB,eAAWsB,KAAUL,EAAa,MAAMG,GAAGA,IAAI,GAAG,GAAG;AACnD,YAAMV,IAAMV,EAAG,IAAI,GAAGC,CAAU,IAAIqB,EAAO,EAAE,EAAE,EAAE,cAAcnB,CAAS;AACxE,MAAIC,EAAQ,QACViB,EAAM,IAAIX,GAAKY,CAAM,IAErBD,EAAM,OAAOX,GAAKY,CAAM;AAAA,IAE5B;AACA,QAAI;AACF,YAAMD,EAAM,OAAA;AAAA,IACd,SAASE,GAAK;AACZ,MAAAhB,EAAM,iBAAiBN,CAAU,KAAKsB,CAAG,EAAE;AAAA,IAC7C;AAAA,EACF;AAEA,EAAAL,EAAI,OAAOD,EAAa,MAAM,GAC9BC,EAAI,KAAA,GACJM,EAAQ,GAAGP,EAAa,MAAM,IAAIhB,CAAU,YAAY;AAC1D;"}
1
+ {"version":3,"file":"collection.js","sources":["../../../../src/cli/utils/collection.ts"],"sourcesContent":["import { styleText } from \"node:util\";\n\nimport { confirm } from \"@inquirer/prompts\";\nimport { fatal, info, success } from \"@olinfo/quizms/utils-node\";\nimport { SingleBar } from \"cli-progress\";\nimport type { Firestore, FirestoreDataConverter } from \"firebase-admin/firestore\";\nimport { partition, upperFirst } from \"lodash-es\";\n\ntype ImportOptions = {\n delete?: true;\n skipExisting?: true;\n force?: true;\n};\n\nexport async function importCollection<T extends { id: string }>(\n db: Firestore,\n collection: string,\n data: T[],\n converter: FirestoreDataConverter<T>,\n options: ImportOptions,\n) {\n const newIds = new Set<string>();\n for (const doc of data) {\n if (newIds.has(doc.id)) {\n fatal(`Cannot import multiple ${collection} with the same id: ${doc.id}`);\n }\n newIds.add(doc.id);\n }\n\n if (options.delete) {\n const confirmed = await confirm({\n message: `You are about to delete all ${styleText(\n \"bold\",\n collection,\n )}. Any previous data will be lost, this operation cannot be undone. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n\n const ref = db.collection(collection);\n await db.recursiveDelete(ref);\n info(`${upperFirst(collection)} deleted!`);\n }\n\n const existingIds = new Set<string>();\n for (const doc of await db.collection(collection).listDocuments()) {\n existingIds.add(doc.id);\n }\n const [existing, nonExisting] = partition(data, (doc) => existingIds.has(doc.id));\n if (existing.length > 0 && !options.skipExisting && !options.force) {\n fatal(\n `Documents already exist in \\`${collection}\\`. Use \\`--force\\` to overwrite or \\`--skip-existing\\` to ignore.`,\n );\n }\n\n const docsToImport = options.skipExisting ? nonExisting : [...existing, ...nonExisting];\n\n if (options.force && existing.length > 0) {\n const confirmed = await confirm({\n message: `You are about to import the ${styleText(\n \"bold\",\n collection,\n )}. ${existing.length} document will be overwritten, the previous data will be lost. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n }\n\n const bar = new SingleBar({\n format: \" {bar} {percentage}% | {value}/{total}\",\n barCompleteChar: \"\\u2588\",\n barIncompleteChar: \"\\u2582\",\n });\n bar.start(docsToImport.length, 0);\n\n for (let i = 0; i < docsToImport.length; i += 400) {\n bar.update(i);\n const batch = db.batch();\n for (const record of docsToImport.slice(i, i + 400)) {\n const ref = db.doc(`${collection}/${record.id}`).withConverter(converter);\n if (options.force) {\n batch.set(ref, record);\n } else {\n batch.create(ref, record);\n }\n }\n try {\n await batch.commit();\n } catch (err) {\n fatal(`Cannot import ${collection}: ${err}`);\n }\n }\n\n bar.update(docsToImport.length);\n bar.stop();\n success(`${docsToImport.length} ${collection} imported!`);\n}\n"],"names":["importCollection","db","collection","data","converter","options","newIds","doc","fatal","confirm","styleText","ref","info","upperFirst","existingIds","existing","nonExisting","partition","docsToImport","bar","SingleBar","i","batch","record","err","success"],"mappings":";;;;;AAcA,eAAsBA,EACpBC,GACAC,GACAC,GACAC,GACAC,GACA;AACA,QAAMC,wBAAa,IAAA;AACnB,aAAWC,KAAOJ;AAChB,IAAIG,EAAO,IAAIC,EAAI,EAAE,KACnBC,EAAM,0BAA0BN,CAAU,sBAAsBK,EAAI,EAAE,EAAE,GAE1ED,EAAO,IAAIC,EAAI,EAAE;AAGnB,MAAIF,EAAQ,QAAQ;AAQlB,IAPkB,MAAMI,EAAQ;AAAA,MAC9B,SAAS,+BAA+BC;AAAA,QACtC;AAAA,QACAR;AAAA,MAAA,CACD;AAAA,MACD,SAAS;AAAA,IAAA,CACV,KAECM,EAAM,kBAAkB;AAG1B,UAAMG,IAAMV,EAAG,WAAWC,CAAU;AACpC,UAAMD,EAAG,gBAAgBU,CAAG,GAC5BC,EAAK,GAAGC,EAAWX,CAAU,CAAC,WAAW;AAAA,EAC3C;AAEA,QAAMY,wBAAkB,IAAA;AACxB,aAAWP,KAAO,MAAMN,EAAG,WAAWC,CAAU,EAAE;AAChD,IAAAY,EAAY,IAAIP,EAAI,EAAE;AAExB,QAAM,CAACQ,GAAUC,CAAW,IAAIC,EAAUd,GAAM,CAACI,MAAQO,EAAY,IAAIP,EAAI,EAAE,CAAC;AAChF,EAAIQ,EAAS,SAAS,KAAK,CAACV,EAAQ,gBAAgB,CAACA,EAAQ,SAC3DG;AAAA,IACE,gCAAgCN,CAAU;AAAA,EAAA;AAI9C,QAAMgB,IAAeb,EAAQ,eAAeW,IAAc,CAAC,GAAGD,GAAU,GAAGC,CAAW;AAEtF,EAAIX,EAAQ,SAASU,EAAS,SAAS,MACnB,MAAMN,EAAQ;AAAA,IAC9B,SAAS,+BAA+BC;AAAA,MACtC;AAAA,MACAR;AAAA,IAAA,CACD,KAAKa,EAAS,MAAM;AAAA,IACrB,SAAS;AAAA,EAAA,CACV,KAECP,EAAM,kBAAkB;AAI5B,QAAMW,IAAM,IAAIC,EAAU;AAAA,IACxB,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,EAAA,CACpB;AACD,EAAAD,EAAI,MAAMD,EAAa,QAAQ,CAAC;AAEhC,WAASG,IAAI,GAAGA,IAAIH,EAAa,QAAQG,KAAK,KAAK;AACjD,IAAAF,EAAI,OAAOE,CAAC;AACZ,UAAMC,IAAQrB,EAAG,MAAA;AACjB,eAAWsB,KAAUL,EAAa,MAAMG,GAAGA,IAAI,GAAG,GAAG;AACnD,YAAMV,IAAMV,EAAG,IAAI,GAAGC,CAAU,IAAIqB,EAAO,EAAE,EAAE,EAAE,cAAcnB,CAAS;AACxE,MAAIC,EAAQ,QACViB,EAAM,IAAIX,GAAKY,CAAM,IAErBD,EAAM,OAAOX,GAAKY,CAAM;AAAA,IAE5B;AACA,QAAI;AACF,YAAMD,EAAM,OAAA;AAAA,IACd,SAASE,GAAK;AACZ,MAAAhB,EAAM,iBAAiBN,CAAU,KAAKsB,CAAG,EAAE;AAAA,IAC7C;AAAA,EACF;AAEA,EAAAL,EAAI,OAAOD,EAAa,MAAM,GAC9BC,EAAI,KAAA,GACJM,EAAQ,GAAGP,EAAa,MAAM,IAAIhB,CAAU,YAAY;AAC1D;"}
@@ -1,43 +1,42 @@
1
- import { contestSchema as a, participationSchema as p, studentSchema as u, variantSchema as c } from "@olinfo/quizms/models";
2
- import { validate as d } from "@olinfo/quizms/utils";
3
- import { Timestamp as e } from "firebase-admin/firestore";
4
- import { cloneDeepWith as s, omit as m, isDate as v, isString as D, mapValues as S } from "lodash-es";
5
- import o, { ZodDate as Z, ZodObject as l, ZodRecord as C, ZodArray as b, ZodOptional as F, ZodDefault as w, ZodUnion as U, ZodDiscriminatedUnion as j } from "zod";
6
- import { userSchema as y } from "../../models/user.js";
7
- import { websiteSchema as O } from "../../models/website.js";
8
- function T(t) {
9
- return s(m(t, "id"), (r) => {
10
- if (v(r))
11
- return e.fromDate(r);
12
- if (D(r))
13
- return r.trim();
14
- if (r === void 0)
1
+ import { contestSchema as c, participationSchema as m, studentSchema as s, variantSchema as a } from "@olinfo/quizms/models";
2
+ import { validate as f } from "@olinfo/quizms/utils";
3
+ import { Timestamp as o } from "firebase-admin/firestore";
4
+ import { cloneDeepWith as n, omit as p, isDate as u, isString as d } from "lodash-es";
5
+ import { userSchema as v } from "../../models/user.js";
6
+ import { websiteSchema as S } from "../../models/website.js";
7
+ function h(r) {
8
+ return n(p(r, "id"), (t) => {
9
+ if (u(t))
10
+ return o.fromDate(t);
11
+ if (d(t))
12
+ return t.trim();
13
+ if (t === void 0)
15
14
  return null;
16
15
  });
17
16
  }
18
- function n(t) {
19
- return t instanceof Z ? o.instanceof(e).transform((r) => r.toDate()).pipe(t) : t instanceof l ? o.object(S(t.shape, (r) => n(r))) : t instanceof C ? o.record(n(t.element)) : t instanceof b ? n(t.element).array() : t instanceof F ? o.preprocess((r) => r ?? void 0, n(t.unwrap()).optional()) : t instanceof w ? n(t.removeDefault()).pipe(t) : t instanceof U ? o.union(t.options.map((r) => n(r))) : t instanceof j ? o.discriminatedUnion(
20
- t.discriminator,
21
- t.options.map((r) => n(r))
22
- ) : t;
17
+ function C(r) {
18
+ return n(r, (t) => {
19
+ if (t instanceof o)
20
+ return t.toDate();
21
+ });
23
22
  }
24
- function g(t, r) {
25
- const f = { ...r.data(), id: r.id };
26
- return d(n(t), f);
23
+ function F(r, t) {
24
+ const i = C({ ...t.data(), id: t.id });
25
+ return f(r, i);
27
26
  }
28
- function i(t) {
27
+ function e(r) {
29
28
  return {
30
- toFirestore: (r) => T(r),
31
- fromFirestore: (r) => g(t, r)
29
+ toFirestore: (t) => h(t),
30
+ fromFirestore: (t) => F(r, t)
32
31
  };
33
32
  }
34
- const q = i(a), B = i(p), E = i(u), G = i(y), H = i(c), I = i(O);
33
+ const W = e(c), j = e(m), k = e(s), q = e(v), y = e(a), z = e(S);
35
34
  export {
36
- q as contestConverter,
37
- B as participationConverter,
38
- E as studentConverter,
39
- G as userConverter,
40
- H as variantConverter,
41
- I as websiteConverter
35
+ W as contestConverter,
36
+ j as participationConverter,
37
+ k as studentConverter,
38
+ q as userConverter,
39
+ y as variantConverter,
40
+ z as websiteConverter
42
41
  };
43
42
  //# sourceMappingURL=converters-admin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"converters-admin.js","sources":["../../../../src/cli/utils/converters-admin.ts"],"sourcesContent":["import {\n contestSchema,\n participationSchema,\n studentSchema,\n variantSchema,\n} from \"@olinfo/quizms/models\";\nimport { validate } from \"@olinfo/quizms/utils\";\nimport {\n type DocumentSnapshot,\n type FirestoreDataConverter,\n Timestamp,\n} from \"firebase-admin/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\nimport { userSchema } from \"~/models/user\";\nimport { websiteSchema } from \"~/models/website\";\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(), 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 studentConverter = converter(studentSchema);\nexport const userConverter = converter(userSchema);\nexport const variantConverter = converter(variantSchema);\nexport const websiteConverter = converter(websiteSchema);\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","studentConverter","studentSchema","userConverter","userSchema","variantConverter","variantSchema","websiteConverter","websiteSchema"],"mappings":";;;;;;;AA6BA,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,QAAQ,IAAIA,EAAS,GAAA;AAChD,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,IAAmBL,EAAUM,CAAa,GAC1CC,IAAgBP,EAAUQ,CAAU,GACpCC,IAAmBT,EAAUU,CAAa,GAC1CC,IAAmBX,EAAUY,CAAa;"}
1
+ {"version":3,"file":"converters-admin.js","sources":["../../../../src/cli/utils/converters-admin.ts"],"sourcesContent":["import {\n contestSchema,\n participationSchema,\n studentSchema,\n variantSchema,\n} from \"@olinfo/quizms/models\";\nimport { validate } from \"@olinfo/quizms/utils\";\nimport {\n type DocumentSnapshot,\n type FirestoreDataConverter,\n Timestamp,\n} from \"firebase-admin/firestore\";\nimport { cloneDeepWith, isDate, isString, omit } from \"lodash-es\";\nimport type z from \"zod\";\n\nimport { userSchema } from \"~/models/user\";\nimport { websiteSchema } from \"~/models/website\";\n\nfunction convertToFirestore(data: object) {\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 convertFromFirestore(data: object) {\n return cloneDeepWith(data, (value) => {\n if (value instanceof Timestamp) {\n return value.toDate();\n }\n });\n}\n\nfunction parse<T>(schema: z.core.$ZodType<T>, snapshot: DocumentSnapshot): T {\n const data = convertFromFirestore({ ...snapshot.data(), id: snapshot.id });\n return validate(schema, data);\n}\n\nfunction converter<T extends object>(schema: z.core.$ZodType<T>): 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 studentConverter = converter(studentSchema);\nexport const userConverter = converter(userSchema);\nexport const variantConverter = converter(variantSchema);\nexport const websiteConverter = converter(websiteSchema);\n"],"names":["convertToFirestore","data","cloneDeepWith","omit","value","isDate","Timestamp","isString","convertFromFirestore","parse","schema","snapshot","validate","converter","contestConverter","contestSchema","participationConverter","participationSchema","studentConverter","studentSchema","userConverter","userSchema","variantConverter","variantSchema","websiteConverter","websiteSchema"],"mappings":";;;;;;AAkBA,SAASA,EAAmBC,GAAc;AACxC,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,EAAqBP,GAAc;AAC1C,SAAOC,EAAcD,GAAM,CAACG,MAAU;AACpC,QAAIA,aAAiBE;AACnB,aAAOF,EAAM,OAAA;AAAA,EAEjB,CAAC;AACH;AAEA,SAASK,EAASC,GAA4BC,GAA+B;AAC3E,QAAMV,IAAOO,EAAqB,EAAE,GAAGG,EAAS,QAAQ,IAAIA,EAAS,IAAI;AACzE,SAAOC,EAASF,GAAQT,CAAI;AAC9B;AAEA,SAASY,EAA4BH,GAAuD;AAC1F,SAAO;AAAA,IACL,aAAa,CAACT,MAASD,EAAmBC,CAAI;AAAA,IAC9C,eAAe,CAACU,MAAaF,EAAMC,GAAQC,CAAQ;AAAA,EAAA;AAEvD;AAEO,MAAMG,IAAmBD,EAAUE,CAAa,GAC1CC,IAAyBH,EAAUI,CAAmB,GACtDC,IAAmBL,EAAUM,CAAa,GAC1CC,IAAgBP,EAAUQ,CAAU,GACpCC,IAAmBT,EAAUU,CAAa,GAC1CC,IAAmBX,EAAUY,CAAa;"}
@@ -1,4 +1,4 @@
1
- import { validate as g } from "@olinfo/quizms/utils";
1
+ import { validate as p } from "@olinfo/quizms/utils";
2
2
  import { intersection as m, sortBy as h } from "lodash-es";
3
3
  import t from "zod";
4
4
  const f = [
@@ -25,21 +25,22 @@ async function q() {
25
25
  async function d(n, a) {
26
26
  const e = await fetch(n);
27
27
  if (!e.ok) throw new Error("Request failed");
28
- return g(a, await e.json());
28
+ return p(a, await e.json());
29
29
  }
30
30
  const b = t.record(
31
+ t.string(),
31
32
  t.object({
32
33
  name: t.string(),
33
34
  latitude: t.number(),
34
35
  longitude: t.number()
35
36
  })
36
- ), R = t.record(t.record(t.boolean())), M = t.object({
37
+ ), R = t.record(t.string(), t.record(t.string(), t.boolean())), M = t.object({
37
38
  latitude: t.number(),
38
39
  longitude: t.number()
39
40
  }), w = 6371e3, r = Math.PI / 180;
40
41
  function j(n, a) {
41
- const e = n.latitude * r, i = n.longitude * r, o = a.latitude * r, s = a.longitude * r, c = o - e, u = s - i, l = Math.sin(c / 2) ** 2 + Math.cos(e) * Math.cos(o) * Math.sin(u / 2) ** 2, p = 2 * Math.atan2(Math.sqrt(l), Math.sqrt(1 - l));
42
- return w * p;
42
+ const e = n.latitude * r, i = n.longitude * r, o = a.latitude * r, s = a.longitude * r, c = o - e, u = s - i, l = Math.sin(c / 2) ** 2 + Math.cos(e) * Math.cos(o) * Math.sin(u / 2) ** 2, g = 2 * Math.atan2(Math.sqrt(l), Math.sqrt(1 - l));
43
+ return w * g;
43
44
  }
44
45
  export {
45
46
  q as getGcpRegions,
@@ -1 +1 @@
1
- {"version":3,"file":"region-finder.js","sources":["../../../../src/cli/utils/region-finder.ts"],"sourcesContent":["import { validate } from \"@olinfo/quizms/utils\";\nimport { intersection, sortBy } from \"lodash-es\";\nimport z, { type ZodType } from \"zod\";\n\nconst productEnabled = [\n \"Cloud Firestore\",\n \"Cloud Run functions\",\n \"Cloud Storage for Firebase\",\n \"Cloud Tasks\",\n];\n\nexport async function getGcpRegions() {\n const [regions, products, geoip] = await Promise.all([\n api(\"https://cloud.withgoogle.com/region-picker/data/regions.json\", regionsSchema),\n api(\"https://cloud.withgoogle.com/region-picker/data/products.json\", productsSchema),\n api(\"https://api.seeip.org/geoip\", geoipSchema),\n ]);\n\n const availableRegions = intersection(\n ...productEnabled.map((p) =>\n Object.entries(products[p])\n .filter(([_, available]) => available)\n .map(([region]) => region),\n ),\n );\n\n return sortBy(\n availableRegions.map((region) => ({ region, ...regions[region] })),\n (region) => haversineDistance(geoip, region),\n );\n}\n\nasync function api<T>(url: string, schema: ZodType<T, any, any>) {\n const resp = await fetch(url);\n if (!resp.ok) throw new Error(\"Request failed\");\n return validate(schema, await resp.json());\n}\n\nconst regionsSchema = z.record(\n z.object({\n name: z.string(),\n latitude: z.number(),\n longitude: z.number(),\n }),\n);\n\nconst productsSchema = z.record(z.record(z.boolean()));\n\nconst geoipSchema = z.object({\n latitude: z.number(),\n longitude: z.number(),\n});\n\nconst R = 6371e3;\nconst toRad = Math.PI / 180;\n\nexport function haversineDistance(\n coord1: { latitude: number; longitude: number },\n coord2: { latitude: number; longitude: number },\n): number {\n const lat1Rad = coord1.latitude * toRad;\n const lng1Rad = coord1.longitude * toRad;\n const lat2Rad = coord2.latitude * toRad;\n const lng2Rad = coord2.longitude * toRad;\n\n const deltaLat = lat2Rad - lat1Rad;\n const deltaLon = lng2Rad - lng1Rad;\n\n const a =\n Math.sin(deltaLat / 2) ** 2 +\n Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.sin(deltaLon / 2) ** 2;\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n"],"names":["productEnabled","getGcpRegions","regions","products","geoip","api","regionsSchema","productsSchema","geoipSchema","availableRegions","intersection","p","_","available","region","sortBy","haversineDistance","url","schema","resp","validate","z","R","toRad","coord1","coord2","lat1Rad","lng1Rad","lat2Rad","lng2Rad","deltaLat","deltaLon","a","c"],"mappings":";;;AAIA,MAAMA,IAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,eAAsBC,IAAgB;AACpC,QAAM,CAACC,GAASC,GAAUC,CAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IACnDC,EAAI,gEAAgEC,CAAa;AAAA,IACjFD,EAAI,iEAAiEE,CAAc;AAAA,IACnFF,EAAI,+BAA+BG,CAAW;AAAA,EAAA,CAC/C,GAEKC,IAAmBC;AAAA,IACvB,GAAGV,EAAe;AAAA,MAAI,CAACW,MACrB,OAAO,QAAQR,EAASQ,CAAC,CAAC,EACvB,OAAO,CAAC,CAACC,GAAGC,CAAS,MAAMA,CAAS,EACpC,IAAI,CAAC,CAACC,CAAM,MAAMA,CAAM;AAAA,IAAA;AAAA,EAC7B;AAGF,SAAOC;AAAA,IACLN,EAAiB,IAAI,CAACK,OAAY,EAAE,QAAAA,GAAQ,GAAGZ,EAAQY,CAAM,EAAA,EAAI;AAAA,IACjE,CAACA,MAAWE,EAAkBZ,GAAOU,CAAM;AAAA,EAAA;AAE/C;AAEA,eAAeT,EAAOY,GAAaC,GAA8B;AAC/D,QAAMC,IAAO,MAAM,MAAMF,CAAG;AAC5B,MAAI,CAACE,EAAK,GAAI,OAAM,IAAI,MAAM,gBAAgB;AAC9C,SAAOC,EAASF,GAAQ,MAAMC,EAAK,MAAM;AAC3C;AAEA,MAAMb,IAAgBe,EAAE;AAAA,EACtBA,EAAE,OAAO;AAAA,IACP,MAAMA,EAAE,OAAA;AAAA,IACR,UAAUA,EAAE,OAAA;AAAA,IACZ,WAAWA,EAAE,OAAA;AAAA,EAAO,CACrB;AACH,GAEMd,IAAiBc,EAAE,OAAOA,EAAE,OAAOA,EAAE,QAAA,CAAS,CAAC,GAE/Cb,IAAca,EAAE,OAAO;AAAA,EAC3B,UAAUA,EAAE,OAAA;AAAA,EACZ,WAAWA,EAAE,OAAA;AACf,CAAC,GAEKC,IAAI,QACJC,IAAQ,KAAK,KAAK;AAEjB,SAASP,EACdQ,GACAC,GACQ;AACR,QAAMC,IAAUF,EAAO,WAAWD,GAC5BI,IAAUH,EAAO,YAAYD,GAC7BK,IAAUH,EAAO,WAAWF,GAC5BM,IAAUJ,EAAO,YAAYF,GAE7BO,IAAWF,IAAUF,GACrBK,IAAWF,IAAUF,GAErBK,IACJ,KAAK,IAAIF,IAAW,CAAC,KAAK,IAC1B,KAAK,IAAIJ,CAAO,IAAI,KAAK,IAAIE,CAAO,IAAI,KAAK,IAAIG,IAAW,CAAC,KAAK,GAC9DE,IAAI,IAAI,KAAK,MAAM,KAAK,KAAKD,CAAC,GAAG,KAAK,KAAK,IAAIA,CAAC,CAAC;AAEvD,SAAOV,IAAIW;AACb;"}
1
+ {"version":3,"file":"region-finder.js","sources":["../../../../src/cli/utils/region-finder.ts"],"sourcesContent":["import { validate } from \"@olinfo/quizms/utils\";\nimport { intersection, sortBy } from \"lodash-es\";\nimport z from \"zod\";\n\nconst productEnabled = [\n \"Cloud Firestore\",\n \"Cloud Run functions\",\n \"Cloud Storage for Firebase\",\n \"Cloud Tasks\",\n];\n\nexport async function getGcpRegions() {\n const [regions, products, geoip] = await Promise.all([\n api(\"https://cloud.withgoogle.com/region-picker/data/regions.json\", regionsSchema),\n api(\"https://cloud.withgoogle.com/region-picker/data/products.json\", productsSchema),\n api(\"https://api.seeip.org/geoip\", geoipSchema),\n ]);\n\n const availableRegions = intersection(\n ...productEnabled.map((p) =>\n Object.entries(products[p])\n .filter(([_, available]) => available)\n .map(([region]) => region),\n ),\n );\n\n return sortBy(\n availableRegions.map((region) => ({ region, ...regions[region] })),\n (region) => haversineDistance(geoip, region),\n );\n}\n\nasync function api<T>(url: string, schema: z.core.$ZodType<T>) {\n const resp = await fetch(url);\n if (!resp.ok) throw new Error(\"Request failed\");\n return validate(schema, await resp.json());\n}\n\nconst regionsSchema = z.record(\n z.string(),\n z.object({\n name: z.string(),\n latitude: z.number(),\n longitude: z.number(),\n }),\n);\n\nconst productsSchema = z.record(z.string(), z.record(z.string(), z.boolean()));\n\nconst geoipSchema = z.object({\n latitude: z.number(),\n longitude: z.number(),\n});\n\nconst R = 6371e3;\nconst toRad = Math.PI / 180;\n\nexport function haversineDistance(\n coord1: { latitude: number; longitude: number },\n coord2: { latitude: number; longitude: number },\n): number {\n const lat1Rad = coord1.latitude * toRad;\n const lng1Rad = coord1.longitude * toRad;\n const lat2Rad = coord2.latitude * toRad;\n const lng2Rad = coord2.longitude * toRad;\n\n const deltaLat = lat2Rad - lat1Rad;\n const deltaLon = lng2Rad - lng1Rad;\n\n const a =\n Math.sin(deltaLat / 2) ** 2 +\n Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.sin(deltaLon / 2) ** 2;\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n"],"names":["productEnabled","getGcpRegions","regions","products","geoip","api","regionsSchema","productsSchema","geoipSchema","availableRegions","intersection","p","_","available","region","sortBy","haversineDistance","url","schema","resp","validate","z","R","toRad","coord1","coord2","lat1Rad","lng1Rad","lat2Rad","lng2Rad","deltaLat","deltaLon","a","c"],"mappings":";;;AAIA,MAAMA,IAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,eAAsBC,IAAgB;AACpC,QAAM,CAACC,GAASC,GAAUC,CAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IACnDC,EAAI,gEAAgEC,CAAa;AAAA,IACjFD,EAAI,iEAAiEE,CAAc;AAAA,IACnFF,EAAI,+BAA+BG,CAAW;AAAA,EAAA,CAC/C,GAEKC,IAAmBC;AAAA,IACvB,GAAGV,EAAe;AAAA,MAAI,CAACW,MACrB,OAAO,QAAQR,EAASQ,CAAC,CAAC,EACvB,OAAO,CAAC,CAACC,GAAGC,CAAS,MAAMA,CAAS,EACpC,IAAI,CAAC,CAACC,CAAM,MAAMA,CAAM;AAAA,IAAA;AAAA,EAC7B;AAGF,SAAOC;AAAA,IACLN,EAAiB,IAAI,CAACK,OAAY,EAAE,QAAAA,GAAQ,GAAGZ,EAAQY,CAAM,EAAA,EAAI;AAAA,IACjE,CAACA,MAAWE,EAAkBZ,GAAOU,CAAM;AAAA,EAAA;AAE/C;AAEA,eAAeT,EAAOY,GAAaC,GAA4B;AAC7D,QAAMC,IAAO,MAAM,MAAMF,CAAG;AAC5B,MAAI,CAACE,EAAK,GAAI,OAAM,IAAI,MAAM,gBAAgB;AAC9C,SAAOC,EAASF,GAAQ,MAAMC,EAAK,MAAM;AAC3C;AAEA,MAAMb,IAAgBe,EAAE;AAAA,EACtBA,EAAE,OAAA;AAAA,EACFA,EAAE,OAAO;AAAA,IACP,MAAMA,EAAE,OAAA;AAAA,IACR,UAAUA,EAAE,OAAA;AAAA,IACZ,WAAWA,EAAE,OAAA;AAAA,EAAO,CACrB;AACH,GAEMd,IAAiBc,EAAE,OAAOA,EAAE,UAAUA,EAAE,OAAOA,EAAE,OAAA,GAAUA,EAAE,QAAA,CAAS,CAAC,GAEvEb,IAAca,EAAE,OAAO;AAAA,EAC3B,UAAUA,EAAE,OAAA;AAAA,EACZ,WAAWA,EAAE,OAAA;AACf,CAAC,GAEKC,IAAI,QACJC,IAAQ,KAAK,KAAK;AAEjB,SAASP,EACdQ,GACAC,GACQ;AACR,QAAMC,IAAUF,EAAO,WAAWD,GAC5BI,IAAUH,EAAO,YAAYD,GAC7BK,IAAUH,EAAO,WAAWF,GAC5BM,IAAUJ,EAAO,YAAYF,GAE7BO,IAAWF,IAAUF,GACrBK,IAAWF,IAAUF,GAErBK,IACJ,KAAK,IAAIF,IAAW,CAAC,KAAK,IAC1B,KAAK,IAAIJ,CAAO,IAAI,KAAK,IAAIE,CAAO,IAAI,KAAK,IAAIG,IAAW,CAAC,KAAK,GAC9DE,IAAI,IAAI,KAAK,MAAM,KAAK,KAAKD,CAAC,GAAG,KAAK,KAAK,IAAIA,CAAC,CAAC;AAEvD,SAAOV,IAAIW;AACb;"}
@@ -1,44 +1,35 @@
1
- import { existsSync as h } from "node:fs";
1
+ import { existsSync as c } from "node:fs";
2
+ import { styleText as h } from "node:util";
2
3
  import { confirm as u } from "@inquirer/prompts";
3
- import { AsyncPool as w } from "@olinfo/quizms/utils";
4
- import { fatal as m, success as x } from "@olinfo/quizms/utils-node";
5
- import { SingleBar as b } from "cli-progress";
6
- import { partition as y } from "lodash-es";
7
- import $ from "picocolors";
8
- async function I(f, i, s, r) {
9
- const t = new b({
10
- format: " {bar} {percentage}% | {value}/{total}",
11
- barCompleteChar: "█",
12
- barIncompleteChar: "▂"
13
- }), l = /* @__PURE__ */ new Set();
14
- t.start(s.length, 0), await Promise.all(
15
- s.map(async ([o, e]) => {
16
- h(o) || m(
17
- `Cannot find ${i}. Make sure to generate them first, use \`quizms --help\` for usage.`
18
- );
19
- const g = f.file(e), [d] = await g.exists().catch(() => [!1]);
20
- d && l.add(e), t.increment();
21
- })
22
- ), t.stop();
23
- const [a, c] = y(s, ([o, e]) => l.has(e));
24
- a.length > 0 && !r.skipExisting && !r.force && m(
4
+ import { withProgress as g, fatal as n, success as x } from "@olinfo/quizms/utils-node";
5
+ import { partition as w } from "lodash-es";
6
+ async function E(f, i, o, s) {
7
+ const m = /* @__PURE__ */ new Set();
8
+ await g(o, o.length, async ([e, t]) => {
9
+ c(e) || n(
10
+ `Cannot find ${i}. Make sure to generate them first, use \`quizms --help\` for usage.`
11
+ );
12
+ const d = f.file(t), [p] = await d.exists().catch(() => [!1]);
13
+ p && m.add(t);
14
+ });
15
+ const [r, l] = w(o, ([e, t]) => m.has(t));
16
+ r.length > 0 && !s.skipExisting && !s.force && n(
25
17
  `Files already exist in \`${i}\`. Use \`--force\` to overwrite or \`--skip-existing\` to ignore.`
26
18
  );
27
- const n = r.skipExisting ? c : [...a, ...c];
28
- r.force && a.length > 0 && (await u({
29
- message: `You are about to import the ${$.bold(
19
+ const a = s.skipExisting ? l : [...r, ...l];
20
+ s.force && r.length > 0 && (await u({
21
+ message: `You are about to import the ${h(
22
+ "bold",
30
23
  i
31
- )}. ${a.length} files will be overwritten, the previous data will be lost. Are you really sure?`,
24
+ )}. ${r.length} files will be overwritten, the previous data will be lost. Are you really sure?`,
32
25
  default: !1
33
- }) || m("Command aborted.")), t.start(n.length, 0);
34
- const p = new w(8);
35
- for (const [o, e] of n)
36
- p.run(async () => {
37
- await f.upload(o, { destination: e }), t.increment();
38
- });
39
- await p.wait(), t.stop(), x(`${n.length} ${i} imported!`);
26
+ }) || n("Command aborted.")), await g(
27
+ a,
28
+ a.length,
29
+ ([e, t]) => f.upload(e, { destination: t })
30
+ ), x(`${a.length} ${i} imported!`);
40
31
  }
41
32
  export {
42
- I as importStorage
33
+ E as importStorage
43
34
  };
44
35
  //# sourceMappingURL=storage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sources":["../../../../src/cli/utils/storage.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\n\nimport type { Bucket } from \"@google-cloud/storage\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { AsyncPool } from \"@olinfo/quizms/utils\";\nimport { fatal, success } from \"@olinfo/quizms/utils-node\";\nimport { SingleBar } from \"cli-progress\";\nimport { partition } from \"lodash-es\";\nimport pc from \"picocolors\";\n\ntype ImportOptions = {\n skipExisting?: true;\n force?: true;\n};\n\nexport async function importStorage(\n bucket: Bucket,\n collection: string,\n files: [string, string][],\n options: ImportOptions,\n) {\n const bar = new SingleBar({\n format: \" {bar} {percentage}% | {value}/{total}\",\n barCompleteChar: \"\\u2588\",\n barIncompleteChar: \"\\u2582\",\n });\n\n const existingFiles = new Set<string>();\n\n bar.start(files.length, 0);\n await Promise.all(\n files.map(async ([local, remote]) => {\n if (!existsSync(local)) {\n fatal(\n `Cannot find ${collection}. Make sure to generate them first, use \\`quizms --help\\` for usage.`,\n );\n }\n\n const file = bucket.file(remote);\n const [exists] = await file.exists().catch(() => [false]);\n if (exists) {\n existingFiles.add(remote);\n }\n bar.increment();\n }),\n );\n bar.stop();\n\n const [existing, nonExisting] = partition(files, ([_, remote]) => existingFiles.has(remote));\n if (existing.length > 0 && !options.skipExisting && !options.force) {\n fatal(\n `Files already exist in \\`${collection}\\`. Use \\`--force\\` to overwrite or \\`--skip-existing\\` to ignore.`,\n );\n }\n\n const filesToImport = options.skipExisting ? nonExisting : [...existing, ...nonExisting];\n\n if (options.force && existing.length > 0) {\n const confirmed = await confirm({\n message: `You are about to import the ${pc.bold(\n collection,\n )}. ${existing.length} files will be overwritten, the previous data will be lost. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n }\n\n bar.start(filesToImport.length, 0);\n\n const pool = new AsyncPool(8);\n for (const [local, remote] of filesToImport) {\n void pool.run(async () => {\n await bucket.upload(local, { destination: remote });\n bar.increment();\n });\n }\n await pool.wait();\n\n bar.stop();\n\n success(`${filesToImport.length} ${collection} imported!`);\n}\n"],"names":["importStorage","bucket","collection","files","options","bar","SingleBar","existingFiles","local","remote","existsSync","fatal","file","exists","existing","nonExisting","partition","_","filesToImport","confirm","pc","pool","AsyncPool","success"],"mappings":";;;;;;;AAeA,eAAsBA,EACpBC,GACAC,GACAC,GACAC,GACA;AACA,QAAMC,IAAM,IAAIC,EAAU;AAAA,IACxB,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,EAAA,CACpB,GAEKC,wBAAoB,IAAA;AAE1B,EAAAF,EAAI,MAAMF,EAAM,QAAQ,CAAC,GACzB,MAAM,QAAQ;AAAA,IACZA,EAAM,IAAI,OAAO,CAACK,GAAOC,CAAM,MAAM;AACnC,MAAKC,EAAWF,CAAK,KACnBG;AAAA,QACE,eAAeT,CAAU;AAAA,MAAA;AAI7B,YAAMU,IAAOX,EAAO,KAAKQ,CAAM,GACzB,CAACI,CAAM,IAAI,MAAMD,EAAK,OAAA,EAAS,MAAM,MAAM,CAAC,EAAK,CAAC;AACxD,MAAIC,KACFN,EAAc,IAAIE,CAAM,GAE1BJ,EAAI,UAAA;AAAA,IACN,CAAC;AAAA,EAAA,GAEHA,EAAI,KAAA;AAEJ,QAAM,CAACS,GAAUC,CAAW,IAAIC,EAAUb,GAAO,CAAC,CAACc,GAAGR,CAAM,MAAMF,EAAc,IAAIE,CAAM,CAAC;AAC3F,EAAIK,EAAS,SAAS,KAAK,CAACV,EAAQ,gBAAgB,CAACA,EAAQ,SAC3DO;AAAA,IACE,4BAA4BT,CAAU;AAAA,EAAA;AAI1C,QAAMgB,IAAgBd,EAAQ,eAAeW,IAAc,CAAC,GAAGD,GAAU,GAAGC,CAAW;AAEvF,EAAIX,EAAQ,SAASU,EAAS,SAAS,MACnB,MAAMK,EAAQ;AAAA,IAC9B,SAAS,+BAA+BC,EAAG;AAAA,MACzClB;AAAA,IAAA,CACD,KAAKY,EAAS,MAAM;AAAA,IACrB,SAAS;AAAA,EAAA,CACV,KAECH,EAAM,kBAAkB,IAI5BN,EAAI,MAAMa,EAAc,QAAQ,CAAC;AAEjC,QAAMG,IAAO,IAAIC,EAAU,CAAC;AAC5B,aAAW,CAACd,GAAOC,CAAM,KAAKS;AAC5B,IAAKG,EAAK,IAAI,YAAY;AACxB,YAAMpB,EAAO,OAAOO,GAAO,EAAE,aAAaC,GAAQ,GAClDJ,EAAI,UAAA;AAAA,IACN,CAAC;AAEH,QAAMgB,EAAK,KAAA,GAEXhB,EAAI,KAAA,GAEJkB,EAAQ,GAAGL,EAAc,MAAM,IAAIhB,CAAU,YAAY;AAC3D;"}
1
+ {"version":3,"file":"storage.js","sources":["../../../../src/cli/utils/storage.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { styleText } from \"node:util\";\n\nimport type { Bucket } from \"@google-cloud/storage\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { fatal, success, withProgress } from \"@olinfo/quizms/utils-node\";\nimport { partition } from \"lodash-es\";\n\ntype ImportOptions = {\n skipExisting?: true;\n force?: true;\n};\n\nexport async function importStorage(\n bucket: Bucket,\n collection: string,\n files: [string, string][],\n options: ImportOptions,\n) {\n const existingFiles = new Set<string>();\n\n await withProgress(files, files.length, async ([local, remote]) => {\n if (!existsSync(local)) {\n fatal(\n `Cannot find ${collection}. Make sure to generate them first, use \\`quizms --help\\` for usage.`,\n );\n }\n\n const file = bucket.file(remote);\n const [exists] = await file.exists().catch(() => [false]);\n if (exists) {\n existingFiles.add(remote);\n }\n });\n\n const [existing, nonExisting] = partition(files, ([_, remote]) => existingFiles.has(remote));\n if (existing.length > 0 && !options.skipExisting && !options.force) {\n fatal(\n `Files already exist in \\`${collection}\\`. Use \\`--force\\` to overwrite or \\`--skip-existing\\` to ignore.`,\n );\n }\n\n const filesToImport = options.skipExisting ? nonExisting : [...existing, ...nonExisting];\n\n if (options.force && existing.length > 0) {\n const confirmed = await confirm({\n message: `You are about to import the ${styleText(\n \"bold\",\n collection,\n )}. ${existing.length} files will be overwritten, the previous data will be lost. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n }\n\n await withProgress(filesToImport, filesToImport.length, ([local, remote]) =>\n bucket.upload(local, { destination: remote }),\n );\n\n success(`${filesToImport.length} ${collection} imported!`);\n}\n"],"names":["importStorage","bucket","collection","files","options","existingFiles","withProgress","local","remote","existsSync","fatal","file","exists","existing","nonExisting","partition","_","filesToImport","confirm","styleText","success"],"mappings":";;;;;AAaA,eAAsBA,EACpBC,GACAC,GACAC,GACAC,GACA;AACA,QAAMC,wBAAoB,IAAA;AAE1B,QAAMC,EAAaH,GAAOA,EAAM,QAAQ,OAAO,CAACI,GAAOC,CAAM,MAAM;AACjE,IAAKC,EAAWF,CAAK,KACnBG;AAAA,MACE,eAAeR,CAAU;AAAA,IAAA;AAI7B,UAAMS,IAAOV,EAAO,KAAKO,CAAM,GACzB,CAACI,CAAM,IAAI,MAAMD,EAAK,OAAA,EAAS,MAAM,MAAM,CAAC,EAAK,CAAC;AACxD,IAAIC,KACFP,EAAc,IAAIG,CAAM;AAAA,EAE5B,CAAC;AAED,QAAM,CAACK,GAAUC,CAAW,IAAIC,EAAUZ,GAAO,CAAC,CAACa,GAAGR,CAAM,MAAMH,EAAc,IAAIG,CAAM,CAAC;AAC3F,EAAIK,EAAS,SAAS,KAAK,CAACT,EAAQ,gBAAgB,CAACA,EAAQ,SAC3DM;AAAA,IACE,4BAA4BR,CAAU;AAAA,EAAA;AAI1C,QAAMe,IAAgBb,EAAQ,eAAeU,IAAc,CAAC,GAAGD,GAAU,GAAGC,CAAW;AAEvF,EAAIV,EAAQ,SAASS,EAAS,SAAS,MACnB,MAAMK,EAAQ;AAAA,IAC9B,SAAS,+BAA+BC;AAAA,MACtC;AAAA,MACAjB;AAAA,IAAA,CACD,KAAKW,EAAS,MAAM;AAAA,IACrB,SAAS;AAAA,EAAA,CACV,KAECH,EAAM,kBAAkB,IAI5B,MAAMJ;AAAA,IAAaW;AAAA,IAAeA,EAAc;AAAA,IAAQ,CAAC,CAACV,GAAOC,CAAM,MACrEP,EAAO,OAAOM,GAAO,EAAE,aAAaC,EAAA,CAAQ;AAAA,EAAA,GAG9CY,EAAQ,GAAGH,EAAc,MAAM,IAAIf,CAAU,YAAY;AAC3D;"}
@@ -1,30 +1,31 @@
1
- import { confirm as m } from "@inquirer/prompts";
2
- import { fatal as s } from "@olinfo/quizms/utils-node";
1
+ import { styleText as m } from "node:util";
2
+ import { confirm as s } from "@inquirer/prompts";
3
+ import { fatal as l } from "@olinfo/quizms/utils-node";
3
4
  import { info as n } from "firebase-functions/logger";
4
5
  import { upperFirst as f } from "lodash-es";
5
- import l from "picocolors";
6
- import { importCollection as p } from "./collection.js";
7
- import { userConverter as u } from "./converters-admin.js";
8
- async function A(e, o, i, t) {
6
+ import { importCollection as u } from "./collection.js";
7
+ import { userConverter as p } from "./converters-admin.js";
8
+ async function x(e, o, i, t) {
9
9
  if (t.delete) {
10
- await m({
11
- message: `You are about to delete all ${l.bold(
10
+ await s({
11
+ message: `You are about to delete all ${m(
12
+ "bold",
12
13
  o
13
14
  )} users. Any previous data will be lost, this operation cannot be undone. Are you really sure?`,
14
15
  default: !1
15
- }) || s("Command aborted.");
16
+ }) || l("Command aborted.");
16
17
  const a = e.collection("users");
17
18
  await e.recursiveDelete(a), n(`${f(o)} users deleted!`);
18
19
  }
19
- await p(
20
+ await u(
20
21
  e,
21
22
  "users",
22
23
  i.map((r) => ({ ...r, id: r.username, role: o })),
23
- u,
24
+ p,
24
25
  { ...t, delete: void 0 }
25
26
  );
26
27
  }
27
28
  export {
28
- A as importUsers
29
+ x as importUsers
29
30
  };
30
31
  //# sourceMappingURL=users.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"users.js","sources":["../../../../src/cli/utils/users.ts"],"sourcesContent":["import { confirm } from \"@inquirer/prompts\";\nimport { fatal } from \"@olinfo/quizms/utils-node\";\nimport type { Firestore } from \"firebase-admin/firestore\";\nimport { info } from \"firebase-functions/logger\";\nimport { upperFirst } from \"lodash-es\";\nimport pc from \"picocolors\";\n\nimport type { User } from \"~/models/user\";\n\nimport { importCollection } from \"./collection\";\nimport { userConverter } from \"./converters-admin\";\n\ntype ImportOptions = {\n delete?: true;\n skipExisting?: true;\n force?: true;\n};\n\nexport async function importUsers(\n db: Firestore,\n role: string,\n users: Omit<User, \"id\" | \"role\">[],\n options: ImportOptions,\n) {\n if (options.delete) {\n const confirmed = await confirm({\n message: `You are about to delete all ${pc.bold(\n role,\n )} users. Any previous data will be lost, this operation cannot be undone. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n\n const ref = db.collection(\"users\");\n await db.recursiveDelete(ref);\n info(`${upperFirst(role)} users deleted!`);\n }\n\n await importCollection(\n db,\n \"users\",\n users.map((u) => ({ ...u, id: u.username, role })),\n userConverter,\n { ...options, delete: undefined },\n );\n}\n"],"names":["importUsers","db","role","users","options","confirm","pc","fatal","ref","info","upperFirst","importCollection","u","userConverter"],"mappings":";;;;;;;AAkBA,eAAsBA,EACpBC,GACAC,GACAC,GACAC,GACA;AACA,MAAIA,EAAQ,QAAQ;AAOlB,IANkB,MAAMC,EAAQ;AAAA,MAC9B,SAAS,+BAA+BC,EAAG;AAAA,QACzCJ;AAAA,MAAA,CACD;AAAA,MACD,SAAS;AAAA,IAAA,CACV,KAECK,EAAM,kBAAkB;AAG1B,UAAMC,IAAMP,EAAG,WAAW,OAAO;AACjC,UAAMA,EAAG,gBAAgBO,CAAG,GAC5BC,EAAK,GAAGC,EAAWR,CAAI,CAAC,iBAAiB;AAAA,EAC3C;AAEA,QAAMS;AAAA,IACJV;AAAA,IACA;AAAA,IACAE,EAAM,IAAI,CAACS,OAAO,EAAE,GAAGA,GAAG,IAAIA,EAAE,UAAU,MAAAV,EAAA,EAAO;AAAA,IACjDW;AAAA,IACA,EAAE,GAAGT,GAAS,QAAQ,OAAA;AAAA,EAAU;AAEpC;"}
1
+ {"version":3,"file":"users.js","sources":["../../../../src/cli/utils/users.ts"],"sourcesContent":["import { styleText } from \"node:util\";\n\nimport { confirm } from \"@inquirer/prompts\";\nimport { fatal } from \"@olinfo/quizms/utils-node\";\nimport type { Firestore } from \"firebase-admin/firestore\";\nimport { info } from \"firebase-functions/logger\";\nimport { upperFirst } from \"lodash-es\";\n\nimport type { User } from \"~/models/user\";\n\nimport { importCollection } from \"./collection\";\nimport { userConverter } from \"./converters-admin\";\n\ntype ImportOptions = {\n delete?: true;\n skipExisting?: true;\n force?: true;\n};\n\nexport async function importUsers(\n db: Firestore,\n role: string,\n users: Omit<User, \"id\" | \"role\">[],\n options: ImportOptions,\n) {\n if (options.delete) {\n const confirmed = await confirm({\n message: `You are about to delete all ${styleText(\n \"bold\",\n role,\n )} users. Any previous data will be lost, this operation cannot be undone. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n\n const ref = db.collection(\"users\");\n await db.recursiveDelete(ref);\n info(`${upperFirst(role)} users deleted!`);\n }\n\n await importCollection(\n db,\n \"users\",\n users.map((u) => ({ ...u, id: u.username, role })),\n userConverter,\n { ...options, delete: undefined },\n );\n}\n"],"names":["importUsers","db","role","users","options","confirm","styleText","fatal","ref","info","upperFirst","importCollection","u","userConverter"],"mappings":";;;;;;;AAmBA,eAAsBA,EACpBC,GACAC,GACAC,GACAC,GACA;AACA,MAAIA,EAAQ,QAAQ;AAQlB,IAPkB,MAAMC,EAAQ;AAAA,MAC9B,SAAS,+BAA+BC;AAAA,QACtC;AAAA,QACAJ;AAAA,MAAA,CACD;AAAA,MACD,SAAS;AAAA,IAAA,CACV,KAECK,EAAM,kBAAkB;AAG1B,UAAMC,IAAMP,EAAG,WAAW,OAAO;AACjC,UAAMA,EAAG,gBAAgBO,CAAG,GAC5BC,EAAK,GAAGC,EAAWR,CAAI,CAAC,iBAAiB;AAAA,EAC3C;AAEA,QAAMS;AAAA,IACJV;AAAA,IACA;AAAA,IACAE,EAAM,IAAI,CAACS,OAAO,EAAE,GAAGA,GAAG,IAAIA,EAAE,UAAU,MAAAV,EAAA,EAAO;AAAA,IACjDW;AAAA,IACA,EAAE,GAAGT,GAAS,QAAQ,OAAA;AAAA,EAAU;AAEpC;"}
@@ -1,13 +1,28 @@
1
- import o from "node:crypto";
2
- import * as s from "firebase-functions/logger";
3
- import { auth as t } from "../common.js";
4
- import { getUser as n } from "./queries.js";
5
- const d = async (a, r) => {
6
- s.info("Admin login request received", { data: r });
7
- const e = await n(r.username);
8
- return e ? e.role !== "admin" ? { success: !1, errorCode: "INVALID_ROLE", error: "Utenza non abilitata" } : e.password !== r.password ? { success: !1, errorCode: "INVALID_PASSWORD", error: "Password non corretta" } : { success: !0, data: { token: await t.createCustomToken(o.randomUUID(), { role: "admin" }) } } : { success: !1, errorCode: "USER_NOT_FOUND", error: "Username non esistente" };
9
- };
1
+ import s from "node:crypto";
2
+ import { TRPCError as e } from "@trpc/server";
3
+ import * as i from "firebase-functions/logger";
4
+ import t from "zod";
5
+ import { auth as a } from "../common.js";
6
+ import { getUser as m } from "./queries.js";
7
+ import { publicProcedure as c } from "./trpc.js";
8
+ const U = c.input(
9
+ t.strictObject({
10
+ username: t.string(),
11
+ password: t.string()
12
+ })
13
+ ).mutation(async (n) => {
14
+ const { input: r } = n;
15
+ i.info("Admin login request received", { data: r });
16
+ const o = await m(r.username);
17
+ if (!o)
18
+ throw new e({ code: "BAD_REQUEST", message: "Username non esistente" });
19
+ if (o.password !== r.password)
20
+ throw new e({ code: "BAD_REQUEST", message: "Password non corretta" });
21
+ if (o.role !== "admin")
22
+ throw new e({ code: "FORBIDDEN", message: "Utenza non abilitata" });
23
+ return a.createCustomToken(s.randomUUID(), { role: "admin" });
24
+ });
10
25
  export {
11
- d as adminLogin
26
+ U as adminLogin
12
27
  };
13
28
  //# sourceMappingURL=admin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sources":["../../../../src/functions/api/admin.ts"],"sourcesContent":["import crypto from \"node:crypto\";\n\nimport * as logger from \"firebase-functions/logger\";\n\nimport { auth, type Endpoint } from \"~/functions/common\";\n\nimport { getUser } from \"./queries\";\nimport type { AdminLogin } from \"./schema\";\n\nexport const adminLogin: Endpoint<AdminLogin> = async (_request, data) => {\n logger.info(\"Admin login request received\", { data });\n\n const user = await getUser(data.username);\n if (!user) {\n return { success: false, errorCode: \"USER_NOT_FOUND\", error: \"Username non esistente\" };\n }\n\n if (user.role !== \"admin\") {\n return { success: false, errorCode: \"INVALID_ROLE\", error: \"Utenza non abilitata\" };\n }\n if (user.password !== data.password) {\n return { success: false, errorCode: \"INVALID_PASSWORD\", error: \"Password non corretta\" };\n }\n const token = await auth.createCustomToken(crypto.randomUUID(), { role: \"admin\" });\n return { success: true, data: { token } };\n};\n"],"names":["adminLogin","_request","data","logger","user","getUser","auth","crypto"],"mappings":";;;;AASO,MAAMA,IAAmC,OAAOC,GAAUC,MAAS;AACxE,EAAAC,EAAO,KAAK,gCAAgC,EAAE,MAAAD,EAAA,CAAM;AAEpD,QAAME,IAAO,MAAMC,EAAQH,EAAK,QAAQ;AACxC,SAAKE,IAIDA,EAAK,SAAS,UACT,EAAE,SAAS,IAAO,WAAW,gBAAgB,OAAO,uBAAA,IAEzDA,EAAK,aAAaF,EAAK,WAClB,EAAE,SAAS,IAAO,WAAW,oBAAoB,OAAO,wBAAA,IAG1D,EAAE,SAAS,IAAM,MAAM,EAAE,OADlB,MAAMI,EAAK,kBAAkBC,EAAO,cAAc,EAAE,MAAM,SAAS,IAC3C,IAV7B,EAAE,SAAS,IAAO,WAAW,kBAAkB,OAAO,yBAAA;AAWjE;"}
1
+ {"version":3,"file":"admin.js","sources":["../../../../src/functions/api/admin.ts"],"sourcesContent":["import crypto from \"node:crypto\";\n\nimport { TRPCError } from \"@trpc/server\";\nimport * as logger from \"firebase-functions/logger\";\nimport z from \"zod\";\n\nimport { auth } from \"../common\";\nimport { getUser } from \"./queries\";\nimport { publicProcedure } from \"./trpc\";\n\nexport const adminLogin = publicProcedure\n .input(\n z.strictObject({\n username: z.string(),\n password: z.string(),\n }),\n )\n .mutation(async (opts) => {\n const { input: data } = opts;\n logger.info(\"Admin login request received\", { data });\n\n const user = await getUser(data.username);\n if (!user) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Username non esistente\" });\n }\n\n if (user.password !== data.password) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Password non corretta\" });\n }\n if (user.role !== \"admin\") {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Utenza non abilitata\" });\n }\n return auth.createCustomToken(crypto.randomUUID(), { role: \"admin\" });\n });\n"],"names":["adminLogin","publicProcedure","z","opts","data","logger","user","getUser","TRPCError","auth","crypto"],"mappings":";;;;;;;AAUO,MAAMA,IAAaC,EACvB;AAAA,EACCC,EAAE,aAAa;AAAA,IACb,UAAUA,EAAE,OAAA;AAAA,IACZ,UAAUA,EAAE,OAAA;AAAA,EAAO,CACpB;AACH,EACC,SAAS,OAAOC,MAAS;AACxB,QAAM,EAAE,OAAOC,EAAA,IAASD;AACxB,EAAAE,EAAO,KAAK,gCAAgC,EAAE,MAAAD,EAAA,CAAM;AAEpD,QAAME,IAAO,MAAMC,EAAQH,EAAK,QAAQ;AACxC,MAAI,CAACE;AACH,UAAM,IAAIE,EAAU,EAAE,MAAM,eAAe,SAAS,0BAA0B;AAGhF,MAAIF,EAAK,aAAaF,EAAK;AACzB,UAAM,IAAII,EAAU,EAAE,MAAM,eAAe,SAAS,yBAAyB;AAE/E,MAAIF,EAAK,SAAS;AAChB,UAAM,IAAIE,EAAU,EAAE,MAAM,aAAa,SAAS,wBAAwB;AAE5E,SAAOC,EAAK,kBAAkBC,EAAO,WAAA,GAAc,EAAE,MAAM,SAAS;AACtE,CAAC;"}
@@ -1,41 +1,30 @@
1
- import { validate as i } from "@olinfo/quizms/utils";
2
- import * as t from "firebase-functions/logger";
3
- import { adminLogin as o } from "./admin.js";
4
- import { apiRequestSchema as c } from "./schema.js";
5
- import { studentLogin as n } from "./student.js";
6
- import { teacherFinalizeParticipation as s, teacherStopParticipation as p, teacherStartParticipation as d, teacherLogin as m } from "./teacher.js";
7
- async function w(a) {
8
- t.info(`Received request for action: ${a.data.action}`);
9
- const r = await f(a);
10
- return r.success || t.error("Request failed", { request: a, result: r }), r;
11
- }
12
- async function f(a) {
13
- let r;
14
- try {
15
- r = i(c, a.data);
16
- } catch (e) {
17
- return t.error("Invalid request", { error: e }), { success: !1, errorCode: "INVALID_REQUEST", error: "Richiesta non valida" };
18
- }
19
- try {
20
- switch (r.action) {
21
- case "adminLogin":
22
- return await o(a, r);
23
- case "studentLogin":
24
- return await n(a, r);
25
- case "teacherLogin":
26
- return await m(a, r);
27
- case "teacherStartParticipation":
28
- return await d(a, r);
29
- case "teacherStopParticipation":
30
- return await p(a, r);
31
- case "teacherFinalizeParticipation":
32
- return await s(a, r);
1
+ import * as a from "@trpc/server/adapters/express";
2
+ import p from "express";
3
+ import { logger as m } from "firebase-functions/logger";
4
+ import { adminLogin as n } from "./admin.js";
5
+ import { studentLogin as s } from "./student.js";
6
+ import { teacherFinalizeParticipation as c, teacherStopParticipation as f, teacherStartParticipation as u, teacherLogin as g } from "./teacher.js";
7
+ import { router as x, createContext as d } from "./trpc.js";
8
+ const h = x({
9
+ adminLogin: n,
10
+ studentLogin: s,
11
+ teacherLogin: g,
12
+ teacherStartParticipation: u,
13
+ teacherStopParticipation: f,
14
+ teacherFinalizeParticipation: c
15
+ }), l = p();
16
+ l.use(
17
+ "/",
18
+ a.createExpressMiddleware({
19
+ router: h,
20
+ createContext: d,
21
+ onError(t) {
22
+ const { error: r, path: o, input: e, ctx: i } = t;
23
+ m.error(r.message, { error: r, path: o, input: e, ctx: i });
33
24
  }
34
- } catch (e) {
35
- return t.error("Error processing request", { error: e }), { success: !1, errorCode: "INTERNAL_ERROR", error: "Errore del server" };
36
- }
37
- }
25
+ })
26
+ );
38
27
  export {
39
- w as apiHandler
28
+ l as default
40
29
  };
41
30
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/functions/api/index.ts"],"sourcesContent":["import { validate } from \"@olinfo/quizms/utils\";\nimport type { CallableRequest } from \"firebase-functions/https\";\nimport * as logger from \"firebase-functions/logger\";\n\nimport { adminLogin } from \"./admin\";\nimport { type ApiRequest, apiRequestSchema } from \"./schema\";\nimport { studentLogin } from \"./student\";\nimport {\n teacherFinalizeParticipation,\n teacherLogin,\n teacherStartParticipation,\n teacherStopParticipation,\n} from \"./teacher\";\n\nexport async function apiHandler(request: CallableRequest) {\n logger.info(`Received request for action: ${request.data.action}`);\n const result = await dispatch(request);\n if (!result.success) {\n logger.error(\"Request failed\", { request, result });\n }\n return result;\n}\n\nasync function dispatch(request: CallableRequest) {\n let data: ApiRequest;\n try {\n data = validate(apiRequestSchema, request.data);\n } catch (error) {\n logger.error(\"Invalid request\", { error });\n return { success: false, errorCode: \"INVALID_REQUEST\", error: \"Richiesta non valida\" };\n }\n\n try {\n switch (data.action) {\n case \"adminLogin\":\n return await adminLogin(request, data);\n case \"studentLogin\":\n return await studentLogin(request, data);\n case \"teacherLogin\":\n return await teacherLogin(request, data);\n case \"teacherStartParticipation\":\n return await teacherStartParticipation(request, data);\n case \"teacherStopParticipation\":\n return await teacherStopParticipation(request, data);\n case \"teacherFinalizeParticipation\":\n return await teacherFinalizeParticipation(request, data);\n }\n } catch (error) {\n logger.error(\"Error processing request\", { error });\n return { success: false, errorCode: \"INTERNAL_ERROR\", error: \"Errore del server\" };\n }\n}\n"],"names":["apiHandler","request","logger","result","dispatch","data","validate","apiRequestSchema","error","adminLogin","studentLogin","teacherLogin","teacherStartParticipation","teacherStopParticipation","teacherFinalizeParticipation"],"mappings":";;;;;;AAcA,eAAsBA,EAAWC,GAA0B;AACzD,EAAAC,EAAO,KAAK,gCAAgCD,EAAQ,KAAK,MAAM,EAAE;AACjE,QAAME,IAAS,MAAMC,EAASH,CAAO;AACrC,SAAKE,EAAO,WACVD,EAAO,MAAM,kBAAkB,EAAE,SAAAD,GAAS,QAAAE,GAAQ,GAE7CA;AACT;AAEA,eAAeC,EAASH,GAA0B;AAChD,MAAII;AACJ,MAAI;AACF,IAAAA,IAAOC,EAASC,GAAkBN,EAAQ,IAAI;AAAA,EAChD,SAASO,GAAO;AACd,WAAAN,EAAO,MAAM,mBAAmB,EAAE,OAAAM,EAAA,CAAO,GAClC,EAAE,SAAS,IAAO,WAAW,mBAAmB,OAAO,uBAAA;AAAA,EAChE;AAEA,MAAI;AACF,YAAQH,EAAK,QAAA;AAAA,MACX,KAAK;AACH,eAAO,MAAMI,EAAWR,GAASI,CAAI;AAAA,MACvC,KAAK;AACH,eAAO,MAAMK,EAAaT,GAASI,CAAI;AAAA,MACzC,KAAK;AACH,eAAO,MAAMM,EAAaV,GAASI,CAAI;AAAA,MACzC,KAAK;AACH,eAAO,MAAMO,EAA0BX,GAASI,CAAI;AAAA,MACtD,KAAK;AACH,eAAO,MAAMQ,EAAyBZ,GAASI,CAAI;AAAA,MACrD,KAAK;AACH,eAAO,MAAMS,EAA6Bb,GAASI,CAAI;AAAA,IAAA;AAAA,EAE7D,SAASG,GAAO;AACd,WAAAN,EAAO,MAAM,4BAA4B,EAAE,OAAAM,EAAA,CAAO,GAC3C,EAAE,SAAS,IAAO,WAAW,kBAAkB,OAAO,oBAAA;AAAA,EAC/D;AACF;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/functions/api/index.ts"],"sourcesContent":["import * as trpcExpress from \"@trpc/server/adapters/express\";\nimport express from \"express\";\nimport { logger } from \"firebase-functions/logger\";\n\nimport { adminLogin } from \"./admin\";\nimport { studentLogin } from \"./student\";\nimport {\n teacherFinalizeParticipation,\n teacherLogin,\n teacherStartParticipation,\n teacherStopParticipation,\n} from \"./teacher\";\nimport { createContext, router } from \"./trpc\";\n\nconst appRouter = router({\n adminLogin,\n studentLogin,\n teacherLogin,\n teacherStartParticipation,\n teacherStopParticipation,\n teacherFinalizeParticipation,\n});\n\nexport type AppRouter = typeof appRouter;\n\nconst app = express();\napp.use(\n \"/\",\n trpcExpress.createExpressMiddleware({\n router: appRouter,\n createContext,\n onError(opts) {\n const { error, path, input, ctx } = opts;\n logger.error(error.message, { error, path, input, ctx });\n },\n }),\n);\n\nexport default app;\n"],"names":["appRouter","router","adminLogin","studentLogin","teacherLogin","teacherStartParticipation","teacherStopParticipation","teacherFinalizeParticipation","app","express","trpcExpress","createContext","opts","error","path","input","ctx","logger"],"mappings":";;;;;;;AAcA,MAAMA,IAAYC,EAAO;AAAA,EACvB,YAAAC;AAAA,EACA,cAAAC;AAAA,EACA,cAAAC;AAAA,EACA,2BAAAC;AAAA,EACA,0BAAAC;AAAA,EACA,8BAAAC;AACF,CAAC,GAIKC,IAAMC,EAAA;AACZD,EAAI;AAAA,EACF;AAAA,EACAE,EAAY,wBAAwB;AAAA,IAClC,QAAQV;AAAA,IACR,eAAAW;AAAA,IACA,QAAQC,GAAM;AACZ,YAAM,EAAE,OAAAC,GAAO,MAAAC,GAAM,OAAAC,GAAO,KAAAC,MAAQJ;AACpC,MAAAK,EAAO,MAAMJ,EAAM,SAAS,EAAE,OAAAA,GAAO,MAAAC,GAAM,OAAAC,GAAO,KAAAC,GAAK;AAAA,IACzD;AAAA,EAAA,CACD;AACH;"}