Skip to content

Commit

Permalink
Allow setting paste title
Browse files Browse the repository at this point in the history
  • Loading branch information
FliegendeWurst committed Jan 10, 2025
1 parent 353182b commit 5fe0ef6
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 18 deletions.
24 changes: 19 additions & 5 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static MIGRATIONS: LazyLock<Migrations> = LazyLock::new(|| {
),
M::up(include_str!("migrations/0005-drop-text-column.sql")),
M::up(include_str!("migrations/0006-add-nonce-column.sql")),
M::up(include_str!("migrations/0007-add-title-column.sql")),
])
});

Expand Down Expand Up @@ -86,6 +87,8 @@ pub mod write {
pub uid: Option<i64>,
/// Optional password to encrypt the entry
pub password: Option<String>,
/// Title
pub title: Option<String>,
}

/// A compressed entry to be inserted.
Expand Down Expand Up @@ -163,6 +166,8 @@ pub mod read {
pub uid: Option<i64>,
/// Nonce for this entry
pub nonce: Option<Vec<u8>>,
/// Title
pub title: Option<String>,
}

/// Potentially decrypted but still compressed entry
Expand All @@ -173,6 +178,8 @@ pub mod read {
must_be_deleted: bool,
/// User identifier that inserted the entry
uid: Option<i64>,
/// Title
title: Option<String>,
}

/// An entry read from the database.
Expand All @@ -183,6 +190,8 @@ pub mod read {
pub must_be_deleted: bool,
/// User identifier that inserted the entry
pub uid: Option<i64>,
/// Title
pub title: Option<String>,
}

impl DatabaseEntry {
Expand All @@ -196,6 +205,7 @@ pub mod read {
data: self.data,
must_be_deleted: self.must_be_deleted,
uid: self.uid,
title: self.title,
}),
(Some(nonce), Some(password)) => {
let encrypted = Encrypted::new(self.data, nonce);
Expand All @@ -204,6 +214,7 @@ pub mod read {
data: decrypted,
must_be_deleted: self.must_be_deleted,
uid: self.uid,
title: self.title,
})
}
}
Expand All @@ -225,6 +236,7 @@ pub mod read {
text,
uid: self.uid,
must_be_deleted: self.must_be_deleted,
title: self.title,
})
}
}
Expand Down Expand Up @@ -255,18 +267,19 @@ impl Database {

spawn_blocking(move || match entry.expires {
None => conn.lock().execute(
"INSERT INTO entries (id, uid, data, burn_after_reading, nonce) VALUES (?1, ?2, ?3, ?4, ?5)",
params![id, entry.uid, data, entry.burn_after_reading, nonce],
"INSERT INTO entries (id, uid, data, burn_after_reading, nonce, title) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
params![id, entry.uid, data, entry.burn_after_reading, nonce, entry.title],
),
Some(expires) => conn.lock().execute(
"INSERT INTO entries (id, uid, data, burn_after_reading, nonce, expires) VALUES (?1, ?2, ?3, ?4, ?5, datetime('now', ?6))",
"INSERT INTO entries (id, uid, data, burn_after_reading, nonce, expires, title) VALUES (?1, ?2, ?3, ?4, ?5, datetime('now', ?6), ?7)",
params![
id,
entry.uid,
data,
entry.burn_after_reading,
nonce,
format!("{expires} seconds")
format!("{expires} seconds"),
entry.title,
],
),
})
Expand All @@ -282,7 +295,7 @@ impl Database {

let entry = spawn_blocking(move || {
conn.lock().query_row(
"SELECT data, burn_after_reading, uid, nonce, expires < datetime('now') FROM entries WHERE id=?1",
"SELECT data, burn_after_reading, uid, nonce, expires < datetime('now'), title FROM entries WHERE id=?1",
params![id_as_u32],
|row| {
Ok(read::DatabaseEntry {
Expand All @@ -291,6 +304,7 @@ impl Database {
uid: row.get(2)?,
nonce: row.get(3)?,
expired: row.get::<_, Option<bool>>(4)?.unwrap_or(false),
title: row.get::<_, Option<String>>(5)?,
})
},
)
Expand Down
1 change: 1 addition & 0 deletions src/migrations/0007-add-title-column.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE entries ADD COLUMN title TEXT;
8 changes: 6 additions & 2 deletions src/pages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,12 @@ pub struct Paste<'a> {
ext: String,
can_delete: bool,
html: String,
title: String,
}

impl Paste<'_> {
/// Construct new paste view from cache `key` and paste `html`.
pub fn new(key: CacheKey, html: Html, can_delete: bool) -> Self {
pub fn new(key: CacheKey, html: Html, can_delete: bool, title: String) -> Self {
let html = html.into_inner();

Self {
Expand All @@ -148,6 +149,7 @@ impl Paste<'_> {
ext: key.ext,
can_delete,
html,
title,
}
}
}
Expand Down Expand Up @@ -202,18 +204,20 @@ pub struct Qr<'a> {
ext: String,
can_delete: bool,
code: qrcodegen::QrCode,
title: String,
}

impl Qr<'_> {
/// Construct new QR code view from `code`.
pub fn new(code: qrcodegen::QrCode, key: CacheKey) -> Self {
pub fn new(code: qrcodegen::QrCode, key: CacheKey, title: String) -> Self {
Self {
meta: &env::METADATA,
base_path: &env::BASE_PATH,
id: key.id(),
ext: key.ext,
code,
can_delete: false,
title,
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/routes/form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ pub struct Entry {
pub extension: Option<String>,
pub expires: String,
pub password: String,
pub title: String,
}

impl From<Entry> for write::Entry {
fn from(entry: Entry) -> Self {
let burn_after_reading = Some(entry.expires == "burn");
let password = (!entry.password.is_empty()).then_some(entry.password);
let title = (!entry.title.is_empty()).then_some(entry.title);

let expires = match entry.expires.parse::<NonZeroU32>() {
Err(_) => None,
Expand All @@ -35,6 +37,7 @@ impl From<Entry> for write::Entry {
burn_after_reading,
uid: None,
password,
title,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/routes/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct Entry {
pub expires: Option<NonZeroU32>,
pub burn_after_reading: Option<bool>,
pub password: Option<String>,
pub title: Option<String>,
}

#[derive(Deserialize, Serialize)]
Expand All @@ -33,6 +34,7 @@ impl From<Entry> for write::Entry {
burn_after_reading: entry.burn_after_reading,
uid: None,
password: entry.password,
title: entry.title,
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/routes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ mod tests {
extension: Some("rs".to_string()),
expires: "0".to_string(),
password: "".to_string(),
title: "".to_string(),
};

let res = client.post(BASE_PATH.path()).form(&data).send().await?;
Expand Down Expand Up @@ -115,6 +116,7 @@ mod tests {
extension: None,
expires: "burn".to_string(),
password: "".to_string(),
title: "".to_string(),
};

let res = client.post(BASE_PATH.path()).form(&data).send().await?;
Expand Down Expand Up @@ -154,6 +156,7 @@ mod tests {
extension: None,
expires: "burn".to_string(),
password: password.to_string(),
title: "".to_string(),
};

let res = client.post(BASE_PATH.path()).form(&data).send().await?;
Expand Down Expand Up @@ -271,6 +274,7 @@ mod tests {
extension: None,
expires: "0".to_string(),
password: "".to_string(),
title: "".to_string(),
};

let res = client.post(BASE_PATH.path()).form(&data).send().await?;
Expand Down Expand Up @@ -311,6 +315,7 @@ mod tests {
extension: None,
expires: "0".to_string(),
password: "".to_string(),
title: "".to_string(),
};

let res = client.post(BASE_PATH.path()).form(&data).send().await?;
Expand Down
19 changes: 15 additions & 4 deletions src/routes/paste.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,14 @@ async fn get_qr(
state: AppState,
key: CacheKey,
headers: HeaderMap,
title: String,
) -> Result<pages::Qr<'static>, pages::ErrorResponse<'static>> {
let id = key.id();
let qr_code = tokio::task::spawn_blocking(move || qr_code_from(state, &headers, &id))
.await
.map_err(Error::from)??;

Ok(pages::Qr::new(qr_code, key))
Ok(pages::Qr::new(qr_code, key, title))
}

fn get_download(
Expand Down Expand Up @@ -116,21 +117,25 @@ async fn get_html(

if let Some(html) = state.cache.get(&key) {
tracing::trace!(?key, "found cached item");
return Ok(pages::Paste::new(key, html, can_delete).into_response());
return Ok(
pages::Paste::new(key, html, can_delete, entry.title.unwrap_or_default())
.into_response(),
);
}

// TODO: turn this upside-down, i.e. cache it but only return a cached version if we were able
// to decrypt the content. Highlighting is probably still much slower than decryption.
let can_be_cached = !entry.must_be_deleted;
let ext = key.ext.clone();
let title = entry.title.clone().unwrap_or_default();
let html = Html::from(entry, ext).await?;

if can_be_cached && !is_protected {
tracing::trace!(?key, "cache item");
state.cache.put(key.clone(), html.clone());
}

Ok(pages::Paste::new(key, html, can_delete).into_response())
Ok(pages::Paste::new(key, html, can_delete, title).into_response())
}

pub async fn get(
Expand Down Expand Up @@ -161,7 +166,13 @@ pub async fn get(

match query.fmt {
Some(Format::Raw) => return Ok(entry.text.into_response()),
Some(Format::Qr) => return Ok(get_qr(state, key, headers).await.into_response()),
Some(Format::Qr) => {
return Ok(
get_qr(state, key, headers, entry.title.clone().unwrap_or_default())
.await
.into_response(),
)
}
None => (),
}

Expand Down
28 changes: 23 additions & 5 deletions src/themes/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ body {

header {
display: flex;
justify-content: flex-end;
justify-content: space-between;
align-items: center;
padding: 0 1em 0 1em;
user-select: none;
Expand All @@ -62,14 +62,17 @@ main {
}

#nav-title {
margin-right: auto;
margin-top: 16px;
margin-bottom: 16px;
/* to cut off very long titles */
overflow: hidden;
display: flex;
flex-direction: row;
align-items: baseline;
}

header ul {
margin: 0;
padding: 0;
display: flex;
}

header li {
Expand All @@ -92,6 +95,21 @@ header .navigation:hover {
cursor: pointer;
}

h1 {
display: inline-block;
margin-top: 0px;
margin-bottom: 0px;
font-size: 1.125rem;
max-width: 80vw;
text-overflow: ellipsis;
overflow: hidden;
vertical-align: text-bottom;
padding-left: 16px;
padding-right: 16px;
text-wrap-mode: nowrap;
user-select: text;
}

button {
font-family: "JetBrains Mono", monospace;
font-size: 1.125rem;
Expand Down Expand Up @@ -189,7 +207,7 @@ a, a:visited, a:hover {
grid-row: 1/2;
}

.expiration-list, .password, .paste-button {
.expiration-list, .password, .paste-button, .title {
margin-top: 2em;
}

Expand Down
4 changes: 2 additions & 2 deletions templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="generator" content="wastebin {{ meta.version }}">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{{ meta.title }}</title>
<title>{{ meta.title }}{% block title_content %}{% endblock %}</title>
<link rel="preload" as="style" href="dark.css">
<link rel="preload" as="style" href="light.css">
<link rel="stylesheet" href="{{ base_path.join(meta.highlight.style.name) }}">
Expand All @@ -14,7 +14,7 @@
<body>
<div id="main-container">
<header>
<span id="nav-title"><a href="{{ base_path.path() }}" class="navigation">home</a></span>
<span id="nav-title"><a href="{{ base_path.path() }}" class="navigation">home</a>{% block title %}{% endblock %}</span>
<nav>
<ul>
{% block nav %}{% endblock %}
Expand Down
3 changes: 3 additions & 0 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
</div>
<div class="password">
<input type="password" name="password" id="password" placeholder="Password ...">
</div>
<div class="title">
<input type="text" name="title" id="title" placeholder="Title ...">
</div>
<div class="paste-button">
<button type="submit" title="Paste" class="button">Paste</button>
Expand Down
5 changes: 5 additions & 0 deletions templates/paste.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{% extends "base.html" %}

{% block title %}
{% if title.len() > 0 %}<h1>{{ title }}</h1>{% endif %}
{% endblock %}
{% block title_content %}{% if title.len() > 0 %}: {{ title }}{% endif %}{% endblock %}

{% block head %}
<script>
document.addEventListener('keydown', onKey);
Expand Down

0 comments on commit 5fe0ef6

Please sign in to comment.