make transactions higher level (pass them everywhere)
This commit is contained in:
@@ -4,6 +4,8 @@ use maud::{Markup, PreEscaped, html};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
api::CompositeError,
|
||||
database::{self, DatabaseError},
|
||||
persons::{Name, Person},
|
||||
quotes::{Quote, QuoteLine},
|
||||
tags::Tag,
|
||||
@@ -20,9 +22,12 @@ const LINKS: &[(&str, &str, &str)] = &[
|
||||
("Add Person", "/persons/add", icons::CONTACT),
|
||||
];
|
||||
|
||||
pub async fn page(req: Request) -> Markup {
|
||||
pub async fn page(req: Request) -> Result<Markup, CompositeError> {
|
||||
let u = User::authenticate(req.headers()).ok().flatten();
|
||||
base(
|
||||
let mut conn = database::conn()?;
|
||||
let tx = conn.transaction().map_err(DatabaseError::from)?;
|
||||
|
||||
Ok(base(
|
||||
"Dashboard | Mnemosyne",
|
||||
html!(
|
||||
(nav(u.as_ref(), req.uri().path()))
|
||||
@@ -55,25 +60,25 @@ pub async fn page(req: Request) -> Markup {
|
||||
}
|
||||
div class="mx-auto max-w-4xl mt-4 flex flex-row gap-2" {
|
||||
(chip(html!({
|
||||
@match Quote::total_count() {
|
||||
@match Quote::total_count(&tx) {
|
||||
Ok(count) => {(count) " QUOTES TOTAL"},
|
||||
Err(_) => span class="text-red-400" {"QUOTE COUNT ERR"},
|
||||
}
|
||||
})))
|
||||
(chip(html!({
|
||||
@match Person::total_count() {
|
||||
@match Person::total_count(&tx) {
|
||||
Ok(count) => {(count) " PERSONS TOTAL"},
|
||||
Err(_) => span class="text-red-400" {"PERSON COUNT ERR"},
|
||||
}
|
||||
})))
|
||||
(chip(html!({
|
||||
@match Tag::total_count() {
|
||||
@match Tag::total_count(&tx) {
|
||||
Ok(count) => {(count) " TAGS TOTAL"},
|
||||
Err(_) => span class="text-red-400" {"TAG COUNT ERR"}
|
||||
}
|
||||
})))
|
||||
(chip(html!({
|
||||
@match User::total_count() {
|
||||
@match User::total_count(&tx) {
|
||||
Ok(count) => {(count) " USERS TOTAL"},
|
||||
Err(_) => span class="text-red-400" {"USER COUNT ERR"}
|
||||
}
|
||||
@@ -82,7 +87,7 @@ pub async fn page(req: Request) -> Markup {
|
||||
|
||||
div class="text-4xl xs:text-6xl sm:text-8xl text-neutral-800/25 mt-16 text-center font-semibold font-lora select-none" {"Mnemosyne"}
|
||||
),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn sample_quote_1() -> Quote {
|
||||
|
||||
@@ -6,6 +6,7 @@ use maud::{PreEscaped, html};
|
||||
|
||||
use crate::{
|
||||
api::CompositeError,
|
||||
database::{self, DatabaseError},
|
||||
logs::LogEntry,
|
||||
users::{User, auth::UserAuthenticate, permissions::Permission},
|
||||
web::{RedirectViaError, components::nav::nav, icons, pages::base},
|
||||
@@ -14,14 +15,16 @@ use crate::{
|
||||
pub async fn page(req: Request) -> Result<Response, CompositeError> {
|
||||
let u = User::authenticate(req.headers())?
|
||||
.ok_or(RedirectViaError(Redirect::to("/login?re=/logs")))?;
|
||||
let logs = LogEntry::get_all()?;
|
||||
let mut conn = database::conn()?;
|
||||
let tx = conn.transaction().map_err(DatabaseError::from)?;
|
||||
let logs = LogEntry::get_all(&tx)?;
|
||||
|
||||
Ok(base(
|
||||
"Persons | Mnemosyne",
|
||||
html!(
|
||||
(nav(Some(&u), req.uri().path()))
|
||||
|
||||
@if let Ok(true) = u.has_permission(Permission::BrowseServerLogs) {
|
||||
@if let Ok(true) = u.has_permission(&tx, Permission::BrowseServerLogs) {
|
||||
div class="max-w-4xl mx-auto px-2" {
|
||||
div class="my-4" {
|
||||
p class="flex items-center gap-2" {
|
||||
|
||||
@@ -9,6 +9,7 @@ use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
api::CompositeError,
|
||||
database::{self, DatabaseError},
|
||||
logs::{LogAction, LogEntry},
|
||||
persons::Person,
|
||||
users::{
|
||||
@@ -20,6 +21,8 @@ use crate::{
|
||||
|
||||
pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
let u = User::authenticate(req.headers())?;
|
||||
let mut conn = database::conn()?;
|
||||
let tx = conn.transaction()?;
|
||||
|
||||
Ok(base(
|
||||
"Persons | Mnemosyne",
|
||||
@@ -33,14 +36,14 @@ pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
span class="text-2xl font-semibold font-lora" {"Persons"}
|
||||
}
|
||||
p class="text-neutral-500 text-sm font-light" {
|
||||
@if let Ok(c) = Person::total_count() {
|
||||
@if let Ok(c) = Person::total_count(&tx) {
|
||||
(c) " persons in total."
|
||||
} @else {
|
||||
"Could not get total person count."
|
||||
}
|
||||
}
|
||||
}
|
||||
@if let Ok(persons) = Person::get_all() {
|
||||
@if let Ok(persons) = Person::get_all(&tx) {
|
||||
div class="max-w-4xl mx-auto px-2 mt-4 flex flex-wrap gap-2" {
|
||||
@for person in &persons {
|
||||
div class="rounded px-4 py-2 bg-neutral-200/10 border border-neutral-200/15 flex items-center" {
|
||||
@@ -49,7 +52,7 @@ pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
div class="w-px h-2/3 my-auto mx-2 bg-neutral-200/15" {}
|
||||
div class="text-xs flex items-center" {
|
||||
(
|
||||
if let Ok(i) = person.get_in_quote_count() {
|
||||
if let Ok(i) = person.get_in_quote_count(&tx) {
|
||||
i.to_string()
|
||||
} else {
|
||||
"?".to_string()
|
||||
@@ -96,13 +99,18 @@ pub async fn create(
|
||||
Form(form): Form<PersonNameForm>,
|
||||
) -> Result<Response, CompositeError> {
|
||||
let u = User::authenticate(&headers)?.required()?;
|
||||
let p = Person::create(form.primary_name, u.id)?;
|
||||
let mut conn = database::conn()?;
|
||||
let tx = conn.transaction().map_err(DatabaseError::from)?;
|
||||
|
||||
let p = Person::create(&tx, form.primary_name, u.id)?;
|
||||
LogEntry::new(
|
||||
&tx,
|
||||
u,
|
||||
LogAction::CreatePerson {
|
||||
id: p.id,
|
||||
pname: p.primary_name,
|
||||
},
|
||||
)?;
|
||||
tx.commit().map_err(DatabaseError::from)?;
|
||||
Ok(Redirect::to("/persons").into_response())
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
api::CompositeError,
|
||||
database::{self, DatabaseError},
|
||||
logs::{LogAction, LogEntry},
|
||||
tags::{Tag, TagName},
|
||||
users::{
|
||||
@@ -20,6 +21,7 @@ use crate::{
|
||||
|
||||
pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
let u = User::authenticate(req.headers())?;
|
||||
let conn = database::conn()?;
|
||||
|
||||
Ok(base(
|
||||
"Tags | Mnemosyne",
|
||||
@@ -33,14 +35,14 @@ pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
span class="text-2xl font-semibold font-lora" {"Tags"}
|
||||
}
|
||||
p class="text-neutral-500 text-sm font-light" {
|
||||
@if let Ok(c) = Tag::total_count() {
|
||||
@if let Ok(c) = Tag::total_count(&conn) {
|
||||
(c) " tags in total."
|
||||
} @else {
|
||||
"Could not get total tag count."
|
||||
}
|
||||
}
|
||||
}
|
||||
@if let Ok(tags) = Tag::get_all() {
|
||||
@if let Ok(tags) = Tag::get_all(&conn) {
|
||||
div class="max-w-4xl mx-auto mt-4 flex flex-wrap gap-2" {
|
||||
@for tag in &tags {
|
||||
div class="rounded-full px-3 py-1 bg-neutral-200/10 border border-neutral-200/15 flex" {
|
||||
@@ -49,7 +51,7 @@ pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
div class="w-px h-2/3 my-auto mx-2 bg-neutral-200/15" {}
|
||||
div class="text-xs flex items-center" {
|
||||
(
|
||||
if let Ok(i) = tag.get_tagged_quotes_count() {
|
||||
if let Ok(i) = tag.get_tagged_quotes_count(&conn) {
|
||||
i.to_string()
|
||||
} else {
|
||||
"?".to_string()
|
||||
@@ -96,13 +98,18 @@ pub async fn create(
|
||||
Form(form): Form<TagForm>,
|
||||
) -> Result<Response, CompositeError> {
|
||||
let u = User::authenticate(&headers)?.required()?;
|
||||
let t = Tag::create(form.tagname)?;
|
||||
let mut conn = database::conn()?;
|
||||
let tx = conn.transaction().map_err(DatabaseError::from)?;
|
||||
|
||||
let t = Tag::create(&tx, form.tagname)?;
|
||||
LogEntry::new(
|
||||
&tx,
|
||||
u,
|
||||
LogAction::CreateTag {
|
||||
id: t.id,
|
||||
name: t.name.to_string(),
|
||||
},
|
||||
)?;
|
||||
tx.commit().map_err(DatabaseError::from)?;
|
||||
Ok(Redirect::to("/tags").into_response())
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use axum::{
|
||||
use maud::{PreEscaped, html};
|
||||
|
||||
use crate::{
|
||||
database,
|
||||
users::{
|
||||
User,
|
||||
auth::{AuthError, UserAuthenticate},
|
||||
@@ -22,8 +23,9 @@ pub mod profile;
|
||||
|
||||
pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
let u = User::authenticate(req.headers())?;
|
||||
let conn = database::conn()?;
|
||||
let us = match u.is_some() {
|
||||
true => User::get_all(),
|
||||
true => User::get_all(&conn),
|
||||
false => Ok(vec![]),
|
||||
};
|
||||
|
||||
@@ -44,7 +46,7 @@ pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
} @else {
|
||||
"Could not fetch user count."
|
||||
}
|
||||
@if let Ok(true) = u.has_permission(Permission::ManuallyCreateUsers) {
|
||||
@if let Ok(true) = u.has_permission(&conn, Permission::ManuallyCreateUsers) {
|
||||
" "
|
||||
a href="/users/create" class="text-blue-500 hover:text-blue-400 hover:underline" {
|
||||
"Create a new user"
|
||||
|
||||
@@ -9,6 +9,7 @@ use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
api::CompositeError,
|
||||
database::{self, DatabaseError},
|
||||
logs::{LogAction, LogEntry},
|
||||
users::{
|
||||
User,
|
||||
@@ -21,6 +22,7 @@ use crate::{
|
||||
|
||||
pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
let u = User::authenticate(req.headers())?;
|
||||
let conn = database::conn()?;
|
||||
|
||||
Ok(base(
|
||||
"Users | Mnemosyne",
|
||||
@@ -34,7 +36,7 @@ pub async fn page(req: Request) -> Result<Response, AuthError> {
|
||||
span class="text-2xl font-semibold font-lora" {"Create a new user"}
|
||||
}
|
||||
}
|
||||
@if let Ok(true) = u.has_permission(Permission::ManuallyCreateUsers) {
|
||||
@if let Ok(true) = u.has_permission(&conn, Permission::ManuallyCreateUsers) {
|
||||
div class="mx-auto max-w-4xl px-2 mt-4" {
|
||||
form action="/users/create-form" method="post" class="flex flex-col" {
|
||||
label for="handle" class="font-light text-neutral-500" {"Handle"}
|
||||
@@ -71,17 +73,22 @@ pub async fn create_user(
|
||||
Form(form): Form<CreateUserWithPasswordForm>,
|
||||
) -> Result<Response, CompositeError> {
|
||||
let u = User::authenticate(&headers)?.required()?;
|
||||
if !u.has_permission(Permission::ManuallyCreateUsers)? {
|
||||
let mut conn = database::conn().map_err(DatabaseError::from)?;
|
||||
let tx = conn.transaction().map_err(DatabaseError::from)?;
|
||||
|
||||
if !u.has_permission(&tx, Permission::ManuallyCreateUsers)? {
|
||||
return Ok((StatusCode::FORBIDDEN).into_response());
|
||||
}
|
||||
let mut nu = User::create(form.handle)?;
|
||||
nu.set_password(Some(&form.password))?;
|
||||
let mut nu = User::create(&tx, form.handle)?;
|
||||
nu.set_password(&tx, Some(&form.password))?;
|
||||
LogEntry::new(
|
||||
&tx,
|
||||
u,
|
||||
LogAction::CreateUser {
|
||||
id: nu.id,
|
||||
handle: nu.handle.as_str().to_string(),
|
||||
},
|
||||
)?;
|
||||
tx.commit().map_err(DatabaseError::from)?;
|
||||
Ok(Redirect::to("/users").into_response())
|
||||
}
|
||||
|
||||
@@ -7,12 +7,11 @@ use maud::{PreEscaped, html};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
api::CompositeError,
|
||||
database::{self, DatabaseError},
|
||||
persons::Name,
|
||||
quotes::{Quote, QuoteLine},
|
||||
users::{
|
||||
User, UserError,
|
||||
auth::{AuthError, UserAuthenticate},
|
||||
},
|
||||
users::{User, UserError, auth::UserAuthenticate},
|
||||
web::{
|
||||
components::{nav::nav, quote::quote},
|
||||
icons,
|
||||
@@ -20,12 +19,15 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
pub async fn page(Path(id): Path<Uuid>, req: Request) -> Result<Response, AuthError> {
|
||||
pub async fn page(Path(id): Path<Uuid>, req: Request) -> Result<Response, CompositeError> {
|
||||
let u = match User::authenticate(req.headers())? {
|
||||
Some(u) => u,
|
||||
None => return Ok(Redirect::to("/users").into_response()),
|
||||
};
|
||||
let user = match User::get_by_id(id) {
|
||||
let mut conn = database::conn().map_err(DatabaseError::from)?;
|
||||
let tx = conn.transaction().map_err(DatabaseError::from)?;
|
||||
|
||||
let user = match User::get_by_id(&tx, id) {
|
||||
Ok(u) => u,
|
||||
Err(UserError::NoUserWithId(_)) => {
|
||||
return Ok(base(
|
||||
|
||||
@@ -9,6 +9,7 @@ use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
api::CompositeError,
|
||||
database::{self, DatabaseError},
|
||||
logs::{LogAction, LogEntry},
|
||||
users::{
|
||||
User,
|
||||
@@ -81,9 +82,13 @@ pub async fn change_handle(
|
||||
Form(form): Form<HandleForm>,
|
||||
) -> Result<Response, CompositeError> {
|
||||
let mut u = User::authenticate(&headers)?.required()?;
|
||||
let mut conn = database::conn()?;
|
||||
let tx = conn.transaction().map_err(DatabaseError::from)?;
|
||||
|
||||
let oldhandle = u.handle.as_str().to_string();
|
||||
u.set_handle(form.handle)?;
|
||||
u.set_handle(&tx, form.handle)?;
|
||||
LogEntry::new(
|
||||
&tx,
|
||||
u.clone(),
|
||||
LogAction::ChangeUserHandle {
|
||||
id: u.id,
|
||||
@@ -103,6 +108,9 @@ pub async fn change_password(
|
||||
Form(form): Form<PasswordForm>,
|
||||
) -> Result<Response, CompositeError> {
|
||||
let mut u = User::authenticate(&headers)?.required()?;
|
||||
u.set_password(Some(&form.password))?;
|
||||
let mut conn = database::conn()?;
|
||||
let tx = conn.transaction().map_err(DatabaseError::from)?;
|
||||
|
||||
u.set_password(&tx, Some(&form.password))?;
|
||||
Ok(Redirect::to("/user-settings").into_response())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user