From 6c86599103fea6ed92562961e216411368f7eba8 Mon Sep 17 00:00:00 2001 From: Condorra Date: Sun, 26 Mar 2023 16:51:10 +1100 Subject: [PATCH] Add corp management commands. --- blastmud_game/src/db.rs | 8 + .../src/message_handler/user_commands/corp.rs | 184 +++++++++++++++++- 2 files changed, 189 insertions(+), 3 deletions(-) diff --git a/blastmud_game/src/db.rs b/blastmud_game/src/db.rs index c109f407..4dcd1acf 100644 --- a/blastmud_game/src/db.rs +++ b/blastmud_game/src/db.rs @@ -846,6 +846,14 @@ impl DBTrans { Ok(CorpId(id)) } + pub async fn update_corp_details(&self, corp: &CorpId, details: &Corp) -> DResult<()> { + self.pg_trans()? + .execute("UPDATE corps SET details=$1 WHERE corp_id = $2", + &[&serde_json::to_value(details)?, &corp.0] + ).await?; + Ok(()) + } + pub async fn expire_old_invites(&self) -> DResult<()> { self.pg_trans()? .execute( diff --git a/blastmud_game/src/message_handler/user_commands/corp.rs b/blastmud_game/src/message_handler/user_commands/corp.rs index 98286650..fe1470e5 100644 --- a/blastmud_game/src/message_handler/user_commands/corp.rs +++ b/blastmud_game/src/message_handler/user_commands/corp.rs @@ -81,6 +81,7 @@ async fn corp_invite(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> let new_mem = CorpMembership { invited_at: Some(Utc::now()), allow_combat: corp.allow_combat_required, + permissions: corp.member_permissions.clone(), ..Default::default() }; ctx.trans.upsert_corp_membership(&corp_id, &target_user.item_code, &new_mem).await?; @@ -221,6 +222,10 @@ async fn corp_fire(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> { if target_user.item_type != "player" { user_error("Only players can be fired.".to_owned())?; } + + if target_user.item_code == player.item_code { + user_error("Fire yourself? You know you can just resign right?".to_owned())?; + } match ctx.trans.match_user_corp_by_name(into_raw.trim(), &target_user.item_code).await? { None => user_error(format!( @@ -358,6 +363,7 @@ async fn corp_promote(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> } } } + if !mem.permissions.contains(&CorpPermission::Holder) && !(&perm_add | &perm_rem).is_subset(&mem.permissions.clone().into_iter().collect()) { user_error("You can only change permissions you have yourself.".to_owned())? @@ -398,11 +404,34 @@ async fn corp_info(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> { std::time::Duration::from_secs( (Utc::now() - corp.founded).num_seconds() as u64)); msg.push_str(&format!(ansi!("{}'s essential information\nFounded: {} ago\n"), - &corp.name, &founded_ago)); + &corp.name, &founded_ago)); + let members = ctx.trans.list_corp_members(&corp_id).await?; + if corp.allow_combat_required { + msg.push_str("Members ARE required to allow the corp to consent to fighting on their behalf"); + let tot_mem = members.len(); + let mem_allow_combat = members.iter().filter(|(_, m)| m.allow_combat).count(); + if tot_mem == mem_allow_combat { + msg.push_str(", and all members have done so.\n"); + } else { + msg.push_str("- waiting on the following members to do so: "); + for (u, _) in members.iter().filter(|(_, m)| !m.allow_combat) { + msg.push_str(&caps_first(&u)); + msg.push(' '); + } + msg.push('\n'); + } + } else { + msg.push_str("Members are NOT required to allow the corp to consent to fighting on their behalf.\n"); + } + + msg.push_str(&format!("Base member privileges: {}\n", + &corp.member_permissions.iter().map(|p| p.display()) + .join(" "))); + msg.push_str("Members:\n"); - msg.push_str(&format!(ansi!("| {:20} | {:20} | {:20} |\n"), "Name", "Title", "Permissions" + msg.push_str(&format!(ansi!("| {:20} | {:20} | {:20} |\n"), "Name", "Title", "Privileges" )); - for (user, mem) in ctx.trans.list_corp_members(&corp_id).await? { + for (user, mem) in members { msg.push_str( &format!(ansi!("| {:20} | {:20} | {:20} |\n"), caps_first(&user), @@ -417,6 +446,136 @@ async fn corp_info(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> { Ok(()) } +async fn corp_allow_combat(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> { + let (command, remaining) = parse_command_name(remaining); + if command != "from" { + user_error("Usage: corp allow combat from corpname".to_owned())?; + } + let user = get_user_or_fail(ctx)?; + let (corp_id, corp, 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 + }; + if mem.allow_combat { + user_error(format!("You already allow combat for {}.", &corp.name))?; + } + mem.allow_combat = true; + ctx.trans.upsert_corp_membership(&corp_id, &user.username.to_lowercase(), &mem).await?; + ctx.trans.queue_for_session( + &ctx.session, + Some("You now allow the corp to consent to fighting on your behalf.\n")).await?; + Ok(()) +} + +async fn corp_disallow_combat(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> { + let (command, remaining) = parse_command_name(remaining); + if command != "from" { + user_error("Usage: corp disallow combat from corpname".to_owned())? + } + let user = get_user_or_fail(ctx)?; + let (corp_id, corp, 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 + }; + if !mem.allow_combat { + user_error("You already disallow combat for that corp.".to_owned())?; + } + if corp.allow_combat_required { + user_error(format!(ansi!("That corp requires everyone to allow combat as a condition \ + of employment, so you can't do that. You could do \ + corp resign {} instead."), + &corp.name) + )?; + } + mem.allow_combat = false; + ctx.trans.upsert_corp_membership(&corp_id, &user.username.to_lowercase(), &mem).await?; + ctx.trans.queue_for_session( + &ctx.session, + Some("You no longer allow the corp to consent to fighting on your behalf.\n")).await?; + Ok(()) +} + +async fn corp_config(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<()> { + let (corp_name_raw, remaining) = match remaining.split_once(" ") { + None => user_error("Usage: corp config corpname ...".to_owned())?, + Some(v) => v + }; + let remaining = remaining.trim().to_lowercase(); + let user = get_user_or_fail(ctx)?; + + let (corp_id, mut corp, mem) = + match ctx.trans.match_user_corp_by_name(corp_name_raw.trim(), &user.username).await? { + None => user_error("You don't seem to belong to a matching corp!".to_owned())?, + Some(c) => c + }; + if !check_corp_perm(&CorpPermission::Configure, &mem) { + user_error("You don't have permission to change settings for that corp.".to_owned())?; + } + + + if remaining == "allow combat required" { + corp.allow_combat_required = true; + ctx.trans.broadcast_to_corp( + &corp_id, + &CorpCommType::Notice, None, + &format!("{} announces a policy decision for {}: all new members must allow the \ + corp to consent to fights on their behalf.\n", + &caps_first(&user.username), + &corp.name)).await?; + ctx.trans.update_corp_details(&corp_id, &corp).await?; + } else if remaining == "allow combat not required" { + corp.allow_combat_required = false; + ctx.trans.update_corp_details(&corp_id, &corp).await?; + ctx.trans.broadcast_to_corp( + &corp_id, + &CorpCommType::Notice, None, + &format!("{} announces a policy decision for {}: new members no longer need to allow the \ + corp to consent to fights on their behalf. Any member can now use \ + \"corp disallow combat from {}\" if they want to.\n", + &caps_first(&user.username), + &corp.name, &corp.name)).await?; + } else if remaining.starts_with("base privileges ") { + let remaining = remaining[("base privileges ".len())..].trim(); + let psplit = remaining.split(" "); + let mut perms: BTreeSet = BTreeSet::new(); + for perm in psplit { + let perm = ignore_special_characters(&perm.trim()).to_lowercase(); + if perm == "none" { + continue; + } + let perm = match CorpPermission::parse(&perm) { + None => user_error(format!("Unknown permission {}", perm))?, + Some(p) if p == CorpPermission::Holder => + user_error("You can't set holder as a base privilege.".to_owned())?, + Some(p) if !check_corp_perm(&p, &mem) => + user_error("You can't set base privilege you don't have yourself." + .to_owned())?, + Some(p) => p + }; + perms.insert(perm); + } + corp.member_permissions = perms.clone().into_iter().collect(); + let perm_str = &corp.member_permissions.iter().map(|p| p.display()).join(" "); + ctx.trans.broadcast_to_corp( + &corp_id, + &CorpCommType::Notice, None, + &format!("{} announces a policy decision for {}: new members get \ + the following privileges: {}.\n", + &caps_first(&user.username), + &corp.name, + if perm_str == "" { "none" } else { &perm_str } + + )).await?; + ctx.trans.update_corp_details(&corp_id, &corp).await?; + } else { + user_error("Configurations you can set:\n\tallow combat required\n\tallow combat not required\nbase permissions permission_name permission_name".to_owned())?; + } + + Ok(()) +} + pub struct Verb; #[async_trait] impl UserVerb for Verb { @@ -430,6 +589,25 @@ impl UserVerb for Verb { "fire" | "dismiss" => corp_fire(ctx, remaining).await?, "promote" | "demote" => corp_promote(ctx, remaining).await?, "info" => corp_info(ctx, remaining).await?, + "allow" => { + let (command, remaining) = parse_command_name(remaining); + if command.to_lowercase() != "combat" { + user_error("Allow must be followed with combat".to_owned())? + } else { + corp_allow_combat(ctx, remaining).await? + } + }, + "disallow" => { + let (command, remaining) = parse_command_name(remaining); + if command.to_lowercase() != "combat" { + user_error("Disallow must be followed with combat".to_owned())? + } else { + corp_disallow_combat(ctx, remaining).await? + } + }, + "configure" | "config" => { + corp_config(ctx, remaining).await?; + } _ => user_error("Unknown command".to_owned())? } Ok(())