170 lines
3.8 KiB
Rust
170 lines
3.8 KiB
Rust
use async_trait::async_trait;
|
|
use chrono::NaiveDateTime;
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlx::{types::Json, FromRow};
|
|
use uuid::Uuid;
|
|
|
|
use crate::cursor::{AsCursor, CursorList};
|
|
|
|
use super::Error;
|
|
|
|
#[derive(Deserialize, Serialize, FromRow)]
|
|
pub struct Post {
|
|
/// Post ID
|
|
pub id: Uuid,
|
|
|
|
/// Site ID
|
|
pub site: Uuid,
|
|
|
|
/// Author ID
|
|
pub author: Uuid,
|
|
|
|
/// URL-friendly short code for the post
|
|
pub slug: String,
|
|
|
|
/// Post title
|
|
pub title: String,
|
|
|
|
/// Post description (for SEO/content)
|
|
pub description: Option<String>,
|
|
|
|
/// Post tags (for internal search)
|
|
pub tags: Vec<String>,
|
|
|
|
/// Post blocks (content)
|
|
pub blocks: Json<Vec<PostBlock>>,
|
|
|
|
/// Collections the post belongs to
|
|
pub collections: Vec<Uuid>,
|
|
|
|
/// Is the post published?
|
|
pub published: bool,
|
|
|
|
/// Times
|
|
pub created_at: NaiveDateTime,
|
|
pub modified_at: Option<NaiveDateTime>,
|
|
pub deleted_at: Option<NaiveDateTime>,
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize)]
|
|
#[serde(tag = "kind")]
|
|
pub enum PostBlock {
|
|
MarkupV1 {
|
|
/// Markup format (markdown, html, plain)
|
|
format: String,
|
|
|
|
/// Markup content (before rendering)
|
|
content: String,
|
|
},
|
|
GalleryV1 {
|
|
/// Images in the gallery
|
|
images: Vec<ImageElement>,
|
|
},
|
|
}
|
|
|
|
/// Picture inside a gallery
|
|
#[derive(Deserialize, Serialize)]
|
|
pub struct ImageElement {
|
|
/// URL of the picture
|
|
pub url: String,
|
|
|
|
/// Image width in pixels
|
|
pub width: i32,
|
|
|
|
/// Image height in pixels
|
|
pub height: i32,
|
|
|
|
/// List of thumbnails, if available
|
|
pub thumbnails: Vec<ImageElement>,
|
|
|
|
/// Optional caption to put near the image
|
|
pub caption: Option<String>,
|
|
}
|
|
|
|
/// Data to create a new post
|
|
#[derive(Deserialize)]
|
|
pub struct CreatePostData {
|
|
pub slug: String,
|
|
pub title: String,
|
|
pub description: Option<String>,
|
|
pub tags: Vec<String>,
|
|
pub blocks: Vec<PostBlock>,
|
|
pub collections: Vec<Uuid>,
|
|
pub published: bool,
|
|
}
|
|
|
|
/// Data to update a new post
|
|
#[derive(Deserialize)]
|
|
pub struct UpdatePostData {
|
|
pub slug: Option<String>,
|
|
pub title: Option<String>,
|
|
pub description: Option<String>,
|
|
pub tags: Option<Vec<String>>,
|
|
pub blocks: Option<Vec<PostBlock>>,
|
|
pub collections: Option<Vec<Uuid>>,
|
|
pub published: Option<bool>,
|
|
}
|
|
|
|
/// Post with site and author dereferenced for convenience
|
|
#[derive(Serialize)]
|
|
pub struct PostWithAuthor {
|
|
pub author_display_name: Option<String>,
|
|
pub author_username: String,
|
|
pub slug: String,
|
|
pub title: String,
|
|
pub description: Option<String>,
|
|
pub tags: Vec<String>,
|
|
pub blocks: Json<Vec<PostBlock>>,
|
|
pub created_at: NaiveDateTime,
|
|
pub modified_at: Option<NaiveDateTime>,
|
|
pub published: bool,
|
|
pub collections: Vec<Uuid>,
|
|
}
|
|
|
|
impl AsCursor<NaiveDateTime> for PostWithAuthor {
|
|
fn cursor(&self) -> NaiveDateTime {
|
|
self.created_at
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
pub trait PostRepository {
|
|
/// Get a post from its slug
|
|
async fn get_post_from_url(&self, site: &str, slug: &str) -> Result<PostWithAuthor, Error>;
|
|
|
|
/// List posts in a collection
|
|
async fn list_posts_in_collection(
|
|
&self,
|
|
site: &Uuid,
|
|
collection: &Uuid,
|
|
cursor: Option<NaiveDateTime>,
|
|
limit: i64,
|
|
) -> Result<CursorList<PostWithAuthor, NaiveDateTime>, Error>;
|
|
|
|
/// Create a new post
|
|
async fn create_post(
|
|
&self,
|
|
owner: &Uuid,
|
|
site: &Uuid,
|
|
data: CreatePostData,
|
|
) -> Result<(), Error>;
|
|
|
|
/// Update a post
|
|
async fn update_post(
|
|
&self,
|
|
owner: &Uuid,
|
|
site: &Uuid,
|
|
slug: &str,
|
|
data: UpdatePostData,
|
|
) -> Result<(), Error>;
|
|
|
|
/// Delete a post
|
|
async fn delete_post(
|
|
&self,
|
|
owner: &Uuid,
|
|
site: &Uuid,
|
|
name: &str,
|
|
soft_delete: bool,
|
|
) -> Result<(), Error>;
|
|
}
|