Skip to content
Snippets Groups Projects
Commit 8b3dc7e8 authored by Victor Löfgren's avatar Victor Löfgren
Browse files

Resolve "Update documentation"

parent bf289051
No related branches found
No related tags found
1 merge request!164Resolve "Update documentation"
Pipeline #46589 passed
Showing
with 60 additions and 83 deletions
......@@ -3,15 +3,13 @@
The people involved in the project, their email, their role in the project, what they worked on generally and, if anything, they worked on most will be described below.
Please feel free to contact us if you have any questions.
| Namn | Email | Roll | Generellt | Speciellt |
| ------------------ | ----------------------- | ---------------------- | --------- | ---------------------- |
| Albin Henriksson | albhe428@student.liu.se | Testledare | Frontend | |
| Sebastian Karlsson | sebka991@student.liu.se | Arkitekt | Frontend | |
| Victor Löfgren | viclo211@student.liu.se | Konfigurationsansvarig | Backend | Dokumentation, Sockets |
| Björn Modée | bjomo323@student.liu.se | Kvalitetsamordnare | Frontend | Redux |
| Josef Olsson | josol381@student.liu.se | Teamledare | Backend | |
| Max Rüdiger | maxru105@student.liu.se | Dokumentansvarig | Frontend | |
| Carl Schönfelder | carsc272@student.liu.se | Utvecklingsledare | Backend | Databas |
| Emil Wahlqvist | emiwa210@student.liu.se | Analysansvarig | Frontend | Presentationseditor |
[comment]: # (Should this really be in swedish?)
\ No newline at end of file
| Name | Email | Role | Generally | Especially |
| ------------------ | ----------------------- | ------------------------ | --------- | ------------------------------ |
| Albin Henriksson | albhe428@student.liu.se | Test Leader | Front end | Presentations, Editor, Testing |
| Sebastian Karlsson | sebka991@student.liu.se | Architect | Front end | Editor, Uploading pictures |
| Victor Löfgren | viclo211@student.liu.se | Configuration Management | Back end | Documentation, Sockets, API |
| Björn Modée | bjomo323@student.liu.se | Quality Assurance | Front end | Redux |
| Josef Olsson | josol381@student.liu.se | Team Leader | Back end | Database, Testing |
| Max Rüdiger | maxru105@student.liu.se | Document Management | Front end | |
| Carl Schönfelder | carsc272@student.liu.se | Development Leader | Back end | Database, Uploading pictures |
| Emil Wahlqvist | emiwa210@student.liu.se | Analyst | Front end | Editor |
# Frontend
[comment]: # (TODO)
Here it is described how to work with the frontend in the system.
## Working with TypeScript
[comment]: # (TODO)
The main programming languange used for the front end is TypeScript.
### npm
......
......@@ -12,5 +12,3 @@ It's very helpful when developing APIs.
[DB Browser for SQlite](https://sqlitebrowser.org/) is used to see what is currently stored in the database.
You can even edit values.
[comment]: # (Add VS CODE?)
\ No newline at end of file
......@@ -20,15 +20,3 @@ A list of all the questions that needs to be supported (and more) can be found o
Here we will give a list of things we think will improve the system.
It is not certain that they are a better solutions but definitely something to look into.
### Replace Flask-RESTX with flask-smorest
[comment]: # (This is already implemented)
We currently use [Flask-RESTX](https://flask-restx.readthedocs.io/en/latest/) to define our endpoints and parse the arguments they take, either as a query string or in the body.
But when responding we use [Marshmallow](https://flask-smorest.readthedocs.io/en/latest/) to generate the JSON objects to return.
We believe that [flask-smorest](https://flask-smorest.readthedocs.io/en/latest/) would integrate a lot better with Marshmallow.
This would give us the ability to more easily show the expected arguments and the return values for our endpoints using Swagger (when visiting `localhost:5000`).
Currently we only show the route.
The work required also seems to be rather small because they look quite similar.
This would also remove the deprecated [reqparse](https://flask-restx.readthedocs.io/en/latest/parsing.html) part from Flask-RESTX, which is desirable.
......@@ -13,8 +13,6 @@ The Python and Pylance extensions help with linting Python code, auto imports, s
Prettier is an extension used to format JavaScript and TypeScript.
ESLint is used to lint JavaScript and TypeScript code.
[comment]: # ("is used to lint JavaScript" what is lint? It's not explained)
Live Share is an extension that is used to write code together at the same time, much like a Google Docs document.
There were however a few issues with the Python extension that made Live Share hard to work with.
......
......@@ -16,5 +16,3 @@ start ./docs/index.html
```
If you want to include the documentation from the tests, go to the file `client/tsconfig.json` and comment out the line `"exlude": "**/*.test.*"`.
[comment]: # (There should be a task for this, or does one exist already?)
\ No newline at end of file
......@@ -19,5 +19,4 @@ npm install
You should now be ready to start the client.
Try it by running `npm run start`.
A web page should open where you can see the [login page](../user_manual/login.md).
[comment]: # (Should we mention the task for starting the client?)
If you are using VS Code you can also start the client with the [task](../development/vscode.md) `start client`.
......@@ -41,5 +41,4 @@ pip install -r requirements.txt
You should now be ready to start the server.
Try it by running `python main.py` and navigate to `localhost:5000`.
If everything worked as it should you should see a list of all available API calls.
[comment]: # (Should we mention the task for starting the server?)
If you are using VS Code you can also start the server with the [task](../development/vscode.md) `start server`.
......@@ -16,10 +16,8 @@ This is to make sure that whoever tries to communicate has the correct level of
### API
[comment]: # (What does "that will proxy the request to the main Python server" mean?)
API calls are used for simple functions that the client wants to perform, such as getting, editing, and saving data.
These are sent from the client to the backend Node server that will proxy the request to the main Python server.
These are sent from the client to the backend Node server that will forward the request to the main Python server.
The request will then be handled there and the response will be sent back.
The Node server will then send them back to the client.
......
......@@ -6,6 +6,17 @@ It also needs to make sure that only authorized people can access these.
The other responsibility is to sync slides, timer and answers between clients in an active competition.
Both of these will be described in more detail below.
## Libraries
The server is built in [Flask](https://flask.palletsprojects.com/en/2.0.x/).
A few extensions to Flask are also used.
[flask-smorest](https://flask-smorest.readthedocs.io/en/latest/) is used to defined the API routes.
It is this libray that automatically documents the API on `localhost:5000` using Swagger.
[marshmallow](https://marshmallow.readthedocs.io/en/stable/) is used to convert database objects in JSON and to parse JSON back into Python objects.
[SQLAlchemy](https://www.sqlalchemy.org/) is used to interface with the SQL database that is used.
More specifically [Flask-SQLAlchemy](https://flask-sqlalchemy.palletsprojects.com/en/2.x/) is used to integrate it with Flask.
[Flask-Bcrypt](https://flask-bcrypt.readthedocs.io/en/latest/) is used to encrypt passwords.
## Receiving API calls
An API call is a way for the client to communicate with the server.
......@@ -26,7 +37,7 @@ When the server receives an API call it will first check that the call is author
The authorization is done using JSON Web Tokens (JWT) by comparing the contents of them with what is expected.
Whenever a client logs into an account or joins a competition, it is given a JWT generated by the server, and the client will need to use this token in every subsequent request sent to the server in order to authenticate itself.
The needed authorization is specified by the `@protect_route()` decorator.
The needed authorization is specified by the `ExtendedBlueprint.authorization()` decorator.
This decorator specifies who is allowed to access this route, which can either be users with specific roles, or people that have joined competitions with specific views.
If the route is not decorated everyone is allowed to access it, and the only routes currently like that is, by necessity, logging in as a user and joining a competition.
......@@ -42,9 +53,9 @@ This is why the server can simply read the contents of the JWT to be sure that t
### Parsing request
After the request is authorized the server will need to parse the contents of the request.
The parsing is done with [reqparse](https://flask-restx.readthedocs.io/en/latest/parsing.html) from RestX (this module is deprecated and should be replaced).
Each API call expects different parameters in different places and this is specified in each of the files in `app/apis/` folder, together with the route.
The server receives data in three ways: In the query string, body and header.
The data in the body and header is sent in JSON format and needs to be converted into Python dictionaries.
What data a route needs is specified by a marshmallow schema and blueprint from flask-smorest.
### Handling request
......@@ -56,7 +67,7 @@ Everything related to the database is located in the `app/database/` folder.
### Responding
When the server har processed the request it usually responds with an item from the database.
Converting a database object to json is done with [Marsmallow](https://marshmallow.readthedocs.io/en/stable/).
Converting a database object to json is done with marshmallow.
This conversion is specified in two files in the folder `app/core/`.
The file `schemas.py` converts a record in the database field by field.
The file `rich_schemas.py` on the other hand converts an `id` in one table to an entire object in the another table, thus the name rich.
......@@ -65,18 +76,18 @@ In this way, for example, an entire competition with its teams, codes, slides an
## Active competitions
Slides, timers, and answers needs to be synced during an active presentation.
This is done using SocketIO together with flask_socketio.
This is done using SocketIO together with flask-socketio.
Sent events are also authorized via JWT, basically the same way as the for the API calls.
But for socket events, the decorator that is used to authenticate them is `@authorize_user()`.
But for socket events, the decorator that is used to authenticate them is `sockets.authorization()`.
Whenever a client joins a competition they will connect via sockets.
A single competition cannot be active more than once at the same time.
This means that you will need to make a copy of a competition if you want to run the same competition at several locations at the same time.
All of the functionality related to an active competition and sockets can be found in the file `app/core/sockets.py`.
The terms *active competition* and *presentation* are equivalent.
The terms _active competition_ and _presentation_ are equivalent.
### Starting and joing presentations
Whenever a code is typed in to the client it will be checked via the `api/auth/login/code` API call.
Whenever a code is typed in to the client it will be checked via the `api/auth/code` API call.
If there is such a code and it was an operator code, the client will receive the JWT it will need to use to authenticate itself.
If there is such a code and the associated competition is active, the client will also receive a JWT for its corresponding role.
Both of these cases will be handled by the default `connect` event, using the JWT received from the API call.
......@@ -84,10 +95,9 @@ The server can see what is stored in the JWT and do different things depending o
### Syncing between clients
[comment]: # (What does `sync` mean? It isn't explained)
The operator will emit the `sync` event and provide either a slide or a timer to update it on the server.
The server will then send `sync` to all connected clients with the updated values, regardless of what was actually updated.
The server will also store the timer and active slide in order to `sync` clients when they join.
The operator can also emit `end_presentation` to disconnect all clients from its competitions.
There are two other events that is used.
The operator will emit the `sync` event to syncronise some values to all other clients connected to the same competition.
The server will then send `sync` to all connected clients with the values that was updated.
The server will also store these values and will syncronise these when a client joins a presentation.
The operator can also emit `end_presentation` to disconnect all clients from its presentation.
This will also end the presentation.
# Testing the client
[comment]: # (TODO)
\ No newline at end of file
The clients tests are the files named `<name>.test.ts`.
They test the file called `<name>.ts`.
They are run using the [VS Code task](../development/vscode.md) `Unit tests`.
# End to end tests
[comment]: # (TODO)
\ No newline at end of file
The end to end tests are tests that test the entire system, both the server and the client.
They are stored in the folder `/client/src/e2e/`.
Both the client and the server need to be running for the end to end tests to work.
The tests are run using the [VS Code task](../development/vscode.md) `Run e2e tests`.
# Editor
[comment]: # 'Explain where to find the competition name. Perhaps an image or link to Admin?'
The [competition manager](./admin.md) will list all competitions.
After clicking on a competition name you will enter the editor and will be able to edit it.
The Teknikåttan logo in the top left corner will take you back to the Admin page and right under that all slides are shown.
A newly created competition will have one empty default slide.
......@@ -9,6 +8,7 @@ Switch to a different slide by clicking on it.
In the bottom left corner you will be able to add a new slide using the "Ny sida" button.
Delete or copy a slide simply by right clicking on it and choosing the appropriate option.
In the top right corner you will be able to change which view you see and edit.
By right clicking on a component you will be able to delete it or copy it to the same or a different view.
![Editor with competition tab open](../_static/editor_competition.png)
......@@ -31,5 +31,3 @@ Below that you will be able to add and remove text and image components as well
The background image for the competition can be overridden by explicitly setting it on a specific page.
![Editor with slide tab open](../_static/editor_slide.jpg)
[comment]: # 'Perhaps mention right clicking a component to make a copy to another view?'
[comment]: # "Why is this file named 'presentation' but the main headline is 'Active competitions'?"
# Presentations
# Active competitions
There are many different views during a competition.
Below it is described how to start a competition, how to join a competition, and how the different kinds of views work.
An active (i.e. started) competition is for simplicity's sake called a presentation.
There are many different views during a presentation.
Below it is described how to start a competition, how to join a presentation, and how the different kinds of views work.
## Competition codes
You can join a competition with codes.
You can join a presentation with codes.
This can either be done by pasting the link that can be copied when listing the codes or can be typed by hand in the login page.
All the views have different purposes and therefore looks a little bit different from one another.
......@@ -16,17 +15,16 @@ All the views have different purposes and therefore looks a little bit different
There are two ways to start a competition.
The first way is to navigate to the competition manager, press the three dots "..." and press "Starta".
You will then enter the operator view.
From there you will be able to go between slides with the "<" and ">" buttons or start the timer, both will be synced between all clients connected to that competition.
You will also be able to view the scores for the teams and view all codes to the competition.
From there you will be able to go between slides with the "<" and ">" buttons and start the timer, both will be synced between all clients connected to that presentation.
You will also be able to view all codes to the competition.
You can also show the current score for all teams to the audience.
![Operator view](../_static/operator.jpg)
## Team
[comment]: # 'What is meant with "(or the code for one of the teams)"? Doesnt a team have to log in using a code?'
The team view (or the code for one of the teams) will be used by teams.
It shows the current slide (that the operator has decided) and allows the user to answer questions on the slide that will be saved.
The team view will be used by teams.
It shows the current slide (that the operator has decided) and allows the user to answer questions on the slide, which will be saved.
![Team view](../_static/team.jpg)
......@@ -38,10 +36,8 @@ The audience view will look like the operator view but without the buttons.
## Judge
[comment]: # 'Update image to show that the current slide is highlighted.'
The judge view will show show the same slide as team view.
To the left you will be able to move between different slides without affecting the other clients and will be shown och which slide the operator currently is.
To the left you will be able to move between different slides without affecting the other clients and will be shown on which slide the operator currently is.
To the right you will see what the teams have answered on every question, what score each team got on each question, their total score and be able to set the score of a team on any and all questions.
In the bottom right you will see instructions for how to grade the current question.
......
......@@ -6,8 +6,6 @@ database. It can add, get, delete, edit, search and copy items.
from app.apis import http_codes
from flask_smorest import abort
from flask_smorest.pagination import PaginationParameters
# from flask_restx import abort
from flask_sqlalchemy import BaseQuery
from flask_sqlalchemy.model import Model
from sqlalchemy import Column, DateTime
......
......@@ -7,8 +7,6 @@ from app.apis import http_codes
from app.core import db
from app.database.models import QuestionAlternativeAnswer, QuestionScore, Whitelist
from flask_smorest import abort
# from flask_restx import abort
from sqlalchemy.exc import IntegrityError
......
......@@ -5,8 +5,6 @@ This file contains functionality to get data from the database.
from app.apis import http_codes
from app.core import db
from flask_smorest import abort
# from flask_restx.errors import abort
from sqlalchemy import exc
......
......@@ -8,8 +8,6 @@ from app.core.codes import generate_code_string
from app.database.models import Code
from flask_smorest import abort
# from flask_restx import abort
def move_order(orders, order_key, from_order, to_order):
"""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment