Compare commits
4 Commits
7fe1b6f8be
...
b1ccd21068
| Author | SHA1 | Date | |
|---|---|---|---|
|
b1ccd21068
|
|||
|
7d284f0777
|
|||
|
84dde9cc4b
|
|||
|
e7c0523841
|
@@ -4,7 +4,7 @@ use crate::{quotes::Quote, web::icons};
|
|||||||
|
|
||||||
pub fn quote(quote: &Quote) -> Markup {
|
pub fn quote(quote: &Quote) -> Markup {
|
||||||
html!(
|
html!(
|
||||||
div class="border border-neutral-200/25 bg-neutral-200/5 p-3 pb-1 overflow-clip rounded-md relative flex flex-col" {
|
div class="border border-neutral-200/25 bg-neutral-200/5 p-3 pb-1 overflow-clip rounded-md relative flex flex-col transition-colors group-hover/a:border-neutral-200/35 group-hover/a:bg-neutral-200/10" {
|
||||||
div class="absolute top-4 right-6 -rotate-12 opacity-[.025] scale-x-[4.5] scale-y-[4]" {
|
div class="absolute top-4 right-6 -rotate-12 opacity-[.025] scale-x-[4.5] scale-y-[4]" {
|
||||||
(PreEscaped(icons::QUOTE))
|
(PreEscaped(icons::QUOTE))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,9 @@ pub async fn page(
|
|||||||
"This just in! This quote was added "
|
"This just in! This quote was added "
|
||||||
(format_time_ago(q.get_creation_timestamp())) " ago."
|
(format_time_ago(q.get_creation_timestamp())) " ago."
|
||||||
}
|
}
|
||||||
div class="flex-1 [&>div]:h-full" {(quote(q))}
|
div class="flex-1 [&>div]:h-full" {
|
||||||
|
a href=(format!("/quotes/{}", q.id)) class="group/a" {(quote(q))}
|
||||||
|
}
|
||||||
} @else {
|
} @else {
|
||||||
p class="text-neutral-500 font-light mb-4" {"No quotes yet."}
|
p class="text-neutral-500 font-light mb-4" {"No quotes yet."}
|
||||||
}
|
}
|
||||||
@@ -76,7 +78,9 @@ pub async fn page(
|
|||||||
"This quote was added "
|
"This quote was added "
|
||||||
(format_time_ago(q.get_creation_timestamp())) " ago."
|
(format_time_ago(q.get_creation_timestamp())) " ago."
|
||||||
}
|
}
|
||||||
div class="flex-1 [&>div]:h-full" {(quote(&q))}
|
div class="flex-1 [&>div]:h-full" {
|
||||||
|
a href=(format!("/quotes/{}", q.id)) class="group/a" {(quote(&q))}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ pub async fn page(
|
|||||||
}
|
}
|
||||||
div class="flex flex-col gap-4 mb-8" {
|
div class="flex flex-col gap-4 mb-8" {
|
||||||
@for q in "es {
|
@for q in "es {
|
||||||
a href=(format!("/quotes/{}", q.id)) {(quote(q))}
|
a href=(format!("/quotes/{}", q.id)) class="group/a" {(quote(q))}
|
||||||
}
|
}
|
||||||
|
|
||||||
div class="flex justify-between items-center mt-4 text-neutral-400" {
|
div class="flex justify-between items-center mt-4 text-neutral-400" {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use axum::{
|
|||||||
http::HeaderMap,
|
http::HeaderMap,
|
||||||
response::{IntoResponse, Redirect, Response},
|
response::{IntoResponse, Redirect, Response},
|
||||||
};
|
};
|
||||||
|
use http::StatusCode;
|
||||||
use maud::{PreEscaped, html};
|
use maud::{PreEscaped, html};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ use crate::{
|
|||||||
users::{
|
users::{
|
||||||
User,
|
User,
|
||||||
auth::{UserAuthRequired, UserAuthenticate},
|
auth::{UserAuthRequired, UserAuthenticate},
|
||||||
|
permissions::Permission,
|
||||||
},
|
},
|
||||||
web::{
|
web::{
|
||||||
components::{nav::nav, quote::quote},
|
components::{nav::nav, quote::quote},
|
||||||
@@ -33,6 +35,9 @@ pub async fn page(
|
|||||||
None => return Ok(Redirect::to(&format!("/login?r={}", req.uri().path())).into_response()),
|
None => return Ok(Redirect::to(&format!("/login?r={}", req.uri().path())).into_response()),
|
||||||
};
|
};
|
||||||
let q = Quote::get_by_id(&mut conn, id).await;
|
let q = Quote::get_by_id(&mut conn, id).await;
|
||||||
|
let can_delete = u
|
||||||
|
.has_permission(&mut conn, Permission::DeleteQuotes)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(base(
|
Ok(base(
|
||||||
"Add Quote | Mnemosyne",
|
"Add Quote | Mnemosyne",
|
||||||
@@ -53,9 +58,11 @@ pub async fn page(
|
|||||||
span class="scale-[.75]" {(PreEscaped(icons::PEN))}
|
span class="scale-[.75]" {(PreEscaped(icons::PEN))}
|
||||||
"Edit"
|
"Edit"
|
||||||
}
|
}
|
||||||
a href=(format!("/quotes/{id}/delete")) class="px-2 py-1 cursor-pointer border rounded flex flex-row gap-1 bg-pink-400/10 border-pink-400/25 hover:bg-pink-400/20 hover:border-pink-400/45" {
|
@if can_delete {
|
||||||
span class="scale-[.75]" {(PreEscaped(icons::TRASH))}
|
a href=(format!("/quotes/{id}/delete")) class="px-2 py-1 cursor-pointer border rounded flex flex-row gap-1 bg-pink-400/10 border-pink-400/25 hover:bg-pink-400/20 hover:border-pink-400/45" {
|
||||||
"Delete"
|
span class="scale-[.75]" {(PreEscaped(icons::TRASH))}
|
||||||
|
"Delete"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} @else {
|
} @else {
|
||||||
@@ -126,6 +133,9 @@ pub async fn delete(
|
|||||||
) -> Result<Response, CompositeError> {
|
) -> Result<Response, CompositeError> {
|
||||||
let mut tx = state.pool.begin().await?;
|
let mut tx = state.pool.begin().await?;
|
||||||
let u = User::authenticate(&mut *tx, &headers).await?.required()?;
|
let u = User::authenticate(&mut *tx, &headers).await?.required()?;
|
||||||
|
if !u.has_permission(&mut tx, Permission::DeleteQuotes).await? {
|
||||||
|
return Ok((StatusCode::FORBIDDEN, "No permission.").into_response());
|
||||||
|
}
|
||||||
|
|
||||||
let q = Quote::get_by_id(&mut *tx, id).await?;
|
let q = Quote::get_by_id(&mut *tx, id).await?;
|
||||||
LogEntry::new(&mut *tx, u, LogAction::DeleteQuote { quote: q.clone() }).await?;
|
LogEntry::new(&mut *tx, u, LogAction::DeleteQuote { quote: q.clone() }).await?;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use axum::{
|
|||||||
response::{IntoResponse, Redirect, Response},
|
response::{IntoResponse, Redirect, Response},
|
||||||
};
|
};
|
||||||
use maud::{PreEscaped, html};
|
use maud::{PreEscaped, html};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
MnemoState,
|
MnemoState,
|
||||||
@@ -27,7 +28,14 @@ pub async fn page(
|
|||||||
Some(u) => u,
|
Some(u) => u,
|
||||||
None => return Ok(Redirect::to(&format!("/login?r={}", req.uri().path())).into_response()),
|
None => return Ok(Redirect::to(&format!("/login?r={}", req.uri().path())).into_response()),
|
||||||
};
|
};
|
||||||
let us = User::get_all(&mut *conn).await;
|
let us = User::get_all(&mut *conn).await.map(|mut v| {
|
||||||
|
v.sort_by_key(|p| match p.id {
|
||||||
|
id if id == Uuid::nil() => (0, p.id),
|
||||||
|
id if id == Uuid::max() => (1, p.id),
|
||||||
|
_ => (2, p.id),
|
||||||
|
});
|
||||||
|
v
|
||||||
|
});
|
||||||
let can_create_users = u
|
let can_create_users = u
|
||||||
.has_permission(&mut *conn, Permission::ManuallyCreateUsers)
|
.has_permission(&mut *conn, Permission::ManuallyCreateUsers)
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
Reference in New Issue
Block a user