refactor(blahd): prefer newtype NoContent

This commit is contained in:
oxalica 2024-10-12 06:57:21 -04:00
parent d1dfda51db
commit a8c29cb9b2
3 changed files with 24 additions and 15 deletions

View file

@ -23,7 +23,7 @@ use blah_types::{get_timestamp, Id, PubKey, Signed, UserKey};
use data_encoding::BASE64_NOPAD; use data_encoding::BASE64_NOPAD;
use database::{Transaction, TransactionOps}; use database::{Transaction, TransactionOps};
use id::IdExt; use id::IdExt;
use middleware::{Auth, ETag, MaybeAuth, ResultExt as _, SignedJson}; use middleware::{Auth, ETag, MaybeAuth, NoContent, ResultExt as _, SignedJson};
use parking_lot::Mutex; use parking_lot::Mutex;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
@ -218,7 +218,7 @@ async fn get_user(State(st): ArcState, auth: MaybeAuth) -> Response {
})(); })();
match ret { match ret {
Ok(_) => StatusCode::NO_CONTENT.into_response(), Ok(_) => NoContent.into_response(),
Err(err) => { Err(err) => {
let (status, raw_err) = err.to_raw(); let (status, raw_err) = err.to_raw();
if status != StatusCode::NOT_FOUND { if status != StatusCode::NOT_FOUND {
@ -475,7 +475,7 @@ async fn post_room_admin(
st: ArcState, st: ArcState,
R(Path(rid), _): RE<Path<Id>>, R(Path(rid), _): RE<Path<Id>>,
SignedJson(op): SignedJson<RoomAdminPayload>, SignedJson(op): SignedJson<RoomAdminPayload>,
) -> Result<StatusCode, ApiError> { ) -> Result<NoContent, ApiError> {
// TODO: This is a temporary endpoint so just reserialize them. // TODO: This is a temporary endpoint so just reserialize them.
fn transcode<T: Serialize, U: DeserializeOwned>(v: &T) -> SignedJson<U> { fn transcode<T: Serialize, U: DeserializeOwned>(v: &T) -> SignedJson<U> {
let v = serde_json::to_value(v).expect("serialization cannot fail"); let v = serde_json::to_value(v).expect("serialization cannot fail");
@ -501,7 +501,7 @@ async fn post_room_member(
st: ArcState, st: ArcState,
R(Path(rid), _): RE<Path<Id>>, R(Path(rid), _): RE<Path<Id>>,
SignedJson(op): SignedJson<AddMemberPayload>, SignedJson(op): SignedJson<AddMemberPayload>,
) -> Result<StatusCode, ApiError> { ) -> Result<NoContent, ApiError> {
api_ensure!(rid == op.signee.payload.room, "room id mismatch with URI"); api_ensure!(rid == op.signee.payload.room, "room id mismatch with URI");
api_ensure!( api_ensure!(
!rid.is_peer_chat(), !rid.is_peer_chat(),
@ -523,7 +523,7 @@ async fn post_room_member(
// Sanity check. // Sanity check.
assert!(!attrs.contains(RoomAttrs::PEER_CHAT)); assert!(!attrs.contains(RoomAttrs::PEER_CHAT));
txn.add_room_member(rid, uid, member.permission)?; txn.add_room_member(rid, uid, member.permission)?;
Ok(StatusCode::NO_CONTENT) Ok(NoContent)
}) })
} }
@ -531,7 +531,7 @@ async fn delete_room_member(
st: ArcState, st: ArcState,
R(Path((rid, id_key)), _): RE<Path<(Id, PubKey)>>, R(Path((rid, id_key)), _): RE<Path<(Id, PubKey)>>,
SignedJson(op): SignedJson<RemoveMemberPayload>, SignedJson(op): SignedJson<RemoveMemberPayload>,
) -> Result<StatusCode, ApiError> { ) -> Result<NoContent, ApiError> {
api_ensure!(rid == op.signee.payload.room, "room id mismatch with URI"); api_ensure!(rid == op.signee.payload.room, "room id mismatch with URI");
api_ensure!( api_ensure!(
!rid.is_peer_chat(), !rid.is_peer_chat(),
@ -550,7 +550,7 @@ async fn delete_room_member(
// Sanity check. // Sanity check.
assert!(!attrs.contains(RoomAttrs::PEER_CHAT)); assert!(!attrs.contains(RoomAttrs::PEER_CHAT));
txn.remove_room_member(rid, uid)?; txn.remove_room_member(rid, uid)?;
Ok(StatusCode::NO_CONTENT) Ok(NoContent)
}) })
} }
@ -558,7 +558,7 @@ async fn delete_room(
st: ArcState, st: ArcState,
R(Path(rid), _): RE<Path<Id>>, R(Path(rid), _): RE<Path<Id>>,
SignedJson(op): SignedJson<DeleteRoomPayload>, SignedJson(op): SignedJson<DeleteRoomPayload>,
) -> Result<StatusCode, ApiError> { ) -> Result<NoContent, ApiError> {
api_ensure!(rid == op.signee.payload.room, "room id mismatch with URI"); api_ensure!(rid == op.signee.payload.room, "room id mismatch with URI");
st.db.with_write(|txn| { st.db.with_write(|txn| {
// TODO: Should we only shadow delete here? // TODO: Should we only shadow delete here?
@ -568,7 +568,7 @@ async fn delete_room(
ApiError::PermissionDenied("the user does not have permission to delete the room") ApiError::PermissionDenied("the user does not have permission to delete the room")
); );
txn.delete_room(rid)?; txn.delete_room(rid)?;
Ok(StatusCode::NO_CONTENT) Ok(NoContent)
}) })
} }
@ -576,7 +576,7 @@ async fn post_room_msg_seen(
st: ArcState, st: ArcState,
R(Path((rid, cid)), _): RE<Path<(Id, i64)>>, R(Path((rid, cid)), _): RE<Path<(Id, i64)>>,
Auth(user): Auth, Auth(user): Auth,
) -> Result<StatusCode, ApiError> { ) -> Result<NoContent, ApiError> {
st.db.with_write(|txn| { st.db.with_write(|txn| {
let (uid, _perm, prev_seen_cid) = txn.get_room_member(rid, &user)?; let (uid, _perm, prev_seen_cid) = txn.get_room_member(rid, &user)?;
if cid < prev_seen_cid.0 { if cid < prev_seen_cid.0 {
@ -584,7 +584,7 @@ async fn post_room_msg_seen(
} }
txn.mark_room_msg_seen(rid, uid, Id(cid as _)) txn.mark_room_msg_seen(rid, uid, Id(cid as _))
})?; })?;
Ok(StatusCode::NO_CONTENT) Ok(NoContent)
} }
async fn list_room_member( async fn list_room_member(

View file

@ -280,3 +280,13 @@ impl<T: fmt::Display> IntoResponseParts for ETag<T> {
Ok(res) Ok(res)
} }
} }
// WAIT: https://github.com/tokio-rs/axum/pull/2978
#[derive(Debug, Clone, Copy)]
pub struct NoContent;
impl IntoResponse for NoContent {
fn into_response(self) -> Response {
StatusCode::NO_CONTENT.into_response()
}
}

View file

@ -2,7 +2,6 @@ use std::num::NonZero;
use std::time::Duration; use std::time::Duration;
use anyhow::{anyhow, ensure}; use anyhow::{anyhow, ensure};
use axum::http::StatusCode;
use blah_types::get_timestamp; use blah_types::get_timestamp;
use blah_types::identity::{IdUrl, UserIdentityDesc}; use blah_types::identity::{IdUrl, UserIdentityDesc};
use blah_types::msg::{UserRegisterChallengeResponse, UserRegisterPayload}; use blah_types::msg::{UserRegisterChallengeResponse, UserRegisterPayload};
@ -15,7 +14,7 @@ use serde::Deserialize;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use crate::database::TransactionOps; use crate::database::TransactionOps;
use crate::middleware::SignedJson; use crate::middleware::{NoContent, SignedJson};
use crate::utils::Instant; use crate::utils::Instant;
use crate::{ApiError, ArcState, SERVER_AND_VERSION}; use crate::{ApiError, ArcState, SERVER_AND_VERSION};
@ -163,7 +162,7 @@ impl State {
pub async fn post_user( pub async fn post_user(
axum::extract::State(st): ArcState, axum::extract::State(st): ArcState,
SignedJson(msg): SignedJson<UserRegisterPayload>, SignedJson(msg): SignedJson<UserRegisterPayload>,
) -> Result<StatusCode, ApiError> { ) -> Result<NoContent, ApiError> {
if !st.config.register.enable_public { if !st.config.register.enable_public {
return Err(ApiError::Disabled("public registration is disabled")); return Err(ApiError::Disabled("public registration is disabled"));
} }
@ -252,7 +251,7 @@ pub async fn post_user(
st.db st.db
.with_write(|txn| txn.create_user(&id_desc, &id_desc_json, fetch_time))?; .with_write(|txn| txn.create_user(&id_desc, &id_desc_json, fetch_time))?;
Ok(StatusCode::NO_CONTENT) Ok(NoContent)
} }
#[cfg(test)] #[cfg(test)]