feat: add abuse prevention and moderation (Phase 5.6)
Add server-side moderation service with report submission, user banning/unbanning, and admin listing endpoints. Add client-side user blocking with message filtering in ConversationStore. Server: - ModerationService domain logic (report, ban, unban, list) - Storage trait methods + FileBackedStore + SqlStore implementations - SQL migration 012_moderation.sql (reports + bans tables) - Error codes E031-E033 for moderation - Domain types for all moderation request/response pairs - 10 new tests (6 domain + 4 storage) SDK: - blocked_users table in ConversationStore - block_user, unblock_user, is_blocked, list_blocked methods - load_recent_messages_filtered excludes blocked senders - QpqClient moderation convenience methods - 4 new tests for block/unblock/filter
This commit is contained in:
@@ -174,6 +174,46 @@ impl QpqClient {
|
||||
self.session_token.as_deref()
|
||||
}
|
||||
|
||||
// ── Moderation (client-side) ────────────────────────────────────────────
|
||||
|
||||
/// Block a user locally. Their messages will be hidden from display.
|
||||
pub fn block_user(&self, identity_key: &[u8], reason: &str) -> Result<(), SdkError> {
|
||||
let store = self.conversations()?;
|
||||
store
|
||||
.block_user(identity_key, reason)
|
||||
.map_err(|e| SdkError::Storage(e.to_string()))?;
|
||||
info!(identity = %hex::encode(identity_key), "user blocked");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unblock a user locally.
|
||||
pub fn unblock_user(&self, identity_key: &[u8]) -> Result<bool, SdkError> {
|
||||
let store = self.conversations()?;
|
||||
let removed = store
|
||||
.unblock_user(identity_key)
|
||||
.map_err(|e| SdkError::Storage(e.to_string()))?;
|
||||
if removed {
|
||||
info!(identity = %hex::encode(identity_key), "user unblocked");
|
||||
}
|
||||
Ok(removed)
|
||||
}
|
||||
|
||||
/// Check if a user is blocked locally.
|
||||
pub fn is_blocked(&self, identity_key: &[u8]) -> Result<bool, SdkError> {
|
||||
let store = self.conversations()?;
|
||||
store
|
||||
.is_blocked(identity_key)
|
||||
.map_err(|e| SdkError::Storage(e.to_string()))
|
||||
}
|
||||
|
||||
/// List all locally blocked users.
|
||||
pub fn list_blocked(&self) -> Result<Vec<crate::conversation::BlockedUser>, SdkError> {
|
||||
let store = self.conversations()?;
|
||||
store
|
||||
.list_blocked()
|
||||
.map_err(|e| SdkError::Storage(e.to_string()))
|
||||
}
|
||||
|
||||
/// Disconnect from the server.
|
||||
pub fn disconnect(&mut self) {
|
||||
if let Some(rpc) = self.rpc.take() {
|
||||
|
||||
Reference in New Issue
Block a user