mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-08-30 22:04:23 +00:00
feat: add an approximate member count to servers (#884)
* feat: add an approximate member count to servers Signed-off-by: Zomatree <me@zomatree.live> * fix: use approx member count on invites Signed-off-by: Zomatree <me@zomatree.live> --------- Signed-off-by: Zomatree <me@zomatree.live>
This commit is contained in:
@@ -307,7 +307,7 @@ impl State {
|
||||
Ok(EventV1::Ready {
|
||||
users: if fields.users { Some(users) } else { None },
|
||||
servers: if fields.servers {
|
||||
Some(servers.into_iter().map(Into::into).collect())
|
||||
Some(join_all(servers.into_iter().map(|server| server.into(db))).await)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
|
||||
@@ -176,7 +176,7 @@ impl Member {
|
||||
|
||||
EventV1::ServerCreate {
|
||||
id: server.id.clone(),
|
||||
server: server.clone().into(),
|
||||
server: server.clone().into(db).await,
|
||||
channels: channels
|
||||
.clone()
|
||||
.into_iter()
|
||||
@@ -317,9 +317,15 @@ impl Member {
|
||||
})
|
||||
{
|
||||
match intention {
|
||||
RemovalIntention::Leave => SystemMessage::UserLeft { id: self.id.user.clone() },
|
||||
RemovalIntention::Kick => SystemMessage::UserKicked { id: self.id.user.clone() },
|
||||
RemovalIntention::Ban => SystemMessage::UserBanned { id: self.id.user.clone() },
|
||||
RemovalIntention::Leave => SystemMessage::UserLeft {
|
||||
id: self.id.user.clone(),
|
||||
},
|
||||
RemovalIntention::Kick => SystemMessage::UserKicked {
|
||||
id: self.id.user.clone(),
|
||||
},
|
||||
RemovalIntention::Ban => SystemMessage::UserBanned {
|
||||
id: self.id.user.clone(),
|
||||
},
|
||||
}
|
||||
.into_message(id.to_string())
|
||||
// TODO: support notifications here in the future?
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use redis_kiss::{
|
||||
get_connection,
|
||||
redis::{SetExpiry, SetOptions},
|
||||
AsyncCommands,
|
||||
};
|
||||
use revolt_models::v0::{self, DataCreateServerChannel};
|
||||
use revolt_permissions::{OverrideField, DEFAULT_PERMISSION_SERVER};
|
||||
use revolt_result::Result;
|
||||
@@ -322,6 +327,30 @@ impl Server {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets a approximate count of the members in this server
|
||||
///
|
||||
/// this value is cached for one hour
|
||||
pub async fn get_approximate_member_count(&self, db: &Database) -> usize {
|
||||
let Ok(mut redis) = get_connection().await else {
|
||||
return 0;
|
||||
};
|
||||
let key = format!("member_count:{}", &self.id);
|
||||
|
||||
if let Some(count) = redis.get::<_, Option<usize>>(&key).await.ok().flatten() {
|
||||
count
|
||||
} else {
|
||||
let count = db.fetch_member_count(&self.id).await.unwrap_or(0);
|
||||
let _ = redis
|
||||
.set_options::<_, _, ()>(
|
||||
&key,
|
||||
count,
|
||||
SetOptions::default().with_expiration(SetExpiry::EX(60 * 60)),
|
||||
)
|
||||
.await;
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Role {
|
||||
|
||||
@@ -751,30 +751,29 @@ impl From<crate::RemovalIntention> for RemovalIntention {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Server> for Server {
|
||||
fn from(value: crate::Server) -> Self {
|
||||
impl crate::Server {
|
||||
pub async fn into(self, db: &Database) -> Server {
|
||||
let approximate_member_count = self.get_approximate_member_count(db).await;
|
||||
|
||||
Server {
|
||||
id: value.id,
|
||||
owner: value.owner,
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
channels: value.channels,
|
||||
categories: value
|
||||
id: self.id,
|
||||
owner: self.owner,
|
||||
name: self.name,
|
||||
description: self.description,
|
||||
channels: self.channels,
|
||||
categories: self
|
||||
.categories
|
||||
.map(|categories| categories.into_iter().map(|v| v.into()).collect()),
|
||||
system_messages: value.system_messages.map(|v| v.into()),
|
||||
roles: value
|
||||
.roles
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v.into()))
|
||||
.collect(),
|
||||
default_permissions: value.default_permissions,
|
||||
icon: value.icon.map(|f| f.into()),
|
||||
banner: value.banner.map(|f| f.into()),
|
||||
flags: value.flags.unwrap_or_default() as u32,
|
||||
nsfw: value.nsfw,
|
||||
analytics: value.analytics,
|
||||
discoverable: value.discoverable,
|
||||
system_messages: self.system_messages.map(|v| v.into()),
|
||||
roles: self.roles.into_iter().map(|(k, v)| (k, v.into())).collect(),
|
||||
default_permissions: self.default_permissions,
|
||||
icon: self.icon.map(|f| f.into()),
|
||||
banner: self.banner.map(|f| f.into()),
|
||||
flags: self.flags.unwrap_or_default() as u32,
|
||||
nsfw: self.nsfw,
|
||||
analytics: self.analytics,
|
||||
discoverable: self.discoverable,
|
||||
approximate_member_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -829,6 +828,7 @@ impl From<crate::PartialServer> for PartialServer {
|
||||
nsfw: value.nsfw,
|
||||
analytics: value.analytics,
|
||||
discoverable: value.discoverable,
|
||||
approximate_member_count: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,9 @@ auto_derived_partial!(
|
||||
serde(skip_serializing_if = "crate::if_false", default)
|
||||
)]
|
||||
pub discoverable: bool,
|
||||
|
||||
/// Approximate amount of members in the server
|
||||
pub approximate_member_count: usize,
|
||||
},
|
||||
"PartialServer"
|
||||
);
|
||||
|
||||
@@ -28,7 +28,7 @@ pub async fn fetch(db: &State<Database>, target: Reference<'_>) -> Result<Json<v
|
||||
|
||||
v0::InviteResponse::Server {
|
||||
code: target.id.to_string(),
|
||||
member_count: db.fetch_member_count(&server.id).await? as i64,
|
||||
member_count: server.get_approximate_member_count(db).await as i64,
|
||||
server_id: server.id,
|
||||
server_name: server.name,
|
||||
server_icon: server.icon.map(|f| f.into()),
|
||||
|
||||
@@ -28,7 +28,7 @@ pub async fn join(
|
||||
|
||||
Ok(Json(InviteJoinResponse::Server {
|
||||
channels: channels.into_iter().map(|c| c.into()).collect(),
|
||||
server: server.into(),
|
||||
server: server.into(db).await,
|
||||
}))
|
||||
}
|
||||
Invite::Group {
|
||||
|
||||
@@ -78,5 +78,5 @@ pub async fn set_role_permission(
|
||||
sync_voice_permissions(db, voice_client, &channel, Some(&server), Some(&role_id)).await?;
|
||||
}
|
||||
|
||||
Ok(Json(server.into()))
|
||||
Ok(Json(server.into(db).await))
|
||||
}
|
||||
|
||||
@@ -66,5 +66,5 @@ pub async fn set_default_server_permissions(
|
||||
sync_voice_permissions(db, voice_client, &channel, Some(&server), None).await?;
|
||||
}
|
||||
|
||||
Ok(Json(server.into()))
|
||||
Ok(Json(server.into(db).await))
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ pub async fn edit_role_ranks(
|
||||
sync_voice_permissions(db, voice_client, &channel, Some(&server), None).await?;
|
||||
}
|
||||
|
||||
Ok(Json(server.into()))
|
||||
Ok(Json(server.into(db).await))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -52,7 +52,7 @@ pub async fn create_server(
|
||||
let (_, channels) = Member::create(db, &server, &user, Some(channels)).await?;
|
||||
|
||||
Ok(Json(v0::CreateServerLegacyResponse {
|
||||
server: server.into(),
|
||||
server: server.into(db).await,
|
||||
channels: channels.into_iter().map(|channel| channel.into()).collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::HashSet;
|
||||
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
AuditLogEntryAction, Database, FieldsServer, File, PartialServer, User, ValidatedTicket
|
||||
AuditLogEntryAction, Database, FieldsServer, File, PartialServer, User, ValidatedTicket,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
@@ -50,7 +50,7 @@ pub async fn edit(
|
||||
&& data.owner.is_none()
|
||||
&& data.remove.is_empty()
|
||||
{
|
||||
return Ok(Json(server.into()));
|
||||
return Ok(Json(server.into(db).await));
|
||||
} else if data.name.is_some()
|
||||
|| data.description.is_some()
|
||||
|| data.icon.is_some()
|
||||
@@ -195,5 +195,5 @@ pub async fn edit(
|
||||
.insert(db, server.id.clone(), reason, user.id, None)
|
||||
.await;
|
||||
|
||||
Ok(Json(server.into()))
|
||||
Ok(Json(server.into(db).await))
|
||||
}
|
||||
|
||||
@@ -39,10 +39,12 @@ pub async fn fetch(
|
||||
}
|
||||
|
||||
Ok(Json(v0::FetchServerResponse::ServerWithChannels {
|
||||
server: server.into(),
|
||||
server: server.into(db).await,
|
||||
channels: visible_channels,
|
||||
}))
|
||||
} else {
|
||||
Ok(Json(v0::FetchServerResponse::JustServer(server.into())))
|
||||
Ok(Json(v0::FetchServerResponse::JustServer(
|
||||
server.into(db).await,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user