pinakes-server: add utoipa annotations to all routes; fix tests

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I28cf5b7b7cff8e90e123d624d97cf9656a6a6964
This commit is contained in:
raf 2026-03-21 02:17:55 +03:00
commit 9d58927cb4
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
60 changed files with 3493 additions and 242 deletions

View file

@ -57,6 +57,19 @@ const DEFAULT_CHANGES_LIMIT: u64 = 100;
/// Register a new sync device
/// POST /api/sync/devices
#[utoipa::path(
post,
path = "/api/v1/sync/devices",
tag = "sync",
request_body = RegisterDeviceRequest,
responses(
(status = 200, description = "Device registered", body = DeviceRegistrationResponse),
(status = 400, description = "Bad request"),
(status = 401, description = "Unauthorized"),
(status = 500, description = "Internal server error"),
),
security(("bearer_auth" = []))
)]
pub async fn register_device(
State(state): State<AppState>,
Extension(username): Extension<String>,
@ -111,6 +124,16 @@ pub async fn register_device(
/// List user's sync devices
/// GET /api/sync/devices
#[utoipa::path(
get,
path = "/api/v1/sync/devices",
tag = "sync",
responses(
(status = 200, description = "List of devices", body = Vec<DeviceResponse>),
(status = 401, description = "Unauthorized"),
),
security(("bearer_auth" = []))
)]
pub async fn list_devices(
State(state): State<AppState>,
Extension(username): Extension<String>,
@ -127,6 +150,19 @@ pub async fn list_devices(
/// Get device details
/// GET /api/sync/devices/{id}
#[utoipa::path(
get,
path = "/api/v1/sync/devices/{id}",
tag = "sync",
params(("id" = Uuid, Path, description = "Device ID")),
responses(
(status = 200, description = "Device details", body = DeviceResponse),
(status = 401, description = "Unauthorized"),
(status = 403, description = "Forbidden"),
(status = 404, description = "Not found"),
),
security(("bearer_auth" = []))
)]
pub async fn get_device(
State(state): State<AppState>,
Extension(username): Extension<String>,
@ -149,6 +185,20 @@ pub async fn get_device(
/// Update a device
/// PUT /api/sync/devices/{id}
#[utoipa::path(
put,
path = "/api/v1/sync/devices/{id}",
tag = "sync",
params(("id" = Uuid, Path, description = "Device ID")),
request_body = UpdateDeviceRequest,
responses(
(status = 200, description = "Device updated", body = DeviceResponse),
(status = 401, description = "Unauthorized"),
(status = 403, description = "Forbidden"),
(status = 404, description = "Not found"),
),
security(("bearer_auth" = []))
)]
pub async fn update_device(
State(state): State<AppState>,
Extension(username): Extension<String>,
@ -185,6 +235,19 @@ pub async fn update_device(
/// Delete a device
/// DELETE /api/sync/devices/{id}
#[utoipa::path(
delete,
path = "/api/v1/sync/devices/{id}",
tag = "sync",
params(("id" = Uuid, Path, description = "Device ID")),
responses(
(status = 204, description = "Device deleted"),
(status = 401, description = "Unauthorized"),
(status = 403, description = "Forbidden"),
(status = 404, description = "Not found"),
),
security(("bearer_auth" = []))
)]
pub async fn delete_device(
State(state): State<AppState>,
Extension(username): Extension<String>,
@ -213,6 +276,19 @@ pub async fn delete_device(
/// Regenerate device token
/// POST /api/sync/devices/{id}/token
#[utoipa::path(
post,
path = "/api/v1/sync/devices/{id}/token",
tag = "sync",
params(("id" = Uuid, Path, description = "Device ID")),
responses(
(status = 200, description = "Token regenerated", body = DeviceRegistrationResponse),
(status = 401, description = "Unauthorized"),
(status = 403, description = "Forbidden"),
(status = 404, description = "Not found"),
),
security(("bearer_auth" = []))
)]
pub async fn regenerate_token(
State(state): State<AppState>,
Extension(username): Extension<String>,
@ -253,6 +329,21 @@ pub async fn regenerate_token(
/// Get changes since cursor
/// GET /api/sync/changes
#[utoipa::path(
get,
path = "/api/v1/sync/changes",
tag = "sync",
params(
("cursor" = Option<u64>, Query, description = "Sync cursor"),
("limit" = Option<u64>, Query, description = "Max changes (max 1000)"),
),
responses(
(status = 200, description = "Changes since cursor", body = ChangesResponse),
(status = 400, description = "Bad request"),
(status = 401, description = "Unauthorized"),
),
security(("bearer_auth" = []))
)]
pub async fn get_changes(
State(state): State<AppState>,
Query(params): Query<GetChangesParams>,
@ -290,6 +381,18 @@ pub async fn get_changes(
/// Report local changes from client
/// POST /api/sync/report
#[utoipa::path(
post,
path = "/api/v1/sync/report",
tag = "sync",
request_body = ReportChangesRequest,
responses(
(status = 200, description = "Changes processed", body = ReportChangesResponse),
(status = 400, description = "Bad request"),
(status = 401, description = "Unauthorized"),
),
security(("bearer_auth" = []))
)]
pub async fn report_changes(
State(state): State<AppState>,
Extension(_username): Extension<String>,
@ -392,6 +495,18 @@ pub async fn report_changes(
/// Acknowledge processed changes
/// POST /api/sync/ack
#[utoipa::path(
post,
path = "/api/v1/sync/ack",
tag = "sync",
request_body = AcknowledgeChangesRequest,
responses(
(status = 200, description = "Changes acknowledged"),
(status = 400, description = "Bad request"),
(status = 401, description = "Unauthorized"),
),
security(("bearer_auth" = []))
)]
pub async fn acknowledge_changes(
State(state): State<AppState>,
Extension(_username): Extension<String>,
@ -422,6 +537,16 @@ pub async fn acknowledge_changes(
/// List unresolved conflicts
/// GET /api/sync/conflicts
#[utoipa::path(
get,
path = "/api/v1/sync/conflicts",
tag = "sync",
responses(
(status = 200, description = "Unresolved conflicts", body = Vec<ConflictResponse>),
(status = 401, description = "Unauthorized"),
),
security(("bearer_auth" = []))
)]
pub async fn list_conflicts(
State(state): State<AppState>,
Extension(_username): Extension<String>,
@ -451,6 +576,19 @@ pub async fn list_conflicts(
/// Resolve a sync conflict
/// POST /api/sync/conflicts/{id}/resolve
#[utoipa::path(
post,
path = "/api/v1/sync/conflicts/{id}/resolve",
tag = "sync",
params(("id" = Uuid, Path, description = "Conflict ID")),
request_body = ResolveConflictRequest,
responses(
(status = 200, description = "Conflict resolved"),
(status = 400, description = "Bad request"),
(status = 401, description = "Unauthorized"),
),
security(("bearer_auth" = []))
)]
pub async fn resolve_conflict(
State(state): State<AppState>,
Extension(_username): Extension<String>,
@ -477,6 +615,18 @@ pub async fn resolve_conflict(
/// Create an upload session for chunked upload
/// POST /api/sync/upload
#[utoipa::path(
post,
path = "/api/v1/sync/upload",
tag = "sync",
request_body = CreateUploadSessionRequest,
responses(
(status = 200, description = "Upload session created", body = UploadSessionResponse),
(status = 400, description = "Bad request"),
(status = 401, description = "Unauthorized"),
),
security(("bearer_auth" = []))
)]
pub async fn create_upload(
State(state): State<AppState>,
Extension(_username): Extension<String>,
@ -541,6 +691,23 @@ pub async fn create_upload(
/// Upload a chunk
/// PUT /api/sync/upload/{id}/chunks/{index}
#[utoipa::path(
put,
path = "/api/v1/sync/upload/{id}/chunks/{index}",
tag = "sync",
params(
("id" = Uuid, Path, description = "Upload session ID"),
("index" = u64, Path, description = "Chunk index"),
),
request_body(content = Vec<u8>, description = "Chunk binary data", content_type = "application/octet-stream"),
responses(
(status = 200, description = "Chunk received", body = ChunkUploadedResponse),
(status = 400, description = "Bad request"),
(status = 401, description = "Unauthorized"),
(status = 404, description = "Not found"),
),
security(("bearer_auth" = []))
)]
pub async fn upload_chunk(
State(state): State<AppState>,
Path((session_id, chunk_index)): Path<(Uuid, u64)>,
@ -590,6 +757,18 @@ pub async fn upload_chunk(
/// Get upload session status
/// GET /api/sync/upload/{id}
#[utoipa::path(
get,
path = "/api/v1/sync/upload/{id}",
tag = "sync",
params(("id" = Uuid, Path, description = "Upload session ID")),
responses(
(status = 200, description = "Upload session status", body = UploadSessionResponse),
(status = 401, description = "Unauthorized"),
(status = 404, description = "Not found"),
),
security(("bearer_auth" = []))
)]
pub async fn get_upload_status(
State(state): State<AppState>,
Path(id): Path<Uuid>,
@ -603,6 +782,19 @@ pub async fn get_upload_status(
/// Complete an upload session
/// POST /api/sync/upload/{id}/complete
#[utoipa::path(
post,
path = "/api/v1/sync/upload/{id}/complete",
tag = "sync",
params(("id" = Uuid, Path, description = "Upload session ID")),
responses(
(status = 200, description = "Upload completed"),
(status = 400, description = "Bad request"),
(status = 401, description = "Unauthorized"),
(status = 404, description = "Not found"),
),
security(("bearer_auth" = []))
)]
pub async fn complete_upload(
State(state): State<AppState>,
Path(id): Path<Uuid>,
@ -759,6 +951,18 @@ pub async fn complete_upload(
/// Cancel an upload session
/// DELETE /api/sync/upload/{id}
#[utoipa::path(
delete,
path = "/api/v1/sync/upload/{id}",
tag = "sync",
params(("id" = Uuid, Path, description = "Upload session ID")),
responses(
(status = 204, description = "Upload cancelled"),
(status = 401, description = "Unauthorized"),
(status = 404, description = "Not found"),
),
security(("bearer_auth" = []))
)]
pub async fn cancel_upload(
State(state): State<AppState>,
Path(id): Path<Uuid>,
@ -789,6 +993,19 @@ pub async fn cancel_upload(
/// Download a file for sync (supports Range header)
/// GET /api/sync/download/{*path}
#[utoipa::path(
get,
path = "/api/v1/sync/download/{path}",
tag = "sync",
params(("path" = String, Path, description = "File path")),
responses(
(status = 200, description = "File content"),
(status = 206, description = "Partial content"),
(status = 401, description = "Unauthorized"),
(status = 404, description = "Not found"),
),
security(("bearer_auth" = []))
)]
pub async fn download_file(
State(state): State<AppState>,
Path(path): Path<String>,