Coverage for polar/file/endpoints.py: 55%
45 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 16:17 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 16:17 +0000
1from typing import Annotated 1a
3from fastapi import Depends, Path, Query 1a
4from pydantic import UUID4 1a
6from polar.exceptions import NotPermitted, ResourceNotFound 1a
7from polar.kit.pagination import ListResource, PaginationParamsQuery 1a
8from polar.kit.schemas import MultipleQueryFilter 1a
9from polar.models import File 1a
10from polar.openapi import APITag 1a
11from polar.organization.resolver import get_payload_organization 1a
12from polar.organization.schemas import OrganizationID 1a
13from polar.postgres import ( 1a
14 AsyncReadSession,
15 AsyncSession,
16 get_db_read_session,
17 get_db_session,
18)
19from polar.routing import APIRouter 1a
21from . import auth 1a
22from .schemas import ( 1a
23 FileCreate,
24 FilePatch,
25 FileRead,
26 FileReadAdapter,
27 FileUpload,
28 FileUploadCompleted,
29)
30from .service import file as file_service 1a
32router = APIRouter(prefix="/files", tags=["files", APITag.public]) 1a
34FileID = Annotated[UUID4, Path(description="The file ID.")] 1a
35FileNotFound = {"description": "File not found.", "model": ResourceNotFound.schema()} 1a
38@router.get("/", summary="List Files", response_model=ListResource[FileRead]) 1a
39async def list( 1a
40 auth_subject: auth.FileRead,
41 pagination: PaginationParamsQuery,
42 organization_id: MultipleQueryFilter[OrganizationID] | None = Query(
43 None, title="OrganizationID Filter", description="Filter by organization ID."
44 ),
45 ids: MultipleQueryFilter[UUID4] | None = Query(
46 None, title="FileID Filter", description="Filter by file ID."
47 ),
48 session: AsyncReadSession = Depends(get_db_read_session),
49) -> ListResource[FileRead]:
50 """List files."""
51 results, count = await file_service.list(
52 session,
53 auth_subject,
54 organization_id=organization_id,
55 ids=ids,
56 pagination=pagination,
57 )
58 return ListResource.from_paginated_results(
59 [FileReadAdapter.validate_python(result) for result in results],
60 count,
61 pagination,
62 )
65@router.post( 1a
66 "/",
67 response_model=FileUpload,
68 summary="Create File",
69 status_code=201,
70 responses={201: {"description": "File created."}},
71)
72async def create( 1a
73 file_create: FileCreate,
74 auth_subject: auth.FileWrite,
75 session: AsyncSession = Depends(get_db_session),
76) -> FileUpload:
77 """Create a file."""
78 organization = await get_payload_organization(session, auth_subject, file_create)
80 file_create.organization_id = organization.id
81 return await file_service.generate_presigned_upload(
82 session,
83 organization=organization,
84 create_schema=file_create,
85 )
88@router.post( 1a
89 "/{id}/uploaded",
90 summary="Complete File Upload",
91 response_model=FileRead,
92 responses={
93 200: {"description": "File upload completed."},
94 403: {
95 "description": "You don't have the permission to update this file.",
96 "model": NotPermitted.schema(),
97 },
98 404: FileNotFound,
99 },
100)
101async def uploaded( 1a
102 id: FileID,
103 completed_schema: FileUploadCompleted,
104 auth_subject: auth.FileWrite,
105 session: AsyncSession = Depends(get_db_session),
106) -> File:
107 """Complete a file upload."""
108 file = await file_service.get(session, auth_subject, id)
109 if file is None:
110 raise ResourceNotFound()
112 return await file_service.complete_upload(
113 session, file=file, completed_schema=completed_schema
114 )
117# Re-introduce with changing version
118@router.patch( 1a
119 "/{id}",
120 summary="Update File",
121 response_model=FileRead,
122 responses={
123 200: {"description": "File updated."},
124 403: {
125 "description": "You don't have the permission to update this file.",
126 "model": NotPermitted.schema(),
127 },
128 404: FileNotFound,
129 },
130)
131async def update( 1a
132 auth_subject: auth.FileWrite,
133 id: FileID,
134 patches: FilePatch,
135 session: AsyncSession = Depends(get_db_session),
136) -> File:
137 """Update a file."""
138 file = await file_service.get(session, auth_subject, id)
139 if file is None:
140 raise ResourceNotFound()
142 return await file_service.patch(session, file=file, patches=patches)
145@router.delete( 1a
146 "/{id}",
147 summary="Delete File",
148 status_code=204,
149 responses={
150 204: {"description": "File deleted."},
151 403: {
152 "description": "You don't have the permission to delete this file.",
153 "model": NotPermitted.schema(),
154 },
155 404: FileNotFound,
156 },
157)
158async def delete( 1a
159 auth_subject: auth.FileWrite,
160 id: UUID4,
161 session: AsyncSession = Depends(get_db_session),
162) -> None:
163 """Delete a file."""
164 file = await file_service.get(session, auth_subject, id)
165 if file is None:
166 raise ResourceNotFound()
168 await file_service.delete(session, file=file)