Restrict access to corp HQ to members + those with consent to fight

This commit is contained in:
Condorra 2023-10-01 22:45:42 +11:00
parent f1a23ac811
commit 64b96f48ab
5 changed files with 108 additions and 26 deletions

View File

@ -1275,6 +1275,32 @@ impl DBTrans {
}
}
pub async fn find_corp_consent_by_consenting_corp_consented_user_type(
&self,
corp_consenting: &CorpId,
usr_consented: &str,
consent_type: &ConsentType,
) -> DResult<Option<Consent>> {
match self
.pg_trans()?
.query_opt(
"SELECT cc.details FROM corp_consent cc \
JOIN corp_membership cm_consented ON cc.consented_corp = cm_consented.corp_id \
WHERE cc.consenting_corp = $1 AND \
cm_consented.member_username = $2 AND cc.consent_type = $3",
&[
&corp_consenting.0,
&usr_consented,
&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(
@ -1444,6 +1470,27 @@ impl DBTrans {
)
}
pub async fn find_corp_membership(
&self,
corp: &CorpId,
username: &str,
) -> DResult<Option<CorpMembership>> {
Ok(
match self
.pg_trans()?
.query_opt(
"SELECT m.details AS mdetails FROM corp_membership m WHERE m.corp_id = $1 \
AND m.member_username = $2 LIMIT 1",
&[&corp.0, &(username.to_lowercase())],
)
.await?
{
None => None,
Some(row) => Some(serde_json::from_value(row.get("mdetails"))?),
},
)
}
pub async fn create_corp(&self, details: &Corp) -> DResult<CorpId> {
let id = self
.pg_trans()?

View File

@ -125,7 +125,8 @@ static REGISTERED_HELP_PAGES: phf::Map<&'static str, &'static str> = phf_map! {
crit fail and do harm), <bold>gifts<reset> (lets them give you things), and \
<bold>visit<reset> (lets them on to a tile owned by you legally).\n\
\n\
To allow, an individual, use the syntax <bold>allow <reset>type <bold>from <reset>player options\n\
To allow, as an individual, use the syntax <bold>allow <reset>type <bold>from <reset>player options\n\
As a corp, use the syntax <bold>allow <reset>type <bold>against <reset>corpname <bold>by<reset> corpname options\n\
Options can be blank to use defaults, or can be one or more of the following, separated by spaces:\n\
\t<bold>for<reset> n <bold>minutes<reset> - replace n with a number. You can use hours, days, or weeks instead of minutes. This makes the consent expire. Fight expires after a week if you don't give a shorter period, and all other consent types have no expiry unless you specify one.\n\
\t<bold>until death<reset> - makes the consent valid only until you next die.\n\
@ -258,7 +259,8 @@ static EXPLICIT_HELP_PAGES: phf::Map<&'static str, &'static str> = phf_map! {
<bold>visit<reset> (lets them on to a tile owned by you legally), and <bold>fuck<reset> \
(lets them do fun but dirty things to you).\n\
\n\
To allow, an individual, use the syntax <bold>allow <reset>type <bold>from <reset>player options\n\
To allow, as an individual, use the syntax <bold>allow <reset>type <bold>from <reset>player options\n\
As a corp, use the syntax <bold>allow <reset>type <bold>against <reset>corpname <bold>by<reset> corpname options\n\
Options can be blank to use defaults, or can be one or more of the following, separated by spaces:\n\
\t<bold>until <reset> n <bold>minutes<reset> - replace n with a number. You can use hours, days, or weeks instead of minutes. This makes the consent expire. Fight expires after a week if you don't give a shorter period, and all other consent types have no expiry unless you specify one.\n\
\t<bold>until death<reset> - makes the consent valid only until you next die.\n\

View File

@ -20,7 +20,7 @@ use crate::{
queue_command, MovementSource, QueueCommand, QueueCommandHandler, QueuedCommandContext,
},
services::{
check_consent,
check_consent, check_one_consent,
combat::{change_health, handle_resurrect, stop_attacking_mut},
comms::broadcast_to_room,
skills::skill_check_and_grind,
@ -225,29 +225,62 @@ pub async fn check_room_access(trans: &DBTrans, player: &Item, room: &Item) -> U
if owner_t == &player.item_type && owner_c == &player.item_code {
return Ok(());
}
let owner = match trans.find_item_by_type_code(owner_t, owner_c).await? {
None => return Ok(()),
Some(v) => v,
};
if check_consent(trans, "enter", &ConsentType::Visit, player, &owner).await? {
return Ok(());
}
if owner_t == "corp" {
let corp = match trans.find_corp_by_name(owner_c).await? {
None => return Ok(()), // Defunct corp HQ somehow...
Some(v) => v,
};
if trans
.find_corp_membership(&corp.0, &player.item_code)
.await?
.map(|cm| cm.joined_at.is_some())
.unwrap_or(false)
{
// Corp members pass the check.
return Ok(());
}
let consent_opt = trans
.find_corp_consent_by_consenting_corp_consented_user_type(
&corp.0,
&player.item_code,
&ConsentType::Fight,
)
.await?;
let mut player_hypothet = (*player).clone();
player_hypothet.location = room.refstr();
if consent_opt
.as_ref()
.map(|c| check_one_consent(c, "enter", &player_hypothet))
.unwrap_or(false)
{
return Ok(());
}
} else {
let owner = match trans.find_item_by_type_code(owner_t, owner_c).await? {
None => return Ok(()),
Some(v) => v,
};
let mut player_hypothet = (*player).clone();
// We are asking hypothetically if they entered the room, could they fight
// the owner? We won't save this yet.
player_hypothet.location = room.refstr();
if check_consent(
trans,
"enter",
&ConsentType::Fight,
&player_hypothet,
&owner,
)
.await?
{
return Ok(());
if check_consent(trans, "enter", &ConsentType::Visit, player, &owner).await? {
return Ok(());
}
let mut player_hypothet = (*player).clone();
// We are asking hypothetically if they entered the room, could they fight
// the owner? We won't save this yet.
player_hypothet.location = room.refstr();
if check_consent(
trans,
"enter",
&ConsentType::Fight,
&player_hypothet,
&owner,
)
.await?
{
return Ok(());
}
}
user_error(ansi!("<yellow>Your wristpad buzzes and your muscles lock up, stopping you entering.<reset> \

View File

@ -24,7 +24,7 @@ pub mod skills;
pub mod spawn;
pub mod urges;
fn check_one_consent(consent: &Consent, action: &str, target: &Item) -> bool {
pub fn check_one_consent(consent: &Consent, action: &str, target: &Item) -> bool {
if let Some((loctype, loccode)) = target.location.split_once("/") {
if !consent.only_in.is_empty() {
if loctype != "room" || !consent.only_in.iter().any(|v| v == loccode) {

View File

@ -11,7 +11,7 @@ pub fn zone() -> Dynzone {
("reception", Dynroom {
subcode: "reception",
name: "Reception",
short: "DS",
short: "RC",
description: "A narrow public area of the corporate suite, with views \
of the bleak wasteland to the north. The walls are painted white, and a long reception \
desk, enamelled to look like dark wood, is built into the room. It is well lit \