mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
feat: Add user creation endpoint
This commit is contained in:
@@ -99,7 +99,7 @@ pub(crate) async fn register_route(
|
||||
.users
|
||||
.create_local_account(&user_id, password, identity.email)
|
||||
.await;
|
||||
|
||||
services.users.join_auto_join_rooms(&user_id).await;
|
||||
user_id
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
use axum::extract::State;
|
||||
use conduwuit::{
|
||||
Err, err, error, info,
|
||||
utils::{IterStream, stream::BroadbandExt},
|
||||
warn,
|
||||
};
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use ruma::UserId;
|
||||
use ruminuwuity::admin::continuwuity::users;
|
||||
use service::users::HashedPassword;
|
||||
|
||||
use crate::router::Ruma;
|
||||
|
||||
/// # `POST /_continuwuity/admin/v1/users/create`
|
||||
///
|
||||
/// Creates a new user.
|
||||
pub(crate) async fn create_user_route(
|
||||
State(services): State<crate::State>,
|
||||
body: Ruma<users::create::v1::Request>,
|
||||
) -> conduwuit::Result<users::create::v1::Response> {
|
||||
let sender_user = body.sender_user();
|
||||
|
||||
if !services.users.is_admin(sender_user).await {
|
||||
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
|
||||
}
|
||||
let user_id =
|
||||
&UserId::parse_with_server_name(&body.localpart, services.globals.server_name())?;
|
||||
if services.users.is_active_local(user_id).await {
|
||||
return Err!(Conflict("A user with this username already exists"));
|
||||
}
|
||||
|
||||
services
|
||||
.users
|
||||
.create_local_account(
|
||||
user_id,
|
||||
HashedPassword::new(&body.password)?,
|
||||
body.email
|
||||
.clone()
|
||||
.map(lettre::Address::try_from)
|
||||
.transpose()
|
||||
.map_err(|e| err!(Request(BadJson("Invalid email address: {e}"))))?,
|
||||
)
|
||||
.await;
|
||||
if body.suspended {
|
||||
services.users.suspend_account(user_id, sender_user).await;
|
||||
}
|
||||
if body.locked {
|
||||
services.users.lock_account(user_id, sender_user).await;
|
||||
}
|
||||
if body.login_disabled {
|
||||
services.users.disable_login(user_id);
|
||||
}
|
||||
if let Some(ref value) = body.display_name {
|
||||
services.users.set_profile_key(
|
||||
user_id,
|
||||
"displayname",
|
||||
Some(serde_json::to_value(value)?),
|
||||
);
|
||||
}
|
||||
if let Some(ref value) = body.avatar_url {
|
||||
services
|
||||
.users
|
||||
.set_profile_key(user_id, "avatar_url", Some(serde_json::to_value(value)?));
|
||||
}
|
||||
if body.admin {
|
||||
services
|
||||
.admin
|
||||
.make_user_admin(user_id)
|
||||
.await
|
||||
.inspect_err(|e| error!("failed to make new user {user_id} an admin: {e}"))
|
||||
.ok();
|
||||
}
|
||||
if !body.skip_auto_join {
|
||||
services.users.join_auto_join_rooms(user_id).await;
|
||||
}
|
||||
|
||||
body.auto_join_rooms
|
||||
.clone()
|
||||
.into_iter()
|
||||
.stream()
|
||||
.broad_filter_map(|room| async move {
|
||||
services
|
||||
.rooms
|
||||
.alias
|
||||
.resolve_with_servers(&room, None)
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
warn!(
|
||||
"Failed to resolve room alias to room ID when attempting to auto join \
|
||||
{room}: {e}"
|
||||
);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.for_each_concurrent(None, |(room_id, servers)| async move {
|
||||
match services
|
||||
.rooms
|
||||
.membership
|
||||
.join_room(
|
||||
user_id,
|
||||
&room_id,
|
||||
Some("Automatically joining this room upon registration".to_owned()),
|
||||
servers.as_ref(),
|
||||
)
|
||||
.boxed()
|
||||
.await
|
||||
{
|
||||
| Err(e) => {
|
||||
warn!("Failed to automatically join {user_id} to {room_id}: {e}");
|
||||
},
|
||||
| _ => {
|
||||
info!("Automatically joined room {user_id} to {room_id}");
|
||||
},
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
Ok(users::create::v1::Response::new(user_id.to_owned()))
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
mod create;
|
||||
mod list;
|
||||
|
||||
pub(crate) use list::list_users_route;
|
||||
pub(crate) use create::*;
|
||||
pub(crate) use list::*;
|
||||
|
||||
@@ -283,6 +283,7 @@ pub fn build(router: Router<State>, state: State) -> Router<State> {
|
||||
{
|
||||
router = router
|
||||
.ruma_route(&admin_api::users::list_users_route)
|
||||
.ruma_route(&admin_api::users::create_user_route)
|
||||
.ruma_route(&admin_api::rooms::ban_room)
|
||||
.ruma_route(&admin_api::rooms::legacy_list_rooms_route)
|
||||
.ruma_route(&admin_api::rooms::list_rooms_route);
|
||||
|
||||
@@ -23,6 +23,10 @@ pub mod v1 {
|
||||
/// The user's desired password. Cannot be blank.
|
||||
pub password: String,
|
||||
|
||||
/// The user's email address, if any.
|
||||
#[serde(default, skip_serializing_if = "ruma::serde::is_default")]
|
||||
pub email: Option<String>,
|
||||
|
||||
/// The display name to set upon creation.
|
||||
#[serde(default, skip_serializing_if = "ruma::serde::is_default")]
|
||||
pub display_name: Option<String>,
|
||||
@@ -80,6 +84,7 @@ pub mod v1 {
|
||||
Self {
|
||||
localpart,
|
||||
password,
|
||||
email: None,
|
||||
display_name: None,
|
||||
avatar_url: None,
|
||||
suspended: false,
|
||||
|
||||
@@ -229,6 +229,9 @@ impl Service {
|
||||
}
|
||||
|
||||
/// Create a new account for a local human or bot user.
|
||||
///
|
||||
/// Does not automatically join the user to auto join rooms. Use
|
||||
/// `join_auto_join_rooms` for that.
|
||||
pub async fn create_local_account(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
@@ -303,8 +306,11 @@ impl Service {
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
info!("Created new user account for {user_id}");
|
||||
}
|
||||
|
||||
// Autojoin the user to the configured autojoin rooms
|
||||
/// Autojoin the user to the configured autojoin rooms
|
||||
pub async fn join_auto_join_rooms(&self, user_id: &UserId) {
|
||||
for room in &self.services.config.auto_join_rooms {
|
||||
let Ok(room_id) = self.services.alias.resolve(room).await else {
|
||||
error!(
|
||||
@@ -320,9 +326,7 @@ impl Service {
|
||||
.server_in_room(self.services.globals.server_name(), &room_id)
|
||||
.await
|
||||
{
|
||||
warn!(
|
||||
"Skipping room {room} to automatically join as we have never joined before."
|
||||
);
|
||||
warn!("Skipping auto-room {room} as we have never joined before.");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -354,8 +358,6 @@ impl Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Created new user account for {user_id}");
|
||||
}
|
||||
|
||||
pub async fn determine_registration_user_id(
|
||||
|
||||
@@ -519,6 +519,7 @@ async fn complete_registration(
|
||||
.registration_tokens
|
||||
.mark_token_as_used(registration_token);
|
||||
}
|
||||
services.users.join_auto_join_rooms(&user_id).await;
|
||||
|
||||
let user_session = UserSession { user_id, last_login: SystemTime::now() };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user