Allow corps to consent to fight each other.

Note it doesn't actually do anything yet - that's coming!
This commit is contained in:
Condorra 2023-03-27 22:41:39 +11:00
parent d35bbbad53
commit 7d1d6675b7
5 changed files with 193 additions and 7 deletions

View File

@ -756,6 +756,18 @@ impl DBTrans {
}
}
pub async fn find_corp_consent_by_parties_type(&self, consenting: &CorpId, consented: &CorpId,
consent_type: &ConsentType) -> DResult<Option<Consent>> {
match self.pg_trans()?.query_opt(
"SELECT details FROM corp_consent WHERE consenting_corp = $1 AND \
consented_corp = $2 AND consent_type = $3",
&[&consenting.0, &consented.0, &ConsentType::to_str(consent_type)]
).await? {
None => Ok(None),
Some(row) => Ok(Some(serde_json::from_value(row.get(0))?))
}
}
pub async fn revoke_until_death_consent(&self, party: &str) -> DResult<()> {
self.pg_trans()?.execute(
"DELETE FROM user_consent WHERE (consenting_user = $1 OR \
@ -763,6 +775,16 @@ impl DBTrans {
details->>'until_death'='true'",
&[&party]
).await?;
self.pg_trans()?.execute(
"DELETE FROM corp_consent cc USING
corp_membership cm
WHERE (cc.consenting_corp = cm.corp_id OR cc.consented_corp = cm.corp_id) AND \
cm.member_username = $1 AND \
cm.details->>'joined_at' IS NOT NULL AND \
cc.consent_type = 'fight' AND \
cc.details->>'until_death'='true'",
&[&party]
).await?;
Ok(())
}
@ -774,6 +796,14 @@ impl DBTrans {
Ok(())
}
pub async fn delete_expired_corp_consent(&self) -> DResult<()> {
self.pg_trans()?.execute(
"DELETE FROM corp_consent WHERE details->>'expires' < $1",
&[&Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Nanos, true)]
).await?;
Ok(())
}
pub async fn delete_user_consent(&self,
consenting: &str,
consented: &str,
@ -786,6 +816,18 @@ impl DBTrans {
Ok(())
}
pub async fn delete_corp_consent(&self,
consenting: &CorpId,
consented: &CorpId,
consent_type: &ConsentType) -> DResult<()> {
self.pg_trans()?.execute(
"DELETE FROM corp_consent WHERE consenting_corp = $1 AND \
consented_corp = $2 AND consent_type = $3",
&[&consenting.0, &consented.0, &ConsentType::to_str(consent_type)]
).await?;
Ok(())
}
pub async fn upsert_user_consent(&self,
consenting: &str,
consented: &str,
@ -800,7 +842,22 @@ impl DBTrans {
&serde_json::to_value(details)?]).await?;
Ok(())
}
pub async fn upsert_corp_consent(&self,
consenting: &CorpId,
consented: &CorpId,
consent_type: &ConsentType,
details: &Consent
) -> DResult<()> {
self.pg_trans()?
.execute("INSERT INTO corp_consent (consenting_corp, consented_corp, consent_type, details) VALUES ($1, $2, $3, $4) \
ON CONFLICT (consenting_corp, consented_corp, consent_type) DO UPDATE SET \
details = EXCLUDED.details",
&[&consenting.0, &consented.0, &ConsentType::to_str(consent_type),
&serde_json::to_value(details)?]).await?;
Ok(())
}
pub async fn find_corp_by_name(&self, name: &str) -> DResult<Option<(CorpId, Corp)>> {
Ok(match self.pg_trans()?
.query_opt("SELECT corp_id, details FROM corps WHERE LOWER(details->>'name') = $1",

View File

@ -16,7 +16,7 @@ mod allow;
pub mod attack;
mod buy;
mod c;
mod corp;
pub mod corp;
pub mod drop;
pub mod get;
mod describe;

View File

@ -5,18 +5,22 @@ use super::{
UResult,
user_error,
get_player_item_or_fail,
get_user_or_fail,
search_item_for_user,
parsing
parsing,
corp::check_corp_perm,
};
use async_trait::async_trait;
use crate::{
models::{
consent::{Consent, ConsentType, ConsentStatus, FightConsent},
corp::{CorpPermission, CorpCommType},
item::Item
},
db::ItemSearchParams,
static_content::room::room_map_by_code,
};
use ansi::ansi;
#[derive(Debug, PartialEq)]
pub enum ConsentTarget<'t> {
@ -669,6 +673,127 @@ async fn handle_user_consent(ctx: &mut VerbContext<'_>, source_player: &Item,
Ok(())
}
async fn handle_corp_consent(ctx: &mut VerbContext<'_>, source_player: &Item,
from_corp: &str,
to_corp: &str,
is_allow: bool,
cmd: &AllowCommand<'_>
) -> UResult<()> {
let user = get_user_or_fail(ctx)?;
let (from_corp_id, from_corp, mem) =
match ctx.trans.match_user_corp_by_name(from_corp, &user.username).await? {
None => user_error("You don't seem to belong to a matching corp!".to_owned())?,
Some(c) => c
};
let (to_corp_id, to_corp) = match ctx.trans.find_corp_by_name(to_corp).await? {
None => user_error("I didn't find the corp you want to fight against.".to_owned())?,
Some(c) => c
};
if !check_corp_perm(&CorpPermission::War, &mem) {
user_error("You don't have permission to declare war on behalf of that corp.".to_owned())?;
}
ctx.trans.delete_expired_corp_consent().await?;
let current_consent = ctx.trans.find_corp_consent_by_parties_type(
&from_corp_id,
&to_corp_id,
&cmd.consent_type
).await?;
let converse_consent = if cmd.consent_type == ConsentType::Fight {
ctx.trans.find_corp_consent_by_parties_type(
&to_corp_id,
&from_corp_id,
&cmd.consent_type
).await?
} else {
None
};
let update = compute_new_consent_state(
&to_corp.name,
"their",
&to_corp.name,
"their",
&("against ".to_owned() + &to_corp.name + " by " + &from_corp.name),
&cmd.consent_type, &cmd.consent_details,
&current_consent, &converse_consent, is_allow
);
match update.new_consent.as_ref() {
None => ctx.trans.delete_corp_consent(
&from_corp_id,
&to_corp_id,
&cmd.consent_type
).await?,
Some(consent) => ctx.trans.upsert_corp_consent(
&from_corp_id,
&to_corp_id,
&cmd.consent_type,
consent
).await?,
}
if update.mirror_to_counterparty {
match update.new_consent.as_ref() {
None => ctx.trans.delete_corp_consent(
&to_corp_id,
&from_corp_id,
&cmd.consent_type
).await?,
Some(consent) => ctx.trans.upsert_corp_consent(
&to_corp_id,
&from_corp_id,
&cmd.consent_type,
consent
).await?,
}
}
match update.first_party_message {
None => {},
Some(msg) =>
if update.counterparty_message.is_some() {
let details_str = cmd.consent_details.as_string(&ConsentType::Fight);
let details_str = if details_str != "" {
format!(" ({})", &details_str.trim())
} else {
"".to_owned()
};
let action_str = if is_allow { "consented" } else { "withdrew consent" };
// If it goes to both corps, it is a diplomatic message so goes to whole source corp.
ctx.trans.broadcast_to_corp(
&from_corp_id,
&CorpCommType::Consent,
None,
&format!(ansi!("<red>{} {} to fight{} against {} on behalf \
of {}<reset>, with result: {}\n"),
&source_player.display_for_sentence(false, 1, true),
action_str,
&details_str,
&to_corp.name,
&from_corp.name,
&msg
)
).await?;
} else {
ctx.trans.queue_for_session(&ctx.session, Some(&(msg + "\n"))).await?;
}
}
match update.counterparty_message {
None => {},
Some(msg) => {
ctx.trans.broadcast_to_corp(
&to_corp_id,
&CorpCommType::Consent,
None,
&format!(ansi!("<yellow>Your wristpad buzzes with an corporate announcement to {}:<reset> {}\n"), &to_corp.name, &msg)
).await?
}
}
Ok(())
}
pub struct Verb;
#[async_trait]
impl UserVerb for Verb {
@ -699,8 +824,8 @@ impl UserVerb for Verb {
}
}
match cmd.consent_target {
ConsentTarget::CorpTarget { .. } => user_error(
"Corporate allow/disallow not implemented yet".to_owned())?,
ConsentTarget::CorpTarget { from_corp, to_corp } =>
handle_corp_consent(ctx, &player_item, from_corp, to_corp, is_allow, &cmd).await?,
ConsentTarget::UserTarget { to_user } =>
handle_user_consent(ctx, &player_item, to_user, is_allow, &cmd).await?
}

View File

@ -21,7 +21,7 @@ use std::collections::BTreeSet;
use itertools::Itertools;
use humantime;
fn check_corp_perm(perm: &CorpPermission, mem: &CorpMembership) -> bool {
pub fn check_corp_perm(perm: &CorpPermission, mem: &CorpMembership) -> bool {
mem.permissions.iter().any(|p| *p == CorpPermission::Holder || *p == *perm)
}
@ -617,7 +617,7 @@ async fn corp_subscribe(ctx: &mut VerbContext<'_>, remaining: &str) -> UResult<(
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())?,
commtypes: chat notice connect reward death consent".to_owned())?,
Some(v) => v
};
let mut subs_del = BTreeSet::<CorpCommType>::new();

View File

@ -47,6 +47,7 @@ pub enum CorpCommType {
Connect,
Reward,
Death,
Consent,
}
impl CorpCommType {
@ -58,6 +59,7 @@ impl CorpCommType {
"connect" => Some(Connect),
"reward" => Some(Reward),
"death" => Some(Death),
"consent" => Some(Consent),
_ => None
}
}
@ -69,6 +71,7 @@ impl CorpCommType {
Connect => "connect",
Reward => "reward",
Death => "death",
Consent => "consent",
}
}
}
@ -126,6 +129,7 @@ impl Default for CorpMembership {
Connect,
Reward,
Death,
Consent,
),
}
}