Skip to content

Commit

Permalink
PH v1 (#368)
Browse files Browse the repository at this point in the history
### Description

I sarted a PH module for the journalism association of ECL.

---------

Co-authored-by: armanddidierjean <95971503+armanddidierjean@users.noreply.github.com>
Co-authored-by: Foucauld Bellanger <63885990+Foukki@users.noreply.github.com>
  • Loading branch information
3 people committed May 14, 2024
1 parent 44c0634 commit fa88160
Show file tree
Hide file tree
Showing 14 changed files with 606 additions and 3 deletions.
1 change: 1 addition & 0 deletions app/core/groups/groups_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class GroupType(str, Enum):
BDE = "53a669d6-84b1-4352-8d7c-421c1fbd9c6a"
CAA = "6c6d7e88-fdb8-4e42-b2b5-3d3cfd12e7d6"
cinema = "ce5f36e6-5377-489f-9696-de70e2477300"
ph = "4ec5ae77-f955-4309-96a5-19cc3c8be71c"

# Auth related groups

Expand Down
1 change: 1 addition & 0 deletions app/core/notification/notification_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Topic(str, Enum):
loan = "loan"
raffle = "raffle"
vote = "vote"
ph = "ph"


class CustomTopic:
Expand Down
Empty file added app/modules/ph/__init__.py
Empty file.
69 changes: 69 additions & 0 deletions app/modules/ph/cruds_ph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from collections.abc import Sequence
from datetime import date

from sqlalchemy import delete, select, update
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession

from app.modules.ph import models_ph, schemas_ph


async def get_papers(
db: AsyncSession,
end_date: date | None = None,
) -> Sequence[models_ph.Paper]:
"""Return papers from the latest to the oldest"""
result = await db.execute(
select(models_ph.Paper)
.where(models_ph.Paper.release_date <= (end_date or date.max))
.order_by(models_ph.Paper.release_date.desc()),
)
return result.scalars().all()


async def get_paper_by_id(
db: AsyncSession,
paper_id: str,
) -> Sequence[models_ph.Paper]:
result = await db.execute(
select(models_ph.Paper).where(models_ph.Paper.id == paper_id),
)
return result.scalars().all()


async def create_paper(
paper: models_ph.Paper,
db: AsyncSession,
) -> models_ph.Paper:
"""Create a new paper in database and return it"""

db.add(paper)
try:
await db.commit()
return paper
except IntegrityError as error:
await db.rollback()
raise ValueError(error)


async def update_paper(
paper_id: str,
paper_update: schemas_ph.PaperUpdate,
db: AsyncSession,
):
await db.execute(
update(models_ph.Paper)
.where(models_ph.Paper.id == paper_id)
.values(**paper_update.model_dump(exclude_none=True)),
)
await db.commit()


async def delete_paper(
paper_id: str,
db: AsyncSession,
):
await db.execute(
delete(models_ph.Paper).where(models_ph.Paper.id == paper_id),
)
await db.commit()
264 changes: 264 additions & 0 deletions app/modules/ph/endpoints_ph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
import uuid
from datetime import UTC, datetime, time, timedelta

from fastapi import Depends, File, HTTPException, UploadFile
from fastapi.responses import FileResponse
from sqlalchemy.ext.asyncio import AsyncSession

from app.core import models_core
from app.core.groups.groups_type import GroupType
from app.core.module import Module
from app.core.notification.notification_types import CustomTopic, Topic
from app.core.notification.schemas_notification import Message
from app.dependencies import (
get_db,
get_notification_tool,
get_request_id,
is_user_a_member,
is_user_a_member_of,
)
from app.modules.ph import cruds_ph, models_ph, schemas_ph
from app.types.content_type import ContentType
from app.utils.communication.notifications import NotificationTool
from app.utils.tools import (
delete_file_from_data,
get_file_from_data,
save_file_as_data,
save_pdf_first_page_as_image,
)

module = Module(
root="ph",
tag="ph",
default_allowed_groups_ids=[GroupType.student],
)


@module.router.get(
"/ph/{paper_id}/pdf",
response_class=FileResponse,
status_code=200,
)
async def get_paper_pdf(
paper_id: str,
db: AsyncSession = Depends(get_db),
user: models_core.CoreUser = Depends(is_user_a_member),
):
paper = await cruds_ph.get_paper_by_id(db=db, paper_id=paper_id)
if paper is None:
raise HTTPException(
status_code=404,
detail="The paper does not exist.",
)

return get_file_from_data(
default_asset="assets/pdf/default_ph.pdf",
directory="ph/pdf",
filename=str(paper_id),
)


@module.router.get(
"/ph/",
response_model=list[schemas_ph.PaperComplete],
status_code=200,
)
async def get_papers(
db: AsyncSession = Depends(get_db),
user: models_core.CoreUser = Depends(is_user_a_member),
):
"""
Return all editions until now, sorted from the latest to the oldest
"""
result = await cruds_ph.get_papers(
db=db,
end_date=datetime.now(tz=UTC).date(),
) # Return papers from the latest to the oldest until now
return result


@module.router.get(
"/ph/admin",
response_model=list[schemas_ph.PaperComplete],
status_code=200,
)
async def get_papers_admin(
db: AsyncSession = Depends(get_db),
user: models_core.CoreUser = Depends(is_user_a_member_of(GroupType.ph)),
):
"""
Return all editions, sorted from the latest to the oldest
"""
result = await cruds_ph.get_papers(
db=db,
) # Return all papers from the latest to the oldest
return result


@module.router.post(
"/ph/",
response_model=schemas_ph.PaperComplete,
status_code=201,
)
async def create_paper(
paper: schemas_ph.PaperBase,
db: AsyncSession = Depends(get_db),
user: models_core.CoreUser = Depends(is_user_a_member_of(GroupType.ph)),
notification_tool: NotificationTool = Depends(get_notification_tool),
):
"""Create a new paper."""

paper_complete = schemas_ph.PaperComplete(
id=str(uuid.uuid4()),
**paper.model_dump(),
)
try:
paper_db = models_ph.Paper(
id=paper_complete.id,
name=paper_complete.name,
release_date=paper_complete.release_date,
)

now = datetime.now(UTC)

# We only want to send a notification if the paper was released less than a month ago.
if paper_db.release_date >= now.date() - timedelta(days=30):
message = Message(
context=f"ph-{paper_db.id}",
is_visible=True,
title=f"📗 PH - {paper_db.name}",
content="Un nouveau journal est disponible! 🎉",
delivery_datetime=datetime.combine(
paper_db.release_date,
time(hour=8, tzinfo=UTC),
),
# The notification will expire in 10 days
expire_on=now + timedelta(days=10),
)
await notification_tool.send_notification_to_topic(
custom_topic=CustomTopic(topic=Topic.ph),
message=message,
)
return await cruds_ph.create_paper(paper=paper_db, db=db)

except ValueError as error:
raise HTTPException(
status_code=400,
detail=str(error),
)


@module.router.post(
"/ph/{paper_id}/pdf",
status_code=201,
)
async def create_paper_pdf_and_cover(
paper_id: str,
pdf: UploadFile = File(...),
user: models_core.CoreUser = Depends(is_user_a_member_of(GroupType.ph)),
request_id: str = Depends(get_request_id),
db: AsyncSession = Depends(get_db),
):
paper = await cruds_ph.get_paper_by_id(db=db, paper_id=paper_id)
if paper is None:
raise HTTPException(
status_code=404,
detail="The paper does not exist.",
)

await save_file_as_data(
upload_file=pdf,
directory="ph/pdf",
filename=str(paper_id),
request_id=request_id,
max_file_size=10 * 1024 * 1024, # 10 MB
accepted_content_types=[ContentType.pdf],
)

await save_pdf_first_page_as_image(
input_pdf_directory="ph/pdf",
output_image_directory="ph/cover",
filename=str(paper_id),
default_pdf_path="assets/pdf/default_ph.pdf",
request_id=request_id,
jpg_quality=95,
)


@module.router.get(
"/ph/{paper_id}/cover",
status_code=200,
)
async def get_cover(
paper_id: str,
user: models_core.CoreUser = Depends(is_user_a_member),
db: AsyncSession = Depends(get_db),
):
paper = await cruds_ph.get_paper_by_id(db=db, paper_id=paper_id)
if paper is None:
raise HTTPException(
status_code=404,
detail="The paper does not exist.",
)

return get_file_from_data(
default_asset="assets/images/default_cover.jpg",
directory="ph/cover",
filename=str(paper_id),
)


@module.router.patch(
"/ph/{paper_id}",
status_code=204,
)
async def update_paper(
paper_id: str,
paper_update: schemas_ph.PaperUpdate,
user: models_core.CoreUser = Depends(is_user_a_member_of(GroupType.ph)),
db: AsyncSession = Depends(get_db),
):
paper = await cruds_ph.get_paper_by_id(paper_id=paper_id, db=db)
if not paper:
raise HTTPException(
status_code=404,
detail="Invalid paper_id",
)

await cruds_ph.update_paper(
paper_id=paper_id,
paper_update=paper_update,
db=db,
)


@module.router.delete(
"/ph/{paper_id}",
status_code=204,
)
async def delete_paper(
paper_id: str,
user: models_core.CoreUser = Depends(is_user_a_member_of(GroupType.ph)),
db: AsyncSession = Depends(get_db),
):
paper = await cruds_ph.get_paper_by_id(paper_id=paper_id, db=db)
if not paper:
raise HTTPException(
status_code=404,
detail="Invalid paper_id",
)

delete_file_from_data(
directory="ph/pdf",
filename=str(paper_id),
)

delete_file_from_data(
directory="ph/cover",
filename=str(paper_id),
)

await cruds_ph.delete_paper(
paper_id=paper_id,
db=db,
)
14 changes: 14 additions & 0 deletions app/modules/ph/models_ph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from datetime import date

from sqlalchemy import Date, String
from sqlalchemy.orm import Mapped, mapped_column

from app.types.sqlalchemy import Base


class Paper(Base):
__tablename__ = "ph_papers"

id: Mapped[str] = mapped_column(String, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String, nullable=False)
release_date: Mapped[date] = mapped_column(Date, nullable=False)
19 changes: 19 additions & 0 deletions app/modules/ph/schemas_ph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from datetime import date

from pydantic import BaseModel


class PaperBase(BaseModel):
"""Base schema for paper's model"""

name: str
release_date: date


class PaperComplete(PaperBase):
id: str


class PaperUpdate(BaseModel):
name: str | None = None
release_date: date | None = None
Loading

0 comments on commit fa88160

Please sign in to comment.