/enrollme

Primary LanguageJava

Compose sample application

Use with Docker Development Environments

You can open this sample in the Dev Environments feature of Docker Desktop version 4.12 or later.

Open in Docker Dev Environments Open in Docker Dev Environments

React application with a Spring backend and a MySQL database

Project structure:

.
├── backend
│   ├── Dockerfile
│   ...
├── db
│   └── password.txt
├── compose.yaml
├── frontend
│   ├── ...
│   └── Dockerfile
└── README.md

compose.yaml

services:
  backend:
    build: backend
    ...
  db:
    # We use a mariadb image which supports both amd64 & arm64 architecture
    image: mariadb:10.6.4-focal
    # If you really want to use MySQL, uncomment the following line
    #image: mysql:8.0.27
    ...
  frontend:
    build: frontend
    ports:
    - 3000:3000
    ...

The compose file defines an application with three services frontend, backend and db. When deploying the application, docker compose maps port 3000 of the frontend service container to port 3000 of the host as specified in the file. Make sure port 3000 on the host is not already being in use.

ℹ️ INFO For compatibility purpose between AMD64 and ARM64 architecture, we use a MariaDB as database instead of MySQL. You still can use the MySQL image by uncommenting the following line in the Compose file #image: mysql:8.0.27

Deploy with docker compose

$ docker compose up -d
Creating network "react-java-mysql-default" with the default driver
Building backend
Step 1/17 : FROM maven:3.6.3-jdk-11 AS builder
...
Successfully tagged react-java-mysql_frontend:latest
WARNING: Image for service frontend was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating react-java-mysql-frontend-1 ... done
Creating react-java-mysql-db-1       ... done
Creating react-java-mysql-backend-1  ... done

Expected result

Listing containers must show three containers running and the port mapping as below:

$ docker ps
ONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                  NAMES
a63dee74d79e        react-java-mysql-backend    "java -Djava.securit…"   39 seconds ago      Up 37 seconds                              react-java-mysql_backend-1
6a7364c0812e        react-java-mysql-frontend   "docker-entrypoint.s…"   39 seconds ago      Up 33 seconds       0.0.0.0:3000->3000/tcp react-java-mysql_frontend-1
b176b18fbec4        mysql:8.0.19                "docker-entrypoint.s…"   39 seconds ago      Up 37 seconds       3306/tcp, 33060/tcp    react-java-mysql_db-1

Stop and remove the containers

$ docker compose down
Stopping react-java-mysql-backend-1  ... done
Stopping react-java-mysql-frontend-1 ... done
Stopping react-java-mysql-db-1       ... done
Removing react-java-mysql-backend-1  ... done
Removing react-java-mysql-frontend-1 ... done
Removing react-java-mysql-db-1       ... done
Removing network react-java-mysql-default

Api Docs

Swagger UI docs - link to REST API docs

Swagger UI config - short tutorial on how to add description of endpoints and other stuff to the Swagger UI docs

Client application

After the aplication starts, you can open the client web application under http://localhost:3000.

Home Page

page From here, you can navigate to Enroll Configuration Page and Results Page.

Enroll Configuration Page

page The teacher pages are secured with Spring Security basic auth. You need the correct email and password to access those pages. page Here, the teacher can configure the whole enrollment for students:

  • Choose the timeslots that he is available at
  • Configure enrollment details:
    • The desired number of groups that algorithm is supposed to generate
    • The planned deadline, which also includes sending email remainders to students about the enrollment closing soon
    • He can choose not to set a deadline, and close the enrollment manually
  • Student access
    • The teacher can insert student emails for them to be able to fill their preferences
    • Get the link with access for students preferences page (it also starts the enrollment for students)
  • He can also reset the application to initial state at any moment

Student Preferences Page

page The page for students is secured with an email access. Only the students who were added to the system can enter. The page is also blocked when the enrollment is not active.

page Here, the student can fill his preferences with possibility to leave a note next to any timeslot. If a student wants to change his preferences later, he's going to get the existing preferences from the server when returning to this page.

Results Page

page Here, after the enrollment is closed, the teacher can:

  • View the results
  • Export results to xlsx file
  • Manually move students between groups and update the results accordingly

page When the teacher clicks on one of the students emails, this student's preferences are going to be shown.

Algorithm

Based on the number of students and the number of groups, the maximum number of students per group is calculated (number of students/number of groups).

First, for each time slot, its frequency in the students' preferences is calculated.

Then, students are divided into those with preferences and those without preferences.

Until there are students with preferences:

  • The slot with highest frequency is selected.
  • Students are assigned to this slot if they have it in their preferences and if number of students is less then the maximum.
  • If a student was assigned, their preferences are removed from the frequency count.
  • The selected slot is removed along with slots whose frequency in preferences has decreased to 0.

If we still have too few groups, those that have not yet appeared are added so that the number matches the required number of groups.

If there are still students with preferences, they are added to the slot with the fewest assigned students. Similarly, students without preferences are assigned.

Finally, an attempt is made to fix the results:

  • All students who were assigned to the wrong group are found.
  • It is checked if there is a slot in student's preferences that has been selected.
  • If so, iterate through the students assigned to that slot.
  • The exchange occurs if the potential student for exchange did not fulfill their preferences or if they have the exchange term in their preferences.

Changelog

SCRUM-85 (31.03.2024)

Nowy entity Enrollment

  • Enrollment przechowuje informacje o liczbie grup, deadlinie, stanie (EnrollmentState), a także zawiera listę List<TimeSlot>, czyli siatkę godzin.

Zastąpienie TimetableController przez EnrollmentController

  • Zmieniono i dodano nowe endpointy (Swagger UI docs)
  • Teraz aby pobrać siatkę godzin trzeba skorzystać z GET /enrollment, a w odpowiedzi JSON zawiera dodatkowo informacje o liczbie grup, deadlinie i stanie enrolla
  • Oddzielono endpointy GET /taecher/timetable oraz POST /teacher/timetable na:
    • GET /enrollment (opisane wyżej)
    • POST /enrollment/timetable

Przeniesienie metod z serwisu TimetableService do EnrollmentService

  • Metody getTimetable(), updateTimetable(), updateTimeslots() są teraz dostępne z EnrollmentService
  • Metoda getTimetable() nie jest teraz wykorzysytwana przez żaden kontroler, korzysta z niej jedynie algorytm i testy algorytmu

Fix prezentacji godzin

  • Usunięto sekundy z godzin we wszystkich DTO dotyczących Timeslot, więc frontend dostaje teraz prawidłowy format
  • Dla obiektów typu LocalDateTime właściwym formatem jest yyyy-MM-dd HH:mm:ss

SCRUM-67 (02.04.2024)

Dodanie autentykacji

  • od teraz na endpointy /enrollment i /enrollment/** może wejść jedynie użytkownik, który za pomocą BasicAuth poda w zapytaniu login i hasło:
login: miidzik@agh.edu.pl
hasło: I<3Burito
  • pozostałe endpointy są otwarte dla wszystkich

Stworzenie klasy Teacher

  • Klasa Teacher odpowiada typowej klasie User, jednak póki co tylko Teacher się może zalogować

Usunięcie pola UserRole z klasy Student

  • klasa student nie potrzebuje już pola typu UserRole, w zasadzie klasa Teacher również i obecnie zamiana autoryzacji po roli na autoryzację po autentykacji (każdy zalogowany ma dostęp) niczego nie zmieni

Modyfikacja obsługi GET /students

  • zastąpiono 3 metody jedną, która w zależości od liczby i rodzaju parametru wykonuje odpowiednie czynności. Problemem było głównie OpenApi, które nie pozwalało na przesłanie tylko 1 z parametrów.

Dodanie OpenApiConfig

  • Aby poprawnie móc testować autentykację potrzebna była konfiguracja OpenApi
  • W przyszłości pewnie warto poprawić i dodać więcej opisów / przykładów np. przykładowy PUT /enrollment/timetable podaje godzinę jako obiekt zamiast napisu. Aby poprawnie wysłać żądanie należy w przykładzie zmienić godzinę na format "startTime": "08:00". Ważne jest, że godziny 1-cyfrowe muszą być poprzedzone 0!