Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added app/modules/misc/__init__.py
Empty file.
8 changes: 8 additions & 0 deletions app/modules/misc/core_data_misc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from app.types.core_data import BaseCoreData


# <-- Contacts for PE5 SafetyCards 2025 -->
class ContactSafetyCards(BaseCoreData):
contacts: str = ""

# <-- End of Contacts for PE5 SafetyCards 2025 -->
71 changes: 71 additions & 0 deletions app/modules/misc/endpoints_misc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import json

from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.groups.groups_type import AccountType, GroupType
from app.core.users import models_users
from app.dependencies import get_db, is_user_a_member, is_user_in
from app.modules.misc import core_data_misc, schemas_misc
from app.types.module import Module
from app.utils import tools

router = APIRouter()


# <-- Contacts for PE5 SafetyCards 2025 -->
module = Module(
root="contacts_safety_cards",
tag="Contact",
default_allowed_account_types=[AccountType.student, AccountType.staff],
)


@module.router.get(
"/contacts_safety_cards/contacts",
response_model=list[schemas_misc.ContactBase],
status_code=200,
)
async def get_contacts(
db: AsyncSession = Depends(get_db),
user: models_users.CoreUser = Depends(is_user_a_member),
):
"""
Get contacts.

**The user must be authenticated to use this endpoint**
This the main purpose of this endpoint, because contacts (phone numbers, emails) should not be leaked in the prevention website
"""

contacts_from_core_data = await tools.get_core_data(
core_data_misc.ContactSafetyCards,
db,
)

serialized_json_contacts = contacts_from_core_data.contacts

return json.loads(serialized_json_contacts)


@module.router.put(
"/contacts_safety_cards/contacts",
status_code=201,
)
async def set_contacts(
contacts: list[schemas_misc.ContactBase],
db: AsyncSession = Depends(get_db),
user: models_users.CoreUser = Depends(is_user_in(GroupType.eclair)),
):
"""
Create a contact.

**This endpoint is only usable by members of the group eclair**
"""

contacts_serialized_json = json.dumps(contacts)

await tools.set_core_data(
core_data_misc.ContactSafetyCards(contacts=contacts_serialized_json),
db,
)
# <-- End of Contacts for PE5 SafetyCards 2025 -->
10 changes: 10 additions & 0 deletions app/modules/misc/schemas_misc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pydantic import BaseModel


# <-- Contacts for PE5 SafetyCards 2025 -->
class ContactBase(BaseModel):
name: str
email: str | None = None
phone: str | None = None
location: str | None = None
# <--End of Contacts for PE5 SafetyCards 2025 -->
23 changes: 23 additions & 0 deletions app/utils/auth/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,3 +418,26 @@
"name": user.full_name,
"email": user.email,
}


class SafetyCardsAuthClient(BaseAuthClient):
# When set to `None`, users from any group can use the auth client
allowed_account_types: list[AccountType] | None = get_ecl_account_types()

def get_userinfo(self, user: models_users.CoreUser) -> dict[str, Any]:
"""
See oidc specifications and `app.endpoints.auth.auth_get_userinfo` for more information:
https://openid.net/specs/openid-connect-core-1_0.html#UserInfo

"""
# Override this method with custom information adapted for the client
# WARNING: The sub (subject) Claim MUST always be returned in the UserInfo Response.
return {
"sub": user.id,
"name": get_display_name(

Check failure on line 437 in app/utils/auth/providers.py

View workflow job for this annotation

GitHub Actions / lintandformat

Ruff (F821)

app/utils/auth/providers.py:437:21: F821 Undefined name `get_display_name`
firstname=user.firstname,
name=user.name,
nickname=user.nickname,
),
"email": user.email,
}
53 changes: 53 additions & 0 deletions tests/test_contacts_safety_cards.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import pytest_asyncio
from fastapi.testclient import TestClient

from app.core.groups.groups_type import GroupType
from tests.commons import create_api_access_token, create_user_with_groups

token_simple: str
token_eclair: str


@pytest_asyncio.fixture(scope="module", autouse=True)
async def init_objects() -> None:
user_simple = await create_user_with_groups(
[],
)

global token_simple
token_simple = create_api_access_token(user_simple)

user_eclair = await create_user_with_groups([GroupType.eclair])

global token_eclair
token_eclair = create_api_access_token(user_eclair)


def test_get_contacts(client: TestClient) -> None:
response = client.get(
"/contacts_safety_cards/contacts",
headers={"Authorization": f"Bearer {token_simple}"},
)
assert response.status_code == 200


def test_set_contacts(client: TestClient) -> None:
response = client.put(
"/contacts_safety_cards/contacts/",
json=[
{
"name": "John Doe",
"phone": "123456789",
"email": "johndoe@example.com",
"location": "Lyon",
},
{
"name": "John Doe bis",
"phone": "323456789",
"email": "johndoebis@example.com",
"location": "Ecully",
},
],
headers={"Authorization": f"Bearer {token_eclair}"},
)
assert response.status_code == 201
Loading