Coverage for src/kwai/api/v1/club/endpoints/upload_members.py: 94%
53 statements
« prev ^ index » next coverage.py v7.6.10, created at 2024-01-01 00:00 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2024-01-01 00:00 +0000
1"""Module that defines the members API."""
3from pathlib import Path
4from typing import Annotated
6from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile, status
7from pydantic import BaseModel, Field
9from kwai.api.dependencies import create_database, get_current_user
10from kwai.api.v1.club.presenters import JsonApiUploadMemberPresenter
11from kwai.api.v1.club.schemas.member import MemberDocument
12from kwai.core.db.database import Database
13from kwai.core.db.uow import UnitOfWork
14from kwai.core.functions import generate_filenames
15from kwai.core.settings import Settings, get_settings
16from kwai.modules.club.import_members import (
17 ImportMembers,
18 ImportMembersCommand,
19)
20from kwai.modules.club.repositories.country_db_repository import CountryDbRepository
21from kwai.modules.club.repositories.file_upload_db_repository import (
22 FileUploadDbRepository,
23)
24from kwai.modules.club.repositories.file_upload_preview_repository import (
25 FileUploadPreviewRepository,
26)
27from kwai.modules.club.repositories.file_upload_repository import (
28 DuplicateMemberUploadedException,
29)
30from kwai.modules.club.repositories.flemish_member_importer import FlemishMemberImporter
31from kwai.modules.club.repositories.member_db_repository import MemberDbRepository
32from kwai.modules.identity.users.user import UserEntity
35router = APIRouter()
38class UploadMemberModel(BaseModel):
39 """Model containing information about a row.
41 The id will be set, when a member is successfully imported. When a member was
42 not imported, the message will contain a description about the problem.
43 """
45 row: int
46 id: int | None = None
47 message: str = ""
50class UploadMembersModel(BaseModel):
51 """Model that contains the information about all rows."""
53 members: list[UploadMemberModel] = Field(default_factory=list)
56@router.post("/members/upload")
57async def upload(
58 member_file: Annotated[
59 UploadFile, File(description="A file with members to upload into kwai")
60 ],
61 settings: Annotated[Settings, Depends(get_settings)],
62 database: Annotated[Database, Depends(create_database)],
63 user: Annotated[UserEntity, Depends(get_current_user)],
64 preview: Annotated[bool, Query(description="Whether or not to preview")] = True,
65) -> MemberDocument:
66 """Upload a members csv file."""
67 if member_file.filename is None:
68 raise HTTPException(
69 status_code=status.HTTP_400_BAD_REQUEST,
70 detail="There is no filename available for the uploaded file.",
71 )
73 try:
74 member_filename = await upload_file(member_file, settings.files.path)
75 except Exception as ex:
76 raise HTTPException(
77 status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
78 detail=f"Failed to upload members file: {ex}",
79 ) from ex
81 presenter = JsonApiUploadMemberPresenter()
82 async with UnitOfWork(database):
83 try:
84 await ImportMembers(
85 FlemishMemberImporter(
86 str(member_filename),
87 user.create_owner(),
88 CountryDbRepository(database),
89 ),
90 (
91 FileUploadPreviewRepository()
92 if preview
93 else FileUploadDbRepository(database)
94 ),
95 MemberDbRepository(database),
96 presenter,
97 ).execute(ImportMembersCommand(preview=preview))
98 except DuplicateMemberUploadedException as ex:
99 raise HTTPException(
100 status_code=status.HTTP_400_BAD_REQUEST,
101 detail=f"Failed to upload members file: {ex}",
102 ) from ex
104 return presenter.get_document()
107async def upload_file(uploaded_file, path: str):
108 """Creates a unique file for the uploaded file."""
109 file_path = Path(path)
110 file_path.mkdir(parents=True, exist_ok=True)
111 member_file_path = file_path / uploaded_file.filename
112 member_filename_generator = generate_filenames(
113 member_file_path.stem + "_", member_file_path.suffix
114 )
115 while True:
116 member_filename = file_path / next(member_filename_generator)
117 if not member_filename.exists():
118 break
120 with open(member_filename, "wb") as fh:
121 fh.write(await uploaded_file.read())
123 return member_filename