Compare commits
No commits in common. "0d49a71459fa387f52b8ecc7f62975f5e263e980" and "548348d05e480a938ce3cd55cd3271cd5ca02e85" have entirely different histories.
0d49a71459
...
548348d05e
|
|
@ -2,7 +2,9 @@
|
||||||
drop trigger insert_enforce_version_titles on versions;
|
drop trigger insert_enforce_version_titles on versions;
|
||||||
drop trigger update_enforce_version_titles on versions;
|
drop trigger update_enforce_version_titles on versions;
|
||||||
drop function enforce_version_titles;
|
drop function enforce_version_titles;
|
||||||
|
drop index sections_shortname_index;
|
||||||
|
|
||||||
drop table versions cascade;
|
drop table versions cascade;
|
||||||
|
drop table tags cascade;
|
||||||
drop table posts cascade;
|
drop table posts cascade;
|
||||||
drop table sections cascade;
|
drop table sections cascade;
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,17 @@ create table sections (
|
||||||
-- Name to use when routing (this just makes for prettier URLs)
|
-- Name to use when routing (this just makes for prettier URLs)
|
||||||
shortname varchar(32) UNIQUE NOT NULL,
|
shortname varchar(32) UNIQUE NOT NULL,
|
||||||
-- Optional description of the section
|
-- Optional description of the section
|
||||||
description text NOT NULL DEFAULT '',
|
description text,
|
||||||
-- Wether to show the section in the default list on the homepage
|
-- Wether to show the section in the default list on the homepage
|
||||||
is_default boolean NOT NULL DEFAULT false,
|
is_default boolean NOT NULL DEFAULT false,
|
||||||
-- Wether the posts should contain titles or not
|
-- Wether the posts should contain titles or not
|
||||||
has_titles boolean NOT NULL DEFAULT true,
|
has_titles boolean NOT NULL DEFAULT true,
|
||||||
-- Wether posts in this section should be shown publicly
|
-- Wether posts in this section should be shown publicly
|
||||||
is_private boolean NOT NULL DEFAULT false,
|
is_private boolean NOT NULL DEFAULT false
|
||||||
-- Wether the section is archived
|
|
||||||
is_archived boolean NOT NULL DEFAULT false
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
create index sections_shortname_index on sections(shortname);
|
||||||
|
|
||||||
create table posts (
|
create table posts (
|
||||||
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
|
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
|
||||||
|
|
||||||
|
|
@ -51,6 +51,13 @@ create table versions (
|
||||||
CONSTRAINT no_null_published_date CHECK (is_draft OR publish_date IS NOT NULL)
|
CONSTRAINT no_null_published_date CHECK (is_draft OR publish_date IS NOT NULL)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
create table tags (
|
||||||
|
post_id uuid NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
|
||||||
|
value varchar(64) NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (post_id, value)
|
||||||
|
);
|
||||||
|
|
||||||
create function enforce_version_titles() returns trigger as $$
|
create function enforce_version_titles() returns trigger as $$
|
||||||
begin
|
begin
|
||||||
-- Draft versions shouldn't be evaluated.
|
-- Draft versions shouldn't be evaluated.
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,9 @@
|
||||||
|
|
||||||
pub mod posts;
|
pub mod posts;
|
||||||
pub mod sections;
|
pub mod sections;
|
||||||
pub mod versions;
|
|
||||||
|
|
||||||
pub use posts::{NewPost, PatchPost, Post};
|
pub use posts::{NewPost, PatchPost, Post};
|
||||||
pub use sections::{NewSection, PatchSection, Section};
|
pub use sections::{NewSection, PatchSection, Section};
|
||||||
pub use versions::{NewVersion, PatchVersion, Version};
|
|
||||||
|
|
||||||
pub const MAX_POSTS: u32 = 64;
|
pub const MAX_POSTS: u32 = 64;
|
||||||
pub const MAX_SECTIONS: u32 = 64;
|
pub const MAX_SECTIONS: u32 = 64;
|
||||||
pub const MAX_VERSIONS: u32 = 16;
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use chrono::NaiveDate;
|
||||||
use diesel::{insert_into, prelude::*, Insertable, PgConnection, Queryable};
|
use diesel::{insert_into, prelude::*, Insertable, PgConnection, Queryable};
|
||||||
use rb::errors::{RbError, RbOption, RbResult};
|
use rb::errors::{RbError, RbOption, RbResult};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -11,8 +12,9 @@ pub struct Post
|
||||||
{
|
{
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub section_id: Uuid,
|
pub section_id: Uuid,
|
||||||
pub is_private: bool,
|
pub title: Option<String>,
|
||||||
pub is_archived: bool,
|
pub publish_date: NaiveDate,
|
||||||
|
pub content: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A new post to be added to the database.
|
/// A new post to be added to the database.
|
||||||
|
|
@ -22,8 +24,9 @@ pub struct Post
|
||||||
pub struct NewPost
|
pub struct NewPost
|
||||||
{
|
{
|
||||||
pub section_id: Uuid,
|
pub section_id: Uuid,
|
||||||
pub is_private: Option<bool>,
|
pub title: Option<String>,
|
||||||
pub is_archived: Option<bool>,
|
pub publish_date: NaiveDate,
|
||||||
|
pub content: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A patch to be applied to a row in the database.
|
/// A patch to be applied to a row in the database.
|
||||||
|
|
@ -32,8 +35,9 @@ pub struct NewPost
|
||||||
pub struct PatchPost
|
pub struct PatchPost
|
||||||
{
|
{
|
||||||
pub section_id: Option<Uuid>,
|
pub section_id: Option<Uuid>,
|
||||||
pub is_private: Option<bool>,
|
pub title: Option<String>,
|
||||||
pub is_archived: Option<bool>,
|
pub publish_date: Option<NaiveDate>,
|
||||||
|
pub content: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a list of posts, specified by the offset & a limit. The maximum for `limit_` is determined
|
/// Get a list of posts, specified by the offset & a limit. The maximum for `limit_` is determined
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,9 @@ pub struct Section
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub shortname: String,
|
pub shortname: String,
|
||||||
pub description: String,
|
pub description: Option<String>,
|
||||||
pub is_default: bool,
|
pub is_default: bool,
|
||||||
pub has_titles: bool,
|
pub has_titles: bool,
|
||||||
pub is_private: bool,
|
|
||||||
pub is_archived: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A new section to add. Any `Option` values will get replaced by their default value in the
|
/// A new section to add. Any `Option` values will get replaced by their default value in the
|
||||||
|
|
@ -31,8 +29,6 @@ pub struct NewSection
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub is_default: Option<bool>,
|
pub is_default: Option<bool>,
|
||||||
pub has_titles: Option<bool>,
|
pub has_titles: Option<bool>,
|
||||||
pub is_private: Option<bool>,
|
|
||||||
pub is_archived: Option<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A patch to apply to a section.
|
/// A patch to apply to a section.
|
||||||
|
|
@ -46,8 +42,6 @@ pub struct PatchSection
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
is_default: Option<bool>,
|
is_default: Option<bool>,
|
||||||
has_titles: Option<bool>,
|
has_titles: Option<bool>,
|
||||||
pub is_private: Option<bool>,
|
|
||||||
pub is_archived: Option<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an amount of sections from the database, given an offset & limit. The maximum value for
|
/// Get an amount of sections from the database, given an offset & limit. The maximum value for
|
||||||
|
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
use chrono::NaiveDate;
|
|
||||||
use diesel::{insert_into, prelude::*, Insertable, PgConnection, Queryable};
|
|
||||||
use rb::errors::{RbError, RbOption, RbResult};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::schema::{versions, versions::dsl::*};
|
|
||||||
|
|
||||||
/// A version inside the database.
|
|
||||||
#[derive(Queryable, Serialize)]
|
|
||||||
pub struct Version
|
|
||||||
{
|
|
||||||
pub id: Uuid,
|
|
||||||
pub post_id: Uuid,
|
|
||||||
pub title: Option<String>,
|
|
||||||
pub publish_date: Option<NaiveDate>,
|
|
||||||
pub content: String,
|
|
||||||
pub is_draft: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Insertable)]
|
|
||||||
#[table_name = "versions"]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct NewVersion
|
|
||||||
{
|
|
||||||
pub post_id: Uuid,
|
|
||||||
pub title: Option<String>,
|
|
||||||
pub publish_date: Option<NaiveDate>,
|
|
||||||
pub content: Option<String>,
|
|
||||||
pub is_draft: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, AsChangeset)]
|
|
||||||
#[table_name = "versions"]
|
|
||||||
pub struct PatchVersion
|
|
||||||
{
|
|
||||||
pub id: Uuid,
|
|
||||||
pub post_id: Option<Uuid>,
|
|
||||||
pub title: Option<String>,
|
|
||||||
pub publish_date: Option<NaiveDate>,
|
|
||||||
pub content: Option<String>,
|
|
||||||
pub is_draft: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(conn: &PgConnection, offset_: u32, limit_: u32) -> RbResult<Vec<Version>>
|
|
||||||
{
|
|
||||||
Ok(versions
|
|
||||||
.offset(offset_.into())
|
|
||||||
.limit(std::cmp::min(limit_, super::MAX_VERSIONS).into())
|
|
||||||
.load(conn)
|
|
||||||
.map_err(|_| RbError::DbError("Couldn't query versions."))?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_for_post(
|
|
||||||
conn: &PgConnection,
|
|
||||||
post_id_: &Uuid,
|
|
||||||
offset_: u32,
|
|
||||||
limit_: u32,
|
|
||||||
) -> RbResult<Vec<Version>>
|
|
||||||
{
|
|
||||||
Ok(versions
|
|
||||||
.offset(offset_.into())
|
|
||||||
.filter(post_id.eq(post_id_))
|
|
||||||
.limit(std::cmp::min(limit_, super::MAX_VERSIONS).into())
|
|
||||||
.load(conn)
|
|
||||||
.map_err(|_| RbError::DbError("Couldn't query versions."))?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find(conn: &PgConnection, id_: &Uuid) -> RbOption<Version>
|
|
||||||
{
|
|
||||||
match versions.find(id_).first(conn) {
|
|
||||||
Ok(val) => Ok(Some(val)),
|
|
||||||
Err(diesel::NotFound) => Ok(None),
|
|
||||||
_ => Err(RbError::DbError("Couldn't find version.")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create(conn: &PgConnection, new: &NewVersion) -> RbResult<Version>
|
|
||||||
{
|
|
||||||
Ok(insert_into(versions)
|
|
||||||
.values(new)
|
|
||||||
.get_result(conn)
|
|
||||||
.map_err(|_| RbError::DbError("Couldn't insert version."))?)
|
|
||||||
|
|
||||||
// TODO check for conflict?
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(conn: &PgConnection, id_: &Uuid, patch: &PatchVersion) -> RbResult<Version>
|
|
||||||
{
|
|
||||||
Ok(diesel::update(versions.filter(id.eq(id_)))
|
|
||||||
.set(patch)
|
|
||||||
.get_result(conn)
|
|
||||||
.map_err(|_| RbError::DbError("Couldn't update version."))?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete(conn: &PgConnection, id_: &Uuid) -> RbResult<()>
|
|
||||||
{
|
|
||||||
diesel::delete(versions.filter(id.eq(id_)))
|
|
||||||
.execute(conn)
|
|
||||||
.map_err(|_| RbError::DbError("Couldn't delete version."))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
11
src/main.rs
11
src/main.rs
|
|
@ -95,17 +95,6 @@ fn rocket() -> _
|
||||||
v1::posts::patch,
|
v1::posts::patch,
|
||||||
v1::posts::delete
|
v1::posts::delete
|
||||||
],
|
],
|
||||||
)
|
|
||||||
.mount(
|
|
||||||
"/v1/versions",
|
|
||||||
routes![
|
|
||||||
v1::versions::get,
|
|
||||||
v1::versions::get_for_post,
|
|
||||||
v1::versions::create,
|
|
||||||
v1::versions::find,
|
|
||||||
v1::versions::patch,
|
|
||||||
v1::versions::delete
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let new_figment = rocket.figment();
|
let new_figment = rocket.figment();
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,17 @@ table! {
|
||||||
id -> Uuid,
|
id -> Uuid,
|
||||||
title -> Varchar,
|
title -> Varchar,
|
||||||
shortname -> Varchar,
|
shortname -> Varchar,
|
||||||
description -> Text,
|
description -> Nullable<Text>,
|
||||||
is_default -> Bool,
|
is_default -> Bool,
|
||||||
has_titles -> Bool,
|
has_titles -> Bool,
|
||||||
is_private -> Bool,
|
is_private -> Bool,
|
||||||
is_archived -> Bool,
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table! {
|
||||||
|
tags (post_id, value) {
|
||||||
|
post_id -> Uuid,
|
||||||
|
value -> Varchar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,10 +38,12 @@ table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
joinable!(posts -> sections (section_id));
|
joinable!(posts -> sections (section_id));
|
||||||
|
joinable!(tags -> posts (post_id));
|
||||||
joinable!(versions -> posts (post_id));
|
joinable!(versions -> posts (post_id));
|
||||||
|
|
||||||
allow_tables_to_appear_in_same_query!(
|
allow_tables_to_appear_in_same_query!(
|
||||||
posts,
|
posts,
|
||||||
sections,
|
sections,
|
||||||
|
tags,
|
||||||
versions,
|
versions,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,2 @@
|
||||||
pub mod posts;
|
pub mod posts;
|
||||||
pub mod sections;
|
pub mod sections;
|
||||||
pub mod versions;
|
|
||||||
|
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
use rb::{
|
|
||||||
errors::{RbOption, RbResult},
|
|
||||||
guards::Admin,
|
|
||||||
};
|
|
||||||
use rb_blog::db;
|
|
||||||
use rocket::serde::json::Json;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::RbDbConn;
|
|
||||||
|
|
||||||
#[get("/?<offset>&<limit>", rank = 1)]
|
|
||||||
pub async fn get(conn: RbDbConn, offset: u32, limit: u32) -> RbResult<Json<Vec<db::Version>>>
|
|
||||||
{
|
|
||||||
Ok(Json(
|
|
||||||
conn.run(move |c| db::versions::get(c, offset, limit))
|
|
||||||
.await?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/?<post_id>&<offset>&<limit>", rank = 0)]
|
|
||||||
pub async fn get_for_post(
|
|
||||||
conn: RbDbConn,
|
|
||||||
post_id: Uuid,
|
|
||||||
offset: u32,
|
|
||||||
limit: u32,
|
|
||||||
) -> RbResult<Json<Vec<db::Version>>>
|
|
||||||
{
|
|
||||||
Ok(Json(
|
|
||||||
conn.run(move |c| db::versions::get_for_post(c, &post_id, offset, limit))
|
|
||||||
.await?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("/", data = "<new>")]
|
|
||||||
pub async fn create(
|
|
||||||
_admin: Admin,
|
|
||||||
conn: RbDbConn,
|
|
||||||
new: Json<db::NewVersion>,
|
|
||||||
) -> RbResult<Json<db::Version>>
|
|
||||||
{
|
|
||||||
Ok(Json(
|
|
||||||
conn.run(move |c| db::versions::create(c, &new.into_inner()))
|
|
||||||
.await?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/<id>")]
|
|
||||||
pub async fn find(conn: RbDbConn, id: uuid::Uuid) -> RbOption<Json<db::Version>>
|
|
||||||
{
|
|
||||||
Ok(conn
|
|
||||||
.run(move |c| db::versions::find(c, &id))
|
|
||||||
.await?
|
|
||||||
.and_then(|p| Some(Json(p))))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[patch("/<id>", data = "<patch>")]
|
|
||||||
pub async fn patch(
|
|
||||||
_admin: Admin,
|
|
||||||
conn: RbDbConn,
|
|
||||||
id: uuid::Uuid,
|
|
||||||
patch: Json<db::PatchVersion>,
|
|
||||||
) -> RbResult<Json<db::Version>>
|
|
||||||
{
|
|
||||||
Ok(Json(
|
|
||||||
conn.run(move |c| db::versions::update(c, &id, &patch.into_inner()))
|
|
||||||
.await?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[delete("/<id>")]
|
|
||||||
pub async fn delete(_admin: Admin, conn: RbDbConn, id: uuid::Uuid) -> RbResult<()>
|
|
||||||
{
|
|
||||||
Ok(conn.run(move |c| db::versions::delete(c, &id)).await?)
|
|
||||||
}
|
|
||||||
Reference in New Issue