From da45beba93a23836e7c97c04bc75eff956a19d3e Mon Sep 17 00:00:00 2001 From: toine Date: Sat, 4 Oct 2025 17:48:13 +0200 Subject: [PATCH] ajout de CRUD total pour toute les routes --- backend/routes/contact.py | 49 +++++++++++++++++++------ backend/routes/cv.py | 42 +++++++++++++++++----- backend/routes/projects.py | 41 ++++++++++++++++++--- backend/routes/services.py | 58 +++++++++++++++++++++++++++++- frontend/app/components/Footer.tsx | 1 + 5 files changed, 166 insertions(+), 25 deletions(-) diff --git a/backend/routes/contact.py b/backend/routes/contact.py index bc5a0cd..24b4556 100644 --- a/backend/routes/contact.py +++ b/backend/routes/contact.py @@ -1,5 +1,5 @@ from flask import Blueprint, jsonify, request, current_app -from utils.json_crud import load_json, save_json, add_entry, delete_entry, update_entry +from utils.json_crud import load_json, save_json from utils.data_loader import load_data from models.contact_model import ContactModel import os @@ -11,19 +11,46 @@ contact_bp = Blueprint('contact', __name__, url_prefix='/api/contact') @contact_bp.route('/', methods=['GET']) def get_contact(): - contacts = load_data('contact.json') - return jsonify(contacts) + contact = load_data('contact.json') + return jsonify(contact) @contact_bp.route('/', methods=['POST']) +def create_or_replace_contact(): + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 + + data = request.json or {} + model = ContactModel(data) + if not model.is_valid(): + return jsonify({"error": "Invalid contact data"}), 400 + new_entry = model.to_dict() + save_json(CONTACTS_FILE, new_entry) + return jsonify(new_entry), 201 + +@contact_bp.route('/', methods=['PUT', 'PATCH']) def update_contact(): key = request.headers.get('x-api-key') if key != current_app.config['API_KEY']: - return jsonify({ - "error": "Unauthorized" - }), 401 + return jsonify({"error": "Unauthorized"}), 401 - data = request.json - new_entry = ContactModel(data).to_dict() - contact = [new_entry] - save_json(CONTACTS_FILE, contact) - return new_entry \ No newline at end of file + current = load_json(CONTACTS_FILE) or {} + payload = request.json or {} + updated = {**current, **payload} + + model = ContactModel(updated) + if not model.is_valid(): + return jsonify({"error": "Invalid contact data"}), 400 + + save_json(CONTACTS_FILE, model.to_dict()) + return jsonify(model.to_dict()), 200 + +@contact_bp.route('/', methods=['DELETE']) +def delete_contact(): + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 + + # Clear contact info + save_json(CONTACTS_FILE, {}) + return jsonify({"status": "success"}), 200 \ No newline at end of file diff --git a/backend/routes/cv.py b/backend/routes/cv.py index ea0e7a7..a281e0d 100644 --- a/backend/routes/cv.py +++ b/backend/routes/cv.py @@ -1,6 +1,6 @@ from flask import Blueprint, jsonify, request, current_app from utils.data_loader import load_data -from utils.json_crud import load_json, save_json, add_entry, delete_entry, update_entry +from utils.json_crud import load_json, save_json from models.cv_model import CVModel import os @@ -15,27 +15,53 @@ def get_cv(): return jsonify(cv) @cv_bp.route('/', methods=['POST']) -def update_cv(): - #key = request.headers.get('x-api-key') - #if key != current_app.config['API_KEY']: - # return jsonify({ - # "error": "Unauthorized" - # }), 401 +def create_or_replace_cv(): + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 - data = request.json + data = request.json or {} new_entry = CVModel(data).to_dict() cv = [new_entry] save_json(CV_FILE, cv) return jsonify(new_entry), 201 +@cv_bp.route('/', methods=['PUT', 'PATCH']) +def update_cv(): + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 + + current_list = load_json(CV_FILE) or [] + current = current_list[0] if current_list else {} + payload = request.json or {} + updated = {**current, **payload} + + new_entry = CVModel(updated).to_dict() + save_json(CV_FILE, [new_entry]) + return jsonify(new_entry), 200 + +@cv_bp.route('/', methods=['DELETE']) +def delete_cv(): + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 + + save_json(CV_FILE, []) + return jsonify({"status": "success"}), 200 + @cv_bp.route('/skills/', methods=['GET']) def get_skills(): cv = load_data('cv.json') + if not cv: + return jsonify([]) skills = cv[0].get('my_skills') return jsonify(skills) @cv_bp.route('/about/', methods=['GET']) def get_about(): cv = load_data('cv.json') + if not cv: + return jsonify("") about = cv[0].get('about_text') return jsonify(about) \ No newline at end of file diff --git a/backend/routes/projects.py b/backend/routes/projects.py index 5a025b1..0a5cb9b 100644 --- a/backend/routes/projects.py +++ b/backend/routes/projects.py @@ -17,8 +17,10 @@ def get_projects(): @projects_bp.route('/', methods=['GET']) def get_project(project_id): projects = load_data('projects.json') - project = next((p for p in projects if p.get('id') == project_id), None) - print(project) + # Ensure numeric comparison for id + project = next((p for p in projects if str(p.get('id')) == str(project_id)), None) + if not project: + return jsonify({"error": "Project not found"}), 404 return jsonify(project) @projects_bp.route('/', methods=['POST']) @@ -30,7 +32,7 @@ def create_project(): "error": "Unauthorized" }), 401 projects = load_data('projects.json') - entry = request.json + entry = request.json or {} project = ProjectModel(entry) @@ -47,10 +49,39 @@ def create_project(): added = add_entry(PROJECTS_FILE, data) return jsonify(added), 201 +@projects_bp.route('/', methods=['PUT', 'PATCH']) +def update_project(project_id): + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 + + projects = load_json(PROJECTS_FILE) + project = next((p for p in projects if str(p.get('id')) == str(project_id)), None) + if not project: + return jsonify({"error": "Project not found"}), 404 + + payload = request.json or {} + # Merge existing with payload + updated = {**project, **payload} + # Preserve id + updated['id'] = project['id'] + + # Validate using model + model = ProjectModel(updated) + if not model.is_valid(): + return jsonify({"error": "Invalid project data"}), 400 + + saved = update_entry(PROJECTS_FILE, updated['id'], model.to_dict()) + return jsonify(saved), 200 + @projects_bp.route('/', methods=['DELETE']) def delete_project(project_id): - projects = load_data(PROJECTS_FILE) - project = next((p for p in projects if str(p.get('id')) == project_id), None) + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 + + projects = load_json(PROJECTS_FILE) + project = next((p for p in projects if str(p.get('id')) == str(project_id)), None) if project: deleted = delete_entry(PROJECTS_FILE, project_id) diff --git a/backend/routes/services.py b/backend/routes/services.py index 06d0687..8017457 100644 --- a/backend/routes/services.py +++ b/backend/routes/services.py @@ -12,4 +12,60 @@ services_bp = Blueprint('services', __name__, url_prefix='/api/services') @services_bp.route('/', methods=['GET']) def get_services(): services = load_data('services.json') - return jsonify(services) \ No newline at end of file + return jsonify(services) + +@services_bp.route('/', methods=['GET']) +def get_service(service_id): + services = load_data('services.json') + service = next((s for s in services if str(s.get('id')) == str(service_id)), None) + if not service: + return jsonify({"error": "Service not found"}), 404 + return jsonify(service) + +@services_bp.route('/', methods=['POST']) +def create_service(): + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 + + services = load_json(SERVICES_FILE) + entry = request.json or {} + # generate new id + new_id = max((s.get('id') for s in services), default=0) + 1 + model = ServiceModel({**entry, 'id': new_id}) + data = model.to_dict() + + added = add_entry(SERVICES_FILE, data) + return jsonify(added), 201 + +@services_bp.route('/', methods=['PUT', 'PATCH']) +def update_service(service_id): + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 + + services = load_json(SERVICES_FILE) + service = next((s for s in services if str(s.get('id')) == str(service_id)), None) + if not service: + return jsonify({"error": "Service not found"}), 404 + + payload = request.json or {} + updated = {**service, **payload} + updated['id'] = service['id'] + + saved = update_entry(SERVICES_FILE, updated['id'], updated) + return jsonify(saved), 200 + +@services_bp.route('/', methods=['DELETE']) +def delete_service(service_id): + key = request.headers.get('x-api-key') + if key != current_app.config['API_KEY']: + return jsonify({"error": "Unauthorized"}), 401 + + services = load_json(SERVICES_FILE) + service = next((s for s in services if str(s.get('id')) == str(service_id)), None) + if not service: + return jsonify({"error": "Service not found"}), 404 + + deleted = delete_entry(SERVICES_FILE, service_id) + return jsonify(deleted), 200 \ No newline at end of file diff --git a/frontend/app/components/Footer.tsx b/frontend/app/components/Footer.tsx index a9085b5..2faee9c 100644 --- a/frontend/app/components/Footer.tsx +++ b/frontend/app/components/Footer.tsx @@ -15,6 +15,7 @@ export default function Footer() { return ( ); }