@olinfo/quizms-firebase 4.1.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/cli.js +14 -14
  2. package/dist/cli.js.map +1 -1
  3. package/dist/package.json.js +1 -1
  4. package/dist/src/cli/definalize.js +17 -17
  5. package/dist/src/cli/definalize.js.map +1 -1
  6. package/dist/src/cli/export.js +42 -34
  7. package/dist/src/cli/export.js.map +1 -1
  8. package/dist/src/cli/files/firestore-indexes.json.js +1 -1
  9. package/dist/src/cli/files/firestore.rules.js +27 -27
  10. package/dist/src/cli/files/firestore.rules.js.map +1 -1
  11. package/dist/src/cli/files/functions-index.js +3 -3
  12. package/dist/src/cli/files/functions-index.js.map +1 -1
  13. package/dist/src/cli/files/storage.rules.js +3 -3
  14. package/dist/src/cli/files/storage.rules.js.map +1 -1
  15. package/dist/src/cli/import.js +65 -71
  16. package/dist/src/cli/import.js.map +1 -1
  17. package/dist/src/cli/update-scores.js +7 -7
  18. package/dist/src/cli/update-scores.js.map +1 -1
  19. package/dist/src/cli/utils/converters-admin.js +23 -22
  20. package/dist/src/cli/utils/converters-admin.js.map +1 -1
  21. package/dist/src/functions/api/index.js +18 -18
  22. package/dist/src/functions/api/index.js.map +1 -1
  23. package/dist/src/functions/api/queries.js +21 -21
  24. package/dist/src/functions/api/queries.js.map +1 -1
  25. package/dist/src/functions/api/student.js +46 -47
  26. package/dist/src/functions/api/student.js.map +1 -1
  27. package/dist/src/functions/api/teacher.js +92 -95
  28. package/dist/src/functions/api/teacher.js.map +1 -1
  29. package/dist/src/functions/submissions.js +11 -7
  30. package/dist/src/functions/submissions.js.map +1 -1
  31. package/dist/src/functions/update-scores.js +14 -14
  32. package/dist/src/functions/update-scores.js.map +1 -1
  33. package/dist/src/models/submission.js +13 -0
  34. package/dist/src/models/submission.js.map +1 -0
  35. package/dist/src/web/admin/announcements.js +45 -42
  36. package/dist/src/web/admin/announcements.js.map +1 -1
  37. package/dist/src/web/admin/contest-settings.js +19 -11
  38. package/dist/src/web/admin/contest-settings.js.map +1 -1
  39. package/dist/src/web/admin/context.js.map +1 -1
  40. package/dist/src/web/admin/dashboard.js +56 -35
  41. package/dist/src/web/admin/dashboard.js.map +1 -1
  42. package/dist/src/web/admin/export.js +100 -43
  43. package/dist/src/web/admin/export.js.map +1 -1
  44. package/dist/src/web/admin/layout.js +25 -21
  45. package/dist/src/web/admin/layout.js.map +1 -1
  46. package/dist/src/web/admin/provider.js +41 -21
  47. package/dist/src/web/admin/provider.js.map +1 -1
  48. package/dist/src/web/admin/school-table.js +20 -24
  49. package/dist/src/web/admin/school-table.js.map +1 -1
  50. package/dist/src/web/common/api.js +24 -20
  51. package/dist/src/web/common/api.js.map +1 -1
  52. package/dist/src/web/common/converters.js +38 -39
  53. package/dist/src/web/common/converters.js.map +1 -1
  54. package/dist/src/web/common/token-login.js +18 -18
  55. package/dist/src/web/common/token-login.js.map +1 -1
  56. package/dist/src/web/entry/admin.js +22 -13
  57. package/dist/src/web/entry/admin.js.map +1 -1
  58. package/dist/src/web/entry/student-statement.js +1 -1
  59. package/dist/src/web/entry/student-statement.js.map +1 -1
  60. package/dist/src/web/entry/student.js +80 -75
  61. package/dist/src/web/entry/student.js.map +1 -1
  62. package/dist/src/web/entry/teacher.js +63 -62
  63. package/dist/src/web/entry/teacher.js.map +1 -1
  64. package/package.json +13 -13
@@ -1,23 +1,23 @@
1
- import { existsSync as I } from "node:fs";
2
- import { readFile as b } from "node:fs/promises";
1
+ import { existsSync as b } from "node:fs";
2
+ import { readFile as I } from "node:fs/promises";
3
3
  import m from "node:path";
4
- import { contestSchema as $, participationSchema as g, studentSchema as C, variantsConfigSchema as j, variantSchema as V } from "@olinfo/quizms/models";
5
- import { Rng as M, validate as P } from "@olinfo/quizms/utils";
6
- import { fatal as u, warning as x, success as z, load as f, loadContests as v } from "@olinfo/quizms/utils-node";
4
+ import { contestSchema as $, venueSchema as g, studentSchema as C, variantsConfigSchema as j, variantSchema as V } from "@olinfo/quizms/models";
5
+ import { Rng as x, validate as z } from "@olinfo/quizms/utils";
6
+ import { fatal as w, warning as M, success as P, load as f, loadContests as v } from "@olinfo/quizms/utils-node";
7
7
  import { deleteApp as D } from "firebase-admin/app";
8
- import { groupBy as O, uniq as y } from "lodash-es";
9
- import U from "picomatch";
10
- import { glob as A } from "tinyglobby";
11
- import l from "zod";
12
- import { userSchema as N } from "../models/user.js";
8
+ import { groupBy as A, uniq as y } from "lodash-es";
9
+ import N from "picomatch";
10
+ import { glob as O } from "tinyglobby";
11
+ import u from "zod";
12
+ import { userSchema as U } from "../models/user.js";
13
13
  import { websiteSchema as k } from "../models/website.js";
14
- import { importCollection as w } from "./utils/collection.js";
15
- import { contestConverter as q, participationConverter as F, studentConverter as Q, variantConverter as B, websiteConverter as E } from "./utils/converters-admin.js";
16
- import { initializeFirebase as J } from "./utils/initialize.js";
17
- import { importStorage as R } from "./utils/storage.js";
14
+ import { importCollection as p } from "./utils/collection.js";
15
+ import { contestConverter as q, venueConverter as F, studentConverter as B, variantConverter as J, websiteConverter as Q } from "./utils/converters-admin.js";
16
+ import { initializeFirebase as R } from "./utils/initialize.js";
17
+ import { importStorage as W } from "./utils/storage.js";
18
18
  import { importUsers as S } from "./utils/users.js";
19
19
  async function ht(t) {
20
- if (process.env.QUIZMS_MODE = "contest", I("data") || u("Cannot find data directory. Make sure you're inside a QuizMS project."), [
20
+ if (b("data") || w("Cannot find data directory. Make sure you're inside a QuizMS project."), [
21
21
  "admins",
22
22
  "contests",
23
23
  "schools",
@@ -26,44 +26,44 @@ async function ht(t) {
26
26
  "teachers",
27
27
  "variants",
28
28
  "websites"
29
- ].every((n) => !t[n])) {
30
- x("`Nothing to import. Use `--help` for usage.`");
29
+ ].every((i) => !t[i])) {
30
+ M("`Nothing to import. Use `--help` for usage.`");
31
31
  return;
32
32
  }
33
- const { app: e, bucket: o, db: i } = await J();
34
- t.admins && await W(i, t), t.contests && await Z(i, t), (t.schools || t.teachers) && await _(i, t), t.students && await G(i, t), t.variants && await H(i, t), t.websites && await K(i, t), t.statements && await L(o, t), z("All done!"), await D(e);
33
+ const { app: n, bucket: o, db: s } = await R();
34
+ t.admins && await E(s, t), t.contests && await G(s, t), (t.schools || t.teachers) && await H(s, t), t.students && await K(s, t), t.variants && await L(s, t), t.websites && await T(s, t), t.statements && await X(o, t), P("All done!"), await D(n);
35
35
  }
36
- async function W(t, s) {
37
- const e = await f("admins", N.omit({ role: !0 }));
38
- await S(t, "admin", e, s);
36
+ async function E(t, e) {
37
+ const n = await f("admins", U.omit({ role: !0 }));
38
+ await S(t, "admin", n, e);
39
39
  }
40
- async function Z(t, s) {
41
- const e = await f("contests", $);
42
- await w(t, "contests", e, q, s);
40
+ async function G(t, e) {
41
+ const n = await f("contests", $);
42
+ await p(t, "contests", n, q, e);
43
43
  }
44
- async function _(t, s) {
45
- const e = g.omit({
44
+ async function H(t, e) {
45
+ const n = g.omit({
46
46
  schoolId: !0,
47
47
  contestId: !0
48
48
  }).extend({
49
- contestIds: l.union([l.string(), l.array(l.string())]).default("*"),
50
- password: l.string()
51
- }), o = await f("schools", e), i = await v();
52
- if (s.teachers) {
53
- const n = o.map((a) => ({
49
+ contestIds: u.union([u.string(), u.array(u.string())]).default("*"),
50
+ password: u.string()
51
+ }), o = await f("schools", n), s = await v();
52
+ if (e.teachers) {
53
+ const i = o.map((a) => ({
54
54
  name: a.name,
55
55
  username: a.id,
56
56
  password: a.password
57
57
  }));
58
- await S(t, "teacher", n, s);
58
+ await S(t, "teacher", i, e);
59
59
  }
60
- if (s.schools) {
61
- const n = [];
62
- for (const a of i)
60
+ if (e.schools) {
61
+ const i = [];
62
+ for (const a of s)
63
63
  for (const r of o) {
64
- if (!U.isMatch(a.id, r.contestIds)) continue;
65
- let c;
66
- a.hasVariants && (r.pdfVariants ? c = r.pdfVariants.map((d) => `${a.id}-${d}`) : c = new M(`${a.secret}-${a.id}-${r.id}-participation`).sample(a.pdfVariantIds, a.pdfPerSchool)), n.push({
64
+ if (!N.isMatch(a.id, r.contestIds)) continue;
65
+ let c = [];
66
+ a.hasVariants && (r.pdfVariants ? c = r.pdfVariants.map((d) => `${a.id}-${d}`) : c = new x(`${a.secret}-${a.id}-${r.id}-venue`).sample(a.pdfVariantIds, a.pdfPerSchool)), i.push({
67
67
  id: `${r.id}-${a.id}`,
68
68
  schoolId: r.id,
69
69
  contestId: a.id,
@@ -73,66 +73,60 @@ async function _(t, s) {
73
73
  disabled: !1
74
74
  });
75
75
  }
76
- await w(t, "participations", n, F, s);
76
+ await p(t, "venues", i, F, e);
77
77
  }
78
78
  }
79
- async function G(t, s) {
80
- const e = await f("students", C), o = O(e, "participationId");
79
+ async function K(t, e) {
80
+ const n = await f("students", C), o = A(n, "venueId");
81
81
  await Promise.all(
82
82
  Object.entries(o).map(
83
- ([i, n]) => w(
84
- t,
85
- `participations/${i}/students`,
86
- n,
87
- Q,
88
- s
89
- )
83
+ ([s, i]) => p(t, `venues/${s}/students`, i, B, e)
90
84
  )
91
85
  );
92
86
  }
93
- async function H(t, s) {
94
- const e = await f("variants", j), o = await Promise.all(
95
- e.flatMap((i) => y([...i.variantIds, ...i.pdfVariantIds]).map(async (a) => {
96
- const r = m.join("variants", i.id, a, "answers.json");
87
+ async function L(t, e) {
88
+ const n = await f("variants", j), o = await Promise.all(
89
+ n.flatMap((s) => y([...s.variantIds, ...s.pdfVariantIds]).map(async (a) => {
90
+ const r = m.join("variants", s.id, a, "answers.json");
97
91
  let c;
98
92
  try {
99
- c = await b(r, "utf8");
93
+ c = await I(r, "utf8");
100
94
  } catch {
101
- u(`Cannot find schema for variant ${a}. Use \`quizms variants\` to generate it.`);
95
+ w(`Cannot find schema for variant ${a}. Use \`quizms variants\` to generate it.`);
102
96
  }
103
97
  try {
104
- return P(V, JSON.parse(c));
98
+ return z(V, JSON.parse(c));
105
99
  } catch (d) {
106
- u(`Invalid schema for variant ${a}: ${d}`);
100
+ w(`Invalid schema for variant ${a}: ${d}`);
107
101
  }
108
102
  }))
109
103
  );
110
- await w(t, "variants", o, B, s);
104
+ await p(t, "variants", o, J, e);
111
105
  }
112
- async function K(t, s) {
113
- const e = await f("websites", k);
114
- await w(t, "websites", e, E, s);
106
+ async function T(t, e) {
107
+ const n = await f("websites", k);
108
+ await p(t, "websites", n, Q, e);
115
109
  }
116
- async function L(t, s) {
117
- const e = await v(), o = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-"), i = e.map(async (n) => {
118
- const a = y([...n.variantIds, ...n.pdfVariantIds]).map(
110
+ async function X(t, e) {
111
+ const n = await v(), o = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-"), s = n.map(async (i) => {
112
+ const a = y([...i.variantIds, ...i.pdfVariantIds]).map(
119
113
  async (r) => {
120
- const c = m.join("variants", n.id, r), d = m.join("statements", n.id, r);
121
- return (await A("*", { cwd: c })).flatMap((p) => {
122
- const h = m.extname(p);
114
+ const c = m.join("variants", i.id, r), d = m.join("statements", i.id, r);
115
+ return (await O("*.{pdf,js,css}", { cwd: c })).flatMap((l) => {
116
+ const h = m.extname(l);
123
117
  return [
124
118
  [
125
- m.join(c, p),
126
- m.join(d, `${m.basename(p, h)}-${o}${h}`)
119
+ m.join(c, l),
120
+ m.join(d, `${m.basename(l, h)}-${o}${h}`)
127
121
  ],
128
- [m.join(c, p), m.join(d, p)]
122
+ [m.join(c, l), m.join(d, l)]
129
123
  ];
130
124
  });
131
125
  }
132
126
  );
133
127
  return (await Promise.all(a)).flat();
134
128
  });
135
- await R(t, "statements", (await Promise.all(i)).flat(), s);
129
+ await W(t, "statements", (await Promise.all(s)).flat(), e);
136
130
  }
137
131
  export {
138
132
  ht as default
@@ -1 +1 @@
1
- {"version":3,"file":"import.js","sources":["../../../src/cli/import.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { Bucket } from \"@google-cloud/storage\";\nimport {\n contestSchema,\n type Participation,\n participationSchema,\n studentSchema,\n variantSchema,\n variantsConfigSchema,\n} from \"@olinfo/quizms/models\";\nimport { Rng, validate } from \"@olinfo/quizms/utils\";\nimport { fatal, load, loadContests, success, warning } from \"@olinfo/quizms/utils-node\";\nimport { deleteApp } from \"firebase-admin/app\";\nimport type { Firestore } from \"firebase-admin/firestore\";\nimport { groupBy, uniq } from \"lodash-es\";\nimport picomatch from \"picomatch\";\nimport { glob } from \"tinyglobby\";\nimport z from \"zod\";\n\nimport { userSchema } from \"~/models/user\";\nimport { websiteSchema } from \"~/models/website\";\n\nimport { importCollection } from \"./utils/collection\";\nimport {\n contestConverter,\n participationConverter,\n studentConverter,\n variantConverter,\n websiteConverter,\n} from \"./utils/converters-admin\";\nimport { initializeFirebase } from \"./utils/initialize\";\nimport { importStorage } from \"./utils/storage\";\nimport { importUsers } from \"./utils/users\";\n\ntype ImportOptions = {\n config: string;\n skipExisting?: true;\n delete?: true;\n force?: true;\n\n admins?: true;\n contests?: true;\n schools?: true;\n statements?: true;\n students?: true;\n teachers?: true;\n variants?: true;\n websites?: true;\n};\n\nexport default async function importData(options: ImportOptions) {\n process.env.QUIZMS_MODE = \"contest\";\n\n if (!existsSync(\"data\")) {\n fatal(\"Cannot find data directory. Make sure you're inside a QuizMS project.\");\n }\n\n const collections: (keyof ImportOptions)[] = [\n \"admins\",\n \"contests\",\n \"schools\",\n \"statements\",\n \"students\",\n \"teachers\",\n \"variants\",\n \"websites\",\n ];\n if (collections.every((key) => !options[key])) {\n warning(\"`Nothing to import. Use `--help` for usage.`\");\n return;\n }\n\n const { app, bucket, db } = await initializeFirebase();\n\n if (options.admins) {\n await importAdmins(db, options);\n }\n if (options.contests) {\n await importContests(db, options);\n }\n if (options.schools || options.teachers) {\n await importParticipations(db, options);\n }\n if (options.students) {\n await importStudents(db, options);\n }\n if (options.variants) {\n await importVariants(db, options);\n }\n if (options.websites) {\n await importWebsites(db, options);\n }\n if (options.statements) {\n await importStatements(bucket, options);\n }\n\n success(\"All done!\");\n await deleteApp(app);\n}\n\nasync function importAdmins(db: Firestore, options: ImportOptions) {\n const users = await load(\"admins\", userSchema.omit({ role: true }));\n await importUsers(db, \"admin\", users, options);\n}\n\nasync function importContests(db: Firestore, options: ImportOptions) {\n const contests = await load(\"contests\", contestSchema);\n await importCollection(db, \"contests\", contests, contestConverter, options);\n}\n\nasync function importParticipations(db: Firestore, options: ImportOptions) {\n const schoolSchema = participationSchema\n .omit({\n schoolId: true,\n contestId: true,\n })\n .extend({\n contestIds: z.union([z.string(), z.array(z.string())]).default(\"*\"),\n password: z.string(),\n });\n const schools = await load(\"schools\", schoolSchema);\n const contests = await loadContests();\n\n if (options.teachers) {\n const teachers = schools.map((school) => ({\n name: school.name,\n username: school.id,\n password: school.password,\n }));\n await importUsers(db, \"teacher\", teachers, options);\n }\n\n if (options.schools) {\n const participations: Participation[] = [];\n\n for (const contest of contests) {\n for (const school of schools) {\n if (!picomatch.isMatch(contest.id, school.contestIds)) continue;\n\n let pdfVariants: string[] | undefined;\n if (contest.hasVariants) {\n if (school.pdfVariants) {\n pdfVariants = school.pdfVariants.map((id) => `${contest.id}-${id}`);\n } else {\n const rng = new Rng(`${contest.secret}-${contest.id}-${school.id}-participation`);\n pdfVariants = rng.sample(contest.pdfVariantIds, contest.pdfPerSchool);\n }\n }\n\n participations.push({\n id: `${school.id}-${contest.id}`,\n schoolId: school.id,\n contestId: contest.id,\n name: school.name,\n finalized: false,\n pdfVariants,\n disabled: false,\n });\n }\n }\n\n await importCollection(db, \"participations\", participations, participationConverter, options);\n }\n}\n\nasync function importStudents(db: Firestore, options: ImportOptions) {\n const students = await load(\"students\", studentSchema);\n const participations = groupBy(students, \"participationId\");\n await Promise.all(\n Object.entries(participations).map(([participationId, students]) =>\n importCollection(\n db,\n `participations/${participationId}/students`,\n students,\n studentConverter,\n options,\n ),\n ),\n );\n}\n\nasync function importVariants(db: Firestore, options: ImportOptions) {\n const variantsConfig = await load(\"variants\", variantsConfigSchema);\n const variants = await Promise.all(\n variantsConfig.flatMap((config) => {\n const ids = uniq([...config.variantIds, ...config.pdfVariantIds]);\n return ids.map(async (id) => {\n const fileName = path.join(\"variants\", config.id, id, \"answers.json\");\n let schema: string;\n try {\n schema = await readFile(fileName, \"utf8\");\n } catch {\n fatal(`Cannot find schema for variant ${id}. Use \\`quizms variants\\` to generate it.`);\n }\n try {\n return validate(variantSchema, JSON.parse(schema));\n } catch (err) {\n fatal(`Invalid schema for variant ${id}: ${err}`);\n }\n });\n }),\n );\n await importCollection(db, \"variants\", variants, variantConverter, options);\n}\n\nasync function importWebsites(db: Firestore, options: ImportOptions) {\n const websites = await load(\"websites\", websiteSchema);\n await importCollection(db, \"websites\", websites, websiteConverter, options);\n}\n\nasync function importStatements(bucket: Bucket, options: ImportOptions) {\n const contests = await loadContests();\n\n const timestamp = new Date().toISOString().replace(/:/g, \"-\");\n\n const statements = contests.map(async (config) => {\n const files = uniq([...config.variantIds, ...config.pdfVariantIds]).map(\n async (id): Promise<[string, string][]> => {\n const localDir = path.join(\"variants\", config.id, id);\n const remoteDir = path.join(\"statements\", config.id, id);\n const files = await glob(\"*\", { cwd: localDir });\n\n return files.flatMap((file) => {\n const ext = path.extname(file);\n return [\n [\n path.join(localDir, file),\n path.join(remoteDir, `${path.basename(file, ext)}-${timestamp}${ext}`),\n ],\n [path.join(localDir, file), path.join(remoteDir, file)],\n ];\n });\n },\n );\n return (await Promise.all(files)).flat();\n });\n await importStorage(bucket, \"statements\", (await Promise.all(statements)).flat(), options);\n}\n"],"names":["importData","options","existsSync","fatal","key","warning","app","bucket","db","initializeFirebase","importAdmins","importContests","importParticipations","importStudents","importVariants","importWebsites","importStatements","success","deleteApp","users","load","userSchema","importUsers","contests","contestSchema","importCollection","contestConverter","schoolSchema","participationSchema","z","schools","loadContests","teachers","school","participations","contest","picomatch","pdfVariants","id","Rng","participationConverter","students","studentSchema","groupBy","participationId","studentConverter","variantsConfig","variantsConfigSchema","variants","config","uniq","fileName","path","schema","readFile","validate","variantSchema","err","variantConverter","websites","websiteSchema","websiteConverter","timestamp","statements","files","localDir","remoteDir","glob","file","ext","importStorage"],"mappings":"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"}
1
+ {"version":3,"file":"import.js","sources":["../../../src/cli/import.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { Bucket } from \"@google-cloud/storage\";\nimport {\n contestSchema,\n studentSchema,\n type Venue,\n variantSchema,\n variantsConfigSchema,\n venueSchema,\n} from \"@olinfo/quizms/models\";\nimport { Rng, validate } from \"@olinfo/quizms/utils\";\nimport { fatal, load, loadContests, success, warning } from \"@olinfo/quizms/utils-node\";\nimport { deleteApp } from \"firebase-admin/app\";\nimport type { Firestore } from \"firebase-admin/firestore\";\nimport { groupBy, uniq } from \"lodash-es\";\nimport picomatch from \"picomatch\";\nimport { glob } from \"tinyglobby\";\nimport z from \"zod\";\n\nimport { userSchema } from \"~/models/user\";\nimport { websiteSchema } from \"~/models/website\";\n\nimport { importCollection } from \"./utils/collection\";\nimport {\n contestConverter,\n studentConverter,\n variantConverter,\n venueConverter,\n websiteConverter,\n} from \"./utils/converters-admin\";\nimport { initializeFirebase } from \"./utils/initialize\";\nimport { importStorage } from \"./utils/storage\";\nimport { importUsers } from \"./utils/users\";\n\ntype ImportOptions = {\n config: string;\n skipExisting?: true;\n delete?: true;\n force?: true;\n\n admins?: true;\n contests?: true;\n schools?: true;\n statements?: true;\n students?: true;\n teachers?: true;\n variants?: true;\n websites?: true;\n};\n\nexport default async function importData(options: ImportOptions) {\n if (!existsSync(\"data\")) {\n fatal(\"Cannot find data directory. Make sure you're inside a QuizMS project.\");\n }\n\n const collections: (keyof ImportOptions)[] = [\n \"admins\",\n \"contests\",\n \"schools\",\n \"statements\",\n \"students\",\n \"teachers\",\n \"variants\",\n \"websites\",\n ];\n if (collections.every((key) => !options[key])) {\n warning(\"`Nothing to import. Use `--help` for usage.`\");\n return;\n }\n\n const { app, bucket, db } = await initializeFirebase();\n\n if (options.admins) {\n await importAdmins(db, options);\n }\n if (options.contests) {\n await importContests(db, options);\n }\n if (options.schools || options.teachers) {\n await importVenues(db, options);\n }\n if (options.students) {\n await importStudents(db, options);\n }\n if (options.variants) {\n await importVariants(db, options);\n }\n if (options.websites) {\n await importWebsites(db, options);\n }\n if (options.statements) {\n await importStatements(bucket, options);\n }\n\n success(\"All done!\");\n await deleteApp(app);\n}\n\nasync function importAdmins(db: Firestore, options: ImportOptions) {\n const users = await load(\"admins\", userSchema.omit({ role: true }));\n await importUsers(db, \"admin\", users, options);\n}\n\nasync function importContests(db: Firestore, options: ImportOptions) {\n const contests = await load(\"contests\", contestSchema);\n await importCollection(db, \"contests\", contests, contestConverter, options);\n}\n\nasync function importVenues(db: Firestore, options: ImportOptions) {\n const schoolSchema = venueSchema\n .omit({\n schoolId: true,\n contestId: true,\n })\n .extend({\n contestIds: z.union([z.string(), z.array(z.string())]).default(\"*\"),\n password: z.string(),\n });\n const schools = await load(\"schools\", schoolSchema);\n const contests = await loadContests();\n\n if (options.teachers) {\n const teachers = schools.map((school) => ({\n name: school.name,\n username: school.id,\n password: school.password,\n }));\n await importUsers(db, \"teacher\", teachers, options);\n }\n\n if (options.schools) {\n const venues: Venue[] = [];\n\n for (const contest of contests) {\n for (const school of schools) {\n if (!picomatch.isMatch(contest.id, school.contestIds)) continue;\n\n let pdfVariants: string[] = [];\n if (contest.hasVariants) {\n if (school.pdfVariants) {\n pdfVariants = school.pdfVariants.map((id) => `${contest.id}-${id}`);\n } else {\n const rng = new Rng(`${contest.secret}-${contest.id}-${school.id}-venue`);\n pdfVariants = rng.sample(contest.pdfVariantIds, contest.pdfPerSchool);\n }\n }\n\n venues.push({\n id: `${school.id}-${contest.id}`,\n schoolId: school.id,\n contestId: contest.id,\n name: school.name,\n finalized: false,\n pdfVariants,\n disabled: false,\n });\n }\n }\n\n await importCollection(db, \"venues\", venues, venueConverter, options);\n }\n}\n\nasync function importStudents(db: Firestore, options: ImportOptions) {\n const students = await load(\"students\", studentSchema);\n const venues = groupBy(students, \"venueId\");\n await Promise.all(\n Object.entries(venues).map(([venueId, students]) =>\n importCollection(db, `venues/${venueId}/students`, students, studentConverter, options),\n ),\n );\n}\n\nasync function importVariants(db: Firestore, options: ImportOptions) {\n const variantsConfig = await load(\"variants\", variantsConfigSchema);\n const variants = await Promise.all(\n variantsConfig.flatMap((config) => {\n const ids = uniq([...config.variantIds, ...config.pdfVariantIds]);\n return ids.map(async (id) => {\n const fileName = path.join(\"variants\", config.id, id, \"answers.json\");\n let schema: string;\n try {\n schema = await readFile(fileName, \"utf8\");\n } catch {\n fatal(`Cannot find schema for variant ${id}. Use \\`quizms variants\\` to generate it.`);\n }\n try {\n return validate(variantSchema, JSON.parse(schema));\n } catch (err) {\n fatal(`Invalid schema for variant ${id}: ${err}`);\n }\n });\n }),\n );\n await importCollection(db, \"variants\", variants, variantConverter, options);\n}\n\nasync function importWebsites(db: Firestore, options: ImportOptions) {\n const websites = await load(\"websites\", websiteSchema);\n await importCollection(db, \"websites\", websites, websiteConverter, options);\n}\n\nasync function importStatements(bucket: Bucket, options: ImportOptions) {\n const contests = await loadContests();\n\n const timestamp = new Date().toISOString().replace(/:/g, \"-\");\n\n const statements = contests.map(async (config) => {\n const files = uniq([...config.variantIds, ...config.pdfVariantIds]).map(\n async (id): Promise<[string, string][]> => {\n const localDir = path.join(\"variants\", config.id, id);\n const remoteDir = path.join(\"statements\", config.id, id);\n const files = await glob(\"*.{pdf,js,css}\", { cwd: localDir });\n\n return files.flatMap((file) => {\n const ext = path.extname(file);\n return [\n [\n path.join(localDir, file),\n path.join(remoteDir, `${path.basename(file, ext)}-${timestamp}${ext}`),\n ],\n [path.join(localDir, file), path.join(remoteDir, file)],\n ];\n });\n },\n );\n return (await Promise.all(files)).flat();\n });\n await importStorage(bucket, \"statements\", (await Promise.all(statements)).flat(), options);\n}\n"],"names":["importData","options","existsSync","fatal","key","warning","app","bucket","db","initializeFirebase","importAdmins","importContests","importVenues","importStudents","importVariants","importWebsites","importStatements","success","deleteApp","users","load","userSchema","importUsers","contests","contestSchema","importCollection","contestConverter","schoolSchema","venueSchema","z","schools","loadContests","teachers","school","venues","contest","picomatch","pdfVariants","id","Rng","venueConverter","students","studentSchema","groupBy","venueId","studentConverter","variantsConfig","variantsConfigSchema","variants","config","uniq","fileName","path","schema","readFile","validate","variantSchema","err","variantConverter","websites","websiteSchema","websiteConverter","timestamp","statements","files","localDir","remoteDir","glob","file","ext","importStorage"],"mappings":"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"}
@@ -1,20 +1,20 @@
1
- import { calcScore as d } from "@olinfo/quizms/models";
1
+ import { calcScore as u } from "@olinfo/quizms/models";
2
2
  import { info as f, withProgress as p } from "@olinfo/quizms/utils-node";
3
3
  import { variantConverter as m, studentConverter as v } from "./utils/converters-admin.js";
4
- import { initializeFirebase as l } from "./utils/initialize.js";
4
+ import { initializeFirebase as w } from "./utils/initialize.js";
5
5
  async function y() {
6
- const { db: n } = await l();
6
+ const { db: n } = await w();
7
7
  f("Updating student scores.");
8
- const s = await n.collection("variants").withConverter(m).get(), c = Object.fromEntries(s.docs.map((t) => [t.id, t.data()])), r = n.collectionGroup("students").withConverter(v), u = await r.count().get();
8
+ const s = await n.collection("variants").withConverter(m).get(), c = Object.fromEntries(s.docs.map((t) => [t.id, t.data()])), r = n.collectionGroup("students").withConverter(v), d = await r.count().get();
9
9
  await p(
10
10
  r.stream(),
11
- u.data().count,
11
+ d.data().count,
12
12
  async (t) => {
13
13
  const e = t.ref;
14
14
  await n.runTransaction(async (o) => {
15
15
  const a = (await o.get(e)).data();
16
- if (!a?.variant) return;
17
- const i = d(a, c[a.variant]?.schema) ?? null;
16
+ if (!a?.variantId) return;
17
+ const i = u(a, c[a.variantId]?.schema);
18
18
  i !== a.score && o.update(e, { score: i });
19
19
  });
20
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"update-scores.js","sources":["../../../src/cli/update-scores.ts"],"sourcesContent":["import { calcScore, type Student } from \"@olinfo/quizms/models\";\nimport { info, withProgress } from \"@olinfo/quizms/utils-node\";\nimport type { QueryDocumentSnapshot } from \"firebase-admin/firestore\";\n\nimport { studentConverter, variantConverter } from \"./utils/converters-admin\";\nimport { initializeFirebase } from \"./utils/initialize\";\n\nexport default async function updateScores() {\n const { db } = await initializeFirebase();\n\n info(\"Updating student scores.\");\n\n const variantRef = db.collection(\"variants\").withConverter(variantConverter);\n const variantSnap = await variantRef.get();\n const variants = Object.fromEntries(variantSnap.docs.map((doc) => [doc.id, doc.data()]));\n\n const ref = db.collectionGroup(\"students\").withConverter(studentConverter);\n\n const count = await ref.count().get();\n await withProgress(\n ref.stream() as AsyncIterable<QueryDocumentSnapshot<Student>>,\n count.data().count,\n async (snapshot) => {\n const ref = snapshot.ref;\n await db.runTransaction(async (t) => {\n const studentSnap = await t.get(ref);\n const student = studentSnap.data();\n if (!student?.variant) return;\n const score = calcScore(student, variants[student.variant]?.schema) ?? null;\n if (score !== student.score) {\n t.update(ref, { score });\n }\n });\n },\n );\n}\n"],"names":["updateScores","db","initializeFirebase","info","variantSnap","variantConverter","variants","doc","ref","studentConverter","count","withProgress","snapshot","t","student","score","calcScore"],"mappings":";;;;AAOA,eAA8BA,IAAe;AAC3C,QAAM,EAAE,IAAAC,MAAO,MAAMC,EAAA;AAErB,EAAAC,EAAK,0BAA0B;AAG/B,QAAMC,IAAc,MADDH,EAAG,WAAW,UAAU,EAAE,cAAcI,CAAgB,EACtC,IAAA,GAC/BC,IAAW,OAAO,YAAYF,EAAY,KAAK,IAAI,CAACG,MAAQ,CAACA,EAAI,IAAIA,EAAI,KAAA,CAAM,CAAC,CAAC,GAEjFC,IAAMP,EAAG,gBAAgB,UAAU,EAAE,cAAcQ,CAAgB,GAEnEC,IAAQ,MAAMF,EAAI,MAAA,EAAQ,IAAA;AAChC,QAAMG;AAAA,IACJH,EAAI,OAAA;AAAA,IACJE,EAAM,OAAO;AAAA,IACb,OAAOE,MAAa;AAClB,YAAMJ,IAAMI,EAAS;AACrB,YAAMX,EAAG,eAAe,OAAOY,MAAM;AAEnC,cAAMC,KADc,MAAMD,EAAE,IAAIL,CAAG,GACP,KAAA;AAC5B,YAAI,CAACM,GAAS,QAAS;AACvB,cAAMC,IAAQC,EAAUF,GAASR,EAASQ,EAAQ,OAAO,GAAG,MAAM,KAAK;AACvE,QAAIC,MAAUD,EAAQ,SACpBD,EAAE,OAAOL,GAAK,EAAE,OAAAO,EAAA,CAAO;AAAA,MAE3B,CAAC;AAAA,IACH;AAAA,EAAA;AAEJ;"}
1
+ {"version":3,"file":"update-scores.js","sources":["../../../src/cli/update-scores.ts"],"sourcesContent":["import { calcScore, type Student } from \"@olinfo/quizms/models\";\nimport { info, withProgress } from \"@olinfo/quizms/utils-node\";\nimport type { QueryDocumentSnapshot } from \"firebase-admin/firestore\";\n\nimport { studentConverter, variantConverter } from \"./utils/converters-admin\";\nimport { initializeFirebase } from \"./utils/initialize\";\n\nexport default async function updateScores() {\n const { db } = await initializeFirebase();\n\n info(\"Updating student scores.\");\n\n const variantRef = db.collection(\"variants\").withConverter(variantConverter);\n const variantSnap = await variantRef.get();\n const variants = Object.fromEntries(variantSnap.docs.map((doc) => [doc.id, doc.data()]));\n\n const ref = db.collectionGroup(\"students\").withConverter(studentConverter);\n\n const count = await ref.count().get();\n await withProgress(\n ref.stream() as AsyncIterable<QueryDocumentSnapshot<Student>>,\n count.data().count,\n async (snapshot) => {\n const ref = snapshot.ref;\n await db.runTransaction(async (t) => {\n const studentSnap = await t.get(ref);\n const student = studentSnap.data();\n if (!student?.variantId) return;\n const score = calcScore(student, variants[student.variantId]?.schema);\n if (score !== student.score) {\n t.update(ref, { score });\n }\n });\n },\n );\n}\n"],"names":["updateScores","db","initializeFirebase","info","variantSnap","variantConverter","variants","doc","ref","studentConverter","count","withProgress","snapshot","t","student","score","calcScore"],"mappings":";;;;AAOA,eAA8BA,IAAe;AAC3C,QAAM,EAAE,IAAAC,MAAO,MAAMC,EAAA;AAErB,EAAAC,EAAK,0BAA0B;AAG/B,QAAMC,IAAc,MADDH,EAAG,WAAW,UAAU,EAAE,cAAcI,CAAgB,EACtC,IAAA,GAC/BC,IAAW,OAAO,YAAYF,EAAY,KAAK,IAAI,CAACG,MAAQ,CAACA,EAAI,IAAIA,EAAI,KAAA,CAAM,CAAC,CAAC,GAEjFC,IAAMP,EAAG,gBAAgB,UAAU,EAAE,cAAcQ,CAAgB,GAEnEC,IAAQ,MAAMF,EAAI,MAAA,EAAQ,IAAA;AAChC,QAAMG;AAAA,IACJH,EAAI,OAAA;AAAA,IACJE,EAAM,OAAO;AAAA,IACb,OAAOE,MAAa;AAClB,YAAMJ,IAAMI,EAAS;AACrB,YAAMX,EAAG,eAAe,OAAOY,MAAM;AAEnC,cAAMC,KADc,MAAMD,EAAE,IAAIL,CAAG,GACP,KAAA;AAC5B,YAAI,CAACM,GAAS,UAAW;AACzB,cAAMC,IAAQC,EAAUF,GAASR,EAASQ,EAAQ,SAAS,GAAG,MAAM;AACpE,QAAIC,MAAUD,EAAQ,SACpBD,EAAE,OAAOL,GAAK,EAAE,OAAAO,EAAA,CAAO;AAAA,MAE3B,CAAC;AAAA,IACH;AAAA,EAAA;AAEJ;"}
@@ -1,42 +1,43 @@
1
- import { contestSchema as c, participationSchema as m, studentSchema as s, variantSchema as a } from "@olinfo/quizms/models";
1
+ import { contestSchema as m, venueSchema as s, studentSchema as c, variantSchema as a } from "@olinfo/quizms/models";
2
2
  import { validate as f } from "@olinfo/quizms/utils";
3
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))
4
+ import { cloneDeepWith as n, omit as u, isDate as p, isString as v } from "lodash-es";
5
+ import { submissionSchema as S } from "../../models/submission.js";
6
+ import { userSchema as d } from "../../models/user.js";
7
+ import { websiteSchema as h } from "../../models/website.js";
8
+ function C(r) {
9
+ return n(u(r, "id"), (t) => {
10
+ if (p(t))
10
11
  return o.fromDate(t);
11
- if (d(t))
12
+ if (v(t))
12
13
  return t.trim();
13
- if (t === void 0)
14
- return null;
15
14
  });
16
15
  }
17
- function C(r) {
16
+ function F(r) {
18
17
  return n(r, (t) => {
19
18
  if (t instanceof o)
20
19
  return t.toDate();
21
20
  });
22
21
  }
23
- function F(r, t) {
24
- const i = C({ ...t.data(), id: t.id });
22
+ function b(r, t) {
23
+ const i = F({ ...t.data(), id: t.id });
25
24
  return f(r, i);
26
25
  }
27
26
  function e(r) {
28
27
  return {
29
- toFirestore: (t) => h(t),
30
- fromFirestore: (t) => F(r, t)
28
+ toFirestore: (t) => C(t),
29
+ fromFirestore: (t) => b(r, t)
31
30
  };
32
31
  }
33
- const W = e(c), j = e(m), k = e(s), q = e(v), y = e(a), z = e(S);
32
+ const k = e(m), q = e(s), y = e(c), z = e(S), A = e(d), B = e(a), E = e(h);
34
33
  export {
35
- W as contestConverter,
36
- j as participationConverter,
37
- k as studentConverter,
38
- q as userConverter,
39
- y as variantConverter,
40
- z as websiteConverter
34
+ k as contestConverter,
35
+ b as parseSnapshot,
36
+ y as studentConverter,
37
+ z as submissionConverter,
38
+ A as userConverter,
39
+ B as variantConverter,
40
+ q as venueConverter,
41
+ E as websiteConverter
41
42
  };
42
43
  //# 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, 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
+ {"version":3,"file":"converters-admin.js","sources":["../../../../src/cli/utils/converters-admin.ts"],"sourcesContent":["import { contestSchema, studentSchema, variantSchema, venueSchema } 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 { submissionSchema } from \"~/models/submission\";\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 });\n}\n\nfunction convertFromFirestore(data: object) {\n return cloneDeepWith(data, (value) => {\n if (value instanceof Timestamp) {\n return value.toDate();\n }\n });\n}\n\nexport function parseSnapshot<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) => parseSnapshot(schema, snapshot),\n };\n}\n\nexport const contestConverter = converter(contestSchema);\nexport const venueConverter = converter(venueSchema);\nexport const studentConverter = converter(studentSchema);\nexport const submissionConverter = converter(submissionSchema);\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","parseSnapshot","schema","snapshot","validate","converter","contestConverter","contestSchema","venueConverter","venueSchema","studentConverter","studentSchema","submissionConverter","submissionSchema","userConverter","userSchema","variantConverter","variantSchema","websiteConverter","websiteSchema"],"mappings":";;;;;;;AAcA,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;AAAA,EAEjB,CAAC;AACH;AAEA,SAASI,EAAqBP,GAAc;AAC1C,SAAOC,EAAcD,GAAM,CAACG,MAAU;AACpC,QAAIA,aAAiBE;AACnB,aAAOF,EAAM,OAAA;AAAA,EAEjB,CAAC;AACH;AAEO,SAASK,EAAiBC,GAA4BC,GAA+B;AAC1F,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,EAAcC,GAAQC,CAAQ;AAAA,EAAA;AAE/D;AAEO,MAAMG,IAAmBD,EAAUE,CAAa,GAC1CC,IAAiBH,EAAUI,CAAW,GACtCC,IAAmBL,EAAUM,CAAa,GAC1CC,IAAsBP,EAAUQ,CAAgB,GAChDC,IAAgBT,EAAUU,CAAU,GACpCC,IAAmBX,EAAUY,CAAa,GAC1CC,IAAmBb,EAAUc,CAAa;"}
@@ -1,26 +1,26 @@
1
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();
2
+ import i from "express";
3
+ import { logger as n } from "firebase-functions/logger";
4
+ import { adminLogin as s } from "./admin.js";
5
+ import { studentLogin as m } from "./student.js";
6
+ import { teacherFinalizeVenue as c, teacherStopContestWindow as f, teacherStartContestWindow as u, teacherLogin as d } from "./teacher.js";
7
+ import { router as g, createContext as x } from "./trpc.js";
8
+ const h = g({
9
+ adminLogin: s,
10
+ studentLogin: m,
11
+ teacherLogin: d,
12
+ teacherStartContestWindow: u,
13
+ teacherStopContestWindow: f,
14
+ teacherFinalizeVenue: c
15
+ }), l = i();
16
16
  l.use(
17
17
  "/",
18
18
  a.createExpressMiddleware({
19
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 });
20
+ createContext: x,
21
+ onError(e) {
22
+ const { error: r, path: t, input: o, ctx: p } = e;
23
+ n.error(r.message, { error: r, path: t, input: o, ctx: p });
24
24
  }
25
25
  })
26
26
  );
@@ -1 +1 @@
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;"}
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 teacherFinalizeVenue,\n teacherLogin,\n teacherStartContestWindow,\n teacherStopContestWindow,\n} from \"./teacher\";\nimport { createContext, router } from \"./trpc\";\n\nconst appRouter = router({\n adminLogin,\n studentLogin,\n teacherLogin,\n teacherStartContestWindow,\n teacherStopContestWindow,\n teacherFinalizeVenue,\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","teacherStartContestWindow","teacherStopContestWindow","teacherFinalizeVenue","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,sBAAAC;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;"}
@@ -1,36 +1,36 @@
1
- import { Rng as i } from "@olinfo/quizms/utils";
2
- import { userConverter as c, participationConverter as o, contestConverter as p, studentConverter as a, variantConverter as h } from "../../cli/utils/converters-admin.js";
3
- import { db as e } from "../common.js";
4
- const u = new i();
5
- async function v(t) {
6
- return (await e.doc(`contests/${t}`).withConverter(p).get()).data();
1
+ import { Rng as c } from "@olinfo/quizms/utils";
2
+ import { userConverter as i, venueConverter as o, contestConverter as u, studentConverter as s, variantConverter as h } from "../../cli/utils/converters-admin.js";
3
+ import { db as n } from "../common.js";
4
+ const d = new c();
5
+ async function g(t) {
6
+ return (await n.doc(`contests/${t}`).withConverter(u).get()).data();
7
7
  }
8
8
  async function C(t) {
9
- return (await e.doc(`participations/${t}`).withConverter(o).get()).data();
9
+ return (await n.doc(`venues/${t}`).withConverter(o).get()).data();
10
10
  }
11
- async function l(t, n) {
12
- return (await e.collection(`participations/${t}/students`).where("token", "==", n).withConverter(a).get()).docs.map((r) => r.data());
11
+ async function l(t, e) {
12
+ return (await n.collection(`venues/${t}/students`).where("token", "==", e).withConverter(s).get()).docs.map((a) => a.data());
13
13
  }
14
14
  async function f(t) {
15
- return (await e.collection("participations").withConverter(o).where("token", "==", t).get()).docs[0]?.data();
15
+ return (await n.collection("venues").withConverter(o).where("token", "==", t).get()).docs[0]?.data();
16
16
  }
17
17
  async function m(t) {
18
- return (await e.collection("users").where("username", "==", t).withConverter(c).get()).docs[0]?.data();
18
+ return (await n.collection("users").where("username", "==", t).withConverter(i).get()).docs[0]?.data();
19
19
  }
20
20
  async function y(t) {
21
- const n = await e.collection("variants").withConverter(h).where("contestId", "==", t).where("isOnline", "==", !0).get();
22
- return u.choice(n.docs).data();
21
+ const e = await n.collection("variants").withConverter(h).where("contestId", "==", t).where("isOnline", "==", !0).get();
22
+ return d.choice(e.docs).data();
23
23
  }
24
- async function $(t, n) {
25
- return (await e.collection(`participations/${t}/students`).withConverter(a).where("userDataHash", "==", n).where("disabled", "!=", !0).get()).docs[0]?.data();
24
+ async function V(t, e) {
25
+ return (await n.collection(`venues/${t}/students`).withConverter(s).where("userDataHash", "==", e).where("disabled", "!=", !0).get()).docs[0]?.data();
26
26
  }
27
27
  export {
28
- v as getContest,
29
- C as getParticipation,
30
- f as getParticipationByToken,
31
- l as getParticipationStudents,
28
+ g as getContest,
32
29
  y as getRandomVariant,
33
- $ as getStudentByHash,
34
- m as getUser
30
+ V as getStudentByHash,
31
+ m as getUser,
32
+ C as getVenue,
33
+ f as getVenueByToken,
34
+ l as getVenueStudents
35
35
  };
36
36
  //# sourceMappingURL=queries.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"queries.js","sources":["../../../../src/functions/api/queries.ts"],"sourcesContent":["import { Rng } from \"@olinfo/quizms/utils\";\n\nimport {\n contestConverter,\n participationConverter,\n studentConverter,\n userConverter,\n variantConverter,\n} from \"~/cli/utils/converters-admin\";\nimport { db } from \"~/functions/common\";\n\nconst rng = new Rng();\n\nexport async function getContest(contestId: string) {\n const snapshot = await db.doc(`contests/${contestId}`).withConverter(contestConverter).get();\n return snapshot.data()!;\n}\n\nexport async function getParticipation(participationId: string) {\n const snapshot = await db\n .doc(`participations/${participationId}`)\n .withConverter(participationConverter)\n .get();\n return snapshot.data();\n}\n\nexport async function getParticipationStudents(participationId: string, token: string) {\n const snapshot = await db\n .collection(`participations/${participationId}/students`)\n .where(\"token\", \"==\", token)\n .withConverter(studentConverter)\n .get();\n return snapshot.docs.map((doc) => doc.data());\n}\n\nexport async function getParticipationByToken(token: string) {\n const snapshot = await db\n .collection(\"participations\")\n .withConverter(participationConverter)\n .where(\"token\", \"==\", token)\n .get();\n return snapshot.docs[0]?.data();\n}\n\nexport async function getUser(username: string) {\n const snapshot = await db\n .collection(\"users\")\n .where(\"username\", \"==\", username)\n .withConverter(userConverter)\n .get();\n return snapshot.docs[0]?.data();\n}\n\nexport async function getRandomVariant(contestId: string) {\n const snapshot = await db\n .collection(\"variants\")\n .withConverter(variantConverter)\n .where(\"contestId\", \"==\", contestId)\n .where(\"isOnline\", \"==\", true)\n .get();\n return rng.choice(snapshot.docs).data();\n}\nexport async function getStudentByHash(participationId: string, userDataHash: string) {\n const snapshot = await db\n .collection(`participations/${participationId}/students`)\n .withConverter(studentConverter)\n .where(\"userDataHash\", \"==\", userDataHash)\n .where(\"disabled\", \"!=\", true)\n .get();\n return snapshot.docs[0]?.data();\n}\n"],"names":["rng","Rng","getContest","contestId","db","contestConverter","getParticipation","participationId","participationConverter","getParticipationStudents","token","studentConverter","doc","getParticipationByToken","getUser","username","userConverter","getRandomVariant","snapshot","variantConverter","getStudentByHash","userDataHash"],"mappings":";;;AAWA,MAAMA,IAAM,IAAIC,EAAA;AAEhB,eAAsBC,EAAWC,GAAmB;AAElD,UADiB,MAAMC,EAAG,IAAI,YAAYD,CAAS,EAAE,EAAE,cAAcE,CAAgB,EAAE,IAAA,GACvE,KAAA;AAClB;AAEA,eAAsBC,EAAiBC,GAAyB;AAK9D,UAJiB,MAAMH,EACpB,IAAI,kBAAkBG,CAAe,EAAE,EACvC,cAAcC,CAAsB,EACpC,IAAA,GACa,KAAA;AAClB;AAEA,eAAsBC,EAAyBF,GAAyBG,GAAe;AAMrF,UALiB,MAAMN,EACpB,WAAW,kBAAkBG,CAAe,WAAW,EACvD,MAAM,SAAS,MAAMG,CAAK,EAC1B,cAAcC,CAAgB,EAC9B,IAAA,GACa,KAAK,IAAI,CAACC,MAAQA,EAAI,MAAM;AAC9C;AAEA,eAAsBC,EAAwBH,GAAe;AAM3D,UALiB,MAAMN,EACpB,WAAW,gBAAgB,EAC3B,cAAcI,CAAsB,EACpC,MAAM,SAAS,MAAME,CAAK,EAC1B,IAAA,GACa,KAAK,CAAC,GAAG,KAAA;AAC3B;AAEA,eAAsBI,EAAQC,GAAkB;AAM9C,UALiB,MAAMX,EACpB,WAAW,OAAO,EAClB,MAAM,YAAY,MAAMW,CAAQ,EAChC,cAAcC,CAAa,EAC3B,IAAA,GACa,KAAK,CAAC,GAAG,KAAA;AAC3B;AAEA,eAAsBC,EAAiBd,GAAmB;AACxD,QAAMe,IAAW,MAAMd,EACpB,WAAW,UAAU,EACrB,cAAce,CAAgB,EAC9B,MAAM,aAAa,MAAMhB,CAAS,EAClC,MAAM,YAAY,MAAM,EAAI,EAC5B,IAAA;AACH,SAAOH,EAAI,OAAOkB,EAAS,IAAI,EAAE,KAAA;AACnC;AACA,eAAsBE,EAAiBb,GAAyBc,GAAsB;AAOpF,UANiB,MAAMjB,EACpB,WAAW,kBAAkBG,CAAe,WAAW,EACvD,cAAcI,CAAgB,EAC9B,MAAM,gBAAgB,MAAMU,CAAY,EACxC,MAAM,YAAY,MAAM,EAAI,EAC5B,IAAA,GACa,KAAK,CAAC,GAAG,KAAA;AAC3B;"}
1
+ {"version":3,"file":"queries.js","sources":["../../../../src/functions/api/queries.ts"],"sourcesContent":["import { Rng } from \"@olinfo/quizms/utils\";\n\nimport {\n contestConverter,\n studentConverter,\n userConverter,\n variantConverter,\n venueConverter,\n} from \"~/cli/utils/converters-admin\";\nimport { db } from \"~/functions/common\";\n\nconst rng = new Rng();\n\nexport async function getContest(contestId: string) {\n const snapshot = await db.doc(`contests/${contestId}`).withConverter(contestConverter).get();\n return snapshot.data()!;\n}\n\nexport async function getVenue(venueId: string) {\n const snapshot = await db.doc(`venues/${venueId}`).withConverter(venueConverter).get();\n return snapshot.data();\n}\n\nexport async function getVenueStudents(venueId: string, token: string) {\n const snapshot = await db\n .collection(`venues/${venueId}/students`)\n .where(\"token\", \"==\", token)\n .withConverter(studentConverter)\n .get();\n return snapshot.docs.map((doc) => doc.data());\n}\n\nexport async function getVenueByToken(token: string) {\n const snapshot = await db\n .collection(\"venues\")\n .withConverter(venueConverter)\n .where(\"token\", \"==\", token)\n .get();\n return snapshot.docs[0]?.data();\n}\n\nexport async function getUser(username: string) {\n const snapshot = await db\n .collection(\"users\")\n .where(\"username\", \"==\", username)\n .withConverter(userConverter)\n .get();\n return snapshot.docs[0]?.data();\n}\n\nexport async function getRandomVariant(contestId: string) {\n const snapshot = await db\n .collection(\"variants\")\n .withConverter(variantConverter)\n .where(\"contestId\", \"==\", contestId)\n .where(\"isOnline\", \"==\", true)\n .get();\n return rng.choice(snapshot.docs).data();\n}\nexport async function getStudentByHash(venueId: string, userDataHash: string) {\n const snapshot = await db\n .collection(`venues/${venueId}/students`)\n .withConverter(studentConverter)\n .where(\"userDataHash\", \"==\", userDataHash)\n .where(\"disabled\", \"!=\", true)\n .get();\n return snapshot.docs[0]?.data();\n}\n"],"names":["rng","Rng","getContest","contestId","db","contestConverter","getVenue","venueId","venueConverter","getVenueStudents","token","studentConverter","doc","getVenueByToken","getUser","username","userConverter","getRandomVariant","snapshot","variantConverter","getStudentByHash","userDataHash"],"mappings":";;;AAWA,MAAMA,IAAM,IAAIC,EAAA;AAEhB,eAAsBC,EAAWC,GAAmB;AAElD,UADiB,MAAMC,EAAG,IAAI,YAAYD,CAAS,EAAE,EAAE,cAAcE,CAAgB,EAAE,IAAA,GACvE,KAAA;AAClB;AAEA,eAAsBC,EAASC,GAAiB;AAE9C,UADiB,MAAMH,EAAG,IAAI,UAAUG,CAAO,EAAE,EAAE,cAAcC,CAAc,EAAE,IAAA,GACjE,KAAA;AAClB;AAEA,eAAsBC,EAAiBF,GAAiBG,GAAe;AAMrE,UALiB,MAAMN,EACpB,WAAW,UAAUG,CAAO,WAAW,EACvC,MAAM,SAAS,MAAMG,CAAK,EAC1B,cAAcC,CAAgB,EAC9B,IAAA,GACa,KAAK,IAAI,CAACC,MAAQA,EAAI,MAAM;AAC9C;AAEA,eAAsBC,EAAgBH,GAAe;AAMnD,UALiB,MAAMN,EACpB,WAAW,QAAQ,EACnB,cAAcI,CAAc,EAC5B,MAAM,SAAS,MAAME,CAAK,EAC1B,IAAA,GACa,KAAK,CAAC,GAAG,KAAA;AAC3B;AAEA,eAAsBI,EAAQC,GAAkB;AAM9C,UALiB,MAAMX,EACpB,WAAW,OAAO,EAClB,MAAM,YAAY,MAAMW,CAAQ,EAChC,cAAcC,CAAa,EAC3B,IAAA,GACa,KAAK,CAAC,GAAG,KAAA;AAC3B;AAEA,eAAsBC,EAAiBd,GAAmB;AACxD,QAAMe,IAAW,MAAMd,EACpB,WAAW,UAAU,EACrB,cAAce,CAAgB,EAC9B,MAAM,aAAa,MAAMhB,CAAS,EAClC,MAAM,YAAY,MAAM,EAAI,EAC5B,IAAA;AACH,SAAOH,EAAI,OAAOkB,EAAS,IAAI,EAAE,KAAA;AACnC;AACA,eAAsBE,EAAiBb,GAAiBc,GAAsB;AAO5E,UANiB,MAAMjB,EACpB,WAAW,UAAUG,CAAO,WAAW,EACvC,cAAcI,CAAgB,EAC9B,MAAM,gBAAgB,MAAMU,CAAY,EACxC,MAAM,YAAY,MAAM,EAAI,EAC5B,IAAA,GACa,KAAK,CAAC,GAAG,KAAA;AAC3B;"}