Version 1 (currently in development).
For full API documentation, check the API Docs
.
For full project information, check the main README file
.
If you want to contribute to the project, you should start by reading the contribution guidelines and the code of conduct.
The project is open source, so feel free to use parts of the code. However, the full project itself is not meant to be reused. The design, the concept and the project itself are personal and belong to the Send A Hug group.
- Python 3.9+
- Postgres 13
- Download or clone the repo.
- cd into the project directory.
- cd into backend.
- Run
pip install -r requirements.txt -r dev_requirements.txt
to install dependencies. - Run
pre-commit install
to install and initialise pre-commit. - Create a database for the app.
- Update the database URI to match your system.
- The database URI comes from an environment variable named DATABASE_URL.
- Set Auth0 configuration variables:
- AUTH0_DOMAIN - environment variable containing your Auth0 domain.
- API_AUDIENCE - environment variable containing your Auth0 API audience.
- CLIENT_ID - environment variable containing your Auth0 application's client ID.
- PRIVATE_KEY - environment variable containing your private VAPID key (required for push notifications).
- MGMT_API_TOKEN - environment variable containing your Auth0 Management API token (required for updating user roles on signup).
- CLIENT_SECRET - environment variable containing your Auth0 application's client secret (required for updating user roles on signup).
- Set up your frontend URI.
- The frontend URI comes from an environment variable named FRONTEND.
- Update your database using
flask db upgrade
- Run flask with:
export FLASK_APP=app.py
flask --debug run
Not yet ready for users!
The app contains several files and folders:
- app.py - The main application file. This file contains all endpoints and error handlers.
- filter.py - The system responsible for filtering words. (Work in progress)
- manage.py - The file managing running database migrations when deploying.
- models.py - The file containing SQLAlchemy models, as well as all database-related methods.
- auth.py - The file dealing with authentication - getting the Authorization header, verifying the JWT and confirming the user has the required permission.
- test_app.py - The file containing the backend's test suite.
The site uses several tools to maximise compatibility:
-
Flask - Flask is a microframework used to build and run the local server on which the app is running. For full Flask documentation, try the Flask website. Flask is a Python framework, so it requires installing Python (or Python3).
-
Flask-SQLAlchemy - This application uses the SQLAlchemy ORM in order to interact with the database, using the Flask-SQLAlchemy extension. You can read more about SQLAlchemy (including API documentation) on the SQLAlchemy website, and about Flask-SQLAlchemy on the Flask-SQLAlchemy website.
-
Flask-Migrate - This application uses Flask-Migrate in order to manage model versions. You can read more on the Flask-Migrate website.
-
Flask-CORS - This application uses Flask-CORS in order to enable communication from the frontend. You can read more on the Flask-CORS website.
-
Python-Jose - This application uses Python-Jose in order to decode and verify the authenticity of a given JWT (see Contents -> auth.py). You can read more on the Python-Jose website.
-
PyWebPush - This application uses pywebpush in order to handle push notifications. For more information, check their GitHub repo.
-
sh - This application uses sh during testing (in order to handle the database). For more information, check the sh PyPi page.
-
Coverage - This application uses coverage in order to provide code coverage for testing. For more information, check the Coverage documentation.
The project uses Auth0 as a third-party authentication provider. Authentication is done by Auth0, which in turn returns a JSON Web Token containing the user's data and permissions.
Decoding and verifying the token is done by auth.py
, in three stages:
-
The server gets the Authorization header from the request and ensures that it exists and is in the right form. (Done by the
get_auth_header()
function.) -
The server uses Jose to decode and verify the token. (Done by the
verify_jwt()
function.) -
Once the JWT is decoded and verified, the user's permissions (taken from the token payload) are checked. Each endpoint that requires authorisation contains a string, which is then compared to the user's permissions. (Done by the
check_permissions()
function.)
Endpoints that require authorisation are marked with the @requires_auth
decorator. The function creating the decorator is written in full in auth.py
.
In case the user's authorisation header is malformed, their JWT is invalid in any way, or they don't have the required permission, the server raises an AuthError. The error handler is defined in full with the rest of the error handlers, in app.py
.
This project utilises Python's unittest for testing. There are two options in terms of setting up authentication for testing: generating JWTs for each of the four required users manually, or using Auth0's Resource Owner Password flow. This project is set up using the latter, but if you want to use the former, skip to the second part of testing.
As said, automated testing takes advantage of Auth0's Resource Owner Password flow. This means that the users' credentials are sent to Auth0 in exchange for a JWT.
The required setup is:
- The password flow needs to be added to the application's grant types. This is done via the Auth0 Management API. See full instructions here.
- Make sure to change only the Test Application's grant types! This is important as this grant type should only be given to highly trusted apps, and doing it in the main application could lower your application's security. This is the purpose of the test application Auth0 automatically creates; use it.
- If you haven't set it before, add the default connection to your account. This tells Auth0's systems where to look for a match for the sent username and password. This is done through your user's settings, in the field
Default Directory
. - Once the password flow was added as a grant type, add the following environment variables:
- TEST_CLIENT_ID - The ID of your Test Application.
- TEST_CLIENT_SECRET - The secret of your Test Application.
- Username and password for each user:
- For the User - USER_USERNAME + USER_PASSWORD
- For the Moderator - MODERATOR_USERNAME + MODERATOR_PASSWORD
- For the Admin - ADMIN_USERNAME + ADMIN_PASSWORD
- For the Blocked New User - BLOCKED_USERNAME + BLOCKED_PASSWORD
Should you choose to manually generate user tokens, the get_user_tokens()
request flow (lines 67-91) can be replaced with the relevant access tokens. These should be saved as environment variables.
The recommended structure is:
- USER_JWT - JWT of a user with the role of a user.
- MOD_JWT - JWT of a user with the role of a moderator.
- ADMIN_JWT - JWT of a user with the role of an admin.
- BLOCKED_JWT - JWT of a user who's currently blocked and is a new user. (This is required for one of the tests, so make sure to manually change the user's role.)
Once you've completed the setup for whichever approach you've chosen, run the following commands:
"CREATE DATABASE test_sah;" | sudo -u postgres psql
python -m unittest tests/test_app.py
Or, if using macOS:
dropdb test_sah && createdb test_sah
python3 -m unittest tests/test_app.py
The project was hosted live on Heroku (we're currently looking at alternatives, due to Heroku removing their free tier). If you want to clone and host your own version, you can do so by using the following guide (the following commands are for Heroku, but they can be adjusted depending on your host):
- Create a Heroku account (skip this step if you already have an account).
- Install the Heroku command line interface.
- In your Terminal, enter
heroku login
. This triggers logging in via the CLI. - Enter
heroku create <APP_NAME>
(with your own app name). If successful, Heroku returns the live version's URL (will be referred to as <LIVE_URL>) and the Git repo link (will be referred to as <GIT_URL>). - Enter
heroku addons:create heroku-postgresql:hobby-dev --app <APP_NAME>
. This creates a Postgres database for your app. Change 'hobby-dev' to another tier if you want to use the app with a paid tier (depending on your needs; for more information check the Heroku guide). - Make sure you're in the top directory (FSND-capstone). In your terminal, enter
git remote add heroku-server <GIT_URL>
. - Enter
git subtree push --prefix backend heroku-server master
. This triggers the app build. If successful, you'll get a 'Verifying deploy... done.' message. - Add the following environment variables (via CLI or via the Heroku website): - API_AUDIENCE - set with your own API audience from Auth0 - AUTH0_DOMAIN - set with your own Auth0 domain - CLIENT_ID - set with your own client ID from Auth0 - FRONTEND - set with your own frontend URL (necessary for setting up CORS!) - PRIVATE_KEY - The private VAPID key (required for sending push notifications).
- Enter
flask db upgrade
to trigger database migrations and bring your live database up to date. - All done! Now you can visit your <GIT_URL> to see the live app.
There are no current issues at the time.