a live version can be found here.
Please make sure you have docker, docker-compose and node installed.
make up
All the following commands assume the dev env is set.
make backend_coverage
make frontend_coverage
make coverage
make backend_lint
make frontend_lint
make lint
make backend_lint_fix
make frontend_lint_fix
make lint_fix
make local_build
make local_build_and_run
Then go to http://127.0.0.1:8000.
This assumes you have built and are running the build.
make e2e_tests
act -j backend
act -j frontend
act -j e2e
The app is made with Django, React, React-Router, Vite, Redux-Toolkit and Ant-Design.
url | method | argument | description |
---|---|---|---|
api/users/ | POST | body must contain username and email | Endpoint to create a user, returns an extra timer time_to_create which isn't persisted. |
api/users/int:pk | GET | pk is the primary key | Endpoint to get a user. |
assets/ | GET | Serves assets (js/css files) | |
* | GET | Catch-all that returns index.html to enable react-router to function on page refresh. |
Linting checks for code style and import order both for frontend and backend.
Unit tests test the front and the back separatly.
Unit tests will fail if the coverage is below 100%.
Additional tests written with selenium in the e2e folder.
Tests are run with firefox.
The docker image is built for amd64/arm64, versionned (by git tags) and pushed to hub.artisandunet.com.
There is a check to predict version conflict, it doesn't push if the version already exists in the registry.
docker pull hub.artisandunet.com/reda_bourial_deezer_assignement:latest
Deployement assumes you already have a nginx reverse proxy for TLS termination and an accessible mysql database.
You must set the following env variables :
Variable | Description | Format |
---|---|---|
DJANGO_SECRET | SECRET_KEY in django | Random string |
DJANGO_CORS_ALLOWED_ORIGINS | CORS_ALLOWED_ORIGINS in django | URLs as string (separated by commas) |
DJANGO_ALLOWED_HOSTS | ALLOWED_HOSTS in django | Hostnames as string (separated by commas) |
MYSQL_HOST | Mysql host to use | String |
MYSQL_DATABASE | Mysql database to use | String |
MYSQL_USER | Mysql user to use | String |
MYSQL_PASSWORD | Mysql password to use | String |
GUNICORN_WORKERS | Number of gunicorn work | Integer (default: 10) |
GUNICORN_INTERFACE | Interface to bind to | IP address (default: 0.0.0.0) |
GUNICORN_PORT | Port to listen to | Integer (default:8000) |
You can check that everything is okay with your env variables using :
docker run \
-e DJANGO_SECRET=$$$$$$$$$$$$$$$$$$$$$$$$$ \
-e DJANGO_CORS_ALLOWED_ORIGINS=$$$$$$$$$$$$ \
-e DJANGO_ALLOWED_HOSTS=$$$$$$$$$$$$$$$$$$$ \
-e MYSQL_HOST=$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ \
-e MYSQL_DATABASE=$$$$$$$$$$$$$$$$$$$$$$$$$ \
-e MYSQL_USER=$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ \
-e MYSQL_PASSWORD=$$$$$$$$$$$$$$$$$$$$$$$$$ \
hub.artisandunet.com/reda_bourial_deezer_assignement \
python manage.py check --deploy
SESSION_COOKIE_SECURE is set to true make sure you set at least the X-Forwarded-Proto header in your nginx config.
Here is the recommended directives :
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
I is also be recommended to set the following (compatible with nginx 1.19.8+ only) :
proxy_cookie_flags Set $cookie_name secure;
An example configuration can be found in the examples folder.
docker run \
-e DJANGO_SECRET=$$$$$$$$$$$$$$$$$$$$$$$$$ \
-e DJANGO_CORS_ALLOWED_ORIGINS=$$$$$$$$$$$$ \
-e DJANGO_ALLOWED_HOSTS=$$$$$$$$$$$$$$$$$$$ \
-e MYSQL_HOST=$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ \
-e MYSQL_DATABASE=$$$$$$$$$$$$$$$$$$$$$$$$$ \
-e MYSQL_USER=$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ \
-e MYSQL_PASSWORD=$$$$$$$$$$$$$$$$$$$$$$$$$ \
hub.artisandunet.com/reda_bourial_deezer_assignement \
python manage.py migrate
While not an issue by itself, i am aware that using a CDN is a more appropriate way of serving static files. But since django does caching and nginx does the compression, the impact is minimal.
Source maps are added to the static folder and served by django. A better way would be to filter source maps and store them as artifacts but that will not be done.
When building the following errors will appear:
node_modules/antd/es/card/index.js (1:0): Error when using sourcemap for reporting an error: Can't resolve original location of error.
node_modules/antd/es/app/index.js (1:0): Error when using sourcemap for reporting an error: Can't resolve original location of error.
node_modules/antd/es/checkbox/index.js (1:0): Error when using sourcemap for reporting an error: Can't resolve original location of error.
node_modules/antd/es/auto-complete/index.js (1:0): Error when using sourcemap for reporting an error: Can't resolve original location of error.
node_modules/antd/es/back-top/index.js (1:0): Error when using sourcemap for reporting an error: Can't resolve original location of error.
...
The build files work fine, beside the fact that exceptions can't be traced in antd. The issue has been reported on github but i couldn't find a fix.
act just isn't compatible with QEMU's setup action.
I couldn't figure out how to do it simply.
I didn't have time to implement it.
I choose to use the matrix exponentiation method for computing fibonnaci. While not the most straightfoward method it is the fastest. My though is that specs change and you should always implement the fastest method for n -> โ .
For the record i known it is slower than this implementation for x in [50,55] :
def fibonacci(x):
# Start with a state corresponding to fib(50)
fib_x = 12586269025
fib_x_minus_one = 7778742049
# Iterate until fib(x) is computed
for _ in range(x - 50):
temp = fib_x
fib_x = fib_x + fib_x_minus_one
fib_x_minus_one = temp
return fib_x
It is assumed nginx does redirection from http to https.
In this case setting SECURE_SSL_REDIRECT results in a redirection loop.
Fixed here
This fix makes the first level of STATIC_ROOT immutable, which means nothing but vite files are immutable, adjust if needed.