1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Add server-side chat command to grant account permissions in-game

This commit is contained in:
NG (Graham)
2025-12-26 20:46:05 -05:00
parent 7f187dcb98
commit 5e05cbdb59
8 changed files with 368 additions and 177 deletions

View File

@@ -76,6 +76,7 @@ impl super::config::SelfValidator for ChatCommand {
self.op,
ChatOperation::BuiltIn(BuiltInChatOperation::Intercom(IntercomChatOperation::DevBroadcast))
| ChatOperation::BuiltIn(BuiltInChatOperation::Intercom(IntercomChatOperation::Maintenance))
| ChatOperation::BuiltIn(BuiltInChatOperation::System(SystemChatOperation::Permissions))
) {
if !matches!(self.permission, ChatPermission::Administrator | ChatPermission::Developer | ChatPermission::Royal) {
info.warn(crate::persist::config::ValidationMessage {
@@ -115,6 +116,7 @@ pub enum ChatOperation {
#[serde(tag = "built_in")]
pub enum BuiltInChatOperation {
Intercom(IntercomChatOperation),
System(SystemChatOperation),
OnlineUsers,
TotalUsers,
Stats,
@@ -130,6 +132,13 @@ pub enum IntercomChatOperation {
Maintenance,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "system")]
pub enum SystemChatOperation {
Permissions,
CheckPermissions,
}
fn default_pub_channs() -> Vec<String> {
vec![

View File

@@ -30,7 +30,7 @@ mod settings;
pub use settings::{Settings, QueueMode};
mod chat;
pub use chat::{ChatConfig, ChatCommand, ChatOperation, BuiltInChatOperation, IntercomChatOperation, ChatPermission};
pub use chat::{ChatConfig, ChatCommand, ChatOperation, BuiltInChatOperation, IntercomChatOperation, ChatPermission, SystemChatOperation};
mod vehicle_factory;
pub use vehicle_factory::{FactoryConfig, AdapterSettings, ArcFactorySettings};

View File

@@ -355,7 +355,7 @@ impl UserData {
}
}
fn check_perms_to_exec(&self, ty: &super::SanctionType) -> Result<(), i16> {
pub(super) fn check_perms_to_exec(&self, ty: &super::SanctionType) -> Result<(), i16> {
match ty {
super::SanctionType::Warn
| super::SanctionType::Mute
@@ -1186,177 +1186,3 @@ impl super::GameEventSetter for GameEventSetterImpl {
self.select_event_now(oj_rc_database::schema::game_event::EventVariant::Singleplayer).await
}
}
#[async_trait::async_trait]
impl super::ChatUser for UserData {
async fn subscribed_channels(&self) -> Result<polariton::operation::Typed<()>, i16> {
let channels = self.subscribed_channels_strings().await?;
log::info!("User is subscribed to channels {:?}", channels);
Ok(polariton::operation::Typed::Arr(polariton::operation::Arr {
ty: polariton::serdes::TypePrefix::HashMap, // hashtable
items: channels.into_iter().map(|name| crate::data::channel::ChatChannelInfo {
channel_name: name,
members: vec![
crate::data::channel::ChatChannelMember {
name: self.account.display_name.clone(),
use_custom_avatar: false,
state: crate::data::channel::ChatPlayerState::Idk0,
custom_avatar: Vec::default(),
avatar_id: 0,
},
],
channel_ty: crate::data::channel::ChatChannelType::Public,
}.as_transmissible()).collect()
}))
}
async fn subscribed_channels_strings(&self) -> Result<Vec<String>, i16> {
let channels = self.db.user_aux_by_user_id_and_descriptor(self.account.id, oj_rc_database::schema::user_aux::Descriptor::SubscribedChannels).await.map_err(|e| {
log::error!("Failed to retrieve SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?.ok_or_else(|| {
log::error!("Failed to find SubscribedChannels (user_aux) for user_id {}", self.account.id);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
let channels = serde_json::from_str::<Vec<String>>(&channels.data).map_err(|e| {
log::error!("Failed to parse SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
Ok(channels)
}
async fn add_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<polariton::operation::Typed<()>, i16> {
if let crate::data::channel::ChatChannelType::Public = channel_ty {
let mut sub_channels = self.subscribed_channels_strings().await?;
sub_channels.push(channel.clone());
let new_data = serde_json::to_string(&sub_channels).map_err(|e| {
log::error!("Failed to convert to JSON SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
self.db.update_user_aux_by_user_id_and_descriptor(oj_rc_database::schema::user_aux::ActiveModel {
data: oj_rc_database::sea_orm::ActiveValue::Set(new_data),
..Default::default()
}, self.account.id, oj_rc_database::schema::user_aux::Descriptor::SubscribedChannels).await.map_err(|e| {
log::error!("Failed to update SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
}
Ok(crate::data::channel::ChatChannelInfo {
channel_name: channel,
members: Vec::default(),
channel_ty,
}.as_transmissible())
}
async fn remove_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<(), i16> {
if let crate::data::channel::ChatChannelType::Public = channel_ty {
let mut sub_channels = self.subscribed_channels_strings().await?;
if let Some(index) = sub_channels.iter().position(|chann| chann == &channel) {
sub_channels.swap_remove(index);
let new_data = serde_json::to_string(&sub_channels).map_err(|e| {
log::error!("Failed to convert to JSON SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
self.db.update_user_aux_by_user_id_and_descriptor(oj_rc_database::schema::user_aux::ActiveModel {
data: oj_rc_database::sea_orm::ActiveValue::Set(new_data),
..Default::default()
}, self.account.id, oj_rc_database::schema::user_aux::Descriptor::SubscribedChannels).await.map_err(|e| {
log::error!("Failed to update SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
}
}
Ok(())
}
/*async fn has_pending_sanctions(&self) -> Result<bool, i16> {
let count = self.db.count_sanctions_to_ack_by_user_id_and_descriptor(self.account.id, oj_rc_database::schema::sanction::Descriptor::Warn).await.map_err(|e| {
log::error!("Failed to count pending sanctions for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
Ok(count != 0)
}*/
async fn get_sanctions(&self, username: String) -> Result<polariton::operation::Typed<()>, i16> {
let user_opt = self.db.user_by_display_name(username.clone()).await.map_err(|e| {
log::error!("Failed to retrieve user by username {} for user_id {}: {}", username, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
if let Some(user) = user_opt {
let sanctions = self.db.sanctions_by_user_id(user.id).await.map_err(|e| {
log::error!("Failed to retrieve sanctions by username {} for user_id {}: {}", username, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
Ok(polariton::operation::Typed::Arr(polariton::operation::Arr {
ty: polariton::serdes::TypePrefix::Str,
items: sanctions.into_iter().map(|x| {
let data = crate::data::sanction::SanctionJson {
type_: crate::data::sanction::SanctionType::from_db(x.descriptor),
reason: x.reason,
reporter: x.issuer_name,
issued: chrono::DateTime::from_timestamp(x.creation_time, 0).unwrap(),
};
polariton::operation::Typed::Str(data.as_json().into())
}).collect(),
}))
} else {
Err(crate::data::error_codes::ChatErrorCodes::DoesNotExist as i16)
}
}
async fn set_sanction(&self, sanction: super::SetSanction) -> Result<(), i16> {
self.check_perms_to_exec(&sanction.type_)?;
let user_opt = self.db.user_by_display_name(sanction.username.clone()).await.map_err(|e| {
log::error!("Failed to retrieve user by username {} for user_id {}: {}", sanction.username, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
if let Some(user) = user_opt {
if sanction.is_adding {
let now = chrono::Utc::now().timestamp();
let sanction_ty = crate::data::sanction::SanctionType::from_persist(sanction.type_).to_db();
let to_add = oj_rc_database::schema::sanction::ActiveModel {
user_id: oj_rc_database::sea_orm::ActiveValue::Set(user.id),
creation_time: oj_rc_database::sea_orm::ActiveValue::Set(now),
issuer_id: oj_rc_database::sea_orm::ActiveValue::Set(self.account.id),
issuer_name: oj_rc_database::sea_orm::ActiveValue::Set(self.account.display_name.clone()),
descriptor: oj_rc_database::sea_orm::ActiveValue::Set(sanction_ty.clone()),
reason: oj_rc_database::sea_orm::ActiveValue::Set(sanction.reason),
duration: oj_rc_database::sea_orm::ActiveValue::Set(if sanction.duration <= 0 { None } else { Some(sanction.duration as i64) }),
..Default::default()
};
if matches!(sanction_ty, oj_rc_database::schema::sanction::Descriptor::Ban) {
self.db.update_perms_by_user_id(oj_rc_database::schema::permissions::ActiveModel {
banned: oj_rc_database::sea_orm::ActiveValue::Set(true),
..Default::default()
}, user.id).await.map_err(|e| {
log::error!("Failed to update permissions (to ban) for user_id {} by user_id {}: {}", user.id, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
}
self.db.insert_sanction(to_add).await.map_err(|e| {
log::error!("Failed to insert sanction for user_id {} by user_id {}: {}", user.id, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
Ok(())
} else {
// FIXME
log::error!("Modifying sanctions is not currently supported");
Err(crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16)
}
} else {
Err(crate::data::error_codes::ChatErrorCodes::DoesNotExist as i16)
}
}
async fn get_total_registered_users(&self) -> Result<u64, polariton_server::operations::SimpleOpError> {
self.db.user_count().await
.map_err(|e| {
log::error!("Failed to retrieve total user count for {}: {}", self.account.id, e);
polariton_server::operations::SimpleOpError::with_message(
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16,
format!("Failed to retrieve total user count: {}", e),
)
})
}
}

View File

@@ -0,0 +1,217 @@
use super::account_json::UserData;
#[async_trait::async_trait]
impl super::ChatUser for UserData {
async fn subscribed_channels(&self) -> Result<polariton::operation::Typed<()>, i16> {
let channels = self.subscribed_channels_strings().await?;
log::info!("User is subscribed to channels {:?}", channels);
Ok(polariton::operation::Typed::Arr(polariton::operation::Arr {
ty: polariton::serdes::TypePrefix::HashMap, // hashtable
items: channels.into_iter().map(|name| crate::data::channel::ChatChannelInfo {
channel_name: name,
members: vec![
crate::data::channel::ChatChannelMember {
name: self.account.display_name.clone(),
use_custom_avatar: false,
state: crate::data::channel::ChatPlayerState::Idk0,
custom_avatar: Vec::default(),
avatar_id: 0,
},
],
channel_ty: crate::data::channel::ChatChannelType::Public,
}.as_transmissible()).collect()
}))
}
async fn subscribed_channels_strings(&self) -> Result<Vec<String>, i16> {
let channels = self.db.user_aux_by_user_id_and_descriptor(self.account.id, oj_rc_database::schema::user_aux::Descriptor::SubscribedChannels).await.map_err(|e| {
log::error!("Failed to retrieve SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?.ok_or_else(|| {
log::error!("Failed to find SubscribedChannels (user_aux) for user_id {}", self.account.id);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
let channels = serde_json::from_str::<Vec<String>>(&channels.data).map_err(|e| {
log::error!("Failed to parse SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
Ok(channels)
}
async fn add_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<polariton::operation::Typed<()>, i16> {
if let crate::data::channel::ChatChannelType::Public = channel_ty {
let mut sub_channels = self.subscribed_channels_strings().await?;
sub_channels.push(channel.clone());
let new_data = serde_json::to_string(&sub_channels).map_err(|e| {
log::error!("Failed to convert to JSON SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
self.db.update_user_aux_by_user_id_and_descriptor(oj_rc_database::schema::user_aux::ActiveModel {
data: oj_rc_database::sea_orm::ActiveValue::Set(new_data),
..Default::default()
}, self.account.id, oj_rc_database::schema::user_aux::Descriptor::SubscribedChannels).await.map_err(|e| {
log::error!("Failed to update SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
}
Ok(crate::data::channel::ChatChannelInfo {
channel_name: channel,
members: Vec::default(),
channel_ty,
}.as_transmissible())
}
async fn remove_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<(), i16> {
if let crate::data::channel::ChatChannelType::Public = channel_ty {
let mut sub_channels = self.subscribed_channels_strings().await?;
if let Some(index) = sub_channels.iter().position(|chann| chann == &channel) {
sub_channels.swap_remove(index);
let new_data = serde_json::to_string(&sub_channels).map_err(|e| {
log::error!("Failed to convert to JSON SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
self.db.update_user_aux_by_user_id_and_descriptor(oj_rc_database::schema::user_aux::ActiveModel {
data: oj_rc_database::sea_orm::ActiveValue::Set(new_data),
..Default::default()
}, self.account.id, oj_rc_database::schema::user_aux::Descriptor::SubscribedChannels).await.map_err(|e| {
log::error!("Failed to update SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
}
}
Ok(())
}
/*async fn has_pending_sanctions(&self) -> Result<bool, i16> {
let count = self.db.count_sanctions_to_ack_by_user_id_and_descriptor(self.account.id, oj_rc_database::schema::sanction::Descriptor::Warn).await.map_err(|e| {
log::error!("Failed to count pending sanctions for user_id {}: {}", self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
Ok(count != 0)
}*/
async fn get_sanctions(&self, username: String) -> Result<polariton::operation::Typed<()>, i16> {
let user_opt = self.db.user_by_display_name(username.clone()).await.map_err(|e| {
log::error!("Failed to retrieve user by username {} for user_id {}: {}", username, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
if let Some(user) = user_opt {
let sanctions = self.db.sanctions_by_user_id(user.id).await.map_err(|e| {
log::error!("Failed to retrieve sanctions by username {} for user_id {}: {}", username, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
Ok(polariton::operation::Typed::Arr(polariton::operation::Arr {
ty: polariton::serdes::TypePrefix::Str,
items: sanctions.into_iter().map(|x| {
let data = crate::data::sanction::SanctionJson {
type_: crate::data::sanction::SanctionType::from_db(x.descriptor),
reason: x.reason,
reporter: x.issuer_name,
issued: chrono::DateTime::from_timestamp(x.creation_time, 0).unwrap(),
};
polariton::operation::Typed::Str(data.as_json().into())
}).collect(),
}))
} else {
Err(crate::data::error_codes::ChatErrorCodes::DoesNotExist as i16)
}
}
async fn set_sanction(&self, sanction: super::SetSanction) -> Result<(), i16> {
self.check_perms_to_exec(&sanction.type_)?;
let user_opt = self.db.user_by_display_name(sanction.username.clone()).await.map_err(|e| {
log::error!("Failed to retrieve user by username {} for user_id {}: {}", sanction.username, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
if let Some(user) = user_opt {
if sanction.is_adding {
let now = chrono::Utc::now().timestamp();
let sanction_ty = crate::data::sanction::SanctionType::from_persist(sanction.type_).to_db();
let to_add = oj_rc_database::schema::sanction::ActiveModel {
user_id: oj_rc_database::sea_orm::ActiveValue::Set(user.id),
creation_time: oj_rc_database::sea_orm::ActiveValue::Set(now),
issuer_id: oj_rc_database::sea_orm::ActiveValue::Set(self.account.id),
issuer_name: oj_rc_database::sea_orm::ActiveValue::Set(self.account.display_name.clone()),
descriptor: oj_rc_database::sea_orm::ActiveValue::Set(sanction_ty.clone()),
reason: oj_rc_database::sea_orm::ActiveValue::Set(sanction.reason),
duration: oj_rc_database::sea_orm::ActiveValue::Set(if sanction.duration <= 0 { None } else { Some(sanction.duration as i64) }),
..Default::default()
};
if matches!(sanction_ty, oj_rc_database::schema::sanction::Descriptor::Ban) {
self.db.update_perms_by_user_id(oj_rc_database::schema::permissions::ActiveModel {
banned: oj_rc_database::sea_orm::ActiveValue::Set(true),
..Default::default()
}, user.id).await.map_err(|e| {
log::error!("Failed to update permissions (to ban) for user_id {} by user_id {}: {}", user.id, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
}
self.db.insert_sanction(to_add).await.map_err(|e| {
log::error!("Failed to insert sanction for user_id {} by user_id {}: {}", user.id, self.account.id, e);
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
})?;
Ok(())
} else {
// FIXME
log::error!("Modifying sanctions is not currently supported");
Err(crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16)
}
} else {
Err(crate::data::error_codes::ChatErrorCodes::DoesNotExist as i16)
}
}
async fn get_total_registered_users(&self) -> Result<u64, polariton_server::operations::SimpleOpError> {
self.db.user_count().await
.map_err(|e| {
log::error!("Failed to retrieve total user count for {}: {}", self.account.id, e);
polariton_server::operations::SimpleOpError::with_message(
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16,
format!("Failed to retrieve total user count: {}", e),
)
})
}
async fn set_permission(&self, username: String, permission: super::UserRole, value: bool) -> Result<(), polariton_server::operations::SimpleOpError> {
if !(self.perms.developer || self.perms.royalty || self.perms.administrator) {
// technically this should already be handled by the chat command permission check
// this is just extra insurance in case of a bad server configuration
return Err(polariton_server::operations::SimpleOpError::with_message(
crate::data::error_codes::ChatErrorCodes::AdminsOnly as i16,
format!("User {} cannot grant permissions for {}", self.account.id, username),
))
}
let account_opt = self.db.user_by_display_name(username.clone()).await.map_err(|e| {
log::error!("Failed to retrieve user {} to grant permission by user {}: {}", username, self.account.id, e);
polariton_server::operations::SimpleOpError::with_message(
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16,
format!("Failed to retrieve user for permission grant: {}", e),
)
})?;
if let Some(account) = account_opt {
self.db.update_perms_by_user_id(oj_rc_database::schema::permissions::ActiveModel {
id: oj_rc_database::sea_orm::ActiveValue::NotSet,
user_id: oj_rc_database::sea_orm::ActiveValue::NotSet,
moderator: if matches!(permission, super::UserRole::Moderator) { oj_rc_database::sea_orm::ActiveValue::Set(value) } else { oj_rc_database::sea_orm::ActiveValue::NotSet },
administrator: if matches!(permission, super::UserRole::Administrator) { oj_rc_database::sea_orm::ActiveValue::Set(value) } else { oj_rc_database::sea_orm::ActiveValue::NotSet },
developer: if matches!(permission, super::UserRole::Developer) { oj_rc_database::sea_orm::ActiveValue::Set(value) } else { oj_rc_database::sea_orm::ActiveValue::NotSet },
royalty: if matches!(permission, super::UserRole::Royalty) { oj_rc_database::sea_orm::ActiveValue::Set(value) } else { oj_rc_database::sea_orm::ActiveValue::NotSet },
banned: oj_rc_database::sea_orm::ActiveValue::NotSet,
}, account.id).await
.map_err(|e| {
log::error!("Failed to update permissions for user {} by user {}: {}", account.id, self.account.id, e);
polariton_server::operations::SimpleOpError::with_message(
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16,
format!("Failed to update user permissions: {}", e),
)
})?;
Ok(())
} else {
Err(polariton_server::operations::SimpleOpError::with_message(
crate::data::error_codes::ChatErrorCodes::DoesNotExist as i16,
format!("User {} not found", username),
))
}
}
}

View File

@@ -11,7 +11,7 @@ mod inventory;
pub use inventory::UnlockedParts;
mod traits;
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserInfo, UserLoginInfo, ExtraUserInfo, UserAuthenticator, NewSlotData, UserId, RegistrationInfo, VehicleUploadData, ChatUser, AvatarInfo, GetAvatarInfo, ControlData, ControlType, CustomisationData, GetCustomisationData, SetSanction, SanctionType, LobbyUser, GameDescriptor, PlayerLobbyDescriptor, MultiplayerUser, MultiplayerError, MultiplayerErrorCode, PlayerDescriptor, GameEventSetter, CurrentGameEvent, AuthError, IntercomUser, FakePlayers, ResolvedVehicle, CommonUser, IntercomListener};
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserInfo, UserLoginInfo, ExtraUserInfo, UserAuthenticator, NewSlotData, UserId, RegistrationInfo, VehicleUploadData, ChatUser, AvatarInfo, GetAvatarInfo, ControlData, ControlType, CustomisationData, GetCustomisationData, SetSanction, SanctionType, LobbyUser, GameDescriptor, PlayerLobbyDescriptor, MultiplayerUser, MultiplayerError, MultiplayerErrorCode, PlayerDescriptor, GameEventSetter, CurrentGameEvent, AuthError, IntercomUser, FakePlayers, ResolvedVehicle, CommonUser, IntercomListener, UserRole};
pub mod intercom;
pub use intercom::generate_token as generate_intercom_token;
@@ -20,6 +20,7 @@ mod multiplayer;
mod lobby;
pub use lobby::TeamChooser;
mod common;
mod chat;
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";

View File

@@ -207,6 +207,7 @@ pub trait ChatUser: CommonUser + IntercomUser {
async fn get_sanctions(&self, username: String) -> Result<polariton::operation::Typed<()>, i16>;
async fn set_sanction(&self, sanction: SetSanction) -> Result<(), i16>;
async fn get_total_registered_users(&self) -> Result<u64, polariton_server::operations::SimpleOpError>;
async fn set_permission(&self, username: String, permission: UserRole, value: bool) -> Result<(), polariton_server::operations::SimpleOpError>;
}
pub struct SetSanction {
@@ -238,6 +239,13 @@ impl SanctionType {
}
}
pub enum UserRole {
Moderator,
Administrator,
Developer,
Royalty,
}
#[async_trait::async_trait]
pub trait LobbyUser {
fn user_id(&self) -> i32;