diff options
Diffstat (limited to 'src/graduation-common.js')
| -rw-r--r-- | src/graduation-common.js | 396 |
1 files changed, 0 insertions, 396 deletions
diff --git a/src/graduation-common.js b/src/graduation-common.js deleted file mode 100644 index 0c28465..0000000 --- a/src/graduation-common.js +++ /dev/null @@ -1,396 +0,0 @@ -import { getSubmitDb, loadFromStudentDatabase, addEntryToStudentDatabase } from "./database.js" - -import NeulingPng from "../assets/Neuling.png"; -import EntdeckerPng from "../assets/Entdecker.png"; -import NavigatorPng from "../assets/Navigator.png"; -import PioneerPng from "../assets/Pioneer.png"; - -const LEVEL_NAMES = ["Neuling", "Entdecker", "Navigator", "Pionieer"]; - -const LEVEL_IMAGES = [ - new URL(NeulingPng), - new URL(EntdeckerPng), - new URL(NavigatorPng), - new URL(PioneerPng), -]; - -class GraduationChange { - constructor(date, change, reason, coach, context) { - this.date = date; - this.change = change; - this.reason = reason; - this.coach = coach; - this.context = context; - } - - isPublic() { - return [ - "Grün", "Orange", "Rot", - "ObservationStart", "ObservationEnd", - "LevelChange" - ].includes(this.change); - } - - publicDBFields () { - return { - "change": this.change, - "date": this.date, - }; - } - - dbFields () { - return { - // We include the date in the json because Moodle reports the timeadded - // locale dependent. - "date": this.date, - "change": this.change, - "reason": this.reason, - "context": this.context, - }; - } - - static fromDBEntry(e) { - const {coach, json} = e; - const change = JSON.parse(json); - return new GraduationChange(new Date(change.date), change.change, change.reason, coach, change.context); - } - - static newObservationRequest() { - return new GraduationChange(new Date(), "ObservationRequest", "", "", ""); - } - - static newObservationStart() { - return new GraduationChange(new Date(), "ObservationStart", "", "", ""); - } - - static newObservationEnd(reason, success) { - return new GraduationChange(new Date(), "ObservationEnd", reason, "", JSON.stringify(success)); - } - - static newObservationChange(observation) { - return new GraduationChange(observation.date, "Observation", "", "", JSON.stringify(observation.status)); - } - - static newGreenPointChange(reason, coach) { - return new GraduationChange(new Date(), "Grün", reason, coach, ""); - } - - static newOrangePointChange(reason, coach) { - return new GraduationChange(new Date(), "Orange", reason, coach, ""); - } - - static newRedPointChange(reason, coach) { - return new GraduationChange(new Date(), "Rot", reason, coach, ""); - } -} - -class Graduation { - constructor(student, green, orange, red, level, stickers, observationRequested, observation, pastObservations, changes) { - this.student = student; - this.green = green; - this.orange = orange; - this.red = red; - this.level = level; - this.stickers = stickers; - this.observationRequested = observationRequested; - this.observation = observation; - this.pastObservations = pastObservations; - this.changes = changes; - - student.graduation = this; - } - - static from(student, changes) { - let green = 0; - let orange = 0; - let red = 0; - let level = 1; - let openObservationRequest = null; - let observationPeriod = null; - let pastObservations = []; - let stickers = []; - - // The parsing logic assumes that changes are ordered chronologically - changes.sort((a, b) => a.date - b.date); - - for (const change of changes) { - switch (change.change) { - case "Grün": - green++; - break; - - case "Orange": - orange++; - break; - - case "Rot": - red++; - break; - - case "ObservationRequest": - openObservationRequest = change.date; - break; - - case "ObservationStart": - console.assert(openObservationRequest, "No request for observation start"); - observationPeriod = new ObservationPeriod(change.date); - openObservationRequest = null; - break; - - case "ObservationEnd": - console.assert(observationPeriod, "No active observation period"); - observationPeriod.finishPeriod(change.context.success); - if (change.context.success) { - level++; - } - pastObservations.push(observationPeriod); - observationPeriod = null; - break; - - case "Observation": - console.assert(observationPeriod, "No active observation period"); - const observation = Observation.fromChange(change); - observationPeriod.addObservation(observation); - break; - - case "LevelChange": - level = change.context.level; - break; - - default: - alert(`Unexpected change: ${change}`); - } - } - return new Graduation(student, green, orange, red, level, - stickers, - openObservationRequest, observationPeriod, pastObservations, - changes); - } - - addChange(change) { - // TODO(muhq): Implement incremental addition - let changes = this.changes; - changes.push(change); - // This updates the student.graduation reference as well - Graduation.from(this.student, changes); - } - - /** - * Request observation - */ - async requestObservation() { - const request = GraduationChange.newObservationRequest(); - this.observationRequested = request.date; - await addEntryToStudentDatabase(this.student, "submit", JSON.stringify(request.publicDBFields())); - } - - /** - * Start an observation - */ - async startObservation() { - if (!this.observationRequested) { - console.assert(this.observationRequested, "No observation requested"); - return; - } - this.observationRequested = null; - this.observation = new ObservationPeriod(new Date()); - return submitGraduationChange(this.student, GraduationChange.newObservationStart()); - } - - /** - * End an observation - */ - async endObservation(reason, success) { - if (!this.observation) { - console.assert(this.observation, "No active observation"); - return; - } - this.observation.end = new Date(); - this.pastObservations.push(this.observation); - this.observation = null; - return submitGraduationChange(this.student, GraduationChange.newObservationEnd(reason, success)); - } - - /** - * Return if the student is in observation. - */ - isObserved() { - return Boolean(this.observation); - } - - /** - * Return the URI of the icon representing the graduation level. - */ - getIcon() { - return LEVEL_IMAGES[this.level - 1]; - } - - /** - * Return the name of the current graduation level. - * @return {String} The name of the current level. - */ - getLevelName() { - return LEVEL_NAMES[this.level - 1]; - } -} - -class ObservationPeriod { - constructor(start) { - this.start = start; - this.observations = []; - } - - finishPeriod(success) { - this.end = new Date(); - this.success = success; - } - - ended() { - return Boolean(this.end); - } - - ready() { - if (this.observations.length < 10) - return false; - - // at least 10 observation on different days - let days = new Map(); - for (const observation of this.observations) { - const d = observation.date; - days.set(`${d.getFullYear()}${d.getMonth()}${d.getDate()}`, true); - } - return days.size >= 10; - } - - getObservationsSums() { - let sums = Array(OBSERVATION_TYPES.length).fill().map(() => ({"yes":0, "no":0})); - for (const observation of this.observations) { - for (let i = 0; i < sums.length; i++) { - if (observation.status[i]) { - if (observation.status[i] === "yes") - sums[i].yes++; - else - sums[i].no++; - } - } - } - return sums; - } - - addObservation(observation) { - this.observations.push(observation); - } -} - -const OBSERVATION_TYPES = [ - "Arbeitet konzentriert an Aufgaben", - "Arbeitet zunehmend selbstständig", - "Führt das Logbuch zuverlässig", - "Bringt Material mit", - "Hält Regeln ein", - "Geht verantwortungsvoll mit Materialien und LernRaum um", - "Nimmt Rückmeldungen an und setzt sie um", -]; - -class Observation { - constructor(date, status) { - console.assert(status.length == OBSERVATION_TYPES.length, "invalid observation status"); - this.date = date; - this.status = status; - } - - static fromChange(change) { - return new Observation(change.date, JSON.parse(change.context)) - } -} - -function changesFromDbEntries(entries) { - let changes = []; - for (const e of entries) { - const gradChange = GraduationChange.fromDBEntry(e); - changes.push(gradChange); - } - return changes; -} - -async function fetchGraduationChangesFromDb(student, type) { - const data = await loadFromStudentDatabase(student, type); - return changesFromDbEntries(data); -} - -const submitEntriesPromise = async function() { - const db = await getSubmitDb(); - const entries = await db.fetchEntries(); - return changesFromDbEntries(entries); -}(); - -async function addSubmittedChanges(student, changes) { - let submitEntries = await submitEntriesPromise; - for (const e of submitEntries.filter( (c) => c.coach === student.name )) { - changes.push(e); - } - return changes; -} - -async function fetchGraduationChanges(student) { - let changes = await fetchGraduationChangesFromDb(student, "shadow"); - return addSubmittedChanges(student, changes); -} - -async function fetchPublicGraduationChanges(student) { - let changes = await fetchGraduationChangesFromDb(student, "public"); - return addSubmittedChanges(student, changes); -} - -async function fetchGraduation(student) { - const changes = await fetchGraduationChanges(student); - return Graduation.from(student, changes); -} - -async function fetchPublicGraduation(student) { - const changes = await fetchPublicGraduationChanges(student); - return Graduation.from(student, changes); -} - -async function submitGraduationChange(student, change) { - student.graduation.addChange(change); - - // Submit changes concurrently - let promises = []; - - if (change.isPublic()) { - promises.push( - // TODO(muhq): strip non public fields from changes - addEntryToStudentDatabase(student, "public", JSON.stringify(change.publicDBFields())) - ); - } - - promises.push( - addEntryToStudentDatabase(student, "shadow", JSON.stringify(change.dbFields())) - ); - - await Promise.all(promises); -} - -async function submitObservation(student, observation) { - console.assert(student.graduation.observation, "no active observation"); - student.graduation.observation.addObservation(observation); - await submitGraduationChange(student, GraduationChange.newObservationChange(observation)); -} - -export { - LEVEL_NAMES, - LEVEL_IMAGES, - GraduationChange, - Graduation, - fetchGraduation, - fetchPublicGraduation, - fetchGraduationChanges, - fetchPublicGraduationChanges, - submitGraduationChange, - submitObservation, - - OBSERVATION_TYPES, - Observation, - ObservationPeriod, -}; |
