This commit is contained in:
parent
3d50d2b4b0
commit
e626ef87dc
5 changed files with 59 additions and 59 deletions
|
@ -1,4 +1,4 @@
|
|||
pub mod page;
|
||||
pub mod post;
|
||||
pub mod site;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
|
|
|
@ -7,8 +7,8 @@ use uuid::Uuid;
|
|||
use super::Error;
|
||||
|
||||
#[derive(Deserialize, Serialize, FromRow)]
|
||||
pub struct Page {
|
||||
/// Page ID
|
||||
pub struct Post {
|
||||
/// Post ID
|
||||
pub id: Uuid,
|
||||
|
||||
/// Site ID
|
||||
|
@ -17,20 +17,20 @@ pub struct Page {
|
|||
/// Author ID
|
||||
pub author: Uuid,
|
||||
|
||||
/// URL-friendly short code for the page
|
||||
/// URL-friendly short code for the post
|
||||
pub slug: String,
|
||||
|
||||
/// Page title
|
||||
/// Post title
|
||||
pub title: String,
|
||||
|
||||
/// Page description (for SEO/content)
|
||||
/// Post description (for SEO/content)
|
||||
pub description: Option<String>,
|
||||
|
||||
/// Page tags (for internal search)
|
||||
/// Post tags (for internal search)
|
||||
pub tags: Vec<String>,
|
||||
|
||||
/// Page blocks (content)
|
||||
pub blocks: Json<Vec<PageBlock>>,
|
||||
/// Post blocks (content)
|
||||
pub blocks: Json<Vec<PostBlock>>,
|
||||
|
||||
/// Times
|
||||
pub created_at: NaiveDateTime,
|
||||
|
@ -40,7 +40,7 @@ pub struct Page {
|
|||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum PageBlock {
|
||||
pub enum PostBlock {
|
||||
MarkupV1 {
|
||||
/// Markup format (markdown, html, plain)
|
||||
format: String,
|
||||
|
@ -73,50 +73,50 @@ pub struct ImageElement {
|
|||
pub caption: Option<String>,
|
||||
}
|
||||
|
||||
/// Data to create a new page
|
||||
/// Data to create a new post
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreatePageData {
|
||||
pub struct CreatePostData {
|
||||
pub slug: String,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub tags: Vec<String>,
|
||||
pub blocks: Vec<PageBlock>,
|
||||
pub blocks: Vec<PostBlock>,
|
||||
}
|
||||
|
||||
/// Data to update a new page
|
||||
/// Data to update a new post
|
||||
#[derive(Deserialize)]
|
||||
pub struct UpdatePageData {
|
||||
pub struct UpdatePostData {
|
||||
pub slug: Option<String>,
|
||||
pub title: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
pub blocks: Option<Vec<PageBlock>>,
|
||||
pub blocks: Option<Vec<PostBlock>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait PageRepository {
|
||||
/// Get a page from its slug
|
||||
async fn get_page_from_url(&self, site: &str, slug: &str) -> Result<Page, Error>;
|
||||
pub trait PostRepository {
|
||||
/// Get a post from its slug
|
||||
async fn get_post_from_url(&self, site: &str, slug: &str) -> Result<Post, Error>;
|
||||
|
||||
/// Create a new page
|
||||
async fn create_page(
|
||||
/// Create a new post
|
||||
async fn create_post(
|
||||
&self,
|
||||
owner: &Uuid,
|
||||
site: &Uuid,
|
||||
data: CreatePageData,
|
||||
data: CreatePostData,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Update a page
|
||||
async fn update_page(
|
||||
/// Update a post
|
||||
async fn update_post(
|
||||
&self,
|
||||
owner: &Uuid,
|
||||
site: &Uuid,
|
||||
slug: &str,
|
||||
data: UpdatePageData,
|
||||
data: UpdatePostData,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Delete a page
|
||||
async fn delete_page(
|
||||
/// Delete a post
|
||||
async fn delete_post(
|
||||
&self,
|
||||
owner: &Uuid,
|
||||
site: &Uuid,
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||
|
||||
use crate::state::AppState;
|
||||
|
||||
pub mod page;
|
||||
pub mod post;
|
||||
pub mod site;
|
||||
|
||||
pub struct Database {
|
||||
|
|
|
@ -4,34 +4,34 @@ use uuid::Uuid;
|
|||
|
||||
use crate::content::{
|
||||
self,
|
||||
page::{CreatePageData, Page, PageRepository, UpdatePageData},
|
||||
post::{CreatePostData, Post, PostRepository, UpdatePostData},
|
||||
Error,
|
||||
};
|
||||
|
||||
use super::Database;
|
||||
|
||||
#[async_trait]
|
||||
impl PageRepository for Database {
|
||||
async fn get_page_from_url(&self, site: &str, slug: &str) -> Result<Page, content::Error> {
|
||||
let page_query = sqlx::query_as(
|
||||
impl PostRepository for Database {
|
||||
async fn get_post_from_url(&self, site: &str, slug: &str) -> Result<Post, content::Error> {
|
||||
let post_query = sqlx::query_as(
|
||||
"SELECT pages.* FROM pages JOIN sites ON site = sites.id WHERE slug = $1 AND name = $2 AND pages.deleted_at IS NULL AND sites.deleted_at IS NULL")
|
||||
.bind(slug)
|
||||
.bind(site);
|
||||
let page: Page = page_query
|
||||
let post: Post = post_query
|
||||
.fetch_one(&self.pool)
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
sqlx::Error::RowNotFound => Error::NotFound,
|
||||
_ => e.into(),
|
||||
})?;
|
||||
Ok(page)
|
||||
Ok(post)
|
||||
}
|
||||
|
||||
async fn create_page(
|
||||
async fn create_post(
|
||||
&self,
|
||||
owner: &Uuid,
|
||||
site: &Uuid,
|
||||
data: CreatePageData,
|
||||
data: CreatePostData,
|
||||
) -> Result<(), Error> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO pages (author, site, slug, title, description, tags, blocks) VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
|
@ -51,12 +51,12 @@ impl PageRepository for Database {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_page(
|
||||
async fn update_post(
|
||||
&self,
|
||||
owner: &Uuid,
|
||||
site: &Uuid,
|
||||
page: &str,
|
||||
data: UpdatePageData,
|
||||
slug: &str,
|
||||
data: UpdatePostData,
|
||||
) -> Result<(), Error> {
|
||||
let result = sqlx::query!(
|
||||
"UPDATE pages SET title = COALESCE($1, title), description = COALESCE($2, description), tags = COALESCE($3, tags), blocks = COALESCE($4, blocks) WHERE author = $5 AND site = $6 AND slug = $7 AND deleted_at IS NULL",
|
||||
|
@ -66,7 +66,7 @@ impl PageRepository for Database {
|
|||
data.blocks.map(|x| json!(x)),
|
||||
owner,
|
||||
site,
|
||||
page
|
||||
slug
|
||||
).execute(&self.pool).await.map_err(|err| match err {
|
||||
sqlx::Error::Database(dberr) if dberr.constraint() == Some("pages_site_slug_unique") => {
|
||||
Error::IdentifierNotAvailable
|
||||
|
@ -81,11 +81,11 @@ impl PageRepository for Database {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_page(
|
||||
async fn delete_post(
|
||||
&self,
|
||||
owner: &Uuid,
|
||||
site: &Uuid,
|
||||
page: &str,
|
||||
slug: &str,
|
||||
soft_delete: bool,
|
||||
) -> Result<(), Error> {
|
||||
let result = if soft_delete {
|
||||
|
@ -93,14 +93,14 @@ impl PageRepository for Database {
|
|||
"UPDATE pages SET deleted_at = NOW() WHERE author = $1 AND site = $2 AND slug = $3 AND deleted_at IS NULL",
|
||||
owner,
|
||||
site,
|
||||
page
|
||||
slug
|
||||
).execute(&self.pool).await?
|
||||
} else {
|
||||
sqlx::query!(
|
||||
"DELETE FROM pages WHERE author = $1 AND site = $2 AND slug = $3",
|
||||
owner,
|
||||
site,
|
||||
page
|
||||
slug
|
||||
)
|
||||
.execute(&self.pool)
|
||||
.await?
|
|
@ -9,7 +9,7 @@ use std::sync::Arc;
|
|||
|
||||
use crate::{
|
||||
content::{
|
||||
page::{CreatePageData, PageRepository, UpdatePageData},
|
||||
post::{CreatePostData, PostRepository, UpdatePostData},
|
||||
site::SiteRepository,
|
||||
},
|
||||
database::Database,
|
||||
|
@ -17,42 +17,42 @@ use crate::{
|
|||
state::AppState,
|
||||
};
|
||||
|
||||
async fn get_page<Repo: PageRepository>(
|
||||
async fn get_post<Repo: PostRepository>(
|
||||
repository: Repo,
|
||||
Path((site, slug)): Path<(String, String)>,
|
||||
) -> Result<impl IntoResponse, ApiError<'static>> {
|
||||
Ok(Json(repository.get_page_from_url(&site, &slug).await?))
|
||||
Ok(Json(repository.get_post_from_url(&site, &slug).await?))
|
||||
}
|
||||
|
||||
async fn create_page<Repo: PageRepository + SiteRepository>(
|
||||
async fn create_post<Repo: PostRepository + SiteRepository>(
|
||||
repository: Repo,
|
||||
Path(site): Path<String>,
|
||||
RequireUser(user): RequireUser,
|
||||
JsonBody(page): JsonBody<CreatePageData>,
|
||||
JsonBody(data): JsonBody<CreatePostData>,
|
||||
) -> Result<impl IntoResponse, ApiError<'static>> {
|
||||
// Resolve site
|
||||
let site_id = repository.get_site_id(&site, &user.id).await?;
|
||||
|
||||
repository.create_page(&user.id, &site_id, page).await?;
|
||||
repository.create_post(&user.id, &site_id, data).await?;
|
||||
Ok(Json(json!({ "ok": true })))
|
||||
}
|
||||
|
||||
async fn update_page<Repo: PageRepository + SiteRepository>(
|
||||
async fn update_post<Repo: PostRepository + SiteRepository>(
|
||||
repository: Repo,
|
||||
Path((site, slug)): Path<(String, String)>,
|
||||
RequireUser(user): RequireUser,
|
||||
JsonBody(page): JsonBody<UpdatePageData>,
|
||||
JsonBody(data): JsonBody<UpdatePostData>,
|
||||
) -> Result<impl IntoResponse, ApiError<'static>> {
|
||||
// Resolve site
|
||||
let site_id = repository.get_site_id(&site, &user.id).await?;
|
||||
|
||||
repository
|
||||
.update_page(&user.id, &site_id, &slug, page)
|
||||
.update_post(&user.id, &site_id, &slug, data)
|
||||
.await?;
|
||||
Ok(Json(json!({ "ok": true })))
|
||||
}
|
||||
|
||||
async fn delete_page<Repo: PageRepository + SiteRepository>(
|
||||
async fn delete_post<Repo: PostRepository + SiteRepository>(
|
||||
repository: Repo,
|
||||
Path((site, slug)): Path<(String, String)>,
|
||||
RequireUser(user): RequireUser,
|
||||
|
@ -61,18 +61,18 @@ async fn delete_page<Repo: PageRepository + SiteRepository>(
|
|||
let site_id = repository.get_site_id(&site, &user.id).await?;
|
||||
|
||||
repository
|
||||
.delete_page(&user.id, &site_id, &slug, true)
|
||||
.delete_post(&user.id, &site_id, &slug, true)
|
||||
.await?;
|
||||
Ok(Json(json!({ "ok": true })))
|
||||
}
|
||||
|
||||
pub fn router() -> Router<Arc<AppState>> {
|
||||
Router::new()
|
||||
.route("/:site", post(create_page::<Database>))
|
||||
.route("/:site", post(create_post::<Database>))
|
||||
.route(
|
||||
"/:site/:slug",
|
||||
get(get_page::<Database>)
|
||||
.put(update_page::<Database>)
|
||||
.delete(delete_page::<Database>),
|
||||
get(get_post::<Database>)
|
||||
.put(update_post::<Database>)
|
||||
.delete(delete_post::<Database>),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue