page -> post
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Hamcha 2023-07-07 01:38:56 +02:00
parent 3d50d2b4b0
commit e626ef87dc
Signed by: hamcha
GPG Key ID: 1669C533B8CF6D89
5 changed files with 59 additions and 59 deletions

View File

@ -1,4 +1,4 @@
pub mod page;
pub mod post;
pub mod site;
#[derive(Debug, thiserror::Error)]

View File

@ -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,

View File

@ -3,7 +3,7 @@ use std::sync::Arc;
use crate::state::AppState;
pub mod page;
pub mod post;
pub mod site;
pub struct Database {

View File

@ -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?

View File

@ -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>),
)
}