# Server overview The server has two main responsibilities. The first is to handle API calls from the client to store, update and delete information, such as competitions or users. 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. When a request is received the server begins by authorizing it (making sure the person sending the request is allowed to access the route). After that it confirms that it got all information in the request that it needed. The server will then process the client request. Finally it generates a response, usually in the form of an object from the database. All of these steps are described in more detail below. ### Routes Each existing route that can be called is specified in the files in the `app/apis/` folder. All available routes can also be seen by navigating to `localhost:5000` after starting the server. ### Authorization When the server receives an API call it will first check that the call is authorized. 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 `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. #### JSON Web Tokens (JWT) JSON Web Tokens (JWT) are used for authentication, both for API and socket events. A JWT is created on the server when a user logs in or connects to a competition. Some information is stored in the JWT, which can be seen in the file `server/app/apis/auth.py`. The JWT is also encrypted using the secret key defined in `server/configmodule.py`. (NOTE: Change this key before running the server in production). The client can read the contents of the JWT but cannot modify them because it doesn't have access to the secret key. This is why the server can simply read the contents of the JWT to be sure that the client is who it says it is. ### Parsing request 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 After the request has been authorized and parsed the server will process the request. What it does depends on the route and the given arguments, but it usually gets, edits or deletes something from the database. The server uses an SQL database and interfaces to it via SQLAlchemy. 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 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. In this way, for example, an entire competition with its teams, codes, slides and the slides' questions and components can be returned in a single API call. ## Active competitions Slides, timers, and answers needs to be synced during an active presentation. 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 `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. ### Starting and joing presentations 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. The server can see what is stored in the JWT and do different things depending on its contents. ### Syncing between clients 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.