Implement "report abuse" command.
This commit is contained in:
parent
590d4640dd
commit
a1495e6731
@ -193,7 +193,7 @@ impl DBPool {
|
||||
let conn = self.get_conn().await?;
|
||||
Ok(conn
|
||||
.query(
|
||||
"SELECT item, session, listener, message FROM sendqueue ORDER BY item ASC LIMIT 10",
|
||||
"SELECT item, session, listener, message FROM sendqueue WHERE sent_at IS NULL ORDER BY item ASC LIMIT 10",
|
||||
&[],
|
||||
)
|
||||
.await?
|
||||
@ -204,7 +204,18 @@ impl DBPool {
|
||||
|
||||
pub async fn delete_from_sendqueue(self: &DBPool, item: &SendqueueItem) -> DResult<()> {
|
||||
let conn = self.get_conn().await?;
|
||||
conn.execute("DELETE FROM sendqueue WHERE item=$1", &[&item.item])
|
||||
conn.execute(
|
||||
"UPDATE sendqueue SET sent_at = NOW() WHERE item=$1",
|
||||
&[&item.item],
|
||||
)
|
||||
.await?;
|
||||
conn.execute("DELETE FROM sendqueue WHERE item IN (\
|
||||
WITH item_rows AS (\
|
||||
SELECT item, row_number() OVER (ORDER BY sent_at DESC) AS rn FROM sendqueue
|
||||
WHERE sent_at IS NOT NULL AND \
|
||||
session = $1 AND listener = $2) \
|
||||
SELECT item FROM item_rows WHERE rn > 80 \
|
||||
)", &[&item.session.session, &item.session.listener])
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@ -1670,6 +1681,42 @@ impl DBTrans {
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn sendqueue_to_abusereport(
|
||||
&self,
|
||||
uuid: &Uuid,
|
||||
username: &str,
|
||||
session: &ListenerSession,
|
||||
) -> DResult<()> {
|
||||
self.pg_trans()?
|
||||
.execute(
|
||||
"INSERT INTO abuselog (id, triggered_by, logdata, expires) \
|
||||
VALUES ($1, $2, (\
|
||||
SELECT json_build_object(\
|
||||
'sendqueue', json_build_array(array_agg(json_build_object(\
|
||||
'message', message, 'sent_at', sent_at)))) FROM sendqueue WHERE \
|
||||
listener = $3 AND session = $4), \
|
||||
NOW() + INTERVAL '60 days')",
|
||||
&[&uuid, &username, &session.listener, &session.session],
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn clean_and_count_abusereports(&self, username: &str) -> DResult<i64> {
|
||||
let trans = self.pg_trans()?;
|
||||
trans
|
||||
.execute("DELETE FROM abuselog WHERE expires < NOW()", &[])
|
||||
.await?;
|
||||
Ok(trans
|
||||
.query_one(
|
||||
"SELECT COUNT(*) AS n FROM abuselog \
|
||||
WHERE triggered_by = $1",
|
||||
&[&username],
|
||||
)
|
||||
.await?
|
||||
.get("n"))
|
||||
}
|
||||
|
||||
pub async fn commit(mut self: Self) -> DResult<()> {
|
||||
let trans_opt = self.with_trans_mut(|t| std::mem::replace(t, None));
|
||||
if let Some(trans) = trans_opt {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::message_handler::ListenerSession;
|
||||
use crate::DResult;
|
||||
use crate::db::DBPool;
|
||||
use crate::message_handler::ListenerSession;
|
||||
use crate::models::session::Session;
|
||||
use crate::DResult;
|
||||
use ansi::ansi;
|
||||
use std::default::Default;
|
||||
use crate::models::session::Session;
|
||||
|
||||
// ANSI art version of the symbol we are legally required to display per:
|
||||
// https://www.legislation.gov.au/Details/F2017C00102
|
||||
@ -35,7 +35,14 @@ const AUS_RATING_SYMBOL: &'static str = "\x1b[48;5;234m \x1b[38;5;252;48;5;235m
|
||||
\x1b[49;38;5;233m▀▀\x1b[49;38;5;235m▀\x1b[49;38;5;242m▀\x1b[49;38;5;249m▀\x1b[49;38;5;254m▀\x1b[49;38;5;255m▀\x1b[49;38;5;253m▀▀\x1b[49;38;5;255m▀\x1b[49;38;5;254m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[49;38;5;255m▀\x1b[49;38;5;254m▀\x1b[49;38;5;7m▀\x1b[49;38;5;243m▀\x1b[49;38;5;235m▀\x1b[49;38;5;233m▀\x1b[49;38;5;234m▀\x1b[49;38;5;233m▀\x1b[m";
|
||||
|
||||
pub async fn handle(session: &ListenerSession, source: String, pool: &DBPool) -> DResult<()> {
|
||||
pool.start_session(session, &Session { source, ..Default::default() }).await?;
|
||||
pool.start_session(
|
||||
session,
|
||||
&Session {
|
||||
source,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
pool.queue_for_session(&session, Some(&(ansi!("\
|
||||
Welcome to <red>BlastMud<reset> - a text-based post-apocalyptic \
|
||||
game <bold>restricted to adults (18+)<reset>\r\n").to_owned() + AUS_RATING_SYMBOL + ansi!("\r\n\
|
||||
@ -47,7 +54,8 @@ pub async fn handle(session: &ListenerSession, source: String, pool: &DBPool) ->
|
||||
\t<bold>help<reset> to learn more.\r\n\
|
||||
[Please contact staff@blastmud.org with any feedback or suggestions on how to \r\n\
|
||||
improve Blastmud, to report any inappropriate user generated content or behaviour, or if you \r\n\
|
||||
need any other help from the game's operators].\r\n\
|
||||
need any other help from the game's operators; use <bold>report abuse<reset> immediately after \r\n\
|
||||
receiving any inappropriate message to store evidence].\r\n\
|
||||
Blastmud's privacy policy: https://blastmud.org/privacy/\r\n")))).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ mod quit;
|
||||
pub mod register;
|
||||
pub mod remove;
|
||||
pub mod rent;
|
||||
mod report;
|
||||
pub mod say;
|
||||
mod score;
|
||||
mod sign;
|
||||
@ -200,9 +201,9 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
|
||||
"reply" => page::VERB,
|
||||
|
||||
"put" => put::VERB,
|
||||
|
||||
"remove" => remove::VERB,
|
||||
"rent" => rent::VERB,
|
||||
"report" => report::VERB,
|
||||
|
||||
"\'" => say::VERB,
|
||||
"say" => say::VERB,
|
||||
|
41
blastmud_game/src/message_handler/user_commands/report.rs
Normal file
41
blastmud_game/src/message_handler/user_commands/report.rs
Normal file
@ -0,0 +1,41 @@
|
||||
use super::{get_user_or_fail, user_error, UResult, UserVerb, UserVerbRef, VerbContext};
|
||||
use ansi::ansi;
|
||||
use async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct Verb;
|
||||
#[async_trait]
|
||||
impl UserVerb for Verb {
|
||||
async fn handle(
|
||||
self: &Self,
|
||||
ctx: &mut VerbContext,
|
||||
_verb: &str,
|
||||
remaining: &str,
|
||||
) -> UResult<()> {
|
||||
if remaining != "abuse" {
|
||||
user_error(ansi!("Try <bold>report abuse<reset>.").to_owned())?;
|
||||
}
|
||||
|
||||
let user = get_user_or_fail(ctx)?;
|
||||
let username = user.username.to_lowercase();
|
||||
if ctx.trans.clean_and_count_abusereports(&username).await? > 10 {
|
||||
user_error(
|
||||
ansi!(
|
||||
"You have too many recent abuse reports logged to record any more. \
|
||||
Contact staff@blastmud.org for help."
|
||||
)
|
||||
.to_owned(),
|
||||
)?;
|
||||
}
|
||||
|
||||
let uuid = Uuid::new_v4();
|
||||
ctx.trans
|
||||
.sendqueue_to_abusereport(&uuid, &username, &ctx.session)
|
||||
.await?;
|
||||
ctx.trans.queue_for_session(ctx.session, Some(&format!("Up to the last 80 things we sent you since you logged in will now be retained for at least 60 days under reference {}. Send an email to staff@blastmud.org explaining exactly what happened, and include this reference. We'll be able to look it up and investigate.\n", &uuid))).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
static VERB_INT: Verb = Verb;
|
||||
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;
|
@ -7,7 +7,7 @@ CREATE DATABASE blast_schemaonly;
|
||||
|
||||
CREATE TABLE listeners (
|
||||
listener UUID NOT NULL PRIMARY KEY,
|
||||
last_seen TIMESTAMP WITH TIME ZONE
|
||||
last_seen TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE TABLE sessions (
|
||||
@ -48,9 +48,19 @@ CREATE UNLOGGED TABLE sendqueue (
|
||||
item BIGSERIAL NOT NULL PRIMARY KEY,
|
||||
session UUID NOT NULL REFERENCES sessions(session),
|
||||
listener UUID REFERENCES listeners(listener),
|
||||
message TEXT /* Nullable, null means disconnect */
|
||||
message TEXT, /* Nullable, null means disconnect */
|
||||
sent_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE TABLE abuselog (
|
||||
id UUID NOT NULL PRIMARY KEY,
|
||||
triggered_by TEXT NOT NULL,
|
||||
logdata JSONB NOT NULL,
|
||||
expires TIMESTAMPTZ NOT NULL
|
||||
);
|
||||
CREATE INDEX abuselog_by_triggerer ON abuselog(triggered_by);
|
||||
CREATE INDEX abuselog_by_expires ON abuselog(expires);
|
||||
|
||||
CREATE TABLE tasks (
|
||||
task_id BIGSERIAL NOT NULL PRIMARY KEY,
|
||||
details JSONB NOT NULL
|
||||
|
Loading…
Reference in New Issue
Block a user