diff --git a/.env b/.env new file mode 100644 index 0000000..0d4a845 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +DEV_DATABASE_URL=postgresql://dev_user:motdepassedev@51.255.51.83:5433/dev_db +FLASK_ENV="development" \ No newline at end of file diff --git a/.gitignore b/.gitignore index e9174b8..39c5882 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -.env +#.env +migrations/ # Byte-compiled / optimized / DLL files __pycache__/ @@ -130,7 +131,7 @@ celerybeat.pid *.sage.py # Environments -.env +#.env .venv env/ venv/ diff --git a/Dockerfile b/Dockerfile index 57ff104..e83726a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,14 @@ FROM python:3.11-slim - COPY requirements.txt . - +RUN apt update && apt install -y git && rm -rf /var/lib/apt/lists/* +RUN pip install --upgrade pip RUN pip install -r requirements.txt COPY . . - CMD ["python","app.py"] - #ENTRYPOINT ["flask"] #CMD ["run"] #EXPOSE 5000 \ No newline at end of file diff --git a/README.md b/README.md index a857685..2dd7f7f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ - # Project Management API -### Ce micro-service va nous permettre de gérer tous les autres micro-services en les ajoutant, supprimant, avec un système de validation /refus et en se basant sur le système d'authentification. +###### Ce micro-service va nous permettre de gérer tous les autres micro-services en les ajoutant, supprimant, avec un système de validation /refus et en se basant sur le système d'authentification. ## Arborescense Voici l'arborescence de notre API, avec en commentaire pour chaque dossier/fichier : diff --git a/app/__init__.py b/app/__init__.py index 806d985..3258753 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,11 +1,10 @@ from flask import Flask, jsonify from app.config import * -from app.extensions import jwt +from app.extensions import jwt, db import os from dotenv import load_dotenv - -__version__ = "1.0.1" # géré automatiquement par la CI +__version__ = "0.1.1" # géré automatiquement par la CI load_dotenv(".env") @@ -16,10 +15,9 @@ def create_app(): app.config.from_object(config[os.getenv("FLASK_ENV") or "development"])#en mode dev par défaut si rien de spécifié - #db.init_app(app) + db.init_app(app) jwt.init_app(app) - @jwt.unauthorized_loader # gérer le cas ou le client n'est pas authentifié def unauthorized_callback(callback): return jsonify({"msg": "Token invalide ou manquant. veuillez vous authentifier."}), 401 diff --git a/app/extensions.py b/app/extensions.py index 1b0b96c..d68a2e7 100644 --- a/app/extensions.py +++ b/app/extensions.py @@ -1,7 +1,9 @@ from flask_sqlalchemy import SQLAlchemy from flask_jwt_extended import JWTManager +from depsec_db.extensions import db + +db = db #from depsec_models.database import db -#db= depsec_models.database.db -jwt = JWTManager() +jwt = JWTManager() \ No newline at end of file diff --git a/app/routes/routes1.py b/app/routes/routes1.py index 1ca3de0..edcd219 100644 --- a/app/routes/routes1.py +++ b/app/routes/routes1.py @@ -1,11 +1,12 @@ -from flask import Blueprint, json, request, jsonify +from flask import Blueprint, current_app, json, request, jsonify from flask_jwt_extended import create_access_token -#from app.extensions import db +from app.extensions import db from flask_limiter import Limiter from flask_limiter.util import get_remote_address import re from app.services.auth import verify_token -from flask import current_app +from app.extensions import db +from depsec_db.models import Project #from depsec_models.models import * #import des modèles depuis le package @@ -13,67 +14,55 @@ limiter = Limiter(get_remote_address, default_limits=["5 per minute"]) -# ---------- Phase de test avant la BDD (comme si test.json était ce qu'on récupérait de la BDD) ------------- # - - -projects = [ - { - "id":1, - "titre":"Gestion des projets", - "auteur":"Solayman", - "status":"Accept", - "SBOM":"Recup" - }, - { - "id":2, - "titre":"Gestion de BDD", - "auteur":"Pierrot la pinto de la mañana", - "status":"Refuse", - "SBOM":"Waiting" - } -] - +# ------------------------------------------------------------------------------------------------------------ # def return_all_proj(): - return projects + return Project.query.all() def return_project(proj): - for p in projects: + for p in return_all_proj(): if proj in p.values(): return p - -def add_dico(dico): +def return_project_by_id(id): + return Project.query.get(id) - for d in projects: - if d["titre"] == dico["titre"]: - return jsonify({"error": f"Le nom de projet {d['titre']} existe deja !"}), 400 +def add_dico(dico): + projects = return_all_proj() + if projects != []: + for d in projects: + if d.titre == dico["titre"]: + return jsonify({"error": f"Le nom de projet {d.titre} existe deja !"}), 400 # trouve le + grand id - max_id = max([elem['id'] for elem in projects]) if projects else 0 + max_id = max([p.id for p in projects]) if projects else 0 dico['id'] = max_id + 1 - projects.append(dico) + + new_project = Project( + id = dico['id'], + auteur_id=dico["auteur_id"], + titre=dico["titre"], + status=dico["status"], + path=dico["path"] + ) + + db.session.add(new_project) + db.session.commit() - return return_all_proj() - #save_json(file_path, data) - #return jsonify(load_json(file_path)), 200 + return jsonify({"message": f"Projet {new_project.titre} ajoute avec succes"}), 200 def del_dico(id): - global projects + project = return_project_by_id(id) - try: - new_data = [item for item in projects if int(item.get("id")) != int(id)] - except : - return jsonify({"error": "Entrez un entier !"}), 404 - - if len(new_data) == len(projects): - return jsonify({"error": f"Le projet avec l'id '{id}' n'existe pas !"}), 404 + if not project: + return jsonify({"error": f"Projet avec l'ID {id} non trouve"}), 404 + + db.session.delete(project) + db.session.commit() - projects = new_data - return return_all_proj() - #return jsonify(load_json(file_path)), 200 + return jsonify({"message": f"Projet avec l'ID {id} supprime avec succes"}), 200 # ------------------------------------------------------------------------------------------------------------ # @@ -81,46 +70,46 @@ def del_dico(id): @projets_bp.route('/', methods=['GET']) def get_projects(): if verify_token() == False and current_app.config["FLASK_ENV"] !="development" : #verifier que le token est valide ( a mettre dans chaque route) et qu'on est pas en environnement de dev - return jsonify({"msg": "Token invalide / Utilisateur non autorisé"}), 401 - - - #data = request.get_json() - - - return return_all_proj(), 200 - #return jsonify({"Projects":data.get('titre')}), 200 + return jsonify({"msg": "Token invalide / Utilisateur non autorise"}), 401 + + return jsonify([project.to_dict() for project in Project.query.all()]) +@projets_bp.route('/', methods=['GET']) +def get_project_by_id(project_id): + project = Project.query.get(project_id) + if not project: + return jsonify({'error': 'Projet non trouvé'}), 404 + return jsonify(project.to_dict()), 200 @projets_bp.route('/', methods=['POST']) def add_project(): - if verify_token() == False and current_app.config["FLASK_ENV"] !="development" : #verifier que le token est valide ( a mettre dans chaque route) et qu'on est pas en environnement de dev - return jsonify({"msg": "Token invalide / Utilisateur non autorisé"}), 401 - + if verify_token() == False and current_app.config["FLASK_ENV"] != "development": + return jsonify({"msg": "Token invalide / Utilisateur non autorise"}), 401 data = request.get_json() - if not data : - return jsonify({"error": "Le fomat de vos donnees n'est pas bon !!"}), 400 - - if data.get("titre") and data.get("auteur") and data.get("status") and data.get("SBOM"): - titre = data.get("titre") - auteur = data.get("auteur") - status = data.get("status") - sbom = data.get("SBOM") - - if isinstance(auteur, str) and status in ["Accept","Refuse"] and sbom in ["Recup","Waiting"]: - format = { - "id":0, - "titre":titre, - "auteur":auteur, - "status":status, - "SBOM":sbom - } - return add_dico(format) - else : - return jsonify({'error': 'Parametres aux mauvais formats !'}), 400 - else : + if not data: + return jsonify({"error": "Le format de vos donnees n'est pas bon !!"}), 400 + + required_fields = ["titre", "auteur_id", "status", "path"] + if not all(field in data for field in required_fields): return jsonify({'error': 'Parametres manquants'}), 400 + + titre = data["titre"] + auteur_id = data["auteur_id"] + status = data["status"] + path = data["path"] + + if isinstance(auteur_id, int) and status in ["Accept", "Refuse"]: + project_data = { + "auteur_id": auteur_id, + "titre": titre, + "status": status, + "path": path + } + return add_dico(project_data) + else: + return jsonify({'error': 'Parametres aux mauvais formats !'}), 400 @projets_bp.route("/", methods=["DELETE"]) diff --git a/requirements.txt b/requirements.txt index 633fc5d..a95b8e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +pip==20.3.4 flask flask-limiter Flask-SQLAlchemy @@ -5,4 +6,8 @@ Flask-JWT-Extended pytest dotenv requests -python-semantic-release \ No newline at end of file +python-semantic-release +setuptools +flask_migrate +psycopg2-binary +git+https://github.com/DEPSEC-Project/DB-Management.git@main \ No newline at end of file diff --git a/test/test_app.py b/test/test_app.py index af6e783..1f3ed70 100644 --- a/test/test_app.py +++ b/test/test_app.py @@ -3,5 +3,4 @@ def test_inutile(): """ A modifier si on décide de définir des tests unitaires """ - assert True - \ No newline at end of file + assert True \ No newline at end of file