Skip to content

Commit

Permalink
Merge pull request #13 from BeneLuWi/development
Browse files Browse the repository at this point in the history
Add Some Meta Infos and License
  • Loading branch information
BeneLuWi committed Jan 6, 2023
2 parents 9111ce6 + 3dd5685 commit 41cb148
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 39 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## 0.1.1

_03.01.23_

- Allow the deletion of `Tasks`
- Allow decimals for `Task` points

## 0.1.0

_02.01.23_

- Initial Release
9 changes: 9 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
The MIT License (MIT)

Copyright © 2023 Benedikt Lüken-Winkels and David Kaub

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 changes: 46 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,57 @@
# Examanager Version 3
<p align="center">
<a href="https://github.com/BeneLuWi/examanager_v3"><img src="docs/Examanager-logos-wide.jpeg" alt="Examanager"></a>
</p>

Examanager is a web app for teachers to manage exams and their classes’ results. It allows viewing and editing exam results, statistical analysis and data export to `Excel`
<p align="center">
<a href="https://hub.docker.com/r/beneluwi/examanager" target="_blank">
<img src="https://img.shields.io/docker/v/beneluwi/examanager?color=%23086dd7&logo=Docker" alt="Docker">
</a>
</p>

<hr/>

Examanager is a web app for teachers to manage exams and their classes’ results. It allows viewing and editing exam
results, statistical analysis and data export to `Excel`

## Quick Start

```shell
git clone https://github.com/BeneLuWi/examanager_v3.git
cd examanager_v3
docker compose up
```

visit `http://localhost:5200`
- Initialize the `admin` user by adding the environment variable `INIT_ADMIN_USER: true` to the `examanager` service

```shell
docker compose up -d
```

- Visit `http://localhost:5200` and login with `admin:ChangeMe`
- Visit the API Docs [Swagger UI](http://localhost:5200/docs)

## Development Setup

You need: `docker compose`, `python@3.10`, `poerty`, `node`, `npm`

- Start Database

```shell
docker compose -f docker-compose-dev.yml up mongodb
```

- Start server

## API-Docs
```shell
cd server
poetry install
poetry shell
uvicorn server.main:app --port 5200
```

- Start app

[Swagger UI](http://localhost:5200/docs)
```shell
cd app
npm install
npm start
```
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1.1
5 changes: 3 additions & 2 deletions docker-compose-prod.yml → docker-compose-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ version: "3.9"

services:
mongodb:
image: mongo:4.4.6
image: mongo
container_name: examanager-db
ports:
- "27017:27017"

examanager:
build:
Expand All @@ -12,7 +14,6 @@ services:
container_name: examanager-app
environment:
MONGO_HOST: "mongodb"
INIT_ADMIN_USER: true
ports:
- "5200:5200"
depends_on:
Expand Down
6 changes: 1 addition & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@ services:
mongodb:
image: mongo
container_name: examanager-db
ports:
- "27017:27017"

examanager:
build:
context: .
dockerfile: Dockerfile
image: beneluwi/examanager
container_name: examanager-app
environment:
MONGO_HOST: "mongodb"
Expand Down
Binary file added docs/Examanager-logos-wide.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Examanager-logos.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Examanager-logos_black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Examanager-logos_white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 18 additions & 26 deletions server/server/api/api_v1/routers/statistics_api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import List
import pandas as pd
from pydantic import ValidationError
from starlette.background import BackgroundTask
from starlette.responses import FileResponse

from server.api.api_v1.routers.statistics_api.models import StatisticsResult, TaskResult, StatisticsElement
Expand Down Expand Up @@ -65,11 +66,6 @@ def create_student_results_dataframe(exam_results_response: ExamResultsResponse)
student_results_df["Gesamtpunkte"] = student_results_df[task_names].sum(axis=1)
student_results_df["Erreichte Punkte relativ"] = student_results_df["Gesamtpunkte"] / max_points_for_exam

# student_results_df = pd.concat([student_results_df, student_results_df.
# apply(lambda row: pd.Series(get_exam_rating_for_reached_percentage(
# exam=exam_results_response.exam,
# reached_percentage=row["Erreichte Punkte relativ"]).dict()), axis=1)], axis=0)

rating_results = [
get_exam_rating_for_reached_percentage(
exam=exam_results_response.exam, reached_percentage=reached_percentage
Expand Down Expand Up @@ -160,7 +156,6 @@ def create_student_statistics_dataframe(exam_results_response: ExamResultsRespon

# 10. Schwierigkeit
reachable_per_task = pd.DataFrame({task.name: task.max_points for task in tasks}, columns=task_names, index=[0])
# reachable_per_task["Sorting"]="per_task"
number_of_w = len(student_results_df[student_results_df["Geschlecht"] == "w"])
number_of_d = len(student_results_df[student_results_df["Geschlecht"] == "d"])
number_of_m = len(student_results_df[student_results_df["Geschlecht"] == "m"])
Expand All @@ -177,26 +172,23 @@ def create_student_statistics_dataframe(exam_results_response: ExamResultsRespon
reachable_d["Geschlecht"] = "d"

reachable_all = pd.concat([reachable_total, reachable_d, reachable_m, reachable_w])
reachable_all["Gesamtpunkte"] = reachable_all.sum(axis=1)
reachable_all["Gesamtpunkte"] = reachable_all.sum(axis=1, numeric_only=True)

columns_for_difficulty = task_names.copy()
columns_for_difficulty.append("Gesamtpunkte")

reached_total = student_results_df[columns_for_difficulty].sum()
reached_total = reached_total.to_frame().T
# reached_total["Statistik"] = "Summe erreichte Punkte"
reached_total["Geschlecht"] = ""

reached_by_gender = students_grouped_by_gender[columns_for_difficulty].sum().reset_index()
# reached_by_gender["Statistik"] = "Summe erreichte Punkte"

reached_all = pd.concat([reached_total, reached_by_gender])

difficulty_df = reached_all.set_index("Geschlecht").div(reachable_all.set_index("Geschlecht"), fill_value=0)
difficulty_df = difficulty_df * 100
difficulty_df.reset_index(inplace=True)
difficulty_df = difficulty_df.assign(Statistik="Schwierigkeit")
# difficulty_df = reachable_all.subtract(reached_all, axis="columns")# * 100

# 11. Trennschärfe

Expand Down Expand Up @@ -317,12 +309,6 @@ def create_task_result_object(student_statistics_df: pd.DataFrame, columns_to_pr


def create_statistics_result_object(student_statistics_df: pd.DataFrame, tasks: List[Task]) -> StatisticsResult:
# metric_names = ["Mittelwert (Mean)", "Mittelwert (Median)", "Schwierigkeit", "Trennschärfe"]
# for metric in metric_names:
# create_task_result_object(student_statistics_df=student_statistics_df, columns_to_process=columns_to_process,
# metric_name=metric)#

# mittelwert mean und median für mss (und note) als getrennte Statistik

task_names = [task.name for task in tasks]

Expand Down Expand Up @@ -371,7 +357,6 @@ def create_statistics_result_object(student_statistics_df: pd.DataFrame, tasks:
metric_name="Trennschärfe",
)

# todo self assessment will look differently
self_assessment_result_mean: TaskResult = create_task_result_object(
student_statistics_df=student_statistics_df,
columns_to_process=["Selbsteinschätzung MSS", "Abweichung Selbsteinschätzung MSS"],
Expand Down Expand Up @@ -429,6 +414,17 @@ async def calculate_statistics_object(exam_results_response: ExamResultsResponse
return statistics


def _cleanup(folder: os.PathLike[str], file: os.PathLike[str]) -> None:
"""
Cleanup after successfully returning the file
:param folder: Folder containing the File
:param file: Actual File
:return:
"""
os.remove(file)
os.rmdir(folder)


async def calculate_statistics_excel(exam_results_response: ExamResultsResponse, include_deactivated_tasks=False):
"""
1. Get ratings for result
Expand All @@ -446,19 +442,15 @@ async def calculate_statistics_excel(exam_results_response: ExamResultsResponse,
exam_results_response=exam_results_response, student_results_df=student_results_df
)

print("student_statistics_df")
print(student_statistics_df.to_string())

# TODO Use tmp dir
folder_id = str(uuid.uuid1())
os.mkdir(os.path.join("data", folder_id))
path = os.path.join("data", folder_id, "Klausurergebnis.xlsx")
folder_path = os.path.join("data", str(uuid.uuid1()))
os.mkdir(folder_path)
file_path = os.path.join(folder_path, "Klausurergebnis.xlsx")

# create an Excel writer object
with pd.ExcelWriter(path) as writer:
with pd.ExcelWriter(file_path) as writer:
# use to_excel function and specify the sheet_name and index
# to store the dataframe in specified sheet
student_results_df.to_excel(writer, sheet_name="Ergebnisse", index=False)
student_statistics_df.to_excel(writer, sheet_name="Statistik", index=False)

return FileResponse(path)
return FileResponse(file_path, background=BackgroundTask(_cleanup, folder_path, file_path))

0 comments on commit 41cb148

Please sign in to comment.