work
This commit is contained in:
@@ -27,6 +27,7 @@ pub struct Note {
|
||||
pub content: String,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
pub owner_map: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, FromRow)]
|
||||
@@ -34,6 +35,8 @@ pub struct Revision {
|
||||
pub id: i64,
|
||||
pub content: String,
|
||||
pub created_at: String,
|
||||
pub author: Option<String>,
|
||||
pub owner_map: String,
|
||||
}
|
||||
|
||||
pub async fn find_workspace(pool: &SqlitePool, slug: &str) -> Result<Option<Workspace>, sqlx::Error> {
|
||||
@@ -86,7 +89,7 @@ pub fn verify_workspace_password(workspace: &Workspace, password: Option<&str>)
|
||||
|
||||
pub async fn list_notes(pool: &SqlitePool, workspace_id: i64) -> Result<Vec<Note>, sqlx::Error> {
|
||||
sqlx::query_as::<_, Note>(
|
||||
"SELECT id, workspace_id, slug, title, content, created_at, updated_at FROM notes WHERE workspace_id = ? ORDER BY updated_at DESC, id DESC",
|
||||
"SELECT id, workspace_id, slug, title, content, created_at, updated_at, owner_map FROM notes WHERE workspace_id = ? ORDER BY updated_at DESC, id DESC",
|
||||
)
|
||||
.bind(workspace_id)
|
||||
.fetch_all(pool)
|
||||
@@ -99,7 +102,7 @@ pub async fn find_note(
|
||||
slug: &str,
|
||||
) -> Result<Option<Note>, sqlx::Error> {
|
||||
sqlx::query_as::<_, Note>(
|
||||
"SELECT id, workspace_id, slug, title, content, created_at, updated_at FROM notes WHERE workspace_id = ? AND slug = ?",
|
||||
"SELECT id, workspace_id, slug, title, content, created_at, updated_at, owner_map FROM notes WHERE workspace_id = ? AND slug = ?",
|
||||
)
|
||||
.bind(workspace_id)
|
||||
.bind(slug)
|
||||
@@ -123,7 +126,7 @@ pub async fn create_note(
|
||||
.await?;
|
||||
|
||||
sqlx::query_as::<_, Note>(
|
||||
"SELECT id, workspace_id, slug, title, content, created_at, updated_at FROM notes WHERE id = ?",
|
||||
"SELECT id, workspace_id, slug, title, content, created_at, updated_at, owner_map FROM notes WHERE id = ?",
|
||||
)
|
||||
.bind(result.last_insert_rowid())
|
||||
.fetch_one(pool)
|
||||
@@ -135,10 +138,13 @@ pub async fn save_revision(
|
||||
note_id: i64,
|
||||
workspace_id: i64,
|
||||
content: &str,
|
||||
author: Option<&str>,
|
||||
owner_map: &str,
|
||||
) -> Result<(i64, String), sqlx::Error> {
|
||||
let mut tx = pool.begin().await?;
|
||||
sqlx::query("UPDATE notes SET content = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
|
||||
sqlx::query("UPDATE notes SET content = ?, owner_map = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
|
||||
.bind(content)
|
||||
.bind(owner_map)
|
||||
.bind(note_id)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
@@ -146,9 +152,11 @@ pub async fn save_revision(
|
||||
.bind(workspace_id)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
let result = sqlx::query("INSERT INTO note_revisions (note_id, content) VALUES (?, ?)")
|
||||
let result = sqlx::query("INSERT INTO note_revisions (note_id, content, author, owner_map) VALUES (?, ?, ?, ?)")
|
||||
.bind(note_id)
|
||||
.bind(content)
|
||||
.bind(author)
|
||||
.bind(owner_map)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
let updated_at: String = sqlx::query_scalar("SELECT updated_at FROM notes WHERE id = ?")
|
||||
@@ -161,7 +169,7 @@ pub async fn save_revision(
|
||||
|
||||
pub async fn list_revisions(pool: &SqlitePool, note_id: i64) -> Result<Vec<Revision>, sqlx::Error> {
|
||||
sqlx::query_as::<_, Revision>(
|
||||
"SELECT id, content, created_at FROM note_revisions WHERE note_id = ? ORDER BY id DESC LIMIT 100",
|
||||
"SELECT id, content, created_at, author, owner_map FROM note_revisions WHERE note_id = ? ORDER BY id DESC LIMIT 100",
|
||||
)
|
||||
.bind(note_id)
|
||||
.fetch_all(pool)
|
||||
@@ -202,11 +210,12 @@ pub struct Pad {
|
||||
pub password_hash: Option<String>,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
pub owner_map: String,
|
||||
}
|
||||
|
||||
pub async fn find_pad(pool: &SqlitePool, slug: &str) -> Result<Option<Pad>, sqlx::Error> {
|
||||
sqlx::query_as::<_, Pad>(
|
||||
"SELECT id, slug, title, content, password_hash, created_at, updated_at FROM pads WHERE slug = ?",
|
||||
"SELECT id, slug, title, content, password_hash, created_at, updated_at, owner_map FROM pads WHERE slug = ?",
|
||||
)
|
||||
.bind(slug)
|
||||
.fetch_optional(pool)
|
||||
@@ -230,7 +239,7 @@ pub async fn create_pad(
|
||||
.await?;
|
||||
|
||||
sqlx::query_as::<_, Pad>(
|
||||
"SELECT id, slug, title, content, password_hash, created_at, updated_at FROM pads WHERE id = ?",
|
||||
"SELECT id, slug, title, content, password_hash, created_at, updated_at, owner_map FROM pads WHERE id = ?",
|
||||
)
|
||||
.bind(result.last_insert_rowid())
|
||||
.fetch_one(pool)
|
||||
@@ -256,16 +265,21 @@ pub async fn save_pad_revision(
|
||||
pool: &SqlitePool,
|
||||
pad_id: i64,
|
||||
content: &str,
|
||||
author: Option<&str>,
|
||||
owner_map: &str,
|
||||
) -> Result<(i64, String), sqlx::Error> {
|
||||
let mut tx = pool.begin().await?;
|
||||
sqlx::query("UPDATE pads SET content = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
|
||||
sqlx::query("UPDATE pads SET content = ?, owner_map = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
|
||||
.bind(content)
|
||||
.bind(owner_map)
|
||||
.bind(pad_id)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
let result = sqlx::query("INSERT INTO revisions (pad_id, content) VALUES (?, ?)")
|
||||
let result = sqlx::query("INSERT INTO revisions (pad_id, content, author, owner_map) VALUES (?, ?, ?, ?)")
|
||||
.bind(pad_id)
|
||||
.bind(content)
|
||||
.bind(author)
|
||||
.bind(owner_map)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
let updated_at: String = sqlx::query_scalar("SELECT updated_at FROM pads WHERE id = ?")
|
||||
@@ -281,9 +295,135 @@ pub async fn list_pad_revisions(
|
||||
pad_id: i64,
|
||||
) -> Result<Vec<Revision>, sqlx::Error> {
|
||||
sqlx::query_as::<_, Revision>(
|
||||
"SELECT id, content, created_at FROM revisions WHERE pad_id = ? ORDER BY id DESC LIMIT 100",
|
||||
"SELECT id, content, created_at, author, owner_map FROM revisions WHERE pad_id = ? ORDER BY id DESC LIMIT 100",
|
||||
)
|
||||
.bind(pad_id)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, FromRow)]
|
||||
pub struct PublishedPage {
|
||||
pub token: String,
|
||||
pub title: String,
|
||||
pub content: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
pub async fn publish_pad(pool: &SqlitePool, pad_id: i64) -> Result<String, sqlx::Error> {
|
||||
if let Some(token) = sqlx::query_scalar::<_, String>("SELECT token FROM published_pages WHERE pad_id = ?")
|
||||
.bind(pad_id)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
{
|
||||
return Ok(token);
|
||||
}
|
||||
let token = random_suffix(18);
|
||||
sqlx::query("INSERT INTO published_pages (token, pad_id) VALUES (?, ?)")
|
||||
.bind(&token)
|
||||
.bind(pad_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(token)
|
||||
}
|
||||
|
||||
pub async fn publish_note(pool: &SqlitePool, note_id: i64) -> Result<String, sqlx::Error> {
|
||||
if let Some(token) = sqlx::query_scalar::<_, String>("SELECT token FROM published_pages WHERE note_id = ?")
|
||||
.bind(note_id)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
{
|
||||
return Ok(token);
|
||||
}
|
||||
let token = random_suffix(18);
|
||||
sqlx::query("INSERT INTO published_pages (token, note_id) VALUES (?, ?)")
|
||||
.bind(&token)
|
||||
.bind(note_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(token)
|
||||
}
|
||||
|
||||
pub async fn find_published_page(pool: &SqlitePool, token: &str) -> Result<Option<PublishedPage>, sqlx::Error> {
|
||||
sqlx::query_as::<_, PublishedPage>(
|
||||
"SELECT pp.token, COALESCE(p.title, n.title) AS title, COALESCE(p.content, n.content) AS content, COALESCE(p.updated_at, n.updated_at) AS updated_at FROM published_pages pp LEFT JOIN pads p ON p.id = pp.pad_id LEFT JOIN notes n ON n.id = pp.note_id WHERE pp.token = ?",
|
||||
)
|
||||
.bind(token)
|
||||
.fetch_optional(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn pad_file_token(pool: &SqlitePool, pad_id: i64) -> Result<String, sqlx::Error> {
|
||||
if let Some(token) = sqlx::query_scalar::<_, Option<String>>("SELECT file_token FROM pads WHERE id = ?")
|
||||
.bind(pad_id)
|
||||
.fetch_one(pool)
|
||||
.await?
|
||||
{
|
||||
return Ok(token);
|
||||
}
|
||||
|
||||
let token = format!("p_{}", random_suffix(24));
|
||||
sqlx::query("UPDATE pads SET file_token = ? WHERE id = ? AND file_token IS NULL")
|
||||
.bind(&token)
|
||||
.bind(pad_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
sqlx::query_scalar::<_, String>("SELECT file_token FROM pads WHERE id = ?")
|
||||
.bind(pad_id)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn note_file_token(pool: &SqlitePool, note_id: i64) -> Result<String, sqlx::Error> {
|
||||
if let Some(token) = sqlx::query_scalar::<_, Option<String>>("SELECT file_token FROM notes WHERE id = ?")
|
||||
.bind(note_id)
|
||||
.fetch_one(pool)
|
||||
.await?
|
||||
{
|
||||
return Ok(token);
|
||||
}
|
||||
|
||||
let token = format!("n_{}", random_suffix(24));
|
||||
sqlx::query("UPDATE notes SET file_token = ? WHERE id = ? AND file_token IS NULL")
|
||||
.bind(&token)
|
||||
.bind(note_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
sqlx::query_scalar::<_, String>("SELECT file_token FROM notes WHERE id = ?")
|
||||
.bind(note_id)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FileOwnerKind {
|
||||
Pad,
|
||||
Note,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct FileOwner {
|
||||
pub kind: FileOwnerKind,
|
||||
pub id: i64,
|
||||
}
|
||||
|
||||
pub async fn find_file_owner(pool: &SqlitePool, token: &str) -> Result<Option<FileOwner>, sqlx::Error> {
|
||||
if let Some(id) = sqlx::query_scalar::<_, i64>("SELECT id FROM pads WHERE file_token = ?")
|
||||
.bind(token)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(FileOwner { kind: FileOwnerKind::Pad, id }));
|
||||
}
|
||||
if let Some(id) = sqlx::query_scalar::<_, i64>("SELECT id FROM notes WHERE file_token = ?")
|
||||
.bind(token)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(FileOwner { kind: FileOwnerKind::Note, id }));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user