use axum::http::{Method, Uri};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Nsid {
ComAtprotoModerationCreateReport,
ToolsOzoneModerationEmitEvent,
ToolsOzoneModerationQueryStatuses,
ToolsOzoneModerationQueryEvents,
}
impl Nsid {
pub fn from_path_segment(s: &str) -> Option<Self> {
match s {
"com.atproto.moderation.createReport" => Some(Self::ComAtprotoModerationCreateReport),
"tools.ozone.moderation.emitEvent" => Some(Self::ToolsOzoneModerationEmitEvent),
"tools.ozone.moderation.queryStatuses" => Some(Self::ToolsOzoneModerationQueryStatuses),
"tools.ozone.moderation.queryEvents" => Some(Self::ToolsOzoneModerationQueryEvents),
_ => None,
}
}
pub fn as_path_segment(self) -> &'static str {
match self {
Self::ComAtprotoModerationCreateReport => "com.atproto.moderation.createReport",
Self::ToolsOzoneModerationEmitEvent => "tools.ozone.moderation.emitEvent",
Self::ToolsOzoneModerationQueryStatuses => "tools.ozone.moderation.queryStatuses",
Self::ToolsOzoneModerationQueryEvents => "tools.ozone.moderation.queryEvents",
}
}
pub fn http_method(self) -> Method {
match self {
Self::ComAtprotoModerationCreateReport | Self::ToolsOzoneModerationEmitEvent => {
Method::POST
}
Self::ToolsOzoneModerationQueryStatuses | Self::ToolsOzoneModerationQueryEvents => {
Method::GET
}
}
}
}
pub fn extract_nsid_from_request_uri(uri: &Uri) -> Option<Nsid> {
uri.path()
.strip_prefix("/xrpc/")
.and_then(Nsid::from_path_segment)
}
#[cfg(test)]
mod tests {
use super::*;
fn all_variants() -> [Nsid; 4] {
[
Nsid::ComAtprotoModerationCreateReport,
Nsid::ToolsOzoneModerationEmitEvent,
Nsid::ToolsOzoneModerationQueryStatuses,
Nsid::ToolsOzoneModerationQueryEvents,
]
}
#[test]
fn from_path_segment_recognizes_all_v1_7_nsids() {
assert_eq!(
Nsid::from_path_segment("com.atproto.moderation.createReport"),
Some(Nsid::ComAtprotoModerationCreateReport)
);
assert_eq!(
Nsid::from_path_segment("tools.ozone.moderation.emitEvent"),
Some(Nsid::ToolsOzoneModerationEmitEvent)
);
assert_eq!(
Nsid::from_path_segment("tools.ozone.moderation.queryStatuses"),
Some(Nsid::ToolsOzoneModerationQueryStatuses)
);
assert_eq!(
Nsid::from_path_segment("tools.ozone.moderation.queryEvents"),
Some(Nsid::ToolsOzoneModerationQueryEvents)
);
}
#[test]
fn from_path_segment_returns_none_for_unallowlisted_nsids() {
for s in [
"tools.ozone.moderation.somethingElse",
"tools.ozone.moderation.emitEventV2",
"com.atproto.moderation.deleteReport",
"com.atproto.server.createSession",
] {
assert_eq!(Nsid::from_path_segment(s), None, "{s}");
}
}
#[test]
fn from_path_segment_returns_none_for_garbage_inputs() {
for s in ["", " ", "/", "not-an-nsid", "tools.ozone", "."] {
assert_eq!(Nsid::from_path_segment(s), None, "{s:?}");
}
}
#[test]
fn from_path_segment_is_case_sensitive() {
assert_eq!(
Nsid::from_path_segment("tools.ozone.moderation.EmitEvent"),
None
);
assert_eq!(
Nsid::from_path_segment("Com.Atproto.Moderation.CreateReport"),
None
);
assert_eq!(
Nsid::from_path_segment("TOOLS.OZONE.MODERATION.EMITEVENT"),
None
);
}
#[test]
fn as_path_segment_round_trips_with_from_path_segment() {
for n in all_variants() {
assert_eq!(
Nsid::from_path_segment(n.as_path_segment()),
Some(n),
"round-trip failed for {n:?}"
);
}
}
#[test]
fn extract_from_uri_recognizes_allowlisted_paths() {
let uri: Uri = "/xrpc/tools.ozone.moderation.emitEvent".parse().unwrap();
assert_eq!(
extract_nsid_from_request_uri(&uri),
Some(Nsid::ToolsOzoneModerationEmitEvent)
);
}
#[test]
fn extract_from_uri_returns_none_for_non_xrpc_path() {
let uri: Uri = "/health".parse().unwrap();
assert_eq!(extract_nsid_from_request_uri(&uri), None);
}
#[test]
fn extract_from_uri_returns_none_for_unknown_nsid_under_xrpc() {
let uri: Uri = "/xrpc/com.atproto.moderation.deleteReport".parse().unwrap();
assert_eq!(extract_nsid_from_request_uri(&uri), None);
}
#[test]
fn extract_from_uri_strips_query_string_implicitly_via_path() {
let uri: Uri = "/xrpc/tools.ozone.moderation.queryStatuses?subject=did:plc:x"
.parse()
.unwrap();
assert_eq!(
extract_nsid_from_request_uri(&uri),
Some(Nsid::ToolsOzoneModerationQueryStatuses)
);
}
#[test]
fn http_method_matches_v1_7_surface() {
assert_eq!(
Nsid::ComAtprotoModerationCreateReport.http_method(),
Method::POST
);
assert_eq!(
Nsid::ToolsOzoneModerationEmitEvent.http_method(),
Method::POST
);
assert_eq!(
Nsid::ToolsOzoneModerationQueryStatuses.http_method(),
Method::GET
);
assert_eq!(
Nsid::ToolsOzoneModerationQueryEvents.http_method(),
Method::GET
);
}
}