ajout d'un backend python RESTful avec Flask
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -40,3 +40,8 @@ testem.log
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Python
|
||||
/backend/.venv
|
||||
/backend/log
|
||||
*.pyc
|
||||
38
backend/requirements.txt
Normal file
38
backend/requirements.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
aniso8601==9.0.1
|
||||
asn1crypto==1.5.1
|
||||
attrs==21.4.0
|
||||
certifi==2022.5.18.1
|
||||
cffi==1.15.0
|
||||
charset-normalizer==2.0.12
|
||||
click==8.1.3
|
||||
cryptography==37.0.3
|
||||
Flask==2.1.2
|
||||
Flask-API==3.0.post1
|
||||
Flask-Cors==3.0.10
|
||||
Flask-JWT-Extended==4.4.1
|
||||
Flask-Login==0.6.1
|
||||
Flask-WTF==1.0.1
|
||||
greenlet==1.1.2
|
||||
idna==3.3
|
||||
importlib-metadata==4.11.4
|
||||
importlib-resources==5.7.1
|
||||
itsdangerous==2.1.2
|
||||
Jinja2==3.1.2
|
||||
jsonschema==4.6.0
|
||||
MarkupSafe==2.1.1
|
||||
pyasn1==0.4.8
|
||||
pycparser==2.21
|
||||
PyJWT==2.4.0
|
||||
pyrsistent==0.18.1
|
||||
pytz==2022.1
|
||||
requests==2.28.0
|
||||
six==1.16.0
|
||||
typing_extensions==4.2.0
|
||||
urllib3==1.26.9
|
||||
waitress==2.1.2
|
||||
Werkzeug==2.1.2
|
||||
WTForms==3.0.1
|
||||
zipp==3.8.0
|
||||
sqlalchemy==1.4.41
|
||||
flask-sqlalchemy==2.5.1
|
||||
pymysql==1.0.2
|
||||
10
backend/run.py
Normal file
10
backend/run.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : Backend Configurateur football-drawing
|
||||
|
||||
from src import app
|
||||
print("Launch Flask Backend ...")
|
||||
ret, application = app.create_app()
|
||||
if application and ret:
|
||||
application.run(host="0.0.0.0", port=6000, use_reloader=False)
|
||||
23
backend/setup.py
Normal file
23
backend/setup.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import io, os
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
def read_requirements(path):
|
||||
ret = []
|
||||
with open(path, "r") as f:
|
||||
ret = f.read().splitlines()
|
||||
return ret
|
||||
|
||||
setup(
|
||||
name='ConfigurateurBack',
|
||||
version="1.0.0",
|
||||
author='Vincent BENOIT',
|
||||
author_email='vincent.benoit@benserv.fr',
|
||||
url='https://git.nas.benserv.fr/vincent/football-drawing.git',
|
||||
description='Backend RESTful API pour l\'outil football-drawing',
|
||||
long_description=read("README.md"),
|
||||
long_description_content_type="text/markdown",
|
||||
packages=["src"],
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=read_requirements("requirements.txt")
|
||||
)
|
||||
0
backend/src/__init__.py
Normal file
0
backend/src/__init__.py
Normal file
100
backend/src/app.py
Normal file
100
backend/src/app.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : football-drawing Flask RESTful API
|
||||
|
||||
#########################################################
|
||||
# Importation de modules externes #
|
||||
|
||||
import sys, re, os
|
||||
from pprint import pprint
|
||||
import logging as log
|
||||
from logging.config import dictConfig
|
||||
|
||||
from flask import Flask
|
||||
from flask.logging import default_handler
|
||||
from flask_cors import CORS, cross_origin
|
||||
from flask_jwt_extended import JWTManager
|
||||
|
||||
import jwt
|
||||
|
||||
from src.config import DefaultConfig
|
||||
from src.db import mydb
|
||||
#from src.drawing import drawing
|
||||
|
||||
#########################################################
|
||||
# Corps principal du programme #
|
||||
|
||||
def create_app(config=None, app_name=None):
|
||||
''' create and configure the app '''
|
||||
print("Create and configure the Flask app ...")
|
||||
if app_name is None:
|
||||
app_name = DefaultConfig.PROJECT
|
||||
|
||||
# create the app
|
||||
# tells the app that configuration files are relative to the instance folder.
|
||||
app = Flask(app_name, instance_path=os.getcwd(), instance_relative_config=True)
|
||||
|
||||
configure_app(app, config)
|
||||
configure_log(app)
|
||||
configure_database(app)
|
||||
#configure_blueprints(app)
|
||||
|
||||
return True, app
|
||||
|
||||
def configure_app(app, config=None):
|
||||
''' configure the app with conf file and/or object '''
|
||||
# load default config
|
||||
app.config.from_object(DefaultConfig)
|
||||
|
||||
if config:
|
||||
# load specific config
|
||||
app.config.from_object(config)
|
||||
|
||||
# setup the Flask-JWT-Extended extension
|
||||
jwt = JWTManager(app)
|
||||
# setup the Flask-CORS extension for handling Cross Origin Resource Sharing
|
||||
CORS(app, resources={r"/api/*": {
|
||||
"origins": ["http://localhost:4200","http://localhost:5000"],
|
||||
"supports_credentials": True
|
||||
}})
|
||||
|
||||
def configure_log(app):
|
||||
''' configure log handler '''
|
||||
if not os.path.exists(app.config['LOG_FOLDER']):
|
||||
try:
|
||||
os.makedirs(app.config['LOG_FOLDER'])
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# On vire tous les handlers
|
||||
for h in app.logger.handlers:
|
||||
app.logger.removeHandler(h)
|
||||
|
||||
# Set info level on logger, which might be overwritten by handers.
|
||||
# Suppress DEBUG messages.
|
||||
app.logger.setLevel(log.DEBUG)
|
||||
|
||||
formatter = log.Formatter('%(asctime)s - %(name)s [%(module)s.%(funcName)s:%(lineno)d] - %(levelname)s - %(message)s')
|
||||
info_log = os.path.join(app.config['LOG_FOLDER'], DefaultConfig.PROJECT + '.log')
|
||||
info_file_handler = log.handlers.RotatingFileHandler(info_log, maxBytes=100000, backupCount=10)
|
||||
info_file_handler.setLevel(log.INFO)
|
||||
info_file_handler.setFormatter(formatter)
|
||||
app.logger.addHandler(info_file_handler)
|
||||
|
||||
fl = log.StreamHandler()
|
||||
fl.setLevel(log.DEBUG)
|
||||
fl.setFormatter(formatter)
|
||||
app.logger.addHandler(fl)
|
||||
|
||||
def configure_database(app):
|
||||
''' configure database parameters '''
|
||||
# SQLAlchemy
|
||||
mydb.init_app(app)
|
||||
with app.app_context():
|
||||
mydb.create_all()
|
||||
|
||||
#def configure_blueprints(app):
|
||||
# ''' configure blueprints '''
|
||||
# for bp in [users, auth, messages]:
|
||||
# app.register_blueprint(bp)
|
||||
53
backend/src/config.py
Normal file
53
backend/src/config.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# @author: vincent.benoit@benserv.fr
|
||||
# @brief: Flask Config classes
|
||||
|
||||
import os
|
||||
import datetime
|
||||
|
||||
class BaseConfig(object):
|
||||
PROJECT = "football-drawing"
|
||||
|
||||
# Get app root path, also can use flask.root_path.
|
||||
PROJECT_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
DEBUG = False
|
||||
TESTING = False
|
||||
|
||||
ADMINS = ['vincent.benoit@benserv.fr']
|
||||
|
||||
LOG_FOLDER = os.path.join(os.getcwd(), 'log')
|
||||
|
||||
class DefaultConfig(BaseConfig):
|
||||
DEBUG = True
|
||||
TESTING = True
|
||||
FLASK_ENV = 'development'
|
||||
|
||||
SECRET_KEY = "thisissecret"
|
||||
|
||||
# Setup the Flask-JWT-Extended extension
|
||||
JWT_SECRET_KEY = "cdscjdsklcfqezffhrevneqggfuhmnvqnmh"
|
||||
JWT_COOKIE_SECURE = False
|
||||
JWT_TOKEN_LOCATION = ["cookies"]
|
||||
JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(hours=1)
|
||||
# Controls if Cross Site Request Forgery (CSRF) protection is enabled when using cookies
|
||||
# This should always be True in production
|
||||
JWT_COOKIE_CSRF_PROTECT = True
|
||||
JWT_CSRF_IN_COOKIES = True
|
||||
|
||||
UPLOAD_FOLDER = os.path.join(os.getcwd(),'static/img')
|
||||
ALLOWED_EXTENSIONS = {'png', 'jpg', 'gif', 'jpeg'}
|
||||
MAX_CONTENT_LENGTH = 1 * 1024 * 1024 # 1 megabytes
|
||||
|
||||
SQL_HOST_URI = '127.0.0.1'
|
||||
SQL_PORT = 3306
|
||||
SQL_USERNAME = 'root'
|
||||
SQL_PASSWORD = 'root'
|
||||
SQL_DATABASE = 'football_drawing'
|
||||
|
||||
# Log all the statements issued to stderr which can be useful for debugging
|
||||
SQLALCHEMY_ECHO = False
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = True
|
||||
# Mariadb for production.
|
||||
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://' + SQL_USERNAME + ':' + SQL_PASSWORD + '@' + SQL_HOST_URI + ':' + str(SQL_PORT) + '/' + SQL_DATABASE + '?charset=utf8'
|
||||
31
backend/src/db.py
Normal file
31
backend/src/db.py
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : wrapper de la base de données mariadb
|
||||
|
||||
#########################################################
|
||||
# Importation de modules externes #
|
||||
|
||||
import sys, re, os
|
||||
import logging as log
|
||||
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
from flask_api import status
|
||||
from flask import current_app
|
||||
|
||||
from functools import wraps
|
||||
from src.config import DefaultConfig
|
||||
|
||||
#########################################################
|
||||
# Class et Methods #
|
||||
|
||||
#########################################################
|
||||
# Decorators #
|
||||
|
||||
#########################################################
|
||||
# Instantiation #
|
||||
|
||||
# Instantiate database via SQLAlchemy
|
||||
mydb = SQLAlchemy()
|
||||
7
backend/src/drawing/__init__.py
Normal file
7
backend/src/drawing/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : Users views and models
|
||||
|
||||
from .views import users
|
||||
from .models import User
|
||||
82
backend/src/drawing/models.py
Normal file
82
backend/src/drawing/models.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : Users model
|
||||
|
||||
#########################################################
|
||||
# Importation de modules externes #
|
||||
|
||||
import sys, re, os
|
||||
import logging as log
|
||||
import json
|
||||
import enum
|
||||
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from werkzeug.exceptions import HTTPException, RequestEntityTooLarge
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from sqlalchemy import Enum
|
||||
|
||||
from src.db import mydb as db
|
||||
|
||||
#########################################################
|
||||
# Class et Methods #
|
||||
|
||||
class Role(enum.Enum):
|
||||
Administrateur = "Administrateur"
|
||||
Coach = "Coach"
|
||||
|
||||
class User(db.Model):
|
||||
__tablename__ = 'utilisateur'
|
||||
|
||||
userId = db.Column(db.Integer, primary_key=True)
|
||||
Prenom = db.Column(db.String(32), nullable=False, default="")
|
||||
Nom = db.Column(db.String(32), nullable=False, default="")
|
||||
Identifiant = db.Column(db.String(32), nullable=False, default="")
|
||||
Role = db.Column(db.String(16), nullable=False, default=Role.Coach)
|
||||
Photo = db.Column(db.String(128), default="")
|
||||
Actif = db.Column(db.Boolean(), nullable=False)
|
||||
__password = db.Column('Password', db.String(256), nullable=False)
|
||||
|
||||
def __init__(self, prenom='', nom='', identifiant='', password='', role='', photo='', actif=False):
|
||||
''' constructor '''
|
||||
self.Prenom = prenom
|
||||
self.Nom = nom
|
||||
self.Identifiant = identifiant
|
||||
self.Password = password
|
||||
self.Role = role
|
||||
self.Photo = photo
|
||||
self.Actif = actif
|
||||
|
||||
def __get_password(self):
|
||||
''' getter password '''
|
||||
return self.__password
|
||||
|
||||
def __set_password(self, password):
|
||||
''' setter hash password '''
|
||||
self.__password = generate_password_hash(password, method='sha256')
|
||||
|
||||
# Hide password encryption by exposing password field only.
|
||||
Password = db.synonym('__password',
|
||||
descriptor=property(__get_password,
|
||||
__set_password))
|
||||
|
||||
# Return a new property that point to the Message class
|
||||
Messages = db.relationship('Message',
|
||||
backref="user",
|
||||
cascade="all, delete-orphan",
|
||||
lazy=True)
|
||||
|
||||
def check_password(self, password):
|
||||
''' check hash password for user '''
|
||||
if self.Password is None:
|
||||
return False
|
||||
return check_password_hash(self.Password, password)
|
||||
|
||||
def as_dict(self):
|
||||
''' User as dictionnary '''
|
||||
result = {}
|
||||
for c in self.__table__.columns:
|
||||
if c.name != 'Password':
|
||||
result[c.name] = getattr(self, c.name)
|
||||
return result
|
||||
338
backend/src/drawing/views.py
Normal file
338
backend/src/drawing/views.py
Normal file
@@ -0,0 +1,338 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : Users routes
|
||||
|
||||
#########################################################
|
||||
# Importation de modules externes #
|
||||
|
||||
import sys, re, os
|
||||
import logging as log
|
||||
import json
|
||||
import datetime
|
||||
|
||||
from flask import Flask, Blueprint, request, abort, jsonify, send_file, current_app
|
||||
from flask_api import status
|
||||
from flask_jwt_extended import create_access_token
|
||||
from flask_jwt_extended import get_jwt
|
||||
from flask_jwt_extended import set_access_cookies
|
||||
from flask_jwt_extended import unset_jwt_cookies
|
||||
from flask_jwt_extended import get_jwt_identity
|
||||
from flask_jwt_extended import jwt_required
|
||||
|
||||
from werkzeug.security import generate_password_hash
|
||||
from werkzeug.exceptions import HTTPException, RequestEntityTooLarge
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from src.db import mydb as db
|
||||
from .models import User
|
||||
|
||||
#########################################################
|
||||
# Class et Methods #
|
||||
|
||||
users = Blueprint('users', __name__, url_prefix='/api/utilisateurs')
|
||||
|
||||
@users.errorhandler(HTTPException)
|
||||
def handle_exception(e):
|
||||
''' return JSON instead of HTML for HTTP errors '''
|
||||
response = e.get_response()
|
||||
# replace the body with JSON
|
||||
response.data = json.dumps({
|
||||
'code': e.code,
|
||||
'name': e.name,
|
||||
'description': e.description,
|
||||
})
|
||||
response.content_type = "application/json"
|
||||
return response
|
||||
|
||||
@users.after_request
|
||||
def refresh_expiring_tokens(response):
|
||||
''' Using an 'after_request' callback, we refresh any token that is within
|
||||
30 minutes of expiring.'''
|
||||
try:
|
||||
exp_timestamp = get_jwt()['exp']
|
||||
now = datetime.datetime.now(datetime.timezone.utc)
|
||||
target_timestamp = datetime.datetime.timestamp(now + datetime.timedelta(minutes=30))
|
||||
### DEBUG ###
|
||||
current_app.logger.debug("exp: {} - target: {}".format(exp_timestamp, target_timestamp))
|
||||
### END DEBUG ###
|
||||
if target_timestamp > exp_timestamp:
|
||||
current_app.logger.warning("On doit recréer un token ....")
|
||||
access_token = create_access_token(identity=get_jwt_identity())
|
||||
set_access_cookies(response, access_token)
|
||||
return response
|
||||
except (RuntimeError, KeyError):
|
||||
return response
|
||||
|
||||
@users.route('', methods=['GET'])
|
||||
@jwt_required()
|
||||
def get_all_users():
|
||||
''' Recuperation de tous les utilisateurs inscrits '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
### DEBUG ###
|
||||
current_app.logger.debug("Current User: {}".format(current_user))
|
||||
### DEBUG END ###
|
||||
# Test si l'utilisateur courant est actif ou pas
|
||||
if not current_user["Actif"]:
|
||||
db.disconnect()
|
||||
abort(status.HTTP_403_FORBIDDEN)
|
||||
|
||||
content = []
|
||||
users = db.session.query(User).all()
|
||||
if len(users):
|
||||
### DEBUG ###
|
||||
current_app.logger.debug("Count: {}".format(len(users)))
|
||||
### END DEBUG ###
|
||||
for user in users:
|
||||
### DEBUG ###
|
||||
current_app.logger.debug("User: {}".format(user.as_dict()))
|
||||
### END DEBUG ###
|
||||
content.append(user.as_dict())
|
||||
return jsonify(content), status.HTTP_200_OK
|
||||
|
||||
@users.route('/<int:userId>', methods=['GET'])
|
||||
@jwt_required()
|
||||
def get_one_user(userId):
|
||||
''' Recuperation d'un seul utilisateur '''
|
||||
content = {}
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
### DEBUG ###
|
||||
current_app.logger.debug("Current User: {}".format(current_user))
|
||||
### DEBUG END ###
|
||||
# Test si l'utilisateur courant est actif ou pas
|
||||
# Si l'utilisateur courant n'est pas administrateur, il ne peut voir que son profil
|
||||
if not current_user["Actif"] or current_user["Role"] != "Administrateur" and current_user['userId'] != userId:
|
||||
abort(status.HTTP_403_FORBIDDEN, description="Not authorized!")
|
||||
|
||||
user = db.session.query(User).filter(User.userId==userId)
|
||||
if user.count():
|
||||
content = user.first().as_dict()
|
||||
else:
|
||||
abort(status.HTTP_404_NOT_FOUND, descrition="User not found")
|
||||
return jsonify(content), status.HTTP_200_OK
|
||||
|
||||
@users.route('', methods=['POST'])
|
||||
@jwt_required()
|
||||
def add_user():
|
||||
''' Ajout d'un utilisateur '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
# Test si l'utilisateur courant est actif et Admin ou pas
|
||||
if not current_user["Actif"] and current_user["Role"] != 'Administrateur':
|
||||
db.disconnect()
|
||||
abort(status.HTTP_403_FORBIDDEN, description='Utilisateur non autorisé')
|
||||
|
||||
# recuperation des attributs (JSON) de la requete
|
||||
data_json = request.get_json()
|
||||
# On vérifie si l'identifiant en base de données est déjà utilisé ou pas
|
||||
user = db.session.query(User).filter(User.Identifiant==data_json['Identifiant'])
|
||||
if user.count():
|
||||
abort(status.HTTP_401_UNAUTHORIZED, description="Identifiant déjà utilisé!")
|
||||
### DEBUG ###
|
||||
current_app.logger.debug("Request datas: {}".format(data_json))
|
||||
### END DEBUG ###
|
||||
# Create new user
|
||||
newUser = User(prenom=data_json['Prenom'],
|
||||
nom=data_json['Nom'],
|
||||
identifiant=data_json['Identifiant'],
|
||||
password=data_json['Password'],
|
||||
role=data_json['Role'],
|
||||
photo=data_json['Photo'],
|
||||
actif=data_json['Actif'])
|
||||
# Send new user to database
|
||||
db.session.add(newUser)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({'message' : 'Nouvel utilisateur créé!'}), status.HTTP_201_CREATED
|
||||
|
||||
@users.route('/<int:userId>', methods=['PUT'])
|
||||
@jwt_required()
|
||||
def modif_user(userId):
|
||||
''' modification d'un utilisateur '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
# Test si l'utilisateur courant est actif ou pas
|
||||
# Si l'utilisateur courant n'est pas administrateur, il ne peut voir que son profil
|
||||
if not current_user["Actif"] or current_user["Role"] != "Administrateur" and current_user['userId'] != userId:
|
||||
abort(status.HTTP_403_FORBIDDEN, description='Utilisateur non autorisé')
|
||||
|
||||
# test des attributs (JSON) de la requete
|
||||
if not request.data.decode("utf-8"):
|
||||
current_app.logger.error("Data not found")
|
||||
abort(status.HTTP_400_BAD_REQUEST, description='Data not found')
|
||||
|
||||
# recuperation des attributs (JSON) de la requete
|
||||
dataDict = request.get_json()
|
||||
# Recupération de l'utilisateur en fonction de l'id
|
||||
user = db.session.query(User).filter(User.userId==userId)
|
||||
if not user.count():
|
||||
abort(status.HTTP_400_BAD_REQUEST, description='User with this id not found')
|
||||
|
||||
user = user.first()
|
||||
user.Prenom = dataDict['Prenom']
|
||||
user.Nom = dataDict['Nom']
|
||||
user.Identifiant = dataDict['Identifiant']
|
||||
user.Password = dataDict['Password']
|
||||
user.Photo = dataDict['Photo']
|
||||
user.Role = dataDict['Role']
|
||||
user.Actif = dataDict['Actif']
|
||||
# Send modified user to database
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({'message' : 'utilisateur {} modifié!'.format(userId)}), status.HTTP_200_OK
|
||||
|
||||
@users.route('/<int:userId>', methods=['DELETE'])
|
||||
@jwt_required()
|
||||
def del_user(userId):
|
||||
''' Suppression d'un utilisateur '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
# Test si l'utilisateur courant est Admin ou pas
|
||||
if not current_user["Actif"] or current_user["Role"] != 'Administrateur':
|
||||
abort(status.HTTP_403_FORBIDDEN, description='Utilisateur non autorisé')
|
||||
|
||||
# test des attributs (JSON) de la requete
|
||||
if request.data.decode("utf-8"):
|
||||
current_app.logger.error("Data found : {}".format(request.data.decode("utf-8")))
|
||||
abort(status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# Recupération de l'utilisateur en fonction de l'id
|
||||
user = db.session.query(User).filter(User.userId==userId)
|
||||
if not user.count():
|
||||
abort(status.HTTP_400_BAD_REQUEST, description='User with this id not found')
|
||||
|
||||
delUser = user.first()
|
||||
# On supprime l'utilisateur de la base de données
|
||||
db.session.delete(delUser)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({'message' : 'utilisateur supprimé!'}), status.HTTP_200_OK
|
||||
|
||||
@users.route('/<int:userId>/reset_password', methods=['GET'])
|
||||
@jwt_required()
|
||||
def reset_passwd_user(userId):
|
||||
''' Reset du mot de passe à un utilisateur représenté par son Id '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
# Test si l'utilisateur courant est Admin ou pas
|
||||
if not current_user["Actif"] or current_user["Role"] != 'Administrateur':
|
||||
abort(status.HTTP_403_FORBIDDEN, description='Utilisateur non autorisé')
|
||||
|
||||
# Recupération de l'utilisateur en fonction de l'id
|
||||
user = db.session.query(User).filter(User.userId==userId)
|
||||
if not user.count():
|
||||
abort(status.HTTP_400_BAD_REQUEST, description='User with this id not found')
|
||||
|
||||
user = user.first()
|
||||
user.Password = 'provisoire'
|
||||
# Send modified user to database
|
||||
db.session.commit()
|
||||
return jsonify({'message' : 'reset du mot de passe!'}), status.HTTP_200_OK
|
||||
|
||||
@users.route('/<int:userId>/activate', methods=['PUT'])
|
||||
@jwt_required()
|
||||
def deactivate_user(userId):
|
||||
''' Désactivation d'un utilisateur représenté par son Id '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
# Test si l'utilisateur courant est Admin ou pas
|
||||
if not current_user["Actif"] or current_user["Role"] != 'Administrateur':
|
||||
abort(status.HTTP_403_FORBIDDEN, description='Utilisateur non autorisé')
|
||||
|
||||
# test des attributs (JSON) de la requete
|
||||
if not request.data.decode("utf-8"):
|
||||
current_app.logger.error("Data not found")
|
||||
abort(status.HTTP_400_BAD_REQUEST, description='Data not found')
|
||||
|
||||
# recuperation des attributs (JSON) de la requete
|
||||
dataDict = request.get_json()
|
||||
# Recupération de l'utilisateur en fonction de l'id
|
||||
user = db.session.query(User).filter(User.userId==userId)
|
||||
if not user.count():
|
||||
abort(status.HTTP_400_BAD_REQUEST, description='User with this id not found')
|
||||
|
||||
user = user.first()
|
||||
user.Actif = dataDict['Actif']
|
||||
# Send modified user to database
|
||||
db.session.commit()
|
||||
return jsonify({'message' : 'desactivation de l\'utilisateur réussi!'}), status.HTTP_200_OK
|
||||
|
||||
@users.route('/<int:userId>/photo', methods=['GET'])
|
||||
@jwt_required()
|
||||
def get_photo(userId):
|
||||
''' Recupere la photo de l'utilisateur suivant son Id '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
# Test si l'utilisateur courant est actif ou pas
|
||||
# Si l'utilisateur courant n'est pas administrateur, il ne peut voir que son profil
|
||||
if not current_user["Actif"] or current_user["Role"] != "Administrateur" and current_user['userId'] != userId:
|
||||
abort(status.HTTP_403_FORBIDDEN, description='Utilisateur non autorisé')
|
||||
|
||||
user = db.session.query(User).filter(User.userId==userId)
|
||||
if not user.count():
|
||||
abort(status.HTTP_404_NOT_FOUND, descrition="User not found")
|
||||
user = user.first()
|
||||
if user.Photo:
|
||||
return send_file(os.path.join(user.Photo), mimetype='image/'+os.path.splitext(user.Photo)[1].split('.')[1])
|
||||
abort(status.HTTP_404_NOT_FOUND, description='Picture not found!')
|
||||
|
||||
@users.route('/current', methods=['GET'])
|
||||
@jwt_required()
|
||||
def current_user():
|
||||
''' retourne l'utilisateur courant connecté '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
return jsonify(current_user)
|
||||
|
||||
def allowed_file(filename):
|
||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in current_app.config['ALLOWED_EXTENSIONS']
|
||||
|
||||
@users.route('/<int:userId>/uploadImage', methods=['POST'])
|
||||
@jwt_required()
|
||||
def uploadImage(userId):
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
# Test si l'utilisateur courant est actif et Admin ou pas
|
||||
# Si l'utilisateur courant n'est pas administrateur, il ne peut voir que son profil
|
||||
if not current_user["Actif"] or current_user["Role"] != "Administrateur" and current_user['userId'] != userId:
|
||||
current_app.logger.error("Utilisateur non autorisé")
|
||||
abort(status.HTTP_403_FORBIDDEN, description='Utilisateur non autorisé')
|
||||
|
||||
# On vérifie que l'utilisateur existe en base de données
|
||||
user = db.session.query(User).filter(User.userId==userId)
|
||||
if not user.count():
|
||||
abort(status.HTTP_404_NOT_FOUND, descrition="User not found")
|
||||
|
||||
user = user.first()
|
||||
|
||||
current_app.logger.debug("Req Headers: {}".format(request.headers))
|
||||
current_app.logger.debug("Req Files: {}".format(request.files))
|
||||
current_app.logger.debug("Req data: {}".format(request.data))
|
||||
|
||||
# check if the post request has the file part
|
||||
if 'photo' not in request.files:
|
||||
current_app.logger.error('No file part in the request')
|
||||
abort(status.HTTP_400_BAD_REQUEST)
|
||||
try:
|
||||
photo = request.files['photo']
|
||||
except RequestEntityTooLarge as e:
|
||||
current_app.logger.error("Fichier trop gros ...")
|
||||
abort(status.HTTP_413_REQUEST_ENTITY_TOO_LARGE)
|
||||
# If the user does not select a file, the browser submits an empty file without a filename
|
||||
if photo.filename == '':
|
||||
current_app.logger.error('No selected file')
|
||||
abort(status.HTTP_401_UNAUTHORIZED)
|
||||
if photo and allowed_file(photo.filename):
|
||||
filename = secure_filename(photo.filename)
|
||||
### DEBUG ###
|
||||
current_app.logger.debug("filename: {}".format(os.path.splitext(filename)))
|
||||
### END DEBUG ###
|
||||
filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], user.Identifiant + os.path.splitext(filename)[1])
|
||||
photo.save(filepath)
|
||||
|
||||
user.Photo = filepath
|
||||
# modify user to database
|
||||
db.session.commit()
|
||||
return jsonify({'message': 'photo saved successfuly!'}), status.HTTP_200_OK
|
||||
Reference in New Issue
Block a user