Skip to content

Commit

Permalink
big refactor : now api work with school code, not with school id
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexTraveylan committed Sep 1, 2024
1 parent 6d82210 commit 2577518
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 42 deletions.
3 changes: 3 additions & 0 deletions app/api/links/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ def make_user_admin(
if user_to_make_admin is None:
raise RessourceNotFoundException("L'utilisateur n'existe pas")

if user_to_make_admin.position_in_list == 0:
raise UnauthorizedException("L'utilisateur est en file d'attente")

LIST_LINK_SERVICE.update(
session,
user_to_make_admin.id,
Expand Down
47 changes: 28 additions & 19 deletions app/api/parents_list/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@

from app.api.links.models import (
LIST_LINK_SERVICE,
SCHOOL_LINK_SERVICE,
ListLink,
SchoolRelation,
UserOnListStatus,
)
from app.api.parents_list.models import PARENTS_LIST_SERVICE, ParentsList
from app.api.parents_list.schema import ParentsListSchema
from app.api.parents_list.schema import ParentsListSchemaIn, ParentsListSchemaOut
from app.api.school.models import SCHOOL_SERVICE
from app.api.user_information.models import USER_INFORMATION_SERVICE
from app.auth.models import USER_SERVICE, User
Expand All @@ -34,26 +36,19 @@
)


@parents_list_router.get("/{school_id}", status_code=status.HTTP_200_OK)
def get_parents_lists_by_school_id(
school_id: int = Annotated[int, Path(title="school_id")],
@parents_list_router.get("/{school_code}", status_code=status.HTTP_200_OK)
def get_parents_lists_by_school_code(
school_code: str = Annotated[str, Path(title="school_code")],
) -> list[ParentsList]:
with unit_api(
"Tentative de récupération de toutes les listes de l'école spécifiée"
) as session:
parents_lists = PARENTS_LIST_SERVICE.get_all_by_school_id(session, school_id)

session.expunge_all()

return parents_lists
school = SCHOOL_SERVICE.get_or_none(session, code=school_code)
if school is None:
raise RessourceNotFoundException("Établissement non trouvé")

parents_lists = PARENTS_LIST_SERVICE.get_all_by_school_id(session, school.id)

@parents_list_router.get("/", status_code=status.HTTP_200_OK)
def get_all_parents_lists() -> list[ParentsList]:
with unit_api(
"Tentative de récupération de toutes les listes de parents"
) as session:
parents_lists = PARENTS_LIST_SERVICE.get_all(session)
session.expunge_all()

return parents_lists
Expand All @@ -64,22 +59,36 @@ def create_parents_list(
current_user: Annotated[
UserWithInformations, Depends(get_current_user_with_informations)
],
payload: ParentsListSchema,
) -> ParentsListSchema:
payload: ParentsListSchemaIn,
) -> ParentsListSchemaOut:
with unit_api("Tentative de création d'une liste de parents") as session:
if current_user.email is None or not current_user.is_email_confirmed:
raise RessourceNotFoundException(
"Tu ne peux pas créer une liste de parents sans email confirmé"
)

school = SCHOOL_SERVICE.get_or_none(session, id=payload.school_id)
school = SCHOOL_SERVICE.get_or_none(session, code=payload.school_code)
if school is None:
raise RessourceNotFoundException("Impossible de trouver l'école")

school_link = SCHOOL_LINK_SERVICE.get_or_none(
session, school_id=school.id, user_id=current_user.id
)

if school_link is None:
raise RessourceNotFoundException(
"Lien entre établissement et utilisateur non trouvé"
)

if school_link.school_relation == SchoolRelation.DIRECTION:
raise UnauthorizedException(
"La direction ne peut pas créer de liste de parents"
)

new_parent_list = ParentsList(
list_name=payload.list_name,
holder_length=payload.holder_length,
school_id=payload.school_id,
school_id=school.id,
creator_id=current_user.id,
)
new_parent_list = PARENTS_LIST_SERVICE.create(session, new_parent_list)
Expand Down
8 changes: 7 additions & 1 deletion app/api/parents_list/schema.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from pydantic import BaseModel


class ParentsListSchema(BaseModel):
class ParentsListSchemaOut(BaseModel):
list_name: str
holder_length: int
school_id: int


class ParentsListSchemaIn(BaseModel):
list_name: str
holder_length: int
school_code: str
52 changes: 32 additions & 20 deletions app/api/school/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
SchoolRelation,
)
from app.api.school.models import SCHOOL_SERVICE, School
from app.api.school.schemas import SchoolSchemaIn, SchoolSchemaOut
from app.api.school.schemas import SchoolSchemaIn, SchoolSchemaMe, SchoolSchemaOut
from app.auth.models import User
from app.auth.token import (
UserWithInformations,
Expand All @@ -32,7 +32,7 @@ def get_school_of_user(
current_user: Annotated[
UserWithInformations, Depends(get_current_user_with_informations)
],
) -> list[SchoolSchemaOut]:
) -> list[SchoolSchemaMe]:
with unit_api(
"Tentative de récupération de l'établissement de l'utilisateur"
) as session:
Expand All @@ -41,17 +41,38 @@ def get_school_of_user(
school = SCHOOL_SERVICE.get_or_none(session, id=school_id)
if school is None:
raise RessourceNotFoundException("Établissement non trouvé")
schools.append(school.to_decrypted())

school_link = SCHOOL_LINK_SERVICE.get_or_none(
session, school_id=school_id, user_id=current_user.id
)

if school_link is None:
raise RessourceNotFoundException(
"Lien entre établissement et utilisateur non trouvé"
)

school_with_relation = SchoolSchemaMe(
id=school.id,
school_name=school.school_name,
city=school.city,
zip_code=school.zip_code,
country=school.country,
adress=school.adress,
school_relation=school_link.school_relation.value,
code=school.code,
)

schools.append(school_with_relation)

return schools


@school_router.get("/{school_id}", status_code=status.HTTP_200_OK)
def get_school_by_id(
school_id: int = Annotated[int, Path(title="school_id")],
@school_router.get("/{school_code}", status_code=status.HTTP_200_OK)
def get_school_by_school_code(
school_code: str = Annotated[str, Path(title="school_code")],
) -> SchoolSchemaOut:
with unit_api("Tentative de récupération de l'établissement") as session:
school = SCHOOL_SERVICE.get_or_none(session, id=school_id)
school = SCHOOL_SERVICE.get_or_none(session, code=school_code)
if school is None:
raise RessourceNotFoundException("Établissement non trouvé")

Expand All @@ -60,16 +81,6 @@ def get_school_by_id(
return decrypted_school


@school_router.get("/", status_code=status.HTTP_200_OK)
def get_all_schools() -> list[SchoolSchemaOut]:
with unit_api("Tentative de récupération de tous les établissements") as session:
schools = SCHOOL_SERVICE.get_all(session)

schools_decrypted = [school.to_decrypted() for school in schools]

return schools_decrypted


@school_router.post("/", status_code=status.HTTP_201_CREATED)
def create_school(
current_user: Annotated[User, Depends(get_current_user)],
Expand All @@ -90,6 +101,7 @@ def create_school(
country=payload.country,
adress=payload.adress,
user_id=current_user.id,
code=payload.code,
)

created_school = SCHOOL_SERVICE.create(session, school)
Expand All @@ -114,7 +126,7 @@ def create_school(
@school_router.get("/join/{school_id}", status_code=status.HTTP_200_OK)
def join_school(
current_user: Annotated[User, Depends(get_current_user)],
school_id: int,
school_code: str,
) -> SchoolSchemaOut:
"""
Join a school
Expand All @@ -123,12 +135,12 @@ def join_school(
He must've a link object
"""
with unit_api("Tentative de rejoindre un établissement") as session:
school = SCHOOL_SERVICE.get_or_none(session, id=school_id)
school = SCHOOL_SERVICE.get_or_none(session, code=school_code)
if school is None:
raise RessourceNotFoundException("Établissement non trouvé")

user_link = SCHOOL_LINK_SERVICE.get_or_none(
session, user_id=current_user.id, school_id=school_id
session, user_id=current_user.id, school_id=school.id
)
if user_link is not None:
raise CannotCreateStillExistsException("L'utilisateur est déjà membre")
Expand Down
7 changes: 6 additions & 1 deletion app/api/school/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from app.api.school.schemas import SchoolSchemaOut
from app.commun.crypto import decrypt, encrypt
from app.commun.validator import validate_string
from app.commun.validator import validate_code, validate_string
from app.database.model_base import BaseSQLModel
from app.database.repository import Repository

Expand All @@ -20,6 +20,7 @@ class School(BaseSQLModel, table=True):
encrypted_zip_code: str = Field(alias="zip_code")
encrypted_country: str = Field(alias="country")
encrypted_adress: str = Field(alias="adress")
code: str = Field(unique=True)

@cached_property
def school_name(self) -> str:
Expand Down Expand Up @@ -71,6 +72,10 @@ def adress_format(cls, value: str) -> str:

return encrypt(value)

@field_validator("code")
def code_format(cls, value: str) -> str:
return validate_code(value)

def to_decrypted(self) -> SchoolSchemaOut:
return SchoolSchemaOut(
id=self.id,
Expand Down
12 changes: 12 additions & 0 deletions app/api/school/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class SchoolSchemaIn(BaseModel):
country: str
adress: str
school_relation: Literal["parent", "direction"]
code: str


class SchoolSchemaOut(BaseModel):
Expand All @@ -19,3 +20,14 @@ class SchoolSchemaOut(BaseModel):
zip_code: str
country: str
adress: str


class SchoolSchemaMe(BaseModel):
id: int
school_name: str
city: str
zip_code: str
country: str
adress: str
school_relation: Literal["parent", "direction"]
code: str
12 changes: 12 additions & 0 deletions app/commun/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,15 @@ def validate_string(value: str) -> str:
raise ValueError("Username is too long. Maximum length is 64 characters.")

return value


def validate_code(value: str) -> str:
value = value.strip()

if not (len(value) == 8 and value.isupper() and value.isalnum()):
raise ValueError(
"Code must be 8 characters long, composed of uppercase letters and numbers."
)
return value

return value
31 changes: 30 additions & 1 deletion tests/commun/test_validator.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from app.commun.validator import validate_email, validate_password
from app.commun.validator import validate_code, validate_email, validate_password


@pytest.mark.parametrize(
Expand Down Expand Up @@ -61,3 +61,32 @@ def test_validate_email_with_invalid_emails(invalid_email):
)
def test_validate_email_with_valid_emails(valid_email):
assert validate_email(valid_email) == valid_email


@pytest.mark.parametrize(
"invalid_code",
[
"abcdefgh",
"1234abcd",
"abcd1234",
"abcdABCD",
"ABCDabcd",
"ABcd1234djkhfsmlkf",
"AB1",
"ABCD123*",
],
)
def test_validate_code_with_invalid_codes(invalid_code):
with pytest.raises(ValueError):
validate_code(invalid_code)


@pytest.mark.parametrize(
"valid_code",
[
"ABCD1234",
"1234ABCD",
],
)
def test_validate_code_with_valid_codes(valid_code):
assert validate_code(valid_code) == valid_code

0 comments on commit 2577518

Please sign in to comment.