mirror of
https://forgejo.ellis.link/continuwuation/continuwuity/
synced 2026-08-28 10:44:15 +00:00
style: Refactor remaining parts of admin service
This commit is contained in:
+100
-107
@@ -1,4 +1,4 @@
|
||||
use conduwuit::{Err, Result, debug, debug_info, error, implement, info};
|
||||
use conduwuit::{Err, Result, debug, debug_info, error, info};
|
||||
use ruma::events::room::message::RoomMessageEventContent;
|
||||
use tokio::time::{Duration, sleep};
|
||||
|
||||
@@ -6,127 +6,120 @@
|
||||
|
||||
pub(super) const SIGNAL: &str = "SIGUSR2";
|
||||
|
||||
/// Possibly spawn the terminal console at startup if configured.
|
||||
#[implement(super::Service)]
|
||||
pub(super) async fn console_auto_start(&self) {
|
||||
#[cfg(feature = "console")]
|
||||
if self.services.server.config.admin_console_automatic {
|
||||
// Allow more of the startup sequence to execute before spawning
|
||||
tokio::task::yield_now().await;
|
||||
self.console.start().await;
|
||||
impl super::Service {
|
||||
/// Possibly spawn the terminal console at startup if configured.
|
||||
pub(super) async fn console_auto_start(&self) {
|
||||
#[cfg(feature = "console")]
|
||||
if self.services.server.config.admin_console_automatic {
|
||||
// Allow more of the startup sequence to execute before spawning
|
||||
tokio::task::yield_now().await;
|
||||
self.console.start().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Shutdown the console when the admin worker terminates.
|
||||
#[implement(super::Service)]
|
||||
pub(super) async fn console_auto_stop(&self) {
|
||||
#[cfg(feature = "console")]
|
||||
self.console.close().await;
|
||||
}
|
||||
/// Shutdown the console when the admin worker terminates.
|
||||
pub(super) async fn console_auto_stop(&self) {
|
||||
#[cfg(feature = "console")]
|
||||
self.console.close().await;
|
||||
}
|
||||
|
||||
/// Execute admin commands after startup
|
||||
#[implement(super::Service)]
|
||||
pub async fn startup_execute(&self) -> Result {
|
||||
// List of commands to execute
|
||||
let commands = &self.services.server.config.admin_execute;
|
||||
/// Execute admin commands after startup
|
||||
pub async fn startup_execute(&self) -> Result {
|
||||
// List of commands to execute
|
||||
let commands = &self.services.server.config.admin_execute;
|
||||
|
||||
// Determine if we're running in smoketest-mode which will change some behaviors
|
||||
let smoketest = self.services.server.config.test.contains("smoke");
|
||||
// Determine if we're running in smoketest-mode which will change some behaviors
|
||||
let smoketest = self.services.server.config.test.contains("smoke");
|
||||
|
||||
// When true, errors are ignored and startup continues.
|
||||
let errors = !smoketest && self.services.server.config.admin_execute_errors_ignore;
|
||||
// When true, errors are ignored and startup continues.
|
||||
let errors = !smoketest && self.services.server.config.admin_execute_errors_ignore;
|
||||
|
||||
//TODO: remove this after run-states are broadcast
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
//TODO: remove this after run-states are broadcast
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
|
||||
for (i, command) in commands.iter().enumerate() {
|
||||
if let Err(e) = self.execute_command(i, command.clone()).await {
|
||||
if !errors {
|
||||
return Err(e);
|
||||
for (i, command) in commands.iter().enumerate() {
|
||||
if let Err(e) = self.execute_command(i, command.clone()).await {
|
||||
if !errors {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
|
||||
// The smoketest functionality is placed here for now and simply initiates
|
||||
// shutdown after all commands have executed.
|
||||
if smoketest {
|
||||
debug_info!("Smoketest mode. All commands complete. Shutting down now...");
|
||||
self.services
|
||||
.server
|
||||
.shutdown()
|
||||
.inspect_err(error::inspect_log)
|
||||
.expect("Error shutting down from smoketest");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Execute admin commands after signal
|
||||
#[implement(super::Service)]
|
||||
pub(super) async fn signal_execute(&self) -> Result {
|
||||
// List of commands to execute
|
||||
let commands = self.services.server.config.admin_signal_execute.clone();
|
||||
|
||||
// When true, errors are ignored and execution continues.
|
||||
let ignore_errors = self.services.server.config.admin_execute_errors_ignore;
|
||||
|
||||
for (i, command) in commands.iter().enumerate() {
|
||||
if let Err(e) = self.execute_command(i, command.clone()).await {
|
||||
if !ignore_errors {
|
||||
return Err(e);
|
||||
}
|
||||
// The smoketest functionality is placed here for now and simply initiates
|
||||
// shutdown after all commands have executed.
|
||||
if smoketest {
|
||||
debug_info!("Smoketest mode. All commands complete. Shutting down now...");
|
||||
self.services
|
||||
.server
|
||||
.shutdown()
|
||||
.inspect_err(error::inspect_log)
|
||||
.expect("Error shutting down from smoketest");
|
||||
}
|
||||
|
||||
tokio::task::yield_now().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
/// Execute admin commands after signal
|
||||
pub(super) async fn signal_execute(&self) -> Result {
|
||||
// List of commands to execute
|
||||
let commands = self.services.server.config.admin_signal_execute.clone();
|
||||
|
||||
/// Execute one admin command after startup or signal
|
||||
#[implement(super::Service)]
|
||||
async fn execute_command(&self, i: usize, command: String) -> Result {
|
||||
debug!("Execute command #{i}: executing {command:?}");
|
||||
// When true, errors are ignored and execution continues.
|
||||
let ignore_errors = self.services.server.config.admin_execute_errors_ignore;
|
||||
|
||||
match self
|
||||
.command_in_place(command, None, InvocationSource::Console)
|
||||
.await
|
||||
{
|
||||
| Ok(Some(output)) => Self::execute_command_output(i, &output),
|
||||
| Err(output) => Self::execute_command_error(i, &output),
|
||||
| Ok(None) => {
|
||||
info!("Execute command #{i} completed (no output).");
|
||||
Ok(())
|
||||
},
|
||||
for (i, command) in commands.iter().enumerate() {
|
||||
if let Err(e) = self.execute_command(i, command.clone()).await {
|
||||
if !ignore_errors {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Execute one admin command after startup or signal
|
||||
async fn execute_command(&self, i: usize, command: String) -> Result {
|
||||
debug!("Execute command #{i}: executing {command:?}");
|
||||
|
||||
match self
|
||||
.command_in_place(command, None, InvocationSource::Console)
|
||||
.await
|
||||
{
|
||||
| Ok(Some(output)) => Self::execute_command_output(i, &output),
|
||||
| Err(output) => Self::execute_command_error(i, &output),
|
||||
| Ok(None) => {
|
||||
info!("Execute command #{i} completed (no output).");
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "console")]
|
||||
fn execute_command_output(i: usize, content: &RoomMessageEventContent) -> Result {
|
||||
debug_info!("Execute command #{i} completed:");
|
||||
super::console::print(content.body());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "console")]
|
||||
fn execute_command_error(i: usize, content: &RoomMessageEventContent) -> Result {
|
||||
super::console::print_err(content.body());
|
||||
Err!(debug_error!("Execute command #{i} failed."))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "console"))]
|
||||
fn execute_command_output(i: usize, content: &RoomMessageEventContent) -> Result {
|
||||
info!("Execute command #{i} completed:\n{:#}", content.body());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "console"))]
|
||||
fn execute_command_error(i: usize, content: &RoomMessageEventContent) -> Result {
|
||||
Err!(error!("Execute command #{i} failed:\n{:#}", content.body()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "console")]
|
||||
#[implement(super::Service)]
|
||||
fn execute_command_output(i: usize, content: &RoomMessageEventContent) -> Result {
|
||||
debug_info!("Execute command #{i} completed:");
|
||||
super::console::print(content.body());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "console")]
|
||||
#[implement(super::Service)]
|
||||
fn execute_command_error(i: usize, content: &RoomMessageEventContent) -> Result {
|
||||
super::console::print_err(content.body());
|
||||
Err!(debug_error!("Execute command #{i} failed."))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "console"))]
|
||||
#[implement(super::Service)]
|
||||
fn execute_command_output(i: usize, content: &RoomMessageEventContent) -> Result {
|
||||
info!("Execute command #{i} completed:\n{:#}", content.body());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "console"))]
|
||||
#[implement(super::Service)]
|
||||
fn execute_command_error(i: usize, content: &RoomMessageEventContent) -> Result {
|
||||
Err!(error!("Execute command #{i} failed:\n{:#}", content.body()))
|
||||
}
|
||||
|
||||
+233
-199
@@ -1,10 +1,8 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use conduwuit::{
|
||||
Err, Result, debug_info, debug_warn, error, implement, matrix::pdu::PartialPdu, warn,
|
||||
};
|
||||
use conduwuit::{Err, Result, debug_info, debug_warn, error, matrix::pdu::PartialPdu, warn};
|
||||
use ruma::{
|
||||
RoomId, UserId,
|
||||
Int, RoomId, UserId,
|
||||
events::{
|
||||
RoomAccountDataEventType, StateEventType,
|
||||
room::{
|
||||
@@ -13,205 +11,241 @@
|
||||
},
|
||||
tag::{TagEvent, TagEventContent, TagInfo},
|
||||
},
|
||||
int,
|
||||
};
|
||||
|
||||
/// Invite the user to the conduwuit admin room.
|
||||
///
|
||||
/// This is equivalent to granting server admin privileges.
|
||||
#[implement(super::Service)]
|
||||
pub async fn make_user_admin(&self, user_id: &UserId) -> Result {
|
||||
let Ok(room_id) = self.get_admin_room().await else {
|
||||
debug_warn!(
|
||||
"make_user_admin was called without an admin room being available or created"
|
||||
);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let state_lock = self.services.state.mutex.lock(room_id.as_str()).await;
|
||||
|
||||
if self.services.state_cache.is_joined(user_id, &room_id).await {
|
||||
return Err!(debug_warn!("User is already joined in the admin room"));
|
||||
}
|
||||
if self
|
||||
.services
|
||||
.state_cache
|
||||
.is_invited(user_id, &room_id)
|
||||
.await
|
||||
{
|
||||
return Err!(debug_warn!("User is already pending an invitation to the admin room"));
|
||||
}
|
||||
|
||||
// Use the server user to grant the new admin's power level
|
||||
let server_user = self.services.globals.server_user.as_ref();
|
||||
|
||||
// if this is our local user, just forcefully join them in the room. otherwise,
|
||||
// invite the remote user.
|
||||
if self.services.globals.user_is_local(user_id) {
|
||||
debug_info!("Inviting local user {user_id} to admin room {room_id}");
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(
|
||||
String::from(user_id),
|
||||
&RoomMemberEventContent::new(MembershipState::Invite),
|
||||
),
|
||||
server_user,
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
debug_info!("Force joining local user {user_id} to admin room {room_id}");
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(
|
||||
String::from(user_id),
|
||||
&RoomMemberEventContent::new(MembershipState::Join),
|
||||
),
|
||||
user_id,
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
debug_info!("Inviting remote user {user_id} to admin room {room_id}");
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(
|
||||
user_id.to_string(),
|
||||
&RoomMemberEventContent::new(MembershipState::Invite),
|
||||
),
|
||||
server_user,
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// Set power levels
|
||||
let mut room_power_levels = self
|
||||
.services
|
||||
.state_accessor
|
||||
.room_state_get_content::<RoomPowerLevelsEventContent>(
|
||||
&room_id,
|
||||
&StateEventType::RoomPowerLevels,
|
||||
"",
|
||||
)
|
||||
.await
|
||||
.expect("admin room should have power levels");
|
||||
|
||||
room_power_levels
|
||||
.users
|
||||
.insert(server_user.into(), 69420.into());
|
||||
room_power_levels.users.insert(user_id.into(), 100.into());
|
||||
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(String::new(), &room_power_levels),
|
||||
server_user,
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Set room tag
|
||||
let room_tag = self.services.server.config.admin_room_tag.as_str();
|
||||
if !room_tag.is_empty() {
|
||||
if let Err(e) = self.set_room_tag(&room_id, user_id, room_tag).await {
|
||||
error!(%room_id, %user_id, %room_tag, "Failed to set tag for admin grant: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[implement(super::Service)]
|
||||
async fn set_room_tag(&self, room_id: &RoomId, user_id: &UserId, tag: &str) -> Result {
|
||||
let mut event = self
|
||||
.services
|
||||
.account_data
|
||||
.get_room(room_id, user_id, RoomAccountDataEventType::Tag)
|
||||
.await
|
||||
.unwrap_or_else(|_| TagEvent::new(TagEventContent::new(BTreeMap::new())));
|
||||
|
||||
event
|
||||
.content
|
||||
.tags
|
||||
.insert(tag.to_owned().into(), TagInfo::new());
|
||||
|
||||
self.services
|
||||
.account_data
|
||||
.update(
|
||||
Some(room_id),
|
||||
user_id,
|
||||
RoomAccountDataEventType::Tag,
|
||||
&serde_json::to_value(event)?,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Demote an admin, removing its rights.
|
||||
#[implement(super::Service)]
|
||||
pub async fn revoke_admin(&self, user_id: &UserId) -> Result {
|
||||
use MembershipState::{Invite, Join, Knock, Leave};
|
||||
|
||||
if self
|
||||
.services
|
||||
.server
|
||||
.config
|
||||
.admins_list
|
||||
.contains(&user_id.to_owned())
|
||||
{
|
||||
warn!(
|
||||
"Revoking the admin status of {user_id} will not work correctly as they are within \
|
||||
the admins_list config."
|
||||
);
|
||||
}
|
||||
|
||||
let Ok(room_id) = self.get_admin_room().await else {
|
||||
return Err!(error!("No admin room available or created."));
|
||||
};
|
||||
|
||||
let state_lock = self.services.state.mutex.lock(room_id.as_str()).await;
|
||||
|
||||
let mut member_content = match self
|
||||
.services
|
||||
.state_accessor
|
||||
.get_member(&room_id, user_id)
|
||||
.await
|
||||
{
|
||||
| Err(e) if e.is_not_found() => return Err!("{user_id} was never an admin."),
|
||||
|
||||
| Err(e) => return Err!(error!(?e, "Failure occurred while attempting revoke.")),
|
||||
|
||||
| Ok(event) if !matches!(event.membership, Invite | Knock | Join) => {
|
||||
return Err!("Cannot revoke {user_id} in membership state {:?}.", event.membership);
|
||||
},
|
||||
|
||||
| Ok(event) => {
|
||||
assert!(
|
||||
matches!(event.membership, Invite | Knock | Join),
|
||||
"Incorrect membership state to remove user."
|
||||
impl super::Service {
|
||||
/// Invite the user to the conduwuit admin room.
|
||||
///
|
||||
/// This is equivalent to granting server admin privileges.
|
||||
pub async fn make_user_admin(&self, user_id: &UserId) -> Result {
|
||||
let Ok(room_id) = self.get_admin_room().await else {
|
||||
debug_warn!(
|
||||
"make_user_admin was called without an admin room being available or created"
|
||||
);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
event
|
||||
},
|
||||
};
|
||||
let state_lock = self.services.state.mutex.lock(room_id.as_str()).await;
|
||||
|
||||
member_content.membership = Leave;
|
||||
member_content.reason = Some("Admin Revoked".to_owned());
|
||||
if self.services.state_cache.is_joined(user_id, &room_id).await {
|
||||
return Err!(debug_warn!("User is already joined in the admin room"));
|
||||
}
|
||||
if self
|
||||
.services
|
||||
.state_cache
|
||||
.is_invited(user_id, &room_id)
|
||||
.await
|
||||
{
|
||||
return Err!(debug_warn!("User is already pending an invitation to the admin room"));
|
||||
}
|
||||
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(user_id.to_string(), &member_content),
|
||||
self.services.globals.server_user.as_ref(),
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
// Use the server user to grant the new admin's power level
|
||||
let server_user = self.services.globals.server_user.as_ref();
|
||||
|
||||
// if this is our local user, just forcefully join them in the room. otherwise,
|
||||
// invite the remote user.
|
||||
if self.services.globals.user_is_local(user_id) {
|
||||
debug_info!("Inviting local user {user_id} to admin room {room_id}");
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(
|
||||
String::from(user_id),
|
||||
&RoomMemberEventContent::new(MembershipState::Invite),
|
||||
),
|
||||
server_user,
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
debug_info!("Force joining local user {user_id} to admin room {room_id}");
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(
|
||||
String::from(user_id),
|
||||
&RoomMemberEventContent::new(MembershipState::Join),
|
||||
),
|
||||
user_id,
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
debug_info!("Inviting remote user {user_id} to admin room {room_id}");
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(
|
||||
user_id.to_string(),
|
||||
&RoomMemberEventContent::new(MembershipState::Invite),
|
||||
),
|
||||
server_user,
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// Set power levels
|
||||
let mut room_power_levels = self
|
||||
.services
|
||||
.state_accessor
|
||||
.room_state_get_content::<RoomPowerLevelsEventContent>(
|
||||
&room_id,
|
||||
&StateEventType::RoomPowerLevels,
|
||||
"",
|
||||
)
|
||||
.await
|
||||
.expect("admin room should have power levels");
|
||||
|
||||
let server_user_power_level = room_power_levels
|
||||
.users
|
||||
.get(server_user)
|
||||
.copied()
|
||||
.unwrap_or(Int::MAX);
|
||||
room_power_levels
|
||||
.users
|
||||
.insert(user_id.into(), server_user_power_level.saturating_sub(int!(1)));
|
||||
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(String::new(), &room_power_levels),
|
||||
server_user,
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Set room tag
|
||||
let room_tag = self.services.server.config.admin_room_tag.as_str();
|
||||
if !room_tag.is_empty() {
|
||||
if let Err(e) = self.set_room_tag(&room_id, user_id, room_tag).await {
|
||||
error!(%room_id, %user_id, %room_tag, "Failed to set tag for admin grant: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_room_tag(&self, room_id: &RoomId, user_id: &UserId, tag: &str) -> Result {
|
||||
let mut event = self
|
||||
.services
|
||||
.account_data
|
||||
.get_room(room_id, user_id, RoomAccountDataEventType::Tag)
|
||||
.await
|
||||
.unwrap_or_else(|_| TagEvent::new(TagEventContent::new(BTreeMap::new())));
|
||||
|
||||
event
|
||||
.content
|
||||
.tags
|
||||
.insert(tag.to_owned().into(), TagInfo::new());
|
||||
|
||||
self.services
|
||||
.account_data
|
||||
.update(
|
||||
Some(room_id),
|
||||
user_id,
|
||||
RoomAccountDataEventType::Tag,
|
||||
&serde_json::to_value(event)?,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Demote an admin, removing its rights.
|
||||
pub async fn revoke_admin(&self, user_id: &UserId) -> Result {
|
||||
use MembershipState::{Invite, Join, Knock, Leave};
|
||||
|
||||
if self
|
||||
.services
|
||||
.server
|
||||
.config
|
||||
.admins_list
|
||||
.contains(&user_id.to_owned())
|
||||
{
|
||||
warn!(
|
||||
"Revoking the admin status of {user_id} will not work correctly as they are \
|
||||
within the admins_list config."
|
||||
);
|
||||
}
|
||||
|
||||
let Ok(room_id) = self.get_admin_room().await else {
|
||||
return Err!(error!("No admin room available or created."));
|
||||
};
|
||||
|
||||
let state_lock = self.services.state.mutex.lock(room_id.as_str()).await;
|
||||
|
||||
let mut room_power_levels = self
|
||||
.services
|
||||
.state_accessor
|
||||
.room_state_get_content::<RoomPowerLevelsEventContent>(
|
||||
&room_id,
|
||||
&StateEventType::RoomPowerLevels,
|
||||
"",
|
||||
)
|
||||
.await
|
||||
.expect("admin room should have power levels");
|
||||
if room_power_levels.users.remove(user_id).is_some() {
|
||||
// drop the target's power level
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(String::new(), &room_power_levels),
|
||||
self.services.globals.server_user.as_ref(),
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
error!(?e, "Failed to update power levels while revoking admin.");
|
||||
})
|
||||
.ok();
|
||||
// Don't treat this as fatal. removing them from the room is more
|
||||
// important.
|
||||
}
|
||||
|
||||
let mut member_content = match self
|
||||
.services
|
||||
.state_accessor
|
||||
.get_member(&room_id, user_id)
|
||||
.await
|
||||
{
|
||||
| Err(e) if e.is_not_found() => return Err!("{user_id} was never an admin."),
|
||||
|
||||
| Err(e) => return Err!(error!(?e, "Failure occurred while attempting revoke.")),
|
||||
|
||||
| Ok(event) if !matches!(event.membership, Invite | Knock | Join) => {
|
||||
return Err!(
|
||||
"Cannot revoke {user_id} in membership state {:?}.",
|
||||
event.membership
|
||||
);
|
||||
},
|
||||
|
||||
| Ok(event) => {
|
||||
assert!(
|
||||
matches!(event.membership, Invite | Knock | Join),
|
||||
"Incorrect membership state to remove user."
|
||||
);
|
||||
|
||||
event
|
||||
},
|
||||
};
|
||||
|
||||
member_content.membership = Leave;
|
||||
member_content.reason = Some("Admin Revoked".to_owned());
|
||||
|
||||
self.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PartialPdu::state(user_id.to_string(), &member_content),
|
||||
self.services.globals.server_user.as_ref(),
|
||||
Some(&room_id),
|
||||
&state_lock,
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
+11
-10
@@ -1,6 +1,6 @@
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use conduwuit::{Config, Result, err, implement, trace};
|
||||
use conduwuit::{Config, Result, err, trace};
|
||||
use either::Either;
|
||||
use ipaddress::IPAddress;
|
||||
use reqwest::redirect;
|
||||
@@ -141,6 +141,16 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
fn name(&self) -> &str { service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn valid_cidr_range(&self, ip: &IPAddress) -> bool {
|
||||
self.cidr_range_denylist
|
||||
.iter()
|
||||
.all(|cidr| !cidr.includes(ip))
|
||||
}
|
||||
}
|
||||
|
||||
fn base(config: &Config) -> Result<reqwest::ClientBuilder> {
|
||||
let mut builder = reqwest::Client::builder()
|
||||
.hickory_dns(true)
|
||||
@@ -227,12 +237,3 @@ fn builder_interface(
|
||||
Ok(builder)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[implement(Service)]
|
||||
pub fn valid_cidr_range(&self, ip: &IPAddress) -> bool {
|
||||
self.cidr_range_denylist
|
||||
.iter()
|
||||
.all(|cidr| !cidr.includes(ip))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user