webringer 1.0.3

A bin/lib crate for a webring site
Documentation
use askama::Template;
use axum::{
	Form,
	extract::State,
	http::StatusCode,
	response::{Html, IntoResponse, Redirect},
};
use axum_messages::{Message, Messages};
use serde::Deserialize;
use std::fmt::Debug;
use tracing::{debug, error};

use crate::ring::{RingError, RingState};

#[derive(Template)]
#[template(path = "admin/add.html")]
pub struct AdminAddTemplate {
	messages: Vec<Message>,
}

#[derive(Deserialize)]
pub struct AddAdminForm {
	username: String,
	email: String,
	password: String,
	confirm_password: String,
}

impl Debug for AddAdminForm {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		f.debug_struct("Admin")
			.field("username", &self.username)
			.field("email", &self.email)
			.field("password", &"redacted")
			.field("confirm_password", &"redacted")
			.finish()
	}
}

pub(super) async fn post(
	State(state): State<RingState>,
	messages: Messages,
	Form(data): Form<AddAdminForm>,
) -> impl IntoResponse {
	static PATH: &str = "/admin/add";
	if data.password != data.confirm_password {
		debug!("Passwords don't match");
		messages.error("Passwords do not match");
		return Redirect::to(PATH).into_response();
	}
	if let Err(e) = state
		.add_admin(data.username.clone(), data.email, data.password)
		.await
	{
		match e {
			RingError::UniqueRowAlreadyPresent(values) => {
				messages.error(format!("Email or username is already taken: {values}"));
				Redirect::to(PATH).into_response()
			}
			RingError::TaskJoin(e) => {
				error!("Task join error when adding admin: {}", e);
				StatusCode::INTERNAL_SERVER_ERROR.into_response()
			}
			RingError::UnrecoverableDatabaseError(e) => {
				error!("Unrecoverable database error when adding admin: {}", e);
				StatusCode::INTERNAL_SERVER_ERROR.into_response()
			}
			e => {
				error!(
					"Recieved an error site::admin::add::post is not equipped to handle: {}",
					e
				);
				StatusCode::INTERNAL_SERVER_ERROR.into_response()
			}
		}
	} else {
		messages.info(format!("Added new admin {}", data.username));
		Redirect::to(PATH).into_response()
	}
}

pub(super) async fn get(messages: Messages) -> impl IntoResponse {
	match {
		AdminAddTemplate {
			messages: messages.into_iter().collect(),
		}
	}
	.render()
	{
		Ok(s) => {
			debug!("Successfully rendered admin add html");
			Html(s).into_response()
		}
		Err(e) => {
			error!("Error when rendering admin add html: {}", e);
			StatusCode::INTERNAL_SERVER_ERROR.into_response()
		}
	}
}