first commit
This commit is contained in:
parent
b216a187bd
commit
f73c77f548
119 changed files with 4504 additions and 4829 deletions
8
backend/.idea/.gitignore
generated
vendored
Normal file
8
backend/.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
16
backend/.idea/backend.iml
generated
Normal file
16
backend/.idea/backend.iml
generated
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="Flask">
|
||||
<option name="enabled" value="true" />
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.13 (backend)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
||||
</component>
|
||||
</module>
|
||||
4
backend/.idea/encodings.xml
generated
Normal file
4
backend/.idea/encodings.xml
generated
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
6
backend/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
backend/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
7
backend/.idea/misc.xml
generated
Normal file
7
backend/.idea/misc.xml
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.13 (backend)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (backend)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
backend/.idea/modules.xml
generated
Normal file
8
backend/.idea/modules.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/backend.iml" filepath="$PROJECT_DIR$/.idea/backend.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
backend/.idea/vcs.xml
generated
Normal file
6
backend/.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
0
backend/__init__.py
Normal file
0
backend/__init__.py
Normal file
BIN
backend/__pycache__/app.cpython-313.pyc
Normal file
BIN
backend/__pycache__/app.cpython-313.pyc
Normal file
Binary file not shown.
32
backend/app.py
Normal file
32
backend/app.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
from flask import Flask, jsonify
|
||||
from flask_cors import CORS
|
||||
|
||||
from routes.projects import projects_bp
|
||||
from routes.contact import contact_bp
|
||||
from routes.cv import cv_bp
|
||||
from routes.services import services_bp
|
||||
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
load_dotenv()
|
||||
|
||||
app = Flask(__name__)
|
||||
CORS(app)
|
||||
|
||||
app.config["API_KEY"] = os.getenv("API_KEY")
|
||||
|
||||
@app.route('/api/')
|
||||
@app.route('/')
|
||||
def get_home():
|
||||
return jsonify({
|
||||
"return": "Welcome to API"
|
||||
})
|
||||
|
||||
app.register_blueprint(projects_bp)
|
||||
app.register_blueprint(contact_bp)
|
||||
app.register_blueprint(cv_bp)
|
||||
app.register_blueprint(services_bp)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, port=5000)
|
||||
9
backend/data/contact.json
Normal file
9
backend/data/contact.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"first_name": "Anthony",
|
||||
"last_name": "VIOLET",
|
||||
"email": "tutu@tutu.com",
|
||||
"phone_number": "bah nope",
|
||||
"linkedin": "tjrs pas... quoique",
|
||||
"git": "non",
|
||||
"web": "ok"
|
||||
}
|
||||
36
backend/data/cv.json
Normal file
36
backend/data/cv.json
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
[
|
||||
{
|
||||
"about_text": "Après environ 15 ans d'apprentissage en autodidacte, j'ai pu approfondir et expérimenter mes connaissances dans le développement web (PHP, POO, CSS, HTML, SQL...).",
|
||||
"my_values": "la montagne, la neige et le caca",
|
||||
"my_skills": [
|
||||
{
|
||||
"Python": [
|
||||
"Numpy",
|
||||
"Pandas"
|
||||
],
|
||||
"Javascript": [
|
||||
"NodeJS",
|
||||
"React"
|
||||
]
|
||||
}
|
||||
],
|
||||
"technologies": [
|
||||
"PHP",
|
||||
"Python"
|
||||
],
|
||||
"work_experience": [
|
||||
{
|
||||
"Vendanges": "lol"
|
||||
}
|
||||
],
|
||||
"education": [
|
||||
{
|
||||
"Technofutur": "rien"
|
||||
}
|
||||
],
|
||||
"hobbies": [
|
||||
"manger",
|
||||
"bouger"
|
||||
]
|
||||
}
|
||||
]
|
||||
34
backend/data/projects.json
Normal file
34
backend/data/projects.json
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "test",
|
||||
"description": "test",
|
||||
"technologies": "test",
|
||||
"image": "test",
|
||||
"url": "test",
|
||||
"source": "test",
|
||||
"created_at": 1758087635.903851,
|
||||
"updated_at": 1758087635.903851,
|
||||
"status": [
|
||||
"En cours",
|
||||
"Terminé",
|
||||
"Futur projet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Maitre pokemon",
|
||||
"description": "je suis le maitre Pokemon avec les 8 badges en ma possesion",
|
||||
"technologies": "IT-PokeMaster",
|
||||
"image": "Masterball.png",
|
||||
"url": "Masterball.png",
|
||||
"source": "Pokepedia",
|
||||
"created_at": 1758089969.696575,
|
||||
"updated_at": 1758089969.696576,
|
||||
"status": [
|
||||
"En cours",
|
||||
"Terminé",
|
||||
"Futur projet"
|
||||
]
|
||||
}
|
||||
]
|
||||
14
backend/data/services.json
Normal file
14
backend/data/services.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name" : "Création de site web",
|
||||
"icon": "🌐",
|
||||
"description": "Des sites web modernes, responsives et optimisés pour tous les appareils."
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name" : "Création de site web",
|
||||
"icon": "🌐",
|
||||
"description": "Des sites web modernes, responsives et optimisés pour tous les appareils."
|
||||
}
|
||||
]
|
||||
0
backend/models/__init__.py
Normal file
0
backend/models/__init__.py
Normal file
BIN
backend/models/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
backend/models/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/models/__pycache__/contact_model.cpython-313.pyc
Normal file
BIN
backend/models/__pycache__/contact_model.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/models/__pycache__/cv_model.cpython-313.pyc
Normal file
BIN
backend/models/__pycache__/cv_model.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/models/__pycache__/project_model.cpython-313.pyc
Normal file
BIN
backend/models/__pycache__/project_model.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/models/__pycache__/service_model.cpython-313.pyc
Normal file
BIN
backend/models/__pycache__/service_model.cpython-313.pyc
Normal file
Binary file not shown.
24
backend/models/contact_model.py
Normal file
24
backend/models/contact_model.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
class ContactModel:
|
||||
def __init__(self, data):
|
||||
self.first_name = data.get('first_name')
|
||||
self.last_name = data.get('last_name')
|
||||
self.email = data.get('email')
|
||||
self.phonenumber = data.get('phone_number')
|
||||
self.linkedin = data.get('linkedin')
|
||||
self.git = data.get('git')
|
||||
self.web = data.get('web')
|
||||
|
||||
|
||||
def is_valid(self):
|
||||
return self.first_name is not None and self.last_name is not None and self.email is not None and self.phonenumber is not None
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"first_name": self.first_name,
|
||||
"last_name": self.last_name,
|
||||
"email": self.email,
|
||||
"phone_number": self.phonenumber,
|
||||
"linkedin": self.linkedin,
|
||||
"git": self.git,
|
||||
"web": self.web,
|
||||
}
|
||||
20
backend/models/cv_model.py
Normal file
20
backend/models/cv_model.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
class CVModel:
|
||||
def __init__(self, data):
|
||||
self.about_text = data.get("about_text")
|
||||
self.my_values = data.get("my_values")
|
||||
self.my_skills = data.get("my_skills")
|
||||
self.technologies = data.get("technologies")
|
||||
self.work_experience = data.get("work_experience")
|
||||
self.education = data.get("education")
|
||||
self.hobbies = data.get("hobbies")
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"about_text": self.about_text,
|
||||
"my_values": self.my_values,
|
||||
"my_skills": self.my_skills,
|
||||
"technologies": self.technologies,
|
||||
"work_experience": self.work_experience,
|
||||
"education": self.education,
|
||||
"hobbies": self.hobbies
|
||||
}
|
||||
31
backend/models/project_model.py
Normal file
31
backend/models/project_model.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import time
|
||||
from utils.enums import enumerates
|
||||
class ProjectModel:
|
||||
def __init__(self, data):
|
||||
self.id = data.get('id')
|
||||
self.name = data.get('name')
|
||||
self.description = data.get('description')
|
||||
self.technologies = data.get('technologies')
|
||||
self.image = data.get('image')
|
||||
self.url = data.get('url')
|
||||
self.source = data.get('source')
|
||||
self.created_at = data.get('created_at')
|
||||
self.updated_at = data.get('updated_at')
|
||||
self.status = data.get('status')
|
||||
|
||||
def is_valid(self):
|
||||
return self.name is not None
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"description": self.description,
|
||||
"technologies": self.technologies,
|
||||
"image": self.image,
|
||||
"url": self.url,
|
||||
"source": self.source,
|
||||
"created_at": time.time() if self.created_at is None else self.created_at,
|
||||
"updated_at": time.time() if self.updated_at is None else self.updated_at,
|
||||
"status": enumerates["status"],
|
||||
}
|
||||
14
backend/models/service_model.py
Normal file
14
backend/models/service_model.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
class ServiceModel:
|
||||
def __init__(self, data):
|
||||
self.service_id = data.get('id')
|
||||
self.service_name = data.get('name')
|
||||
self.service_icon = data.get('icon')
|
||||
self.service_description = data.get('description')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.service_id,
|
||||
"name": self.service_name,
|
||||
"icon": self.service_icon,
|
||||
"description": self.service_description
|
||||
}
|
||||
3
backend/requirements.txt
Normal file
3
backend/requirements.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
flask
|
||||
flask-cors
|
||||
dotenv
|
||||
0
backend/routes/__init__.py
Normal file
0
backend/routes/__init__.py
Normal file
BIN
backend/routes/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
backend/routes/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/routes/__pycache__/contact.cpython-313.pyc
Normal file
BIN
backend/routes/__pycache__/contact.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/routes/__pycache__/cv.cpython-313.pyc
Normal file
BIN
backend/routes/__pycache__/cv.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/routes/__pycache__/projects.cpython-313.pyc
Normal file
BIN
backend/routes/__pycache__/projects.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/routes/__pycache__/services.cpython-313.pyc
Normal file
BIN
backend/routes/__pycache__/services.cpython-313.pyc
Normal file
Binary file not shown.
29
backend/routes/contact.py
Normal file
29
backend/routes/contact.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
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.data_loader import load_data
|
||||
from models.contact_model import ContactModel
|
||||
import os
|
||||
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), '../data')
|
||||
CONTACTS_FILE = os.path.join(DATA_DIR, 'contact.json')
|
||||
|
||||
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_bp.route('/', methods=['POST'])
|
||||
def update_contact():
|
||||
key = request.headers.get('x-api-key')
|
||||
if key != current_app.config['API_KEY']:
|
||||
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
|
||||
41
backend/routes/cv.py
Normal file
41
backend/routes/cv.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
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 models.cv_model import CVModel
|
||||
import os
|
||||
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), '../data')
|
||||
CV_FILE = os.path.join(DATA_DIR, 'cv.json')
|
||||
|
||||
cv_bp = Blueprint('cv', __name__, url_prefix='/api/cv')
|
||||
|
||||
@cv_bp.route('/', methods=['GET'])
|
||||
def get_cv():
|
||||
cv = load_data('cv.json')
|
||||
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
|
||||
|
||||
data = request.json
|
||||
new_entry = CVModel(data).to_dict()
|
||||
cv = [new_entry]
|
||||
save_json(CV_FILE, cv)
|
||||
return jsonify(new_entry), 201
|
||||
|
||||
@cv_bp.route('/skills/', methods=['GET'])
|
||||
def get_skills():
|
||||
cv = load_data('cv.json')
|
||||
skills = cv[0].get('my_skills')
|
||||
return jsonify(skills)
|
||||
|
||||
@cv_bp.route('/about/', methods=['GET'])
|
||||
def get_about():
|
||||
cv = load_data('cv.json')
|
||||
about = cv[0].get('about_text')
|
||||
return jsonify(about)
|
||||
48
backend/routes/projects.py
Normal file
48
backend/routes/projects.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
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 models.project_model import ProjectModel
|
||||
import os
|
||||
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), '../data')
|
||||
PROJECTS_FILE = os.path.join(DATA_DIR, 'projects.json')
|
||||
|
||||
projects_bp = Blueprint('projects', __name__, url_prefix='/api/projects')
|
||||
|
||||
@projects_bp.route('/', methods=['GET'])
|
||||
def get_projects():
|
||||
projects = load_data('projects.json')
|
||||
return jsonify(projects)
|
||||
|
||||
@projects_bp.route('/<project_id>', 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)
|
||||
return jsonify(project)
|
||||
|
||||
@projects_bp.route('/', methods=['POST'])
|
||||
def create_project():
|
||||
key = request.headers.get('x-api-key')
|
||||
|
||||
if key != current_app.config['API_KEY']:
|
||||
return jsonify({
|
||||
"error": "Unauthorized"
|
||||
}), 401
|
||||
projects = load_data('projects.json')
|
||||
entry = request.json
|
||||
|
||||
project = ProjectModel(entry)
|
||||
|
||||
if not project.is_valid():
|
||||
return jsonify({
|
||||
"error": "Invalid project data"
|
||||
}), 400
|
||||
|
||||
new_id = max((p.get('id') for p in projects), default=0) + 1
|
||||
|
||||
data = project.to_dict()
|
||||
data['id'] = new_id
|
||||
|
||||
added = add_entry(PROJECTS_FILE, data)
|
||||
return jsonify(added), 201
|
||||
15
backend/routes/services.py
Normal file
15
backend/routes/services.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
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 models.service_model import ServiceModel
|
||||
import os
|
||||
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), '../data')
|
||||
SERVICES_FILE = os.path.join(DATA_DIR, 'services.json')
|
||||
|
||||
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)
|
||||
0
backend/utils/__init__.py
Normal file
0
backend/utils/__init__.py
Normal file
BIN
backend/utils/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/utils/__pycache__/data_loader.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/data_loader.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/utils/__pycache__/enums.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/enums.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/utils/__pycache__/json_crud.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/json_crud.cpython-313.pyc
Normal file
Binary file not shown.
8
backend/utils/data_loader.py
Normal file
8
backend/utils/data_loader.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), '../data')
|
||||
|
||||
def load_data(filename):
|
||||
with open(os.path.join(DATA_DIR, filename), 'r') as f:
|
||||
return json.load(f)
|
||||
21
backend/utils/enums.py
Normal file
21
backend/utils/enums.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
enumerates = {
|
||||
"status": [
|
||||
"En cours",
|
||||
"Terminé",
|
||||
"Futur projet"
|
||||
],
|
||||
"technologies": [
|
||||
"HTML & CSS",
|
||||
"Python",
|
||||
"Django",
|
||||
"React",
|
||||
"NodeJS",
|
||||
"Angular",
|
||||
"C#",
|
||||
"PHP",
|
||||
"Javascript",
|
||||
"TypeScript",
|
||||
"Unity",
|
||||
"Godot"
|
||||
],
|
||||
}
|
||||
33
backend/utils/json_crud.py
Normal file
33
backend/utils/json_crud.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
def load_json(filename):
|
||||
if not os.path.exists(filename):
|
||||
return []
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
|
||||
def save_json(filename, data):
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
|
||||
def add_entry(filename, entry):
|
||||
data = load_json(filename)
|
||||
data.append(entry)
|
||||
save_json(filename, data)
|
||||
return entry
|
||||
|
||||
def update_entry(filename, entry_id, new_entry):
|
||||
data = load_json(filename)
|
||||
for i, item in enumerate(data):
|
||||
if item.get('id') == entry_id:
|
||||
data[i] = new_entry
|
||||
save_json(filename, data)
|
||||
return new_entry
|
||||
return None
|
||||
|
||||
def delete_entry(filename, entry_id):
|
||||
data = load_json(filename)
|
||||
new_data = [item for item in data if item.get('id') != entry_id]
|
||||
save_json(filename, new_data)
|
||||
return len(data) != len(new_data)
|
||||
Loading…
Add table
Add a link
Reference in a new issue