Implement messaging to corps.
This commit is contained in:
parent
6c86599103
commit
d35bbbad53
@ -893,6 +893,24 @@ impl DBTrans {
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn get_default_corp_for_user(&self, username: &str) -> DResult<Option<(CorpId, Corp)>> {
|
||||
Ok(match self.pg_trans()?
|
||||
.query_opt("SELECT m.corp_id, c.details FROM corp_membership m \
|
||||
JOIN corps c ON c.corp_id = m.corp_id WHERE m.member_username = $1 \
|
||||
AND m.details->>'joined_at' IS NOT NULL \
|
||||
ORDER BY (m.details->>'priority')::int ASC NULLS LAST, \
|
||||
(m.details->>'joined_at') :: TIMESTAMPTZ ASC LIMIT 1",
|
||||
&[&username.to_lowercase()])
|
||||
.await? {
|
||||
None => None,
|
||||
Some(row) => match serde_json::from_value(row.get(1)) {
|
||||
Err(_) => None,
|
||||
Ok(j) =>
|
||||
Some((CorpId(row.get(0)), j))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn broadcast_to_corp<'a>(self: &'a Self,
|
||||
corp_id: &'a CorpId,
|
||||
|
@ -15,6 +15,7 @@ mod agree;
|
||||
mod allow;
|
||||
pub mod attack;
|
||||
mod buy;
|
||||
mod c;
|
||||
mod corp;
|
||||
pub mod drop;
|
||||
pub mod get;
|
||||
@ -119,6 +120,7 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
|
||||
|
||||
"attack" => attack::VERB,
|
||||
"buy" => buy::VERB,
|
||||
"c" => c::VERB,
|
||||
"corp" => corp::VERB,
|
||||
"drop" => drop::VERB,
|
||||
"get" => get::VERB,
|
||||
|
55
blastmud_game/src/message_handler/user_commands/c.rs
Normal file
55
blastmud_game/src/message_handler/user_commands/c.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use super::{VerbContext, UserVerb, UserVerbRef, UResult,
|
||||
get_user_or_fail, get_player_item_or_fail, user_error};
|
||||
use async_trait::async_trait;
|
||||
use crate::{
|
||||
models::corp::CorpCommType
|
||||
};
|
||||
use ansi::{ansi, ignore_special_characters};
|
||||
|
||||
pub struct Verb;
|
||||
#[async_trait]
|
||||
impl UserVerb for Verb {
|
||||
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> {
|
||||
let user = get_user_or_fail(ctx)?;
|
||||
|
||||
let (corp_id, corp, msg) = if remaining.starts_with("@") {
|
||||
match remaining[1..].split_once(" ") {
|
||||
None => user_error("Usage: c message (lowest ordered corp) or c @corpname message"
|
||||
.to_owned())?,
|
||||
Some((corpname, msg)) => {
|
||||
let (corp_id, corp, _) =
|
||||
match ctx.trans.match_user_corp_by_name(corpname.trim(), &user.username).await? {
|
||||
None => user_error("You don't seem to belong to a matching corp!".to_owned())?,
|
||||
Some(c) => c
|
||||
};
|
||||
(corp_id, corp, msg.trim())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let (corp_id, corp) =
|
||||
match ctx.trans.get_default_corp_for_user(&user.username).await? {
|
||||
None => user_error("You're not a member of any corps.".to_owned())?,
|
||||
Some(v) => v
|
||||
};
|
||||
(corp_id, corp, remaining.trim())
|
||||
};
|
||||
|
||||
let msg = ignore_special_characters(msg);
|
||||
|
||||
if msg.trim() == "" {
|
||||
user_error("Message required.".to_owned())?;
|
||||
}
|
||||
|
||||
let player = get_player_item_or_fail(ctx).await?;
|
||||
ctx.trans.broadcast_to_corp(&corp_id, &CorpCommType::Chat,
|
||||
Some(&user.username),
|
||||
&format!(ansi!("<yellow>{} (to {}): <reset><bold>\"{}\"<reset>\n"),
|
||||
&player.display_for_sentence(false, 1, true),
|
||||
&corp.name,
|
||||
&msg)).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
static VERB_INT: Verb = Verb;
|
||||
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;
|
@ -576,6 +576,91 @@ async fn corp_config(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn corp_subscribe(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> {
|
||||
let user = get_user_or_fail(ctx)?;
|
||||
let (subs, remaining) = match remaining.split_once(" from ") {
|
||||
None => {
|
||||
let (_, corp, mem) =
|
||||
match ctx.trans.match_user_corp_by_name(remaining.trim(), &user.username).await? {
|
||||
None => user_error("You don't seem to belong to a matching corp!".to_owned())?,
|
||||
Some(c) => c
|
||||
};
|
||||
ctx.trans.queue_for_session(
|
||||
&ctx.session,
|
||||
Some(&format!("Subscriptions for {}: {}\n",
|
||||
&corp.name,
|
||||
&mem.comms_on.iter().map(|m| m.display()).join(" ")))
|
||||
).await?;
|
||||
return Ok(());
|
||||
}
|
||||
Some(v) => v
|
||||
};
|
||||
let mut subs_add = BTreeSet::<CorpCommType>::new();
|
||||
for sub in subs.trim().split(" ") {
|
||||
let sub = ignore_special_characters(&sub.trim());
|
||||
match CorpCommType::parse(&sub) {
|
||||
None => user_error(format!("Invalid commtype: {}", sub))?,
|
||||
Some(t) => subs_add.insert(t)
|
||||
};
|
||||
}
|
||||
let (corp_id, _, mut mem) =
|
||||
match ctx.trans.match_user_corp_by_name(remaining.trim(), &user.username).await? {
|
||||
None => user_error("You don't seem to belong to a matching corp!".to_owned())?,
|
||||
Some(c) => c
|
||||
};
|
||||
mem.comms_on = (&mem.comms_on.into_iter().collect::<BTreeSet<CorpCommType>>() | &subs_add).into_iter().collect();
|
||||
ctx.trans.upsert_corp_membership(&corp_id, &user.username, &mem).await?;
|
||||
ctx.trans.queue_for_session(&ctx.session, Some("Subscriptions updated.\n")).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn corp_unsubscribe(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> {
|
||||
let (subs, remaining) = match remaining.split_once(" from ") {
|
||||
None => user_error("Usage: corp unsubscribe commtype commtype ... from corpname\n\
|
||||
commtypes: chat notice connect reward death".to_owned())?,
|
||||
Some(v) => v
|
||||
};
|
||||
let mut subs_del = BTreeSet::<CorpCommType>::new();
|
||||
for sub in subs.trim().split(" ") {
|
||||
let sub = ignore_special_characters(&sub.trim());
|
||||
match CorpCommType::parse(&sub) {
|
||||
None => user_error(format!("Invalid commtype: {}", sub))?,
|
||||
Some(t) => subs_del.insert(t)
|
||||
};
|
||||
}
|
||||
let user = get_user_or_fail(ctx)?;
|
||||
let (corp_id, _, mut mem) =
|
||||
match ctx.trans.match_user_corp_by_name(remaining.trim(), &user.username).await? {
|
||||
None => user_error("You don't seem to belong to a matching corp!".to_owned())?,
|
||||
Some(c) => c
|
||||
};
|
||||
mem.comms_on = (&mem.comms_on.into_iter().collect::<BTreeSet<CorpCommType>>() - &subs_del).into_iter().collect();
|
||||
ctx.trans.upsert_corp_membership(&corp_id, &user.username, &mem).await?;
|
||||
ctx.trans.queue_for_session(&ctx.session, Some("Subscriptions updated.\n")).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn corp_order(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> {
|
||||
let (corpname, number_s) = match remaining.split_once(" as ") {
|
||||
None => user_error("Usage: corp order corpname as number".to_owned())?,
|
||||
Some(v) => v
|
||||
};
|
||||
let number = match nom::character::complete::i64::<&str, ()>(number_s) {
|
||||
Ok((rest, num)) if rest.trim() == "" => num,
|
||||
_ => user_error("Usage: corp order corpname as number".to_owned())?
|
||||
};
|
||||
let user = get_user_or_fail(ctx)?;
|
||||
let (corp_id, _, mut mem) =
|
||||
match ctx.trans.match_user_corp_by_name(corpname.trim(), &user.username).await? {
|
||||
None => user_error("You don't seem to belong to a matching corp!".to_owned())?,
|
||||
Some(c) => c
|
||||
};
|
||||
mem.priority = number;
|
||||
ctx.trans.upsert_corp_membership(&corp_id, &user.username, &mem).await?;
|
||||
ctx.trans.queue_for_session(&ctx.session, Some("Updated!\n")).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct Verb;
|
||||
#[async_trait]
|
||||
impl UserVerb for Verb {
|
||||
@ -607,7 +692,16 @@ impl UserVerb for Verb {
|
||||
},
|
||||
"configure" | "config" => {
|
||||
corp_config(ctx, remaining).await?;
|
||||
}
|
||||
},
|
||||
"sub" | "subscribe" => {
|
||||
corp_subscribe(ctx, remaining).await?;
|
||||
},
|
||||
"unsub" | "unsubscribe" => {
|
||||
corp_unsubscribe(ctx, remaining).await?;
|
||||
},
|
||||
"order" => {
|
||||
corp_order(ctx, remaining).await?;
|
||||
},
|
||||
_ => user_error("Unknown command".to_owned())?
|
||||
}
|
||||
Ok(())
|
||||
|
@ -19,7 +19,8 @@ pub fn is_invalid_username(name: &str) -> bool {
|
||||
"bot"
|
||||
));
|
||||
let invalid_words = INVALID_WORDS.get_or_init(|| HashSet::from(
|
||||
["corp", "to", "from", "dog", "bot"]
|
||||
["corp", "to", "from", "dog", "bot", "for", "against", "on",
|
||||
"privileges", "as"]
|
||||
));
|
||||
if invalid_words.contains(name) {
|
||||
return true;
|
||||
|
@ -40,7 +40,7 @@ impl CorpPermission {
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd, Clone)]
|
||||
pub enum CorpCommType {
|
||||
Chat,
|
||||
Notice,
|
||||
@ -49,6 +49,30 @@ pub enum CorpCommType {
|
||||
Death,
|
||||
}
|
||||
|
||||
impl CorpCommType {
|
||||
pub fn parse(s: &str) -> Option<CorpCommType> {
|
||||
use CorpCommType::*;
|
||||
match s {
|
||||
"chat" => Some(Chat),
|
||||
"notice" => Some(Notice),
|
||||
"connect" => Some(Connect),
|
||||
"reward" => Some(Reward),
|
||||
"death" => Some(Death),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn display(&self) -> &'static str {
|
||||
use CorpCommType::*;
|
||||
match self {
|
||||
Chat => "chat",
|
||||
Notice => "notice",
|
||||
Connect => "connect",
|
||||
Reward => "reward",
|
||||
Death => "death",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CorpId(pub i64);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
Loading…
Reference in New Issue
Block a user