diff --git a/server/central/src/db/dbimpl.rs b/server/central/src/db/dbimpl.rs index 7ceed731f..bbe30f5ec 100644 --- a/server/central/src/db/dbimpl.rs +++ b/server/central/src/db/dbimpl.rs @@ -1,7 +1,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use globed_shared::{debug, AdminPunishUserAction, PunishmentType, ServerUserEntry, UserPunishment}; -use rocket_db_pools::sqlx::{query_as, Result}; +use globed_shared::{AdminPunishUserAction, PunishmentType, ServerUserEntry, UserPunishment}; +use rocket_db_pools::sqlx::{Result, query_as}; use serde::Serialize; use sqlx::{prelude::*, query, query_scalar, sqlite::SqliteRow}; @@ -36,6 +36,7 @@ impl<'r> FromRow<'r, SqliteRow> for UserEntryWrapper { admin_password_hash, active_mute, active_ban, + punishment_count: 0, // this will be initialized later })) } } @@ -217,26 +218,7 @@ impl GlobedDb { Ok(()) } - async fn migrate_admin_password(&self, user: &mut ServerUserEntry) -> Result<()> { - if let Some(password) = user.admin_password.as_ref() { - let hash = globed_shared::generate_argon2_hash(password); - debug!("generating hash for password {password}: {hash}"); - - query("UPDATE users SET admin_password = NULL, admin_password_hash = ? WHERE account_id = ?") - .bind(&hash) - .bind(user.account_id) - .execute(&self.0) - .await?; - - user.admin_password_hash = Some(hash); - }; - - user.admin_password = None; - - Ok(()) - } - - /// Convert a `Option` into `Option` and expire their ban/mute if needed. + /// Convert a `Option` into `Option`, expire their ban/mute if needed, count amount of punishments, etc. #[inline] async fn unwrap_user(&self, user: Option) -> Result> { let mut user = user.map(|x| x.0); @@ -247,11 +229,12 @@ impl GlobedDb { self.maybe_expire_punishments(user).await?; } - // TODO: remove this in the near future - // migrate admin password to hashed form - if user.as_ref().is_some_and(|user| user.admin_password.is_some()) { - let user = user.as_mut().unwrap(); - self.migrate_admin_password(user).await?; + // count punishments + if let Some(user) = user.as_mut() { + user.punishment_count = query_scalar("SELECT COUNT(*) FROM punishments WHERE account_id = ?") + .bind(user.account_id) + .fetch_one(&self.0) + .await?; } Ok(user) diff --git a/server/game/src/client/translator/impls/mod.rs b/server/game/src/client/translator/impls/mod.rs index 9755e3815..f6cb43ee4 100644 --- a/server/game/src/client/translator/impls/mod.rs +++ b/server/game/src/client/translator/impls/mod.rs @@ -5,8 +5,8 @@ mod general; mod room; #[allow(unused)] -pub use super::{Packet, PacketTranslationError, Translatable, CURRENT_PROTOCOL}; +pub use super::{CURRENT_PROTOCOL, Packet, PacketTranslationError, Translatable}; #[allow(unused)] -pub use crate::data::{v13, v_current, Decodable, DynamicSize, Encodable, StaticSize}; +pub use crate::data::{Decodable, DynamicSize, Encodable, StaticSize, v_current}; #[allow(unused)] pub use v_current::{packets::*, types::*}; diff --git a/server/game/src/client/translator/mod.rs b/server/game/src/client/translator/mod.rs index a7810da93..48d839748 100644 --- a/server/game/src/client/translator/mod.rs +++ b/server/game/src/client/translator/mod.rs @@ -27,7 +27,7 @@ use esp::{ByteReader, Decodable, DecodeResult}; -pub use crate::data::{Packet, CURRENT_PROTOCOL}; +pub use crate::data::{CURRENT_PROTOCOL, Packet}; mod error; mod impls; diff --git a/server/game/src/data/mod.rs b/server/game/src/data/mod.rs index 84b50ce05..cffdb1dd0 100644 --- a/server/game/src/data/mod.rs +++ b/server/game/src/data/mod.rs @@ -13,11 +13,10 @@ pub use v_current::types; pub use packets::*; pub use types::*; -pub mod v13; pub mod v14; // change this to the latest version as needed -pub use v13 as v_current; +pub use v14 as v_current; // our own extension diff --git a/server/game/src/data/v13/mod.rs b/server/game/src/data/v13/mod.rs deleted file mode 100644 index 0843e254e..000000000 --- a/server/game/src/data/v13/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod packets; -pub mod types; - -pub use packets::*; -pub use types::*; - -pub const VERSION: u16 = 13; diff --git a/server/game/src/data/v13/packets/mod.rs b/server/game/src/data/v13/packets/mod.rs deleted file mode 100644 index 359c1e47d..000000000 --- a/server/game/src/data/v13/packets/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -pub mod client; -pub mod server; - -pub use client::*; -pub use server::*; - -use crate::data::*; - -pub trait Packet: PacketMetadata {} - -// god i hate this -pub trait PacketMetadata { - const PACKET_ID: u16; - const ENCRYPTED: bool; - const SHOULD_USE_TCP: bool; - const NAME: &'static str; -} - -#[derive(Encodable, Decodable, StaticSize)] -pub struct PacketHeader { - pub packet_id: u16, - pub encrypted: bool, -} - -impl PacketHeader { - #[inline] - pub const fn from_packet() -> Self { - Self { - packet_id: P::PACKET_ID, - encrypted: P::ENCRYPTED, - } - } - - pub const SIZE: usize = Self::ENCODED_SIZE; -} diff --git a/server/game/src/data/v13/types/mod.rs b/server/game/src/data/v13/types/mod.rs deleted file mode 100644 index 10bbba80c..000000000 --- a/server/game/src/data/v13/types/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -pub mod audio_frame; -pub mod cocos; -pub mod crypto; -pub mod game; -pub mod gd; -pub mod misc; -pub mod room; -pub mod user; - -use std::sync::atomic::AtomicI64; - -pub use audio_frame::*; -pub use cocos::*; -pub use crypto::*; -pub use esp::types::*; -pub use game::*; -pub use gd::*; -pub use misc::*; -pub use room::*; -pub use user::*; -pub type LevelId = i64; -pub type AtomicLevelId = AtomicI64; - -pub const fn is_editorcollab_level(id: LevelId) -> bool { - // if changing back to i32 for whatever reason, remove this condition - id > (2 as LevelId).pow(32) -} diff --git a/server/game/src/data/v13/packets/client/admin.rs b/server/game/src/data/v14/packets/client/admin.rs similarity index 100% rename from server/game/src/data/v13/packets/client/admin.rs rename to server/game/src/data/v14/packets/client/admin.rs diff --git a/server/game/src/data/v13/packets/client/connection.rs b/server/game/src/data/v14/packets/client/connection.rs similarity index 100% rename from server/game/src/data/v13/packets/client/connection.rs rename to server/game/src/data/v14/packets/client/connection.rs diff --git a/server/game/src/data/v13/packets/client/game.rs b/server/game/src/data/v14/packets/client/game.rs similarity index 100% rename from server/game/src/data/v13/packets/client/game.rs rename to server/game/src/data/v14/packets/client/game.rs diff --git a/server/game/src/data/v13/packets/client/general.rs b/server/game/src/data/v14/packets/client/general.rs similarity index 100% rename from server/game/src/data/v13/packets/client/general.rs rename to server/game/src/data/v14/packets/client/general.rs diff --git a/server/game/src/data/v13/packets/client/mod.rs b/server/game/src/data/v14/packets/client/mod.rs similarity index 100% rename from server/game/src/data/v13/packets/client/mod.rs rename to server/game/src/data/v14/packets/client/mod.rs diff --git a/server/game/src/data/v13/packets/client/room.rs b/server/game/src/data/v14/packets/client/room.rs similarity index 100% rename from server/game/src/data/v13/packets/client/room.rs rename to server/game/src/data/v14/packets/client/room.rs diff --git a/server/game/src/data/v14/packets/mod.rs b/server/game/src/data/v14/packets/mod.rs index f0c04b761..359c1e47d 100644 --- a/server/game/src/data/v14/packets/mod.rs +++ b/server/game/src/data/v14/packets/mod.rs @@ -1 +1,35 @@ -pub use crate::data::v13::packets::*; +pub mod client; +pub mod server; + +pub use client::*; +pub use server::*; + +use crate::data::*; + +pub trait Packet: PacketMetadata {} + +// god i hate this +pub trait PacketMetadata { + const PACKET_ID: u16; + const ENCRYPTED: bool; + const SHOULD_USE_TCP: bool; + const NAME: &'static str; +} + +#[derive(Encodable, Decodable, StaticSize)] +pub struct PacketHeader { + pub packet_id: u16, + pub encrypted: bool, +} + +impl PacketHeader { + #[inline] + pub const fn from_packet() -> Self { + Self { + packet_id: P::PACKET_ID, + encrypted: P::ENCRYPTED, + } + } + + pub const SIZE: usize = Self::ENCODED_SIZE; +} diff --git a/server/game/src/data/v13/packets/server/admin.rs b/server/game/src/data/v14/packets/server/admin.rs similarity index 100% rename from server/game/src/data/v13/packets/server/admin.rs rename to server/game/src/data/v14/packets/server/admin.rs diff --git a/server/game/src/data/v13/packets/server/connection.rs b/server/game/src/data/v14/packets/server/connection.rs similarity index 100% rename from server/game/src/data/v13/packets/server/connection.rs rename to server/game/src/data/v14/packets/server/connection.rs diff --git a/server/game/src/data/v13/packets/server/game.rs b/server/game/src/data/v14/packets/server/game.rs similarity index 100% rename from server/game/src/data/v13/packets/server/game.rs rename to server/game/src/data/v14/packets/server/game.rs diff --git a/server/game/src/data/v13/packets/server/general.rs b/server/game/src/data/v14/packets/server/general.rs similarity index 100% rename from server/game/src/data/v13/packets/server/general.rs rename to server/game/src/data/v14/packets/server/general.rs diff --git a/server/game/src/data/v13/packets/server/mod.rs b/server/game/src/data/v14/packets/server/mod.rs similarity index 100% rename from server/game/src/data/v13/packets/server/mod.rs rename to server/game/src/data/v14/packets/server/mod.rs diff --git a/server/game/src/data/v13/packets/server/room.rs b/server/game/src/data/v14/packets/server/room.rs similarity index 100% rename from server/game/src/data/v13/packets/server/room.rs rename to server/game/src/data/v14/packets/server/room.rs diff --git a/server/game/src/data/v13/types/audio_frame.rs b/server/game/src/data/v14/types/audio_frame.rs similarity index 100% rename from server/game/src/data/v13/types/audio_frame.rs rename to server/game/src/data/v14/types/audio_frame.rs diff --git a/server/game/src/data/v13/types/cocos.rs b/server/game/src/data/v14/types/cocos.rs similarity index 100% rename from server/game/src/data/v13/types/cocos.rs rename to server/game/src/data/v14/types/cocos.rs diff --git a/server/game/src/data/v13/types/crypto.rs b/server/game/src/data/v14/types/crypto.rs similarity index 100% rename from server/game/src/data/v13/types/crypto.rs rename to server/game/src/data/v14/types/crypto.rs diff --git a/server/game/src/data/v13/types/game.rs b/server/game/src/data/v14/types/game.rs similarity index 100% rename from server/game/src/data/v13/types/game.rs rename to server/game/src/data/v14/types/game.rs diff --git a/server/game/src/data/v13/types/gd.rs b/server/game/src/data/v14/types/gd.rs similarity index 100% rename from server/game/src/data/v13/types/gd.rs rename to server/game/src/data/v14/types/gd.rs diff --git a/server/game/src/data/v13/types/misc.rs b/server/game/src/data/v14/types/misc.rs similarity index 100% rename from server/game/src/data/v13/types/misc.rs rename to server/game/src/data/v14/types/misc.rs diff --git a/server/game/src/data/v14/types/mod.rs b/server/game/src/data/v14/types/mod.rs index 2387ec200..10bbba80c 100644 --- a/server/game/src/data/v14/types/mod.rs +++ b/server/game/src/data/v14/types/mod.rs @@ -1 +1,27 @@ -pub use crate::data::v13::types::*; +pub mod audio_frame; +pub mod cocos; +pub mod crypto; +pub mod game; +pub mod gd; +pub mod misc; +pub mod room; +pub mod user; + +use std::sync::atomic::AtomicI64; + +pub use audio_frame::*; +pub use cocos::*; +pub use crypto::*; +pub use esp::types::*; +pub use game::*; +pub use gd::*; +pub use misc::*; +pub use room::*; +pub use user::*; +pub type LevelId = i64; +pub type AtomicLevelId = AtomicI64; + +pub const fn is_editorcollab_level(id: LevelId) -> bool { + // if changing back to i32 for whatever reason, remove this condition + id > (2 as LevelId).pow(32) +} diff --git a/server/game/src/data/v13/types/room.rs b/server/game/src/data/v14/types/room.rs similarity index 100% rename from server/game/src/data/v13/types/room.rs rename to server/game/src/data/v14/types/room.rs diff --git a/server/game/src/data/v13/types/user.rs b/server/game/src/data/v14/types/user.rs similarity index 100% rename from server/game/src/data/v13/types/user.rs rename to server/game/src/data/v14/types/user.rs diff --git a/server/shared/src/data.rs b/server/shared/src/data.rs index 402a76368..5d1ce0bfd 100644 --- a/server/shared/src/data.rs +++ b/server/shared/src/data.rs @@ -2,8 +2,8 @@ use std::time::UNIX_EPOCH; use super::*; use argon2::{ - password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, Argon2, + password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString, rand_core::OsRng}, }; use esp::{FastString, InlineString}; use serde::{Deserialize, Serialize}; @@ -74,6 +74,7 @@ pub struct ServerUserEntry { pub admin_password_hash: Option, pub active_mute: Option, pub active_ban: Option, + pub punishment_count: u16, } // this is pure laziness i was just too lazy to get derive macros n shit into the central server @@ -108,6 +109,7 @@ impl ServerUserEntry { is_whitelisted: self.is_whitelisted, active_ban, active_mute, + punishment_count: self.punishment_count, } } @@ -157,6 +159,7 @@ pub struct UserEntry { pub is_whitelisted: bool, pub active_ban: Option, pub active_mute: Option, + pub punishment_count: u16, } impl UserEntry { diff --git a/src/data/types/admin.hpp b/src/data/types/admin.hpp index d8bd0cc07..b7c33554f 100644 --- a/src/data/types/admin.hpp +++ b/src/data/types/admin.hpp @@ -13,8 +13,9 @@ class UserEntry { const std::vector& userRoles, bool isWhitelisted, std::optional activeBan, - std::optional activeMute - ) : accountId(accountId), userName(userName), nameColor(nameColor), userRoles(userRoles), isWhitelisted(isWhitelisted), activeBan(activeBan), activeMute(activeMute) {} + std::optional activeMute, + uint16_t punishmentCount = 0 + ) : accountId(accountId), userName(userName), nameColor(nameColor), userRoles(userRoles), isWhitelisted(isWhitelisted), activeBan(activeBan), activeMute(activeMute), punishmentCount(punishmentCount) {} int accountId; std::optional userName; @@ -23,6 +24,7 @@ class UserEntry { bool isWhitelisted; std::optional activeBan; std::optional activeMute; + uint16_t punishmentCount; }; GLOBED_SERIALIZABLE_STRUCT( @@ -34,6 +36,7 @@ GLOBED_SERIALIZABLE_STRUCT( userRoles, isWhitelisted, activeBan, - activeMute + activeMute, + punishmentCount ) ); diff --git a/src/ui/menu/admin/user_popup.cpp b/src/ui/menu/admin/user_popup.cpp index 8f81f9843..dea6b5c4a 100644 --- a/src/ui/menu/admin/user_popup.cpp +++ b/src/ui/menu/admin/user_popup.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -236,6 +237,17 @@ void AdminUserPopup::onProfileLoaded() { // History button Build::createSpriteName("button-admin-history.png"_spr) .scale(btnScale) + .with([&](auto* btn) { + // if the user has past punishments, show a little badge with the count + if (userEntry.punishmentCount > 0) { + Build::create(userEntry.punishmentCount) + .pos(btn->getScaledContentSize() + CCPoint{1.f, 1.f}) + .scale(0.7f) + .id("count-icon"_spr) + .parent(btn) + ; + } + }) .intoMenuItem([this] { AdminPunishmentHistoryPopup::create(userEntry.accountId)->show(); })