(&'out self, ns: NS, mut f: F)
{
const ENCODE : percent_encoding::AsciiSet =
- percent_encoding::NON_ALPHANUMERIC.remove(b':');
+ percent_encoding::NON_ALPHANUMERIC;
match &self {
AS::Server => {
},
};
for n in ns {
+ f(":")?;
for frag in utf8_percent_encode(n, &ENCODE) {
f(frag)?;
}
chan
}
+const PLAYER_ALWAYS_PERMS : &[Perm] = [
+ TP::TestExistence,
+ TP::ViewPublic,
+ TP::AddPlayer,
+];
+
+const PLAYER_DEFAULT_PERMS : &[Perm] = [
+ TP::ChangePiecse
+];
+
fn setup_table(ma: &MainOpts, chan: &mut ConnForGame,
- spec: &TableSpec) -> Result<(),AE> {
+ spec: &TableSpec, purge_old_players: bool) -> Result<(),AE> {
+ let TableSpec { players, player_perms, timezone } = spec;
+ let mut player_perms = player_perms.clone()
+ .unwrap_or(PLAYER_DEFAULT_PERMS.iter().collect());
+ player_perms.extend(PLAYER_ALWAYS_PERMS.iter());
+
+ let mut acl =
+ players.iter().map(|tps| AclEntry {
+ account_glob: tps.account_glob();
+ allow: player_perms.clone(),
+ deny: default()
+ })
+ .chain(
+ spec.acl.iter()
+ )
+ .collect();
+
+ let mut insns = vec![];
+ insns.push(MGI::SetACL { acl });
+ isnns.push(MGI::SetTimezone { tz: timezone.clone() });
+
+
+
let (_, nick2id) = chan.get_info()?;
#[derive(Default)]
.map(|(nick,id)| (nick, St { id, old: true, new: false }))
.collect();
- let mut insns = vec![];
for pspec in &spec.players {
let nick = pspec.nick.unwrap_or_else(|| pspec.account.default_nick());
let st = nick2st.entry(nick.clone()).or_default();
Fine, ig)
}
- Insn::AddPlayer {
- account,
+ Insn::JoinGame {
details: MgmtPlayerDetails { timezone, nick }
} => {
- // todo some kind of permissions check for player too
+ let account = &cs.current_account()?.notional_account;
+ let (_arecord, acctid) = ag.lookup(account)?;
let (ig, auth) = cs.check_acl(ag, ig, PCH::Instance, &[TP::AddPlayer])?;
- let (_arecord, acctid) = ag.lookup(&account)?;
let nick = nick.ok_or(ME::ParameterMissing)?;
let logentry = LogEntry {
- html: Html(format!("{} added a player: {}", &who,
- htmlescape::encode_minimal(&nick))),
+ html: Html(format!("{} ({}) joined the game",
+ &nick, &account)),
};
let timezone = timezone.as_ref().map(String::as_str)
.unwrap_or("");
(U{ pcs: vec![],
log: vec![ logentry ],
raw: None },
- Resp::AddPlayer { account, nick, player, token: atr },
+ Resp::JoinGame { nick, player, token: atr },
ig)
},
// xxx ^ prevent use of Fixed when not wanted
RedeliverPlayerAccess(PlayerId),
- AddPlayer { account: AccountName, details: MgmtPlayerDetails },
+ JoinGame { details: MgmtPlayerDetails },
UpdatePlayer { player: PlayerId, details: MgmtPlayerDetails },
RemovePlayer { player: PlayerId },
+
+ SetACL { acl: Acl<TablePermission> },
+ SetTimezone { tz: String },
}
// xxx facilitator name?
Pieces(Vec<MgmtGamePieceInfo>),
- AddPlayer {
- #[serede(flatten)] info: MgmtPlayerInfo,
- player: PlayerId, token: Option<AccessTokenReport>,
+ JoinGame {
+ nick: String,
+ player: PlayerId,
+ token: Option<AccessTokenReport>,
},
PlayerAccessToken(Option<AccessTokenReport>),
}
#[derive(Debug,Serialize,Deserialize)]
pub struct TableSpec {
#[serde(default)] pub players: Vec<TablePlayerSpec>,
- #[serde(default)] pub acl: Acl<TablePermission>,
+ pub player_perms: Option<HashSet<Perm>>,
+ #[serde(default)] pub acl: Acl<AclEntry>,
pub timezone: Option<String>,
}
#[derive(Debug,Serialize,Deserialize)]
#[serde(rename_all="snake_case")]
pub enum TablePlayerSpec {
- Account(String),
+ Account(AccountName),
AccountGlob(String),
Local(String),
AllLocal,
const NOT_FOUND : MgmtError = MgmtError::GameNotFound;
}
+ impl TablePlayerSpec {
+ fn account_glob(&self) -> String {
+ fn scope_glob(scope: AccountScope) -> String {
+ foramt!("{}:*", &scope)
+ }
+ match self {
+ Account(account) => account.to_string(),
+ AccountGlob(s) => s.clone(),
+ Local(user) => scope_glob(AS::Unix { user: user.clone() }),
+ AllLocal => {
+ // abuse that usernames are not encoded
+ scope_glob(AS::Unix { user: "*".clone() })
+ },
+ }
+ }
+ }
+
type TDE = TokenDeliveryError;
pub fn raw_token_debug_as_str(s: &str, f: &mut fmt::Formatter)