mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-13 12:16:54 +00:00
feat(admin): Create user route
This commit is contained in:
7 files changed
+133
-3
No files matched your search
@@ -0,0 +1,69 @@
|
||||
use axum::extract::State;
|
||||
use conduwuit::{Err, error};
|
||||
use ruma::{api::client::profile::PropagateTo, profile::ProfileFieldValue};
|
||||
use ruminuwuity::admin::continuwuity::users::create::v1::{Request, Response};
|
||||
use service::users::{HashedPassword, ProfileFieldChange};
|
||||
|
||||
use crate::router::Ruma;
|
||||
|
||||
/// # `POST /_continuwuity/admin/v1/users`
|
||||
///
|
||||
/// Creates a new user on the homeserver.
|
||||
pub(crate) async fn create_user(
|
||||
State(services): State<crate::State>,
|
||||
body: Ruma<Request>,
|
||||
) -> conduwuit::Result<Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
if !services.users.is_admin(sender_user).await {
|
||||
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
|
||||
}
|
||||
|
||||
if !services.globals.user_is_local(&body.user_id) {
|
||||
return Err!(Request(InvalidParam("User ID does not belong to this server.")));
|
||||
}
|
||||
if services.users.status(&body.user_id).await.is_found() {
|
||||
return Err!(Request(UserInUse("An account with this user ID already exists.")));
|
||||
}
|
||||
|
||||
services
|
||||
.users
|
||||
.create_local_account(
|
||||
&body.user_id,
|
||||
body.password
|
||||
.as_ref()
|
||||
.and_then(|raw| HashedPassword::new(raw).ok()),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
if body.locked {
|
||||
services
|
||||
.users
|
||||
.lock_account(&body.user_id, sender_user)
|
||||
.await;
|
||||
}
|
||||
if body.suspended {
|
||||
services
|
||||
.users
|
||||
.suspend_account(&body.user_id, sender_user)
|
||||
.await;
|
||||
}
|
||||
for (key, value) in body.profile.clone().unwrap_or_default() {
|
||||
services
|
||||
.users
|
||||
.set_profile_field(
|
||||
&body.user_id,
|
||||
ProfileFieldChange::Set(ProfileFieldValue::new(&key, value)?),
|
||||
PropagateTo::All,
|
||||
)
|
||||
.await
|
||||
.inspect_err(|e| error!(error=?e, %key, "Failed to set profile field"))
|
||||
.ok();
|
||||
}
|
||||
if body.admin {
|
||||
services.admin.make_user_admin(&body.user_id).await?;
|
||||
}
|
||||
|
||||
Ok(Response::default())
|
||||
}
|
||||
@@ -11,7 +11,7 @@ use service::users::AccountStatus;
|
||||
|
||||
use crate::router::Ruma;
|
||||
|
||||
/// # `PUT /_continuwuity/admin/v1/users`
|
||||
/// # `GET /_continuwuity/admin/v1/users`
|
||||
///
|
||||
/// Lists users on this homeserver
|
||||
pub(crate) async fn list_users(
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
pub mod create;
|
||||
pub mod list;
|
||||
+2
-1
@@ -198,7 +198,8 @@ pub fn build(router: Router<State>, state: State) -> Router<State> {
|
||||
.route("/_continuwuity/server_version", get(client::continuwuity_server_version))
|
||||
.ruma_route(&admin::rooms::ban::ban_room)
|
||||
.ruma_route(&admin::rooms::list::list_rooms)
|
||||
.ruma_route(&admin::users::list::list_users);
|
||||
.ruma_route(&admin::users::list::list_users)
|
||||
.ruma_route(&admin::users::create::create_user);
|
||||
|
||||
if config.allow_federation {
|
||||
router = router
|
||||
|
||||
@@ -11,7 +11,7 @@ version.workspace = true
|
||||
path = "mod.rs"
|
||||
|
||||
[features]
|
||||
default = ["client", "server"]
|
||||
default = ["client", "server", "unstable-msc4484"]
|
||||
client = []
|
||||
server = []
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
pub mod v1 {
|
||||
|
||||
use ruma::{
|
||||
OwnedUserId,
|
||||
api::{OAuthClientScope, auth_scheme::AccessToken, request, response},
|
||||
metadata,
|
||||
profile::UserProfile,
|
||||
};
|
||||
|
||||
metadata! {
|
||||
method: POST,
|
||||
rate_limited: false,
|
||||
authentication: AccessToken,
|
||||
history: {
|
||||
1.0 => "/_continuwuity/admin/v1/users",
|
||||
},
|
||||
required_client_scopes: [OAuthClientScope::ServerAdministration]
|
||||
}
|
||||
|
||||
#[request]
|
||||
pub struct Request {
|
||||
/// The full user ID to create. Must belong to the server.
|
||||
pub user_id: OwnedUserId,
|
||||
/// The password to set for the new user.
|
||||
///
|
||||
/// If `None`, the user will not be able to log in.
|
||||
#[serde(default, skip_serializing_if = "ruma::serde::is_default")]
|
||||
pub password: Option<String>,
|
||||
/// The profile fields to set for the user. This can be used to set the
|
||||
/// new user's display name and profile picture.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub profile: Option<UserProfile>,
|
||||
#[serde(default, skip_serializing_if = "ruma::serde::is_default")]
|
||||
pub admin: bool,
|
||||
#[serde(default, skip_serializing_if = "ruma::serde::is_default")]
|
||||
pub suspended: bool,
|
||||
#[serde(default, skip_serializing_if = "ruma::serde::is_default")]
|
||||
pub locked: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[response]
|
||||
pub struct Response;
|
||||
|
||||
impl Request {
|
||||
#[must_use]
|
||||
pub fn new(user_id: OwnedUserId) -> Self {
|
||||
Self {
|
||||
user_id,
|
||||
password: None,
|
||||
profile: None,
|
||||
admin: false,
|
||||
suspended: false,
|
||||
locked: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod create;
|
||||
pub mod list;
|
||||
Reference in new issue
Block a user