From 60181ae53fe0a61cba43365578a7ed57efd1ae09 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Tue, 14 Jan 2025 21:41:11 +0000 Subject: [PATCH] Add fetch doc version endpoints --- backend/sync_server/src/server.rs | 10 ++ .../src/server/fetch_document_version.rs | 57 +++++++++ .../server/fetch_document_version_content.rs | 59 ++++++++++ plugin/src/services/types.ts | 111 ++++++++++++++++++ 4 files changed, 237 insertions(+) create mode 100644 backend/sync_server/src/server/fetch_document_version.rs create mode 100644 backend/sync_server/src/server/fetch_document_version_content.rs diff --git a/backend/sync_server/src/server.rs b/backend/sync_server/src/server.rs index da809c8e..bf62fec5 100644 --- a/backend/sync_server/src/server.rs +++ b/backend/sync_server/src/server.rs @@ -35,6 +35,8 @@ mod app_state; mod auth; mod create_document; mod delete_document; +mod fetch_document_version; +mod fetch_document_version_content; mod fetch_latest_document_version; mod fetch_latest_documents; mod ping; @@ -94,6 +96,14 @@ pub async fn create_server() -> Result<()> { "/vaults/:vault_id/documents/:document_id/json", put(update_document::update_document_json), ) + .api_route( + "/vaults/:vault_id/documents/:document_id/versions/:version_id", + put(fetch_document_version::fetch_document_version), + ) + .api_route( + "/vaults/:vault_id/documents/:document_id/versions/:version_id/content", + put(fetch_document_version_content::fetch_document_version_content), + ) .api_route( "/vaults/:vault_id/documents/:document_id", delete(delete_document::delete_document), diff --git a/backend/sync_server/src/server/fetch_document_version.rs b/backend/sync_server/src/server/fetch_document_version.rs new file mode 100644 index 00000000..c6431601 --- /dev/null +++ b/backend/sync_server/src/server/fetch_document_version.rs @@ -0,0 +1,57 @@ +use anyhow::anyhow; +use axum::extract::{Path, State}; +use axum_extra::{ + TypedHeader, + headers::{Authorization, authorization::Bearer}, +}; +use axum_jsonschema::Json; +use schemars::JsonSchema; +use serde::Deserialize; + +use super::{app_state::AppState, auth::auth}; +use crate::{ + database::models::{DocumentId, DocumentVersion, VaultId, VaultUpdateId}, + errors::{SyncServerError, not_found_error, server_error}, +}; + +// This is required for aide to infer the path parameter types and names +#[derive(Deserialize, JsonSchema)] +pub struct PathParams { + vault_id: VaultId, + document_id: DocumentId, + vault_update_id: VaultUpdateId, +} + +#[axum::debug_handler] +pub async fn fetch_document_version( + TypedHeader(auth_header): TypedHeader>, + Path(PathParams { + vault_id, + document_id, + vault_update_id, + }): Path, + State(state): State, +) -> Result, SyncServerError> { + auth(&state, auth_header.token())?; + + let result = state + .database + .get_document_version(&vault_id, vault_update_id, None) + .await + .map_err(server_error)? + .map(Ok) + .unwrap_or_else(|| { + Err(not_found_error(anyhow!( + "Document with vault update id `{vault_update_id}` not found", + ))) + })?; + + if result.document_id != document_id { + return Err(not_found_error(anyhow!( + "Document with document id `{document_id}` does not have a version with id \ + `{vault_update_id}`", + ))); + } + + Ok(Json(result.into())) +} diff --git a/backend/sync_server/src/server/fetch_document_version_content.rs b/backend/sync_server/src/server/fetch_document_version_content.rs new file mode 100644 index 00000000..68e38254 --- /dev/null +++ b/backend/sync_server/src/server/fetch_document_version_content.rs @@ -0,0 +1,59 @@ +use anyhow::anyhow; +use axum::{ + body::Bytes, + extract::{Path, State}, +}; +use axum_extra::{ + TypedHeader, + headers::{Authorization, authorization::Bearer}, +}; +use schemars::JsonSchema; +use serde::Deserialize; + +use super::{app_state::AppState, auth::auth}; +use crate::{ + database::models::{DocumentId, VaultId, VaultUpdateId}, + errors::{SyncServerError, not_found_error, server_error}, +}; + +// This is required for aide to infer the path parameter types and names +#[derive(Deserialize, JsonSchema)] +pub struct PathParams { + vault_id: VaultId, + document_id: DocumentId, + vault_update_id: VaultUpdateId, +} + +#[axum::debug_handler] +pub async fn fetch_document_version_content( + TypedHeader(auth_header): TypedHeader>, + Path(PathParams { + vault_id, + document_id, + vault_update_id, + }): Path, + State(state): State, +) -> Result { + auth(&state, auth_header.token())?; + + let result = state + .database + .get_document_version(&vault_id, vault_update_id, None) + .await + .map_err(server_error)? + .map(Ok) + .unwrap_or_else(|| { + Err(not_found_error(anyhow!( + "Document with vault update id `{vault_update_id}` not found", + ))) + })?; + + if result.document_id != document_id { + return Err(not_found_error(anyhow!( + "Document with document id `{document_id}` does not have a version with id \ + `{vault_update_id}`", + ))); + } + + Ok(result.content.into()) +} diff --git a/plugin/src/services/types.ts b/plugin/src/services/types.ts index d920e1e8..6a18e16a 100644 --- a/plugin/src/services/types.ts +++ b/plugin/src/services/types.ts @@ -347,6 +347,103 @@ export interface paths { patch?: never; trace?: never; }; + "/vaults/{vault_id}/documents/{document_id}/versions/{version_id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put: { + parameters: { + query?: never; + header: { + authorization: string; + }; + path: { + document_id: string; + vault_id: string; + vault_update_id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DocumentVersion"]; + }; + }; + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SerializedError"]; + }; + }; + }; + }; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/vaults/{vault_id}/documents/{document_id}/versions/{version_id}/content": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put: { + parameters: { + query?: never; + header: { + authorization: string; + }; + path: { + document_id: string; + vault_id: string; + vault_update_id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description byte stream */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/octet-stream": unknown; + }; + }; + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SerializedError"]; + }; + }; + }; + }; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; } export type webhooks = Record; export interface components { @@ -458,6 +555,20 @@ export interface components { /** Format: uuid */ document_id: string; vault_id: string; + /** Format: int64 */ + vault_update_id: number; + }; + PathParams6: { + /** Format: uuid */ + document_id: string; + vault_id: string; + /** Format: int64 */ + vault_update_id: number; + }; + PathParams7: { + /** Format: uuid */ + document_id: string; + vault_id: string; }; /** @description Response to a ping request. */ PingResponse: {