Skip to content
Merged
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
103 changes: 59 additions & 44 deletions app/core/core_endpoints/endpoints_core.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from os import path
from pathlib import Path

from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi import APIRouter, Depends, Request
from fastapi.responses import FileResponse

from app.core.core_endpoints import schemas_core
Expand All @@ -10,6 +9,7 @@
get_settings,
)
from app.types.module import CoreModule
from app.utils.tools import patch_identity_in_text

router = APIRouter(tags=["Core"])

Expand Down Expand Up @@ -43,118 +43,133 @@ async def read_information(

@router.get(
"/privacy",
response_class=FileResponse,
status_code=200,
)
async def read_privacy():
async def read_privacy(settings: Settings = Depends(get_settings)):
"""
Return Hyperion privacy
"""

return FileResponse("assets/privacy.txt")
return patch_identity_in_text(
Path("assets/privacy.txt").read_text(encoding="utf-8"),
settings,
)


@router.get(
"/terms-and-conditions",
response_class=FileResponse,
status_code=200,
)
async def read_terms_and_conditions():
async def read_terms_and_conditions(settings: Settings = Depends(get_settings)):
"""
Return Hyperion terms and conditions pages
"""

return FileResponse("assets/terms-and-conditions.txt")
return patch_identity_in_text(
Path("assets/terms-and-conditions.txt").read_text(encoding="utf-8"),
settings,
)


@router.get(
"/myeclpay-terms-of-service",
response_class=FileResponse,
"/mypayment-terms-of-service",
status_code=200,
)
async def read_myeclpay_tos():
async def read_mypayment_tos(settings: Settings = Depends(get_settings)):
"""
Return MyECLPay latest ToS
Return MyPayment latest ToS
"""
return FileResponse("assets/myeclpay-terms-of-service.txt")
return patch_identity_in_text(
Path("assets/mypayment-terms-of-service.txt").read_text(encoding="utf-8"),
settings,
)


@router.get(
"/support",
response_class=FileResponse,
status_code=200,
)
async def read_support():
async def read_support(settings: Settings = Depends(get_settings)):
"""
Return Hyperion support
"""

return FileResponse("assets/support.txt")
return patch_identity_in_text(
Path("assets/support.txt").read_text(encoding="utf-8"),
settings,
)


@router.get(
"/security.txt",
response_class=FileResponse,
status_code=200,
)
async def read_security_txt():
async def read_security_txt(settings: Settings = Depends(get_settings)):
"""
Return Hyperion security.txt file
"""

return FileResponse("assets/security.txt")
return patch_identity_in_text(
Path("assets/security.txt").read_text(encoding="utf-8"),
settings,
)


@router.get(
"/.well-known/security.txt",
response_class=FileResponse,
status_code=200,
)
async def read_wellknown_security_txt():
async def read_wellknown_security_txt(settings: Settings = Depends(get_settings)):
"""
Return Hyperion security.txt file
"""

return FileResponse("assets/security.txt")
return patch_identity_in_text(
Path("assets/security.txt").read_text(encoding="utf-8"),
settings,
)


@router.get(
"/robots.txt",
response_class=FileResponse,
status_code=200,
)
async def read_robots_txt():
async def read_robots_txt(settings: Settings = Depends(get_settings)):
"""
Return Hyperion robots.txt file
"""

return FileResponse("assets/robots.txt")
return patch_identity_in_text(
Path("assets/robots.txt").read_text(encoding="utf-8"),
settings,
)


@router.get(
"/style/{file}.css",
response_class=FileResponse,
"/variables",
response_model=schemas_core.CoreVariables,
status_code=200,
)
async def get_style_file(
file: str,
):
async def get_variables(settings: Settings = Depends(get_settings)):
"""
Return a style file from the assets folder
"""
css_dir = "assets/style/"
css_path = f"{css_dir}{file}.css"

# Security check (even if FastAPI parsing of path parameters does not allow path traversal)
if path.commonprefix(
(path.realpath(css_path), path.realpath(css_dir)),
) != path.realpath(css_dir):
raise HTTPException(status_code=404, detail="File not found")

if not Path(css_path).is_file():
raise HTTPException(status_code=404, detail="File not found")

return FileResponse(css_path)
return schemas_core.CoreVariables(
name=settings.school.application_name,
entity_name=settings.school.entity_name,
email_placeholder=settings.school.email_placeholder,
main_activation_form=settings.school.main_activation_form,
play_store_url=settings.school.play_store_url,
app_store_url=settings.school.app_store_url,
student_email_regex=settings.school.student_email_regex.pattern,
staff_email_regex=settings.school.staff_email_regex.pattern
if settings.school.staff_email_regex
else None,
former_student_email_regex=settings.school.former_student_email_regex.pattern
if settings.school.former_student_email_regex
else None,
# `as_hsl()` return a string in the format `hsl(hue saturation lightness)`, we need to convert it to `24.6 95% 53.1%` for TailwindCSS
primary_color=settings.school.primary_color.as_hsl()[4:-1],
)


@router.get(
Expand Down
56 changes: 55 additions & 1 deletion app/core/core_endpoints/schemas_core.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"""Common schemas file for endpoint /users et /groups because it would cause circular import"""

from pydantic import BaseModel
from enum import Enum

from pydantic import BaseModel, ConfigDict, Field

from app.core.groups.groups_type import AccountType


class CoreInformation(BaseModel):
Expand All @@ -9,3 +13,53 @@ class CoreInformation(BaseModel):
ready: bool
version: str
minimal_titan_version_code: int


class ModuleVisibility(BaseModel):
root: str
allowed_group_ids: list[str]
allowed_account_types: list[AccountType]
model_config = ConfigDict(from_attributes=True)


class ModuleVisibilityCreate(BaseModel):
root: str
allowed_group_id: str | None = None
allowed_account_type: AccountType | None = None
model_config = ConfigDict(from_attributes=True)


class ActivationFormField(Enum):
NICKNAME = "nickname"
BIRTHDATE = "birthdate"
PHONE = "phone"
PROMOTION = "promotion"
FLOOR = "floor"


class MainActivationForm(BaseModel):
fields: list[ActivationFormField] = Field(
description="List of fields that are to be asked in the main activation form",
)
floor_choices: list[str] = Field(
description="List of choices for the floor field if it is asked",
default_factory=list,
)
promotion_offset: int | None = None


class CoreVariables(BaseModel):
"""Variables used by Hyperion"""

name: str
entity_name: str
email_placeholder: str
main_activation_form: MainActivationForm
student_email_regex: str
staff_email_regex: str | None = None
former_student_email_regex: str | None = None
primary_color: str = Field(
description="Returned as an HSL triplet (ex: `24.6 95% 53.1%`)",
)
play_store_url: str | None = None
app_store_url: str | None = None
9 changes: 0 additions & 9 deletions app/core/myeclpay/coredata_myeclpay.py

This file was deleted.

File renamed without changes.
9 changes: 9 additions & 0 deletions app/core/mypayment/coredata_mypayment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from uuid import UUID

from app.types.core_data import BaseCoreData


class MyPaymentBankAccountHolder(BaseCoreData):
"""Bank account holder information for MyPayment."""

holder_structure_id: UUID
Loading