diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2026-07-01 18:34:18 +0200 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2026-07-01 18:34:18 +0200 |
| commit | 38456da30c1729ef3696ec935f19dfa982e07ec7 (patch) | |
| tree | 9ec83b5b9327b114b83ca72fc95a480d1e53685c | |
| parent | d15e27a939c1095a231eebc3629663fa48b5f521 (diff) | |
| download | bycs-sol-38456da30c1729ef3696ec935f19dfa982e07ec7.tar.gz bycs-sol-38456da30c1729ef3696ec935f19dfa982e07ec7.zip | |
implement observation and adapt graduation code to the separate databases
| -rw-r--r-- | js/graduation-common.js | 172 | ||||
| -rw-r--r-- | js/graduation-mock.js | 28 | ||||
| -rw-r--r-- | js/graduation-prod.js | 15 | ||||
| -rw-r--r-- | js/mock.js | 32 |
4 files changed, 174 insertions, 73 deletions
diff --git a/js/graduation-common.js b/js/graduation-common.js index 10524d5..94fd0d6 100644 --- a/js/graduation-common.js +++ b/js/graduation-common.js @@ -1,53 +1,46 @@ -import { GRADUATION_DB_ID, GRADUATION_ACTIVITY_ID, GRADUATION_DB_PARAMS_MAP } from "./config.js"; -import { loadFromDatabase, addEntryToDatabaseActivity } from "./database.js" +import { loadFromStudentDatabase, addEntryToStudentDatabase } from "./database.js" -const LEVEL_NAMES = ["Beginner", "Entdecker"]; +const LEVEL_NAMES = ["Neuling", "Entdecker", "Pionieer"]; class GraduationChange { - constructor(date, id, name, change, reason, coach, json) { + constructor(date, change, reason, coach, context) { this.date = date; - this.id = id; - this.name = name; this.change = change; this.reason = reason; this.coach = coach; - this.json = json; + this.context = context; } - static newGreenPointChange(student, reason, coach) { - return new GraduationChange( - new Date(), - student.id, student.name, - "Grün", reason, coach, "" - ); + isPublic() { + return [ + "Grün", "Orange", "Rot", + "ObservationStart", "ObservationEnd", + "LevelChange" + ].includes(this.change); } - static newOrangePointChange(student, reason, coach) { - return new GraduationChange( - new Date(), - student.id, student.name, - "Orange", reason, coach, "" - ); + static newGreenPointChange(reason, coach) { + return new GraduationChange(new Date(), "Grün", reason, coach, ""); } - static newRedPointChange(student, reason, coach) { - return new GraduationChange( - new Date(), - student.id, student.name, - "Rot", 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, observed, changes) { + constructor(student, green, orange, red, level, stickers, observation, changes) { this.student = student; this.green = green; this.orange = orange; this.red = red; this.level = level; this.stickers = stickers; - this.observed = observed; + this.observation = observation; this.changes = changes; student.graduation = this; @@ -58,7 +51,8 @@ class Graduation { let orange = 0; let red = 0; let level = 1; - let observed = false; + let observationPeriod = null; + let pastObservations = []; let stickers = []; for (const change of changes) { switch (change.change) { @@ -71,24 +65,27 @@ class Graduation { case "Rot": red++; break; - case "Gespräch": - orange = 0; + case "ObservationStart": + observationPeriod = new ObservationPeriod(change.date, null, []); + break; + case "ObservationEnd": + observationPeriod.end = change.date; + pastObservations.push(observationPeriod); + observationPeriod = null; break; - case "Änderung": - let ctx = JSON.parse(change.json) - switch (ctx.type) { - case "ObservationStart": - observed = true; - break; - default: - alert(`Unexpected ctx type: ${ctx.type}`); + case "Observation": + const observation = Observation.fromContext(change.context); + if (observationPeriod) { + observationPeriod.addObservation(observation); + } else { + alert(`No active observation period`); } break; default: alert(`Unexpected change: ${change}`); } } - return new Graduation(student, green, orange, red, level, stickers, observed, changes); + return new Graduation(student, green, orange, red, level, stickers, observationPeriod, changes); } addChange(change) { @@ -103,15 +100,14 @@ class Graduation { * Request observation */ async requestObservation() { - // TODO(muhq): Implement observation mark - this.observed = true; + await addEntryToStudentDatabase(this.student, "submit", {change: "ObservationRequest"}); } /** * Return if the student is in observation. */ isObserved() { - return this.observed; + return Boolean(this.observation); } /** @@ -130,16 +126,64 @@ class Graduation { } } -async function fetchGraduationChanges(student) { - let params = {}; - // The id is enough - params[GRADUATION_DB_PARAMS_MAP["id"]] = student.id; +class ObservationPeriod { + constructor(start, end, observations) { + this.start = start; + this.end = end; + this.observations = observations; + } - const data = await loadFromDatabase(GRADUATION_DB_ID, params); + ended() { + return Boolean(this.end); + } + + ready() { + // TODO(muhq): add time contraint + return this.observations > 10; + } + + getObservationsSums() { + let sums = Array(OBSERVATION_TYPES.length).fill({"yes":0, "no":0}); + for (const observation of this.observations) { + for (let i = 0; i < sums.length; i++) { + if (observation.status[i]) + 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; + } +} + +async function fetchGraduationChanges(student) { + const data = await loadFromStudentDatabase(student, "shadow"); let changes = []; for (const e of data) { - const gradChange = new GraduationChange(e.date, e.id, e.change, e.reason, e.coach, e.json); + const gradChange = GraduationChange.fromDBEntry(e); changes.push(gradChange); } return changes; @@ -151,13 +195,28 @@ async function fetchGraduation(student) { } async function submitGraduationChange(student, change) { - let params = {}; student.graduation.addChange(change); - for (const key in GRADUATION_DB_PARAMS_MAP) { - params[GRADUATION_DB_PARAMS_MAP[key]] = change[key]; + + // Submit changes concurrently + let promises = []; + + if (change.isPublic()) { + promises.push( + // TODO(muhq): strip non public fields from changes + addEntryToStudentDatabase(student, "public", JSON.stringify(change)) + ); } - addEntryToDatabaseActivity(GRADUATION_ACTIVITY_ID, params); + promises.push( + addEntryToStudentDatabase(student, "shadow", JSON.stringify(change)) + ); + + await Promise.all(promises); +} + +async function submitObservation(student, observation) { + student.graduation.addObservation(observation); + await addEntryToStudentDatabase(student, "shadow", JSON.stringify(observation)); } export { @@ -166,5 +225,10 @@ export { Graduation, fetchGraduation, fetchGraduationChanges, - submitGraduationChange -};
\ No newline at end of file + submitGraduationChange, + submitObservation, + + OBSERVATION_TYPES, + Observation, + ObservationPeriod, +}; diff --git a/js/graduation-mock.js b/js/graduation-mock.js index d35901e..eb8b3a4 100644 --- a/js/graduation-mock.js +++ b/js/graduation-mock.js @@ -1,6 +1,28 @@ -import { LEVEL_NAMES, Graduation, GraduationChange, } from "./graduation-common.js"; +import { + LEVEL_NAMES, + GraduationChange, + Graduation, + + OBSERVATION_TYPES, + Observation, + ObservationPeriod, +} from "./graduation-common.js"; + import { fetchGraduationMock as fetchGraduation, - submitGraduationChangeMock as submitGraduationChange + submitGraduationChangeMock as submitGraduationChange, + submitObservationMock as submitObservation } from "./mock.js"; -export { LEVEL_NAMES, GraduationChange, Graduation, fetchGraduation, submitGraduationChange};
\ No newline at end of file + +export { + LEVEL_NAMES, + GraduationChange, + Graduation, + fetchGraduation, + submitGraduationChange, + submitObservation, + + OBSERVATION_TYPES, + Observation, + ObservationPeriod, +}; diff --git a/js/graduation-prod.js b/js/graduation-prod.js index cbc8d48..198be4d 100644 --- a/js/graduation-prod.js +++ b/js/graduation-prod.js @@ -1,2 +1,13 @@ -import { LEVEL_NAMES, GraduationChange, Graduation, fetchGraduation, submitGraduationChange } from "./graduation-common.js"; -export { LEVEL_NAMES, GraduationChange, Graduation, fetchGraduation, submitGraduationChange };
\ No newline at end of file +export { + LEVEL_NAMES, + GraduationChange, + Graduation, + fetchGraduation, + fetchGraduationChanges, + submitGraduationChange, + submitObservation, + + OBSERVATION_TYPES, + Observation, + ObservationPeriod, +} from "./graduation-common.js"; @@ -3,9 +3,9 @@ import { Student } from "./student-common.js"; import { buildGroups } from "./group.js"; const students = [ - new Student(1, 'foo bar', ['test']), - new Student(2, 'maxi mustermensch', ['test']), - new Student(3, 'b b b', ['5a']) + new Student(1, 'foo bar', 'test'), + new Student(2, 'maxi mustermensch', 'test'), + new Student(3, 'b b b', '5a') ]; // Build the groups from our mock students @@ -40,20 +40,20 @@ for (const s of students) { switch (s.name) { case "foo bar": graduationChanges[s.name] = [ - GraduationChange.newGreenPointChange(s, "", "Florian Fischer"), - GraduationChange.newOrangePointChange(s, "", "Florian Fischer"), + GraduationChange.newGreenPointChange("Gute Arbeit", "Florian Fischer"), + GraduationChange.newOrangePointChange("", "Florian Fischer"), ]; break; case "maxi mustermensch": graduationChanges[s.name] = [ - GraduationChange.newGreenPointChange(s, "", "Florian Fischer"), - GraduationChange.newGreenPointChange(s, "", "Florian Fischer"), - new GraduationChange(new Date(), s.id, s.name, "Änderung", "", "", '{"type": "ObservationStart"}'), + GraduationChange.newGreenPointChange("", "Florian Fischer"), + GraduationChange.newGreenPointChange("", "Florian Fischer"), + new GraduationChange(new Date(), "ObservationStart", "", "Florian Fischer", ""), ]; break; case "b b b": graduationChanges[s.name] = [ - GraduationChange.newRedPointChange(s, "", "Florian Fischer"), + GraduationChange.newRedPointChange("", "Florian Fischer"), ]; } // Build the student's graduation @@ -72,11 +72,14 @@ function fetchGraduationMock(s) { } function submitGraduationChangeMock(s, c) { - if (s.graduation) { - s.graduation.addChange(c); - } else { - s.graduation = Graduation.from(s, [c]); - } + assert(s.graduation, "no graduation") + s.graduation.addChange(c); +} + +function submitObservationMock(s, o) { + assert(s.graduation, "no graduation") + assert(s.graduation.observation, "no observation period") + s.graduation.observation.addObservation(o); } export { @@ -85,4 +88,5 @@ export { fetchProgressMock, fetchGraduationMock, submitGraduationChangeMock, + submitObservationMock, }; |
