Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: migrate live quiz to unified data structure (i.e., from question instances/blocks to element block and element instances) #4338

Merged
merged 38 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
72fa749
refactor: simplify response logic for element stacks and add unit tes…
sjschlapbach Oct 28, 2024
9a54f78
fix: migrate numerical question evaluation on asynchronous activities…
sjschlapbach Oct 29, 2024
25859ff
fix: use full combined results for student evaluation on asynchronous…
sjschlapbach Oct 29, 2024
b8cef82
enhance: define new element blocks for improved live quiz data struct…
sjschlapbach Oct 30, 2024
524bb29
refactor: migrate creation and editing process to new element instanc…
sjschlapbach Oct 31, 2024
1e8b0c5
refactor: add query components of running live quiz on lecturer and s…
sjschlapbach Oct 31, 2024
218bdee
refactor: migrate test seed and demo quiz to new live quiz structure …
sjschlapbach Nov 4, 2024
6ce6287
refactor: implement functionalities for live quiz interaction besides…
sjschlapbach Nov 4, 2024
4a1ddc5
refactor: migrate live quiz execution (including cache operations) to…
sjschlapbach Nov 4, 2024
7bc80d6
enhance: introduce statistics for numerical questions in asynchronous…
sjschlapbach Nov 5, 2024
8dd73f1
refactor: migrate live quiz evaluation to new database structure (#4355)
sjschlapbach Nov 5, 2024
9a82194
refactor: replace question preview with student element and move arti…
sjschlapbach Nov 5, 2024
cf9198f
chore: remove components related to live session and question instanc…
sjschlapbach Nov 6, 2024
761360a
Merge branch 'v3' of https://github.com/uzh-bf/klicker-uzh into v3-ne…
sjschlapbach Nov 6, 2024
d56edb2
enhance: add direct forwarding for live quiz evaluation embedding (#4…
sjschlapbach Nov 6, 2024
ec964c8
enhance(packages/graphql): store correctness along open answers in li…
sjschlapbach Nov 6, 2024
37f5a32
chore: cleanup formulations and variables related to old live session…
sjschlapbach Nov 6, 2024
dbbfe41
Merge branch 'v3' of https://github.com/uzh-bf/klicker-uzh into v3-ne…
sjschlapbach Nov 8, 2024
c3a7691
chore: migrate live session data to live quiz table (#4363)
sjschlapbach Nov 10, 2024
ad44023
fix: ensure that app replicas variable in helmfile can be correctly read
sjschlapbach Nov 10, 2024
7114952
chore: add script for dumping redis
rschlaefli Nov 10, 2024
3cab4a2
chore: add working redis restore script
rschlaefli Nov 10, 2024
48b5675
fix: improve live session to live quiz migration script (#4368)
rschlaefli Nov 10, 2024
53dcc38
fix(packages/graphql): ensure we read the old instances by originalId…
rschlaefli Nov 10, 2024
c06d004
Merge branch 'v3' of https://github.com/uzh-bf/klicker-uzh into v3-ne…
sjschlapbach Nov 13, 2024
444e3b0
Merge branch 'v3' of https://github.com/uzh-bf/klicker-uzh into v3-ne…
rschlaefli Nov 25, 2024
d2f3a43
fix: message for PQ start date
rschlaefli Nov 25, 2024
b6d98f1
Update README.md
rschlaefli Nov 25, 2024
1d804f2
deps: restore necessary production deps
rschlaefli Nov 25, 2024
d346609
Merge branch 'v3-new-live-quiz' of https://github.com/uzh-bf/klicker-…
rschlaefli Nov 25, 2024
1a789b7
deps(apps/frontend-manage): move react-tagcloud to production deps
rschlaefli Nov 25, 2024
8ae67c3
deps: upgrade design system to include fix in free text field
rschlaefli Nov 25, 2024
b8f65b8
Merge branch 'v3' of https://github.com/uzh-bf/klicker-uzh into v3-ne…
rschlaefli Nov 29, 2024
20eb487
fix: only parse solutions in processCachedData if they are not undefined
rschlaefli Nov 30, 2024
20ab05a
refactor(packages/graphql): merge functions into getCachedBlockResults
rschlaefli Nov 30, 2024
8fa77cb
fix(packages/graphql): update getCachedBlockResults to fetch from red…
rschlaefli Nov 30, 2024
1cfab1c
fix(packages/graphql): use originalIds in live quiz migration where m…
rschlaefli Nov 30, 2024
c4e050f
fix(packages/graphql): await instance migrations in redis migration s…
rschlaefli Nov 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/cypress-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ jobs:

- name: Cypress run
uses: cypress-io/github-action@v6
timeout-minutes: 20
timeout-minutes: 60
with:
install: false
wait-on: 'http://127.0.0.1:3000/api/graphql, http://127.0.0.1:3001, http://127.0.0.1:3002, http://127.0.0.1:3003, http://127.0.0.1:3010'
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/test-graphql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,13 @@ jobs:
- name: Test functions
shell: bash
run: |
cd packages/graphql
cd packages/prisma
pnpm run build
cd ../types
pnpm run build
cd ../util
pnpm run build
cd ../grading
pnpm run build
cd ../graphql
pnpm run test
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ All notable changes to this project will be documented in this file. See [standa

### Bug Fixes

* ensure that validation in quesiton edit modal works properly ([#4251](https://github.com/uzh-bf/klicker-uzh/issues/4251)) ([5e26453](https://github.com/uzh-bf/klicker-uzh/commit/5e2645381465ccfbf26dac17d2f36b380ef9e4bf))
* ensure that validation in question edit modal works properly ([#4251](https://github.com/uzh-bf/klicker-uzh/issues/4251)) ([5e26453](https://github.com/uzh-bf/klicker-uzh/commit/5e2645381465ccfbf26dac17d2f36b380ef9e4bf))
* require that the user specifies sample solutions for open questions when activated ([#4252](https://github.com/uzh-bf/klicker-uzh/issues/4252)) ([0c5aa6b](https://github.com/uzh-bf/klicker-uzh/commit/0c5aa6b1c15e00813f4485e9380d53728ca527c7))

## [3.2.0-alpha.20](https://github.com/uzh-bf/klicker-uzh/compare/v3.2.0-alpha.19...v3.2.0-alpha.20) (2024-09-06)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
KlickerUZH v3.0 uses multiple different web applications and services, which communicate with each other:

- [Frontend PWA](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/frontend-pwa) is the student frontend of KlickerUZH, which contains the student views for live quizzes, microlearnings, practice quizzes, leaderboards and more.
- [Frontend Manage](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/frontend-manage) is the lecturer frontend of KlickerUZH, which provides all the functionalities that lecturers need, including but not limited to question management, session management, course management and analytics.
- [Fontend Control](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/frontend-control) is a minimal controller frontend, which allows to control live sessions from mobile devices in an optimized layout. Soon, this app will also be available as a [PowerPoint integration](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/office-addin) (work in progress) for catalyst users.
- [Frontend Manage](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/frontend-manage) is the lecturer frontend of KlickerUZH, which provides all the functionalities that lecturers need, including but not limited to question management, activity management, course management and analytics.
- [Frontend Control](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/frontend-control) is a minimal controller frontend, which allows to control live quizzes from mobile devices in an optimized layout. Soon, this app will also be available as a [PowerPoint integration](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/office-addin) (work in progress) for catalyst users.
- [Fontend Authentication](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/auth) is the authentication frontend of KlickerUZH, providing login functionalities through Edu-ID accounts and delegated logins to the manage frontend.
- [Backend Docker](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/backend-docker) is the main backend service of KlickerUZH.
- [Backend Responses](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/func-incoming-responses) is a service that handles incoming student responses during a live session and puts them into an Azure queue for improved load handling.
- [Backend Responses](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/func-incoming-responses) is a service that handles incoming student responses during a live quizzes and puts them into an Azure queue for improved load handling.
- [Backend Response Processor](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/func-response-processor) accesses queued elements from the aforementioned service and processes them by computing scores and experience points, updating the cache, etc.

In addition to the key application components, this repository also includes the codebases for our landing page and documentation at [www.klicker.uzh.ch](https://www.klicker.uzh.ch/), as well as deployment scripts for Helm/Kubernetes. An updated deployment documentation for self-hosting KlickerUZH v3.0 will be added until the end of the year.
Expand Down
3 changes: 3 additions & 0 deletions _down_macos.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

docker compose down postgres redis_exec redis_cache reverse_proxy_macos
3 changes: 1 addition & 2 deletions apps/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"@klicker-uzh/prisma": "workspace:*",
"@klicker-uzh/shared-components": "workspace:*",
"@next-auth/prisma-adapter": "1.0.7",
"@uzh-bf/design-system": "3.0.0-alpha.34",
"@uzh-bf/design-system": "3.0.0-alpha.35",
"axios": "1.7.7",
"bcryptjs": "2.4.3",
"js-cookie": "3.0.5",
Expand All @@ -17,7 +17,6 @@
"next": "15.0.0",
"next-auth": "4.24.8",
"next-intl": "3.21.1",
"nookies": "2.5.2",
"react": "18.3.1",
"react-dom": "18.3.1",
"sharp": "0.33.5",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is a prod dependency especially in standalone deployments but this might have changed with Next.js 15. I'll add it back and we can check it later :)

Expand Down
2 changes: 1 addition & 1 deletion apps/backend-docker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"@types/passport": "^1.0.16",
"@types/passport-jwt": "^4.0.1",
"@types/ws": "^8.5.12",
"@uzh-bf/design-system": "3.0.0-alpha.34",
"@uzh-bf/design-system": "3.0.0-alpha.35",
"axios": "~1.7.7",
"cross-env": "~7.0.3",
"dotenv": "~16.4.5",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// @ts-nocheck

import type { PrismaMigrationClient } from '@klicker-uzh/graphql/src/types/app.js'
// import { PrismaClient } from '@klicker-uzh/prisma'

Expand Down
10 changes: 5 additions & 5 deletions apps/backend-docker/scripts/checkRedisConsistency.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PrismaClient } from '@klicker-uzh/prisma'
import { PrismaClient, PublicationStatus } from '@klicker-uzh/prisma'
import { Redis } from 'ioredis'

async function run() {
Expand All @@ -12,18 +12,18 @@ async function run() {
tls: process.env.REDIS_TLS ? {} : undefined,
})

const sessions = await prisma.liveSession.findMany({
const quizzes = await prisma.liveQuiz.findMany({
where: {
status: {
not: 'RUNNING',
not: PublicationStatus.PUBLISHED,
},
},
})

let count = 0

for (const session of sessions) {
const invalidKeys = await redisExec.keys(`s:${session.id}:*`)
for (const quiz of quizzes) {
const invalidKeys = await redisExec.keys(`lq:${quiz.id}:*`)

if (invalidKeys.length > 0) {
count += invalidKeys.length
Expand Down
10 changes: 5 additions & 5 deletions apps/backend-docker/scripts/fixPointsInconsistency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ const redisExec = new Redis({
tls: process.env.REDIS_TLS ? {} : undefined,
})

// deduct points from course leaderboard entries: 1x points in sessionLB
// deduct points from course leaderboard entries: 1x points in quizLB
const FAILURES = 1

const COURSE_ID = ''
const SESSION_ID = ''
const QUIZ_ID = ''

const sessionLB = await redisExec.hgetall(`s:${SESSION_ID}:lb`)
const sessionXP = await redisExec.hgetall(`s:${SESSION_ID}:xp`)
const quizLB = await redisExec.hgetall(`lq:${QUIZ_ID}:lb`)
const quizXP = await redisExec.hgetall(`lq:${QUIZ_ID}:xp`)

const results = await Promise.allSettled(
Object.entries(sessionLB).map(async ([participantId, score]) => {
Object.entries(quizLB).map(async ([participantId, score]) => {
const lbEntry = await prisma.leaderboardEntry.findFirst({
where: {
participantId,
Expand Down
41 changes: 0 additions & 41 deletions apps/backend-docker/scripts/fixQuestionData.ts

This file was deleted.

2 changes: 1 addition & 1 deletion apps/docs/docs/gamification/experience.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: XP and Levels
---

While participants collect points for correct answers on a course level, experience points (XP) are collected across courses and allow students to level up. This represents an important part of our gamification concept, making sure that students keep making progress across different courses and activities. However, students are not only awarded experience points for answering questions correctly (in live settings as well as learning elements and micro sessions), but also when obtaining achievements, solving group challenges and many more activities.
While participants collect points for correct answers on a course level, experience points (XP) are collected across courses and allow students to level up. This represents an important part of our gamification concept, making sure that students keep making progress across different courses and activities. However, students are not only awarded experience points for answering questions correctly (in live settings as well as practice quizzes and microlearnings), but also when obtaining achievements, solving group challenges and many more activities.

As usual, levelling up will be faster in the beginning and then require a growing amount of additional points later on. KlickerUZH currently uses the following formula to compute the required amount of experience points for some level $i$ as $\text{XP}_{\text{req}}(i)$:

Expand Down
10 changes: 5 additions & 5 deletions apps/docs/docs/gamification/grading_logic.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Grading Logic

In order to distribute points, XP and achievements based on the performance of the participants in various activities, an automated grading logic has been implemented in KlickerUZH. This chapter provides a detailed explanation of the approaches employed for different element and activity types, including practice quizzes, microlearnings and live quizzes.

The presented grading approach assumes that all considered questions have a defined correct solution (or possibly multiple solutions), as this is required in asynchronous activities, except for free-text questions. During live sessions where questions without sample solutions were used, the participants are awarded a fixed amount of 10 points for taking part in each poll. Please also note that the [grading approach for live quizzes](#grading-in-live-quizzes) slightly extends the logic of asynchronous activities and that some element types are only available in select activities.
The presented grading approach assumes that all considered questions have a defined correct solution (or possibly multiple solutions), as this is required in asynchronous activities, except for free-text questions. During live quizzes where questions without sample solutions were used, the participants are awarded a fixed amount of 10 points for taking part in each poll. Please also note that the [grading approach for live quizzes](#grading-in-live-quizzes) slightly extends the logic of asynchronous activities and that some element types are only available in select activities.

## Grading by Question Type

Expand All @@ -14,7 +14,7 @@ The grading logic will first be described on the example of practice quizzes and

The point multipliers, which can be specified both on a question and activity level, are combined during the creation of the activity and applied to the total awarded points (including basic points and potential bonuses). If no multipliers were specified, this factor defaults to 1.

Multipliers can be used to weigh questions according to their difficulty and reward participation in certain quizzes with more points (e.g. quiz on exam level during the last lecture of the semester vs. an introductory quiz in the first lecture). The same multiplier concept also applies to live sessions.
Multipliers can be used to weigh questions according to their difficulty and reward participation in certain quizzes with more points (e.g. quiz on exam level during the last lecture of the semester vs. an introductory quiz in the first lecture). The same multiplier concept also applies to live quizzes.

### Grading Single Choice Questions

Expand Down Expand Up @@ -70,14 +70,14 @@ For free text questions, you can currently specify a selection of correct respon

During synchronous live quizzes, every participant will receive 10 points for each submitted answer, independent of its correctness. If the submitted answer is correct, 5 additional points will be awarded. For partially correct answers, these 5 points are multiplied with a factor described in the sections above. If no sample solution is defined, students will not receive any time-dependent bonus, but only the fixed amount of 10 points (no multiplication with multiplier).

To incentivize fast and correct answers during live sessions, additional bonus points are awarded. Starting time with the first correct answer, players will receive up to 45 points (default setting), depending on the time that passed between the first correct answer and theirs. By default, the slope to zero points is implemented with a duration of 20 seconds.
To incentivize fast and correct answers during live quizzes, additional bonus points are awarded. Starting time with the first correct answer, players will receive up to 45 points (default setting), depending on the time that passed between the first correct answer and theirs. By default, the slope to zero points is implemented with a duration of 20 seconds.

The corresponding resulting point curves for correct and wrong answers during live sessions, when starting time with the first correct response, are shown in the plot below (not considering multipliers).
The corresponding resulting point curves for correct and wrong answers during live quizzes, when starting time with the first correct response, are shown in the plot below (not considering multipliers).

<div align="center">
<img
style={{ width: 600 }}
alt="Illustration of Grading in Live Sessions"
alt="Illustration of Grading in Live Quizzes"
src="/img_v3/21_live_quiz_awarded_points.svg"
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/docs/tutorials/course_management.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,6 @@ This process helps ensure that groups are formed **fairly and efficiently**. The
1. Participants that are **alone** in a group are automatically added to the random assignment pool, while their group is resolved.
2. Students remaining in the assignment pool are evenly distributed into **new groups** to match the preferred group size.

5. **Manual group creation** during the creation period: Lecturers can manually finalize group assignments at any time through the course's **group overview page** (ahead of the group formation deadline). This allows you to use randomized group formation in a single in-class session instead of across a longer timespan. To do so, you can select the "**Assign random groups**" button within the group overview on the course page (screenshot below). This will close group creation and distribute students from the pool into existing groups as described in the previous step. To reopen group formation after manual finalization, lecturers can **extend the deadline** in the course settings.
5. **Manual group creation** during the creation period: Lecturers can manually finalize group assignments at any time through the course's **group overview page** (ahead of the group formation deadline). This allows you to use randomized group formation in a single in-class quizzes instead of across a longer timespan. To do so, you can select the "**Assign random groups**" button within the group overview on the course page (screenshot below). This will close group creation and distribute students from the pool into existing groups as described in the previous step. To reopen group formation after manual finalization, lecturers can **extend the deadline** in the course settings.

![Random Group Creation - Lecturer View](/img_v3/18_random_groups_lecturer.png)
2 changes: 1 addition & 1 deletion apps/docs/docs/tutorials/element_management.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,5 @@ Elements (questions, flashcards, and content elements) are the building blocks o
- **Delete**: Remove unwanted elements (note: this action is irreversible)

:::info
Most elements can be used in any learning activity, with some restrictions. For detailed information on embedding elements into different activities, refer to the following sections. Remember, elements are persistent within existing sessions, even if deleted from your element pool.
Most elements can be used in any learning activity, with some restrictions. For detailed information on embedding elements into different activities, refer to the following sections. Remember, elements are persistent within existing quizzes, even if deleted from your element pool.
:::
2 changes: 1 addition & 1 deletion apps/docs/docs/tutorials/group_activity.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ To create a group activity, navigate to the question pool and use the button at

In a first step, you will be asked to provide general information about the group activity. The following fields are available for customization:

- **Name**: The name of the group activity allows the user to distinguish the particular session from others. It is therefore only visible to the users themselves.
- **Name**: The name of the group activity allows the user to distinguish the particular activity from others. It is therefore only visible to the users themselves.
- **Display Name**: This name will be shown to the participants while the group activity is being performed.
- **Description**: A description of the group activity can optionally be added and will be displayed to the participants as an introduction to the group activity. While not required, we highly recommend to provide general information about the group activity here.

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/docs/tutorials/live_qa.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Live Quizzes in KlickerUZH can be coupled with a Live Q&A that enables students
title="KlickerUZH - Live Q&A"
></iframe>

A Live Q&A is embedded in the Live Quiz and can be activated during a Live Quiz session. For more details on the Live Quiz, review the dedicated [tutorial on live quiz creation](/tutorials/live_quiz/).
A Live Q&A is embedded in the Live Quiz and can be activated during its execution. For more details on the Live Quiz, review the dedicated [tutorial on live quiz creation](/tutorials/live_quiz/).

1. Activate Live Q&A: As soon as you activate a question block (displayed in green), the Live Q&A can be activated.
2. Manage questions: By clicking on the eye symbol, you can make the question visible for all the participants. The question can then not only be seen by others, but also be upvoted. Furthermore, you can sort the incoming questions or delete them.
Expand Down
Loading
Loading