Skip to content

Commit

Permalink
Add End Of Year Project
Browse files Browse the repository at this point in the history
  • Loading branch information
Franck Courtaux committed Oct 25, 2022
0 parents commit 7b2a3e9
Show file tree
Hide file tree
Showing 167 changed files with 32,998 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.DS_STORE
.vscode
node_modules
vendor
33 changes: 33 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
stages:
- triggers


statfive_api:
stage: triggers
trigger:
include: api/.gitlab-ci.yml
rules:
- changes:
- api/*
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never

statfive_web:
stage: triggers
trigger:
include: web/.gitlab-ci.yml
rules:
- changes:
- web/*
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never

statfive_tracker:
stage: triggers
trigger:
include: tracker/.gitlab-ci.yml
rules:
- changes:
- tracker/*
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never
Binary file added Fiche Projet GPE_StatFive.pdf
Binary file not shown.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# StatFive

## Start the project

### Azure AKS
#### Prerequisites
- 1 Azure Account
- 1 Azure AKS Cluster
- Azure CLI
- Kubectl
- Helm CLI
- OVH Account with a Domain Name
- Generate API OVH Credentials

#### Deploy
- `$> az login`
- `$> az account set --subscription xxxxxxxxxxxxxxxxxxxxxxxx`
- `$> az aks get-credentials --resource-group xxxxxxxx --name xxxxxxxx`
- `$> cd Statfive/kubernetes`
- Edit Traefik Ingress Files to match the proxy redirection urls with your domain name
- Edit Ovh API credentials
- `$> ./deploy.sh`
- go to https://dashboard.{YOUR_DOMAIN}/

### Docker-compose
#### Prerequisites
- Docker
- Docker-Compose
- Letsencrypt
- Certbot

#### Generate Certificates
- `$> sudo certbot certonly --server https://acme-v02.api.letsencrypt.org/directory --manual -d '*.{YOUR_DOMAIN}'`
- Change conf in nginx/\*.conf files to match the proxy redirection urls with your domain name

#### Deploy:
- `$> sudo docker-compose up -d`
- go to https://dashboard.{YOUR_DOMAIN}/
5 changes: 5 additions & 0 deletions api/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
**/venv
**/.idea
**/log
__pycache__/
migrations
5 changes: 5 additions & 0 deletions api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
**/venv
**/.idea
**/log
__pycache__/
migrations
90 changes: 90 additions & 0 deletions api/.gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
stages:
- test
- setup
- build
- publish
- deploy


.ssh-connect-preprod:
image: debian:11
variables:
COMMAND: "echo 'You need to implement COMMAND Variable'"
before_script:
- 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- touch ~/.ssh/known_hosts
- echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
script:
- ssh "$PREPROD_GITUSER"@"$PREPROD_SERVER_IP" "cd $PATH_GPE_DIR; $COMMAND"


unit-test-api:
image: python:3.9
stage: test
before_script:
- cd api/
- python -V
- pip install --upgrade pip
- pip install -r requirements.txt
script:
- echo "Running unit test"
- python route.py
only:
refs:
- staging

pull-api-git:
stage: setup
extends: .ssh-connect-preprod
variables:
COMMAND: "cd api/ && sudo git pull origin staging"
needs: [unit-test-api]
only:
refs:
- staging


build-api:
stage: build
extends: .ssh-connect-preprod
variables:
COMMAND: "sudo docker-compose build api"
needs: [pull-api-git]
only:
refs:
- staging


publish-api:
stage: publish
extends: .ssh-connect-preprod
variables:
COMMAND: "sudo docker push acalhabi/statfive_api"
only:
refs:
- master


deploy-preprod-api:
stage: deploy
extends: .ssh-connect-preprod
variables:
COMMAND: "sudo docker-compose up -d"
needs: [build-api]
only:
refs:
- staging

deploy-prod-api:
stage: deploy
extends: .ssh-connect-preprod
variables:
COMMAND: "kubectl rollout restart deployment api -n statfive"
needs: [publish-api]
only:
refs:
- master
15 changes: 15 additions & 0 deletions api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM --platform=linux/amd64 debian:11

RUN apt-get update && apt-get upgrade -y
RUN apt-get -y install python3 python3-pip python3-venv python3-dev
RUN apt-get -y install build-essential libssl-dev libffi-dev default-libmysqlclient-dev

COPY requirements.txt requirements.txt
RUN python3 -m venv venv
RUN venv/bin/pip3 install wheel
RUN venv/bin/pip3 install -r requirements.txt

COPY . ./
RUN chmod +x boot.sh

ENTRYPOINT ["bash", "./boot.sh"]
5 changes: 5 additions & 0 deletions api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# statfive_api

docker-compose up --build -d

http://0.0.0.0:5001
5 changes: 5 additions & 0 deletions api/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from src.launcher import create_app

if __name__ == '__main__':
app = create_app('docker')
app.run(host='0.0.0.0')
14 changes: 14 additions & 0 deletions api/boot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

source venv/bin/activate
sleep 1
rm -rf migrations
for i in $(seq 1 10);
do
# nohup python manage.py db init
# nohup python manage.py db upgrade
# nohup python manage.py db migrate
sleep 1
done
nohup python -u app.py --host 0.0.0.0 --port 5000 --conf docker
exec tail -f /dev/null
Empty file added api/manage.py
Empty file.
32 changes: 32 additions & 0 deletions api/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
aniso8601==9.0.1
apispec==5.0.0
apispec-webframeworks==0.5.2
attrs==21.2.0
blinker==1.4
click==8.0.1
flasgger==0.9.5
Flask==2.0.1
flask-apispec==0.11.0
Flask-Cors==3.0.10
Flask-Mail==0.9.1
Flask-MySQLdb==0.2.0
Flask-RESTful==0.3.9
flask-restplus==0.13.0
flask-restx==0.5.0
Flask-SQLAlchemy==2.5.1
flask-swagger-ui==3.36.0
greenlet==1.1.0
itsdangerous==2.0.1
jsonschema==3.2.0
marshmallow==3.13.0
mistune==0.8.4
mysqlclient==2.0.3
PyJWT==2.1.0
pyrsistent==0.18.0
pytz==2021.1
PyYAML==5.4.1
six==1.16.0
SQLAlchemy==1.4.22
webargs==8.0.0
Werkzeug==2.0.1
requests==2.28.1
Empty file added api/src/__init__.py
Empty file.
133 changes: 133 additions & 0 deletions api/src/auth/authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from functools import wraps
from flask import json, Response, request, g
from ..models.user import User
import datetime
import jwt


class Auth:

@staticmethod
def auth_required(func):
@wraps(func)
def decorated_auth(*args, **kwargs):
if 'api-token' not in request.headers:
return Response(mimetype='application/json',
response=json.dumps(
{'error': 'Authentication token is not available, please login to get one'}),
status=400)
else:
token = request.headers.get('api-token')
data = Auth.decode_token(token)
if data['error']:
return Response(mimetype='application/json',
response=json.dumps(data['error']),
status=400)
user_id = data['data']['user_id']
check_user = User.get_one_user(user_id)
if not check_user:
return Response(mimetype='application/json',
response=json.dumps({'error': 'user does not exist, invalid token'}),
status=400)
g.user = {'id': user_id}
return func(*args, **kwargs)

return decorated_auth

@staticmethod
def super_admin_required(func):
@wraps(func)
def decorated_auth(*args, **kwargs):
if 'api-token' not in request.headers:
return Response(mimetype='application/json',
response=json.dumps(
{'error': 'Authentication token is not available, please login to get one'}),
status=400)
else:
token = request.headers.get('api-token')
data = Auth.decode_token(token)
if data['error']:
return Response(mimetype='application/json',
response=json.dumps(data['error']),
status=400)
user_id = data['data']['user_id']
check_user = User.get_one_user(user_id)
if not check_user:
return Response(mimetype='application/json',
response=json.dumps({'error': 'user does not exist, invalid token'}),
status=400)
elif check_user.role != 2:
return Response(mimetype='application/json',
response=json.dumps({'error': 'user not super admin'}),
status=400)
g.user = {'id': user_id}
return func(*args, **kwargs)

return decorated_auth

@staticmethod
def admin_required(func):
@wraps(func)
def decorated_auth(*args, **kwargs):
if 'api-token' not in request.headers:
return Response(mimetype='application/json',
response=json.dumps(
{'error': 'Authentication token is not available, please login to get one'}),
status=400)
else:
token = request.headers.get('api-token')
data = Auth.decode_token(token)
if data['error']:
return Response(mimetype='application/json',
response=json.dumps(data['error']),
status=400)
user_id = data['data']['user_id']
check_user = User.get_one_user(user_id)
if not check_user:
return Response(mimetype='application/json',
response=json.dumps({'error': 'user does not exist, invalid token'}),
status=400)
elif check_user.role != 2 and check_user.role != 1:
return Response(mimetype='application/json',
response=json.dumps({'error': 'user not super admin or admin'}),
status=400)
g.user = {'id': user_id}
return func(*args, **kwargs)

return decorated_auth


@staticmethod
def generate_token(user_id):

try:
payload = {'exp': datetime.datetime.utcnow() + (datetime.timedelta(days=1)),
'iat': datetime.datetime.utcnow(),
'sub': user_id}
return jwt.encode(payload, 'StatFive', 'HS256')
except Exception as e:
try:
return Response(mimetype='application/json',
response=json.dumps({'error': 'error in generating user token'}),
status=400)
finally:
e = None
del e

@staticmethod
def decode_token(token):
re = {'data': {}, 'error': {}}
try:
payload = jwt.decode(token, 'StatFive', 'HS256')
re['data'] = {'user_id': payload['sub']}
return re
except jwt.ExpiredSignatureError as e1:
try:
re['error'] = {'message': 'token expired, please login again.'}
return re
finally:
e1 = None
del e1
except jwt.InvalidTokenError:
re['error'] = {'message': 'Invalid token, please try again with a new token.'}
return re
Loading

0 comments on commit 7b2a3e9

Please sign in to comment.