mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Add minimum chat moderation to enable bans for #22
This commit is contained in:
47
rc_chat_room/src/operations/add_modify_sanction.rs
Normal file
47
rc_chat_room/src/operations/add_modify_sanction.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use polariton_server::operations::{SimpleOpError, SimpleOperation, SimpleOpImpl};
|
||||||
|
use polariton::operation::{ParameterTable, Typed};
|
||||||
|
|
||||||
|
const CODE: u8 = 7;
|
||||||
|
|
||||||
|
const SANCTION_TY_PARAM_KEY: u8 = 9; // int; in
|
||||||
|
const IS_ADDING_PARAM_KEY: u8 = 10; // bool; in
|
||||||
|
const DURATION_PARAM_KEY: u8 = 11; // int; in
|
||||||
|
const REASON_PARAM_KEY: u8 = 2; // str; in
|
||||||
|
const USERNAME_PARAM_KEY: u8 = 7; // str; in
|
||||||
|
|
||||||
|
pub(super) struct AddSanctionProvider;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl <C: Send + 'static> SimpleOperation<C> for AddSanctionProvider {
|
||||||
|
type User = crate::UserTy;
|
||||||
|
const CODE: u8 = CODE;
|
||||||
|
|
||||||
|
async fn handle(&self, params: ParameterTable<C>, user: &Self::User) -> Result<ParameterTable<C>, SimpleOpError> {
|
||||||
|
let mut params = params.to_dict();
|
||||||
|
if let Some(Typed::Int(sanction_ty)) = params.remove(&SANCTION_TY_PARAM_KEY) {
|
||||||
|
if let Some(Typed::Bool(is_adding)) = params.remove(&IS_ADDING_PARAM_KEY) {
|
||||||
|
if let Some(Typed::Int(duration)) = params.remove(&DURATION_PARAM_KEY) {
|
||||||
|
if let Some(Typed::Str(reason)) = params.remove(&REASON_PARAM_KEY) {
|
||||||
|
if let Some(Typed::Str(username)) = params.remove(&USERNAME_PARAM_KEY) {
|
||||||
|
let user_info = user.user()?;
|
||||||
|
let sanction = rc_core::persist::user::SetSanction {
|
||||||
|
type_: rc_core::persist::user::SanctionType::from_i32(sanction_ty)?,
|
||||||
|
is_adding,
|
||||||
|
duration,
|
||||||
|
reason: reason.string,
|
||||||
|
username: username.string,
|
||||||
|
};
|
||||||
|
user_info.set_sanction(sanction).await?;
|
||||||
|
return Ok(params.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err((rc_core::data::error_codes::ChatErrorCodes::UnexpectedError as i16).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn add_modify_sanction_provider<C: Send + 'static>() -> SimpleOpImpl<C, crate::UserTy, AddSanctionProvider> {
|
||||||
|
SimpleOpImpl::new(AddSanctionProvider)
|
||||||
|
}
|
||||||
30
rc_chat_room/src/operations/list_sanctions.rs
Normal file
30
rc_chat_room/src/operations/list_sanctions.rs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
use polariton_server::operations::{SimpleOpError, SimpleOperation, SimpleOpImpl};
|
||||||
|
use polariton::operation::{ParameterTable, Typed};
|
||||||
|
|
||||||
|
const CODE: u8 = 16;
|
||||||
|
|
||||||
|
const SANCTIONS_PARAM_KEY: u8 = 31; // arr of str; out
|
||||||
|
const USERNAME_PARAM_KEY: u8 = 22; // str; in
|
||||||
|
|
||||||
|
pub(super) struct GetSanctionsProvider;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl SimpleOperation<()> for GetSanctionsProvider {
|
||||||
|
type User = crate::UserTy;
|
||||||
|
const CODE: u8 = CODE;
|
||||||
|
|
||||||
|
async fn handle(&self, params: ParameterTable, user: &Self::User) -> Result<ParameterTable, SimpleOpError> {
|
||||||
|
let mut params = params.to_dict();
|
||||||
|
if let Some(Typed::Str(username)) = params.remove(&USERNAME_PARAM_KEY) {
|
||||||
|
let user_info = user.user()?;
|
||||||
|
let sanctions = user_info.get_sanctions(username.string).await?;
|
||||||
|
params.insert(SANCTIONS_PARAM_KEY, sanctions);
|
||||||
|
return Ok(params.into());
|
||||||
|
}
|
||||||
|
Err((rc_core::data::error_codes::ChatErrorCodes::UnexpectedError as i16).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn list_sanctions_provider() -> SimpleOpImpl<(), crate::UserTy, GetSanctionsProvider> {
|
||||||
|
SimpleOpImpl::new(GetSanctionsProvider)
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ mod public_channels;
|
|||||||
mod join_channel;
|
mod join_channel;
|
||||||
mod user_online;
|
mod user_online;
|
||||||
mod subscribed_channels;
|
mod subscribed_channels;
|
||||||
|
mod add_modify_sanction;
|
||||||
|
mod list_sanctions;
|
||||||
|
|
||||||
use polariton_server::operations::OperationsHandler;
|
use polariton_server::operations::OperationsHandler;
|
||||||
|
|
||||||
@@ -25,5 +27,7 @@ pub fn handler(chat_system: crate::state::chat::ChatImpl, conf: &rc_core::persis
|
|||||||
.add(send_message::send_private_message_handler(chat_system.clone()))
|
.add(send_message::send_private_message_handler(chat_system.clone()))
|
||||||
.add(join_channel::leave_channel_provider(chat_system.clone()))
|
.add(join_channel::leave_channel_provider(chat_system.clone()))
|
||||||
.add(subscribed_channels::all_subbed_channels_provider())
|
.add(subscribed_channels::all_subbed_channels_provider())
|
||||||
|
.add(add_modify_sanction::add_modify_sanction_provider())
|
||||||
|
.add(list_sanctions::list_sanctions_provider())
|
||||||
//.add(polariton_server::operations::Ack::<00000, _>::default())
|
//.add(polariton_server::operations::Ack::<00000, _>::default())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,26 @@
|
|||||||
use polariton_server::operations::SimpleFunc;
|
use polariton_server::operations::{SimpleOpError, SimpleOperation, SimpleOpImpl};
|
||||||
use polariton::operation::{ParameterTable, Typed};
|
use polariton::operation::{ParameterTable, Typed};
|
||||||
|
|
||||||
|
const CODE: u8 = 15;
|
||||||
|
|
||||||
const PARAM_KEY: u8 = 28;
|
const PARAM_KEY: u8 = 28;
|
||||||
|
|
||||||
pub(super) fn pending_sanctions_checker() -> SimpleFunc<15, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
|
pub(super) struct PendingSanctionsProvider;
|
||||||
SimpleFunc::new(|params, _| {
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl <C: Send + 'static> SimpleOperation<C> for PendingSanctionsProvider {
|
||||||
|
type User = crate::UserTy;
|
||||||
|
const CODE: u8 = CODE;
|
||||||
|
|
||||||
|
async fn handle(&self, params: ParameterTable<C>, _user: &Self::User) -> Result<ParameterTable<C>, SimpleOpError> {
|
||||||
let mut params = params.to_dict();
|
let mut params = params.to_dict();
|
||||||
params.insert(PARAM_KEY, Typed::Bool(false.into()));
|
//let user_info = user.user()?;
|
||||||
|
//params.insert(PARAM_KEY, Typed::Bool(user_info.has_pending_sanctions().await?));
|
||||||
|
params.insert(PARAM_KEY, Typed::Bool(false));
|
||||||
Ok(params.into())
|
Ok(params.into())
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn pending_sanctions_checker<C: Send + 'static>() -> SimpleOpImpl<C, crate::UserTy, PendingSanctionsProvider> {
|
||||||
|
SimpleOpImpl::new(PendingSanctionsProvider)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ pub mod weapon_list;
|
|||||||
pub mod weapon_upgrade;
|
pub mod weapon_upgrade;
|
||||||
pub mod crf;
|
pub mod crf;
|
||||||
pub mod channel;
|
pub mod channel;
|
||||||
|
pub mod sanction;
|
||||||
|
|
||||||
pub mod error_codes;
|
pub mod error_codes;
|
||||||
|
|
||||||
|
|||||||
72
rc_core/src/data/sanction.rs
Normal file
72
rc_core/src/data/sanction.rs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct SanctionJson {
|
||||||
|
#[serde(rename="Type")]
|
||||||
|
pub type_: SanctionType,
|
||||||
|
#[serde(rename="Reason")]
|
||||||
|
pub reason: String,
|
||||||
|
#[serde(rename="Reporter")]
|
||||||
|
pub reporter: String,
|
||||||
|
#[serde(rename="Issued", serialize_with="serde_issued::serialize")]
|
||||||
|
pub issued: chrono::DateTime<chrono::Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SanctionJson {
|
||||||
|
pub fn as_json(&self) -> String {
|
||||||
|
serde_json::to_string(&self).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod serde_issued {
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
|
/*pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<DateTime<Utc>, D::Error> {
|
||||||
|
d.deserialize_str(todo!())
|
||||||
|
}*/
|
||||||
|
|
||||||
|
pub fn serialize<S: serde::Serializer>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
serializer.serialize_str(&dt.to_rfc2822())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
|
||||||
|
pub enum SanctionType {
|
||||||
|
Warning = 0,
|
||||||
|
Mute = 1,
|
||||||
|
Suspension = 2,
|
||||||
|
Note = 3,
|
||||||
|
Kick = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SanctionType {
|
||||||
|
pub(crate) fn from_db(t: rc_database::schema::sanction::Descriptor) -> Self {
|
||||||
|
match t {
|
||||||
|
rc_database::schema::sanction::Descriptor::Warn => Self::Warning,
|
||||||
|
rc_database::schema::sanction::Descriptor::Mute => Self::Mute,
|
||||||
|
rc_database::schema::sanction::Descriptor::Ban => Self::Suspension,
|
||||||
|
rc_database::schema::sanction::Descriptor::Note => Self::Note,
|
||||||
|
rc_database::schema::sanction::Descriptor::Kick => Self::Kick,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_db(self) -> rc_database::schema::sanction::Descriptor {
|
||||||
|
match self {
|
||||||
|
Self::Warning => rc_database::schema::sanction::Descriptor::Warn,
|
||||||
|
Self::Mute => rc_database::schema::sanction::Descriptor::Mute,
|
||||||
|
Self::Suspension => rc_database::schema::sanction::Descriptor::Ban,
|
||||||
|
Self::Note => rc_database::schema::sanction::Descriptor::Note,
|
||||||
|
Self::Kick => rc_database::schema::sanction::Descriptor::Kick,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_persist(t: crate::persist::user::SanctionType) -> Self {
|
||||||
|
match t {
|
||||||
|
crate::persist::user::SanctionType::Warn => Self::Warning,
|
||||||
|
crate::persist::user::SanctionType::Mute => Self::Mute,
|
||||||
|
crate::persist::user::SanctionType::Ban => Self::Suspension,
|
||||||
|
crate::persist::user::SanctionType::Note => Self::Note,
|
||||||
|
crate::persist::user::SanctionType::Kick => Self::Kick,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -198,6 +198,33 @@ impl UserData {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_perms_to_exec(&self, ty: &super::SanctionType) -> Result<(), i16> {
|
||||||
|
match ty {
|
||||||
|
super::SanctionType::Warn
|
||||||
|
| super::SanctionType::Mute
|
||||||
|
| super::SanctionType::Note => if self.has_any_elevated_perms() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(crate::data::error_codes::ChatErrorCodes::ModeratorsOnly as i16)
|
||||||
|
},
|
||||||
|
super::SanctionType::Ban
|
||||||
|
| super::SanctionType::Kick => if self.has_admin_or_better_perms() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(crate::data::error_codes::ChatErrorCodes::AdminsOnly as i16)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn has_any_elevated_perms(&self) -> bool {
|
||||||
|
self.perms.moderator | self.perms.administrator | self.perms.developer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_admin_or_better_perms(&self) -> bool {
|
||||||
|
self.perms.administrator | self.perms.developer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const INVALID_ROBOT_ERR: i16 = crate::data::error_codes::WebServicesError::InvalidRobot as i16; // 140
|
const INVALID_ROBOT_ERR: i16 = crate::data::error_codes::WebServicesError::InvalidRobot as i16; // 140
|
||||||
@@ -716,4 +743,83 @@ impl super::ChatUser for UserData {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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, 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 = rc_database::schema::sanction::ActiveModel {
|
||||||
|
user_id: rc_database::sea_orm::ActiveValue::Set(user.id),
|
||||||
|
creation_time: rc_database::sea_orm::ActiveValue::Set(now),
|
||||||
|
issuer_id: rc_database::sea_orm::ActiveValue::Set(self.account.id),
|
||||||
|
issuer_name: rc_database::sea_orm::ActiveValue::Set(self.account.display_name.clone()),
|
||||||
|
descriptor: rc_database::sea_orm::ActiveValue::Set(sanction_ty.clone()),
|
||||||
|
reason: rc_database::sea_orm::ActiveValue::Set(sanction.reason),
|
||||||
|
duration: rc_database::sea_orm::ActiveValue::Set(if sanction.duration <= 0 { None } else { Some(sanction.duration as i64) }),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
if matches!(sanction_ty, rc_database::schema::sanction::Descriptor::Ban) {
|
||||||
|
self.db.update_perms_by_user_id(rc_database::schema::permissions::ActiveModel {
|
||||||
|
banned: 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ mod inventory;
|
|||||||
pub use inventory::UnlockedParts;
|
pub use inventory::UnlockedParts;
|
||||||
|
|
||||||
mod traits;
|
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};
|
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};
|
||||||
|
|
||||||
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";
|
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";
|
||||||
|
|
||||||
|
|||||||
@@ -190,5 +190,36 @@ pub trait ChatUser {
|
|||||||
async fn subscribed_channels_strings(&self) -> Result<Vec<String>, i16>;
|
async fn subscribed_channels_strings(&self) -> Result<Vec<String>, i16>;
|
||||||
async fn add_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<polariton::operation::Typed<()>, i16>;
|
async fn add_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<polariton::operation::Typed<()>, i16>;
|
||||||
async fn remove_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<(), i16>;
|
async fn remove_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<(), i16>;
|
||||||
|
//async fn has_pending_sanctions(&self) -> Result<bool, i16>;
|
||||||
|
async fn get_sanctions(&self, username: String) -> Result<polariton::operation::Typed<()>, i16>;
|
||||||
|
async fn set_sanction(&self, sanction: SetSanction) -> Result<(), i16>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SetSanction {
|
||||||
|
pub is_adding: bool, // if false, it's modifying
|
||||||
|
pub type_: SanctionType,
|
||||||
|
pub duration: i32,
|
||||||
|
pub reason: String,
|
||||||
|
pub username: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SanctionType {
|
||||||
|
Warn = 0,
|
||||||
|
Mute = 1,
|
||||||
|
Ban = 2,
|
||||||
|
Note = 3,
|
||||||
|
Kick = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SanctionType {
|
||||||
|
pub fn from_i32(i: i32) -> Result<Self, i16> {
|
||||||
|
match i {
|
||||||
|
0 => Ok(Self::Warn),
|
||||||
|
1 => Ok(Self::Mute),
|
||||||
|
2 => Ok(Self::Ban),
|
||||||
|
3 => Ok(Self::Note),
|
||||||
|
4 => Ok(Self::Kick),
|
||||||
|
_ => Err(crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
impl MigrationName for Migration {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"m20250529_000001_create_sanction_table"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
// Define how to apply this migration: Create the Sanctions table.
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(crate::schema::sanction::Entity)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(crate::schema::sanction::Column::Id)
|
||||||
|
.unsigned()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::UserId).unsigned().not_null())
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("fk-sanction-user_id")
|
||||||
|
.from(crate::schema::sanction::Entity, crate::schema::sanction::Column::UserId)
|
||||||
|
.to(crate::schema::user::Entity, crate::schema::user::Column::Id),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::CreationTime).big_integer().not_null())
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::IssuerId).unsigned().not_null())
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("fk-sanction-issuer_id")
|
||||||
|
.from(crate::schema::sanction::Entity, crate::schema::sanction::Column::IssuerId)
|
||||||
|
.to(crate::schema::user::Entity, crate::schema::user::Column::Id),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::IssuerName).string().not_null())
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::Descriptor).string().not_null())
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::Reason).string().not_null())
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::Duration).big_integer())
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::Acknowledged).big_integer())
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::AppealerId).unsigned())
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("fk-sanction-appealer_id")
|
||||||
|
.from(crate::schema::sanction::Entity, crate::schema::sanction::Column::AppealerId)
|
||||||
|
.to(crate::schema::user::Entity, crate::schema::user::Column::Id),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(crate::schema::sanction::Column::AppealTime).big_integer())
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define how to rollback this migration: Drop the Sanctions table.
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(crate::schema::sanction::Entity).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ mod m20250424_000003_create_garage_table;
|
|||||||
mod m20250424_000004_create_user_aux_table;
|
mod m20250424_000004_create_user_aux_table;
|
||||||
mod m20250424_000005_create_campaign_tables;
|
mod m20250424_000005_create_campaign_tables;
|
||||||
mod m20250526_000001_add_garage_customisation;
|
mod m20250526_000001_add_garage_customisation;
|
||||||
|
mod m20250529_000001_create_sanction_table;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ impl MigratorTrait for Migrator {
|
|||||||
Box::new(m20250424_000004_create_user_aux_table::Migration),
|
Box::new(m20250424_000004_create_user_aux_table::Migration),
|
||||||
Box::new(m20250424_000005_create_campaign_tables::Migration),
|
Box::new(m20250424_000005_create_campaign_tables::Migration),
|
||||||
Box::new(m20250526_000001_add_garage_customisation::Migration),
|
Box::new(m20250526_000001_add_garage_customisation::Migration),
|
||||||
|
Box::new(m20250529_000001_create_sanction_table::Migration),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ pub mod garage;
|
|||||||
pub mod campaign;
|
pub mod campaign;
|
||||||
pub mod campaign_difficulty_completion;
|
pub mod campaign_difficulty_completion;
|
||||||
pub mod common_query;
|
pub mod common_query;
|
||||||
|
pub mod sanction;
|
||||||
|
|
||||||
pub fn parse_int_csv(s: &str) -> Vec<u32> {
|
pub fn parse_int_csv(s: &str) -> Vec<u32> {
|
||||||
s.split(',').filter_map(|i_as_s| {
|
s.split(',').filter_map(|i_as_s| {
|
||||||
|
|||||||
46
rc_database/src/schema/sanction.rs
Normal file
46
rc_database/src/schema/sanction.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "sanctions")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub id: u32,
|
||||||
|
pub user_id: u32,
|
||||||
|
pub creation_time: i64, // seconds since unix epoch
|
||||||
|
pub issuer_id: u32,
|
||||||
|
pub issuer_name: String,
|
||||||
|
pub descriptor: Descriptor,
|
||||||
|
pub reason: String,
|
||||||
|
pub duration: Option<i64>, // seconds after creation_time (null means permanent or irrelevant)
|
||||||
|
pub acknowledged: Option<i64>, // seconds since unix epoch
|
||||||
|
pub appealer_id: Option<u32>, // moderator who approved appeal
|
||||||
|
pub appeal_time: Option<i64>, // seconds since unix epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::user::Entity",
|
||||||
|
from = "Column::UserId",
|
||||||
|
to = "super::user::Column::Id"
|
||||||
|
)]
|
||||||
|
User,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::user::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::User.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
||||||
|
#[sea_orm(rs_type = "String", db_type = "String(StringLen::None)", rename_all = "PascalCase")]
|
||||||
|
pub enum Descriptor {
|
||||||
|
Warn,
|
||||||
|
Mute,
|
||||||
|
Ban,
|
||||||
|
Note,
|
||||||
|
Kick,
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use sea_orm_migration::MigratorTrait;
|
use sea_orm_migration::MigratorTrait;
|
||||||
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, TransactionTrait};
|
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect, TransactionTrait};
|
||||||
|
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
orm: sea_orm::DatabaseConnection,
|
orm: sea_orm::DatabaseConnection,
|
||||||
@@ -105,6 +105,24 @@ impl Database {
|
|||||||
entity.insert(&self.orm).await
|
entity.insert(&self.orm).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn update_perms_by_user_id(&self, mut entity: crate::schema::permissions::ActiveModel, user_id: u32) -> Result<Option<crate::schema::permissions::Model>, sea_orm::DbErr> {
|
||||||
|
let id_opt = crate::schema::permissions::Entity::find()
|
||||||
|
.select_only()
|
||||||
|
.column(crate::schema::permissions::Column::Id)
|
||||||
|
.filter(crate::schema::permissions::Column::UserId.eq(user_id))
|
||||||
|
.into_model::<crate::schema::common_query::Id>()
|
||||||
|
.one(&self.orm)
|
||||||
|
.await?;
|
||||||
|
if let Some(id) = id_opt {
|
||||||
|
entity.id = sea_orm::ActiveValue::Set(id.id);
|
||||||
|
Ok(Some(crate::schema::permissions::Entity::update(entity)
|
||||||
|
.exec(&self.orm)
|
||||||
|
.await?))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn garage_max_slot_by_user_id(&self, user_id: u32) -> Result<u32, sea_orm::DbErr> {
|
pub async fn garage_max_slot_by_user_id(&self, user_id: u32) -> Result<u32, sea_orm::DbErr> {
|
||||||
let result = crate::schema::garage::Entity::find()
|
let result = crate::schema::garage::Entity::find()
|
||||||
.select_only()
|
.select_only()
|
||||||
@@ -227,4 +245,26 @@ impl Database {
|
|||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn count_sanctions_to_ack_by_user_id_and_descriptor(&self, user_id: u32, desc: crate::schema::sanction::Descriptor) -> Result<u64, sea_orm::DbErr> {
|
||||||
|
crate::schema::sanction::Entity::find()
|
||||||
|
.filter(crate::schema::sanction::Column::UserId.eq(user_id))
|
||||||
|
.filter(crate::schema::sanction::Column::Descriptor.eq(desc))
|
||||||
|
.filter(crate::schema::sanction::Column::Acknowledged.is_null())
|
||||||
|
.count(&self.orm)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sanctions_by_user_id(&self, user_id: u32) -> Result<Vec<crate::schema::sanction::Model>, sea_orm::DbErr> {
|
||||||
|
crate::schema::sanction::Entity::find()
|
||||||
|
.filter(crate::schema::sanction::Column::UserId.eq(user_id))
|
||||||
|
.filter(crate::schema::sanction::Column::Acknowledged.is_null())
|
||||||
|
.order_by_asc(crate::schema::sanction::Column::CreationTime)
|
||||||
|
.all(&self.orm)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn insert_sanction(&self, entity: crate::schema::sanction::ActiveModel) -> Result<crate::schema::sanction::Model, sea_orm::DbErr> {
|
||||||
|
entity.insert(&self.orm).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy>
|
|||||||
.add(polariton_server::operations::Ack::<152, _>::default()) // custom game player state changed (188 is desired state)
|
.add(polariton_server::operations::Ack::<152, _>::default()) // custom game player state changed (188 is desired state)
|
||||||
.add(custom_games_invite::pending_invite_provider())
|
.add(custom_games_invite::pending_invite_provider())
|
||||||
.add(chat_settings::chat_settings_provider())
|
.add(chat_settings::chat_settings_provider())
|
||||||
|
.add(polariton_server::operations::Ack::<19, _>::default()) // save chat settings
|
||||||
.add(prebuilt_robots::garage_robot_data_provider())
|
.add(prebuilt_robots::garage_robot_data_provider())
|
||||||
.add(prebuilt_colours::garage_colour_combo_provider())
|
.add(prebuilt_colours::garage_colour_combo_provider())
|
||||||
.add(robopass_preview_items::robopass_preview_provider())
|
.add(robopass_preview_items::robopass_preview_provider())
|
||||||
|
|||||||
Reference in New Issue
Block a user