created_at swagger

This commit is contained in:
2025-10-30 23:03:57 +01:00
parent 5386724e0d
commit 4a3cb63263
15 changed files with 217 additions and 142 deletions
+4
View File
@@ -56,6 +56,7 @@ impl PreparedPasskey {
pub struct RegistrationChallengeResponse {
pub challenge_id: Uuid,
#[serde(flatten)]
#[schema(value_type = Object)]
pub challenge: CreationChallengeResponse,
}
@@ -64,6 +65,7 @@ pub struct RegistrationChallengeResponse {
pub struct AuthenticationChallengeResponse {
pub challenge_id: Uuid,
#[serde(flatten)]
#[schema(value_type = Object)]
pub challenge: RequestChallengeResponse,
}
@@ -651,6 +653,7 @@ impl From<UserPasskey> for PasskeySummary {
#[serde(rename_all = "camelCase")]
pub struct PasskeyRegistrationFinishPayload {
pub challenge_id: Uuid,
#[schema(value_type = Object)]
pub credential: RegisterPublicKeyCredential,
#[serde(default)]
pub nickname: Option<String>,
@@ -666,5 +669,6 @@ pub struct PasskeyLoginStartPayload {
#[serde(rename_all = "camelCase")]
pub struct PasskeyLoginFinishPayload {
pub challenge_id: Uuid,
#[schema(value_type = Object)]
pub credential: PublicKeyCredential,
}
+1 -1
View File
@@ -240,7 +240,7 @@ pub struct Document {
pub original_name: String,
pub content_type: Option<String>,
pub folder_id: Option<Uuid>,
pub uploaded_at: NaiveDateTime,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
pub deleted_at: Option<NaiveDateTime>,
pub metadata: serde_json::Value,
+3 -2
View File
@@ -721,6 +721,7 @@ pub mod schemas {
#[derive(Serialize, Deserialize, ToSchema)]
pub struct SignupFinishRequest {
pub signup_token: String,
#[schema(value_type = Object)]
pub credential: RegisterPublicKeyCredential,
#[schema(nullable)]
pub nickname: Option<String>,
@@ -867,7 +868,7 @@ pub mod schemas {
pub content_type: Option<String>,
#[schema(nullable)]
pub folder_id: Option<Uuid>,
pub uploaded_at: String,
pub created_at: String,
pub updated_at: String,
#[schema(nullable)]
pub deleted_at: Option<String>,
@@ -1038,7 +1039,7 @@ pub mod schemas {
#[schema(nullable)]
pub version_number: Option<i32>,
#[schema(nullable)]
pub uploaded_at: Option<String>,
pub created_at: Option<String>,
}
#[derive(Serialize, Deserialize, ToSchema)]
+7 -7
View File
@@ -108,7 +108,7 @@ pub struct DocumentCheckResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub version_number: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uploaded_at: Option<String>,
pub created_at: Option<String>,
}
#[derive(Serialize, ToSchema)]
@@ -136,7 +136,7 @@ pub struct DocumentResponse {
pub original_name: String,
pub content_type: Option<String>,
pub folder_id: Option<Uuid>,
pub uploaded_at: String,
pub created_at: String,
pub updated_at: String,
pub deleted_at: Option<String>,
pub issued_at: Option<String>,
@@ -554,14 +554,14 @@ pub async fn list_documents(
if !by_id.is_empty() {
let mut remaining: Vec<Document> = by_id.into_values().collect();
remaining.sort_by(|a, b| b.uploaded_at.cmp(&a.uploaded_at));
remaining.sort_by(|a, b| b.created_at.cmp(&a.created_at));
ordered.extend(remaining);
}
ordered
} else {
docs_query
.order(documents::uploaded_at.desc())
.order(documents::created_at.desc())
.load(&mut conn)?
};
@@ -627,7 +627,7 @@ pub async fn check_document(
filename: Some(document.filename.clone()),
version_id: Some(version.id),
version_number: Some(version.version_number),
uploaded_at: Some(to_iso(document.uploaded_at)),
created_at: Some(to_iso(document.created_at)),
}))
} else {
Ok(Json(DocumentCheckResponse {
@@ -637,7 +637,7 @@ pub async fn check_document(
filename: None,
version_id: None,
version_number: None,
uploaded_at: None,
created_at: None,
}))
}
}
@@ -2190,7 +2190,7 @@ pub(crate) fn to_document_response(
original_name: doc.original_name,
content_type: doc.content_type,
folder_id: doc.folder_id,
uploaded_at: to_iso(doc.uploaded_at),
created_at: to_iso(doc.created_at),
updated_at: to_iso(doc.updated_at),
deleted_at: doc.deleted_at.map(to_iso),
issued_at: doc.issued_at.map(to_iso),
+1 -1
View File
@@ -308,7 +308,7 @@ pub async fn list_folder_contents(
let docs_query = documents::table
.filter(documents::deleted_at.is_null())
.filter(documents::tenant_id.eq(tenant_id))
.order(documents::uploaded_at.desc());
.order(documents::created_at.desc());
let docs: Vec<Document> = if let Some(current_folder) = folder_id {
docs_query
+47 -14
View File
@@ -2,7 +2,7 @@ use axum::http::HeaderValue;
use axum::{
extract::DefaultBodyLimit,
middleware,
response::Json,
response::{Html, Json},
routing::{delete, get, patch, post},
Router,
};
@@ -164,24 +164,26 @@ pub fn create_router(state: AppState) -> Router<()> {
.nest("/api/assets", assets_routes)
.layer(middleware::from_extractor_with_state::<AuthenticatedUser, _>(protected_state));
let openapi_arc = Arc::new(ApiDoc::openapi());
let docs_route = Router::new().route(
"/api/docs/openapi.json",
get({
let spec = openapi_arc.clone();
move || {
let spec = spec.clone();
async move { Json((*spec).clone()) }
}
}),
);
let upload_limit = state.config.upload_body_limit_bytes;
let openapi_spec = Arc::new(ApiDoc::openapi());
let docs_router = Router::new()
.route(
"/api/docs",
get(move || async { Html(render_swagger_ui("/api/docs/openapi.json")) }),
)
.route(
"/api/docs/openapi.json",
get({
let spec = openapi_spec.clone();
move || async move { Json((*spec).clone()) }
}),
);
Router::new()
.merge(download_routes)
.merge(protected_routes)
.merge(docs_route)
.merge(docs_router)
.nest("/api/auth", auth_routes)
.route("/api/health", get(health::health_check))
.with_state(state)
@@ -196,3 +198,34 @@ pub fn create_router(state: AppState) -> Router<()> {
.on_failure(DefaultOnFailure::new().level(tracing::Level::ERROR)),
)
}
fn render_swagger_ui(spec_url: &str) -> String {
format!(
r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Papercrate API Docs</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css" />
<style>
html {{ box-sizing: border-box; font-family: sans-serif; }}
*, *:before, *:after {{ box-sizing: inherit; }}
body {{ margin: 0; background: #fafafa; }}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
<script>
window.addEventListener('load', () => {{
window.ui = SwaggerUIBundle({{
url: '{spec_url}',
dom_id: '#swagger-ui',
deepLinking: true,
}});
}});
</script>
</body>
</html>"#
)
}
+1 -1
View File
@@ -273,7 +273,7 @@ fn fetch_folder_contents(
};
let documents: Vec<Document> = docs_query
.order(documents_dsl::uploaded_at.desc())
.order(documents_dsl::created_at.desc())
.load(&mut conn)?;
let version_ids: Vec<Uuid> = documents.iter().map(|doc| doc.current_version_id).collect();
+1 -1
View File
@@ -88,7 +88,7 @@ diesel::table! {
#[max_length = 100]
content_type -> Nullable<Varchar>,
folder_id -> Nullable<Uuid>,
uploaded_at -> Timestamptz,
created_at -> Timestamptz,
updated_at -> Timestamptz,
deleted_at -> Nullable<Timestamptz>,
metadata -> Jsonb,