Compare commits

..
43 Commits
Author SHA1 Message Date
Giovanni 357b47bd61 Refactor: deplacer backend dans apps/backend 2026-10-03 12:17:10 +02:00
Giovanni ca3de277b4 Merge backend history 2026-10-03 12:15:35 +02:00
Giovanni 505355769b add /api prefix to all routers 2026-06-15 11:13:01 +02:00
Giovanni 91c1e1a621 correct missing import 2026-06-03 14:06:12 +02:00
Giovanni 916b6f7ca2 update .gitignore 2026-06-03 11:39:14 +02:00
Giovanni b76566aea4 update .gitignore 2026-06-03 11:38:02 +02:00
Giovanni 5ff02c0ff5 initialize backend with FastAPI and Docker setup 2026-06-03 11:35:09 +02:00
Giovanni-Josserand 5d724e37ab Merge pull request 'add of short_description in longProjects.py' (#5) from dev into main
Reviewed-on: Giovanni-Josserand/Portfolio-API#5
2025-09-14 16:21:05 +00:00
Giovanni 510eb13d8c add of short_description in longProjects.py 2025-09-14 12:39:39 +02:00
Giovanni-Josserand fa4dbde0b8 Merge pull request 'dev' (#4) from dev into main
Reviewed-on: Giovanni-Josserand/Portfolio-API#4
2025-09-06 09:49:13 +00:00
Giovanni 15dce53e86 remove of nb_image in shortProjects 2025-09-04 23:43:57 +02:00
Giovanni e97d7def89 change date in projects instead of beginning_year and end_year, 2025-09-03 21:41:52 +02:00
Giovanni 0d2e1374ed add of longProjects and update of projects table 2025-09-03 14:31:04 +02:00
Giovanni 2c68620c66 add of school attribute in projects 2025-09-02 22:59:56 +02:00
Giovanni-Josserand 9ea48ffbf7 Merge pull request 'debug error 404' (#3) from dev into main
Reviewed-on: Giovanni-Josserand/Portfolio-API#3
2025-08-31 19:50:09 +00:00
Giovanni 6e20a308ab debug error 404 2025-08-31 21:49:31 +02:00
Giovanni-Josserand 9b33e36826 Merge pull request 'debug error 404' (#2) from dev into main
Reviewed-on: Giovanni-Josserand/Portfolio-API#2
2025-08-31 19:40:46 +00:00
Giovanni cec4fb3234 debug error 404 2025-08-31 21:40:21 +02:00
Giovanni-Josserand 840de088aa Merge pull request 'dev' (#1) from dev into main
Reviewed-on: Giovanni-Josserand/Portfolio-API#1
2025-08-31 16:28:37 +00:00
Giovanni 900a17eac5 add of projects router 2025-08-31 18:22:58 +02:00
Giovanni d75a5590cc add of experiences router and experienceTasks router 2025-08-31 00:21:39 +02:00
Giovanni 6902f844fb fix skills router 2025-08-29 23:27:30 +02:00
Giovanni d284ce534a fix skills router 2025-08-29 23:25:25 +02:00
Giovanni bd97946caa fix skills router 2025-08-29 23:21:50 +02:00
Giovanni 4144586b5c fix skills router 2025-08-29 23:16:46 +02:00
Giovanni 9a74817a08 fix skills router 2025-08-29 23:14:52 +02:00
Giovanni 4e14592fdb fix of skills router 2025-08-29 23:08:56 +02:00
Giovanni 1175c0030b correction of skills router 2025-08-29 23:03:33 +02:00
Giovanni f7a09291af add of skills router 2025-08-29 23:00:22 +02:00
Giovanni 16f6048479 test .sh 2025-08-29 19:47:17 +02:00
Giovanni c03a1e136d test 2025-08-29 19:41:37 +02:00
Giovanni 05c7d8cc5a add of .env in .gitignore 2025-08-29 19:32:13 +02:00
Giovanni-Josserand 0c6c69fcf3 Supprimer .env 2025-08-29 17:25:40 +00:00
Giovanni 8304940daf update requierements.txt, add of db connection function and root 2025-08-29 18:40:08 +02:00
Giovanni-Josserand 7a89aee31f Ajouter test.txt 2025-06-01 13:48:10 +00:00
Giovanni 2154440766 add of .gitignore 2025-06-01 15:47:47 +02:00
Giovanni-Josserand 8caa17af41 Ajouter requirements.txt 2025-05-31 17:06:15 +00:00
Giovanni-Josserand 9adc90de29 Actualiser main.py 2025-05-31 17:05:42 +00:00
Giovanni-Josserand 44ee3724d8 Ajouter main.py 2025-05-31 17:04:40 +00:00
Giovanni-Josserand d61c9ee44a Supprimer test.txt 2025-05-31 17:04:20 +00:00
Giovanni-Josserand e2210cd9ca Supprimer a.txt 2025-05-31 17:04:15 +00:00
Giovanni-Josserand b31a0a8def Ajouter test.txt 2025-05-30 13:05:53 +00:00
Giovanni-Josserand 24a836de3c Ajouter a.txt 2025-05-30 12:58:09 +00:00
18 changed files with 431 additions and 0 deletions

No files matched your search

+7
View File
@@ -0,0 +1,7 @@
DB_HOST=
DB_PORT=3306
DB_NAME=
DB_USER=
DB_PASSWORD=
+8
View File
@@ -0,0 +1,8 @@
__pycache__/
*.pyc
*.pyo
*.pyd
.env
../../.idea
+13
View File
@@ -0,0 +1,13 @@
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY ../.. .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
+38
View File
@@ -0,0 +1,38 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import declarative_base
from dotenv import load_dotenv
import os
load_dotenv()
DATABASE_URL = (
f"mysql+pymysql://"
f"{os.getenv('DB_USER')}:"
f"{os.getenv('DB_PASSWORD')}@"
f"{os.getenv('DB_HOST')}:"
f"{os.getenv('DB_PORT')}/"
f"{os.getenv('DB_NAME')}"
)
engine = create_engine(
DATABASE_URL,
pool_pre_ping=True
)
SessionLocal = sessionmaker(
autocommit=False,
autoflush=False,
bind=engine
)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
+9
View File
@@ -0,0 +1,9 @@
from fastapi import FastAPI
from app.routers import projects, experiences, skills
app = FastAPI()
app.include_router(projects.router, prefix="/api")
app.include_router(experiences.router, prefix="/api")
app.include_router(skills.router, prefix="/api")
+47
View File
@@ -0,0 +1,47 @@
from app.models.experience_task import ExperienceTask
from sqlalchemy import (
Column,
Integer,
String
)
from sqlalchemy.orm import relationship
from app.database import Base
class Experience(Base):
__tablename__ = "experiences"
id = Column(
Integer,
primary_key=True,
index=True
)
company = Column(
String(255),
nullable=False
)
location = Column(
String(255),
nullable=False
)
duration = Column(
String(255),
nullable=False
)
role = Column(
String(255),
nullable=False
)
tasks = relationship(
"ExperienceTask",
back_populates="experience",
cascade="all, delete-orphan"
)
@@ -0,0 +1,39 @@
from sqlalchemy import (
Column,
Integer,
String,
ForeignKey
)
from sqlalchemy.orm import relationship
from app.database import Base
class ExperienceTask(Base):
__tablename__ = "experience_tasks"
id = Column(
Integer,
primary_key=True,
index=True
)
description = Column(
String(255),
nullable=False
)
experience_id = Column(
Integer,
ForeignKey(
"experiences.id",
ondelete="CASCADE"
),
nullable=False
)
experience = relationship(
"Experience",
back_populates="tasks"
)
+70
View File
@@ -0,0 +1,70 @@
from sqlalchemy import (
Column,
Integer,
String,
Text,
Boolean
)
from sqlalchemy.orm import relationship
from app.database import Base
from app.models.project_skill import project_skills
class Project(Base):
__tablename__ = "projects"
id = Column(Integer, primary_key=True, index=True)
title = Column(
String(255),
nullable=False
)
nb_image = Column(
Integer,
default=1
)
short_description = Column(
Text,
nullable=False
)
image_name = Column(
String(255),
nullable=False,
default="empty"
)
school = Column(
Boolean,
nullable=False
)
long_description = Column(
Text,
nullable=False
)
repo_link = Column(
String(255),
nullable=True
)
beginning_year = Column(
Integer,
nullable=False
)
end_year = Column(
Integer,
nullable=True
)
skills = relationship(
"Skill",
secondary=project_skills,
back_populates="projects"
)
+22
View File
@@ -0,0 +1,22 @@
from sqlalchemy import Table, Column, Integer, ForeignKey
from app.database import Base
project_skills = Table(
"project_skills",
Base.metadata,
Column(
"project_id",
Integer,
ForeignKey("projects.id", ondelete="CASCADE"),
primary_key=True
),
Column(
"skill_id",
Integer,
ForeignKey("skills.id", ondelete="CASCADE"),
primary_key=True
)
)
+28
View File
@@ -0,0 +1,28 @@
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import relationship
from app.database import Base
from app.models.project_skill import project_skills
class Skill(Base):
__tablename__ = "skills"
id = Column(Integer, primary_key=True, index=True)
name = Column(
String(255),
nullable=False,
unique=True
)
type = Column(
String(255),
nullable=False
)
projects = relationship(
"Project",
secondary=project_skills,
back_populates="skills"
)
+17
View File
@@ -0,0 +1,17 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session, joinedload
from app.database import get_db
from app.models.experience import Experience
from app.schemas.experience import ExperienceResponse
router = APIRouter(prefix="/experiences", tags=["Experiences"])
@router.get("/", response_model=list[ExperienceResponse])
def get_experiences(db: Session = Depends(get_db)):
return (
db.query(Experience)
.options(joinedload(Experience.tasks))
.all()
)
+32
View File
@@ -0,0 +1,32 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session, joinedload
from app.database import get_db
from app.models.project import Project
from app.schemas.project import ProjectCard, ProjectPage
router = APIRouter(prefix="/projects", tags=["Projects"])
@router.get("/", response_model=list[ProjectCard])
def get_projects(db: Session = Depends(get_db)):
return (
db.query(Project)
.options(joinedload(Project.skills))
.all()
)
@router.get("/{project_id}", response_model=ProjectPage)
def get_project(project_id: int, db: Session = Depends(get_db)):
project = (
db.query(Project)
.options(joinedload(Project.skills))
.filter(Project.id == project_id)
.first()
)
if not project:
raise HTTPException(status_code=404, detail="Project not found")
return project
+13
View File
@@ -0,0 +1,13 @@
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.database import get_db
from app.models.skill import Skill
from app.schemas.skill import SkillResponse
router = APIRouter(prefix="/skills", tags=["Skills"])
@router.get("/", response_model=list[SkillResponse])
def get_skills(db: Session = Depends(get_db)):
return db.query(Skill).all()
+20
View File
@@ -0,0 +1,20 @@
from pydantic import BaseModel
class ExperienceTaskResponse(BaseModel):
id: int
description: str
class Config:
from_attributes = True
class ExperienceResponse(BaseModel):
id: int
company: str
location: str
duration: str
role: str
tasks: list[ExperienceTaskResponse]
class Config:
from_attributes = True
+33
View File
@@ -0,0 +1,33 @@
from pydantic import BaseModel
from app.schemas.skill import ProjectSkill
class ProjectCard(BaseModel):
id: int
title: str
short_description: str
image_name: str
school: bool
beginning_year: int
end_year: int | None
skills: list[ProjectSkill]
class Config:
from_attributes = True
class ProjectPage(BaseModel):
id: int
title: str
short_description: str
long_description: str
repo_link: str | None
nb_image: int
image_name: str
school: bool
beginning_year: int
end_year: int | None
skills: list[ProjectSkill]
class Config:
from_attributes = True
+17
View File
@@ -0,0 +1,17 @@
from pydantic import BaseModel
class SkillResponse(BaseModel):
id: int
name: str
type: str
class Config:
from_attributes = True
class ProjectSkill(BaseModel):
id: int
name: str
class Config:
from_attributes = True
+13
View File
@@ -0,0 +1,13 @@
version: "3.8"
services:
backend:
build: ../..
container_name: portfolio-backend
restart: unless-stopped
env_file:
- .env
ports:
- "8000:8000"
volumes:
- .:/app
+5
View File
@@ -0,0 +1,5 @@
fastapi
uvicorn[standard]
sqlalchemy
pymysql
python-dotenv