1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-04 18:22:34 +03:00

admin: add operation IDs on user operations & other improvements

This also documents better the user list operation parameters
This commit is contained in:
Quentin Gliech
2024-07-30 17:31:35 +02:00
parent 78e988b7cc
commit d03dd41345
4 changed files with 65 additions and 38 deletions

View File

@ -58,6 +58,7 @@ pub struct UsernamePathParam {
pub fn doc(operation: TransformOperation) -> TransformOperation {
operation
.id("getUserByUsername")
.summary("Get a user by its username (localpart)")
.tag("user")
.response_with::<200, Json<SingleResponse<User>>, _>(|t| {

View File

@ -52,6 +52,7 @@ impl IntoResponse for RouteError {
pub fn doc(operation: TransformOperation) -> TransformOperation {
operation
.id("getUser")
.summary("Get a user")
.tag("user")
.response_with::<200, Json<SingleResponse<User>>, _>(|t| {

View File

@ -34,44 +34,57 @@ use crate::{
impl_from_error_for_route,
};
#[derive(Deserialize, JsonSchema)]
#[derive(Deserialize, JsonSchema, Clone, Copy)]
#[serde(rename_all = "snake_case")]
enum UserStatus {
/// The user is active
Active,
/// The user is locked
Locked,
}
impl std::fmt::Display for UserStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Active => write!(f, "active"),
Self::Locked => write!(f, "locked"),
}
}
}
#[derive(FromRequestParts, Deserialize, JsonSchema, OperationIo)]
#[serde(rename = "UserFilter")]
#[aide(input_with = "Query<FilterParams>")]
#[from_request(via(Query), rejection(RouteError))]
pub struct FilterParams {
/// Retrieve users with (or without) the `can_request_admin` flag set
#[serde(rename = "filter[can_request_admin]")]
can_request_admin: Option<bool>,
/// Retrieve the items with the given status
///
/// Defaults to retrieve all users, including locked ones.
///
/// * `active`: Only retrieve active users
///
/// * `locked`: Only retrieve locked users
#[serde(rename = "filter[status]")]
status: Option<UserStatus>,
}
impl<'a> From<&'a FilterParams> for UserFilter<'a> {
fn from(val: &'a FilterParams) -> Self {
let filter = UserFilter::default();
impl std::fmt::Display for FilterParams {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut sep = '?';
let filter = match val.can_request_admin {
Some(true) => filter.can_request_admin_only(),
Some(false) => filter.cannot_request_admin_only(),
None => filter,
};
if let Some(can_request_admin) = self.can_request_admin {
write!(f, "{sep}filter[can_request_admin]={can_request_admin}")?;
sep = '&';
}
if let Some(status) = self.status {
write!(f, "{sep}filter[status]={status}")?;
sep = '&';
}
let filter = match val.status {
Some(UserStatus::Active) => filter.active_only(),
Some(UserStatus::Locked) => filter.locked_only(),
None => filter,
};
filter
let _ = sep;
Ok(())
}
}
@ -100,6 +113,7 @@ impl IntoResponse for RouteError {
pub fn doc(operation: TransformOperation) -> TransformOperation {
operation
.id("listUsers")
.summary("List users")
.tag("user")
.response_with::<200, Json<PaginatedResponse<User>>, _>(|t| {
@ -120,9 +134,22 @@ pub fn doc(operation: TransformOperation) -> TransformOperation {
pub async fn handler(
CallContext { mut repo, .. }: CallContext,
Pagination(pagination): Pagination,
filter: FilterParams,
params: FilterParams,
) -> Result<Json<PaginatedResponse<User>>, RouteError> {
let filter = UserFilter::from(&filter);
let base = format!("{path}{params}", path = User::PATH);
let filter = UserFilter::default();
let filter = match params.can_request_admin {
Some(true) => filter.can_request_admin_only(),
Some(false) => filter.cannot_request_admin_only(),
None => filter,
};
let filter = match params.status {
Some(UserStatus::Active) => filter.active_only(),
Some(UserStatus::Locked) => filter.locked_only(),
None => filter,
};
let page = repo.user().list(filter, pagination).await?;
let count = repo.user().count(filter).await?;
@ -131,6 +158,6 @@ pub async fn handler(
page.map(User::from),
pagination,
count,
User::PATH,
&base,
)))
}

View File

@ -22,6 +22,7 @@
"user"
],
"summary": "List users",
"operationId": "listUsers",
"parameters": [
{
"in": "query",
@ -74,7 +75,9 @@
{
"in": "query",
"name": "filter[can_request_admin]",
"description": "Retrieve users with (or without) the `can_request_admin` flag set",
"schema": {
"description": "Retrieve users with (or without) the `can_request_admin` flag set",
"type": "boolean",
"nullable": true
},
@ -83,7 +86,9 @@
{
"in": "query",
"name": "filter[status]",
"description": "Retrieve the items with the given status\n\nDefaults to retrieve all users, including locked ones.\n\n* `active`: Only retrieve active users\n\n* `locked`: Only retrieve locked users",
"schema": {
"description": "Retrieve the items with the given status\n\nDefaults to retrieve all users, including locked ones.\n\n* `active`: Only retrieve active users\n\n* `locked`: Only retrieve locked users",
"$ref": "#/components/schemas/UserStatus",
"nullable": true
},
@ -162,6 +167,7 @@
"user"
],
"summary": "Get a user",
"operationId": "getUser",
"parameters": [
{
"in": "path",
@ -229,6 +235,7 @@
"user"
],
"summary": "Get a user by its username (localpart)",
"operationId": "getUserByUsername",
"parameters": [
{
"in": "path",
@ -355,35 +362,26 @@
"type": "string",
"pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$"
},
"FilterParams": {
"UserFilter": {
"type": "object",
"properties": {
"filter[can_request_admin]": {
"description": "Retrieve users with (or without) the `can_request_admin` flag set",
"type": "boolean",
"nullable": true
},
"filter[status]": {
"description": "Retrieve the items with the given status\n\nDefaults to retrieve all users, including locked ones.\n\n* `active`: Only retrieve active users\n\n* `locked`: Only retrieve locked users",
"$ref": "#/components/schemas/UserStatus",
"nullable": true
}
}
},
"UserStatus": {
"oneOf": [
{
"description": "The user is active",
"type": "string",
"enum": [
"active"
]
},
{
"description": "The user is locked",
"type": "string",
"enum": [
"locked"
]
}
"type": "string",
"enum": [
"active",
"locked"
]
},
"PaginatedResponse_for_User": {