Skip to main content

docbox_http/models/
link.rs

1use crate::error::HttpError;
2use axum::http::StatusCode;
3use docbox_core::{database::models::folder::FolderId, links::create_link::CreateLinkError};
4use garde::Validate;
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7use utoipa::ToSchema;
8
9/// Request to create a document box
10#[derive(Debug, Validate, Deserialize, ToSchema)]
11pub struct CreateLink {
12    /// Name for the link
13    #[garde(length(min = 1, max = 255))]
14    #[schema(min_length = 1, max_length = 255)]
15    pub name: String,
16
17    /// Link URL
18    #[garde(length(min = 1))]
19    #[schema(min_length = 1)]
20    pub value: String,
21
22    /// ID of the folder to store link in
23    #[garde(skip)]
24    #[schema(value_type = Uuid)]
25    pub folder_id: FolderId,
26}
27
28/// Request to rename a file
29#[derive(Debug, Validate, Deserialize, ToSchema)]
30pub struct UpdateLinkRequest {
31    /// Name for the link
32    #[garde(inner(length(min = 1, max = 255)))]
33    #[schema(min_length = 1, max_length = 255)]
34    pub name: Option<String>,
35
36    /// Value for the link
37    #[garde(inner(length(min = 1)))]
38    #[schema(min_length = 1)]
39    pub value: Option<String>,
40
41    /// New parent folder ID for the link
42    #[garde(skip)]
43    #[schema(value_type = Option<Uuid>)]
44    pub folder_id: Option<FolderId>,
45
46    /// Whether to pin the link
47    #[garde(skip)]
48    #[schema(value_type = Option<bool>)]
49    pub pinned: Option<bool>,
50}
51
52/// Response metadata for a resolved link
53#[derive(Debug, Serialize, ToSchema)]
54pub struct LinkMetadataResponse {
55    /// Title from the website metadata
56    pub title: Option<String>,
57    /// Alternative title from the website OGP metadata
58    pub og_title: Option<String>,
59    /// Description from the OGP metadata
60    pub og_description: Option<String>,
61
62    /// Whether the metadata resolved a favicon
63    pub favicon: bool,
64    /// Whether the metadata resolved a image
65    pub image: bool,
66}
67
68#[derive(Debug, Error)]
69pub enum HttpLinkError {
70    #[error("unknown link")]
71    UnknownLink,
72
73    #[error("invalid link url")]
74    InvalidLinkUrl,
75
76    /// Failed to create the link
77    #[error(transparent)]
78    CreateError(CreateLinkError),
79
80    // Failed resolving of metadata is treated as a 404 as we were
81    // unable to find the website data
82    #[error("failed to resolve metadata")]
83    FailedResolve,
84
85    #[error("website favicon not present")]
86    NoFavicon,
87
88    #[error("website image not present")]
89    NoImage,
90}
91
92impl HttpError for HttpLinkError {
93    fn status(&self) -> axum::http::StatusCode {
94        match self {
95            HttpLinkError::UnknownLink
96            | HttpLinkError::NoFavicon
97            | HttpLinkError::NoImage
98            | HttpLinkError::FailedResolve => StatusCode::NOT_FOUND,
99            HttpLinkError::InvalidLinkUrl => StatusCode::BAD_REQUEST,
100            HttpLinkError::CreateError(_) => StatusCode::INTERNAL_SERVER_ERROR,
101        }
102    }
103}