chiark / gitweb /
wip new game joining
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 7 Nov 2020 21:20:12 +0000 (21:20 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 7 Nov 2020 21:20:12 +0000 (21:20 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/accounts.rs
src/bin/otter.rs
src/cmdlistener.rs
src/commands.rs
src/spec.rs

index 3ca4d13fc1a931cfc995f9969a20cad042985fd3..e931b0c83158ee8239d403bed5b3453258c5d37c 100644 (file)
@@ -46,7 +46,7 @@ impl AccountScope {
     (&'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 => {
@@ -59,6 +59,7 @@ impl AccountScope {
       },
     };
     for n in ns {
+      f(":")?;
       for frag in utf8_percent_encode(n, &ENCODE) {
         f(frag)?;
       }
index 49a9412ff6491628ac1e7539da64a4154526efdb..af88ef4593c88251762121a6232d95798701ab8d 100644 (file)
@@ -354,8 +354,40 @@ fn connect(ma: &MainOpts) -> Conn {
   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)]
@@ -366,7 +398,6 @@ fn setup_table(ma: &MainOpts, chan: &mut ConnForGame,
     .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();
index 7178d3de869aac19c6ca1b83ba84e97b5d3d1a13..8884b43e86c6362f90be90063d272851d33ae8fa 100644 (file)
@@ -295,17 +295,16 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>(
        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("");
@@ -324,7 +323,7 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>(
       (U{ pcs: vec![],
           log: vec![ logentry ],
           raw: None },
-       Resp::AddPlayer { account, nick, player, token: atr },
+       Resp::JoinGame { nick, player, token: atr },
        ig)
     },
 
index 66b9b4bc6e055c21ea01be0cb693208b6aa0ca8d..23e1d7e63639295f964ea3474de197744fabf368 100644 (file)
@@ -78,9 +78,12 @@ pub enum MgmtGameInstruction {
   // 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?
@@ -98,9 +101,10 @@ pub enum MgmtGameResponse {
 
   Pieces(Vec<MgmtGamePieceInfo>),
 
-  AddPlayer {
-    #[serede(flatten)] info: MgmtPlayerInfo,
-    player: PlayerId, token: Option<AccessTokenReport>,
+  JoinGame {
+    nick: String,
+    player: PlayerId,
+    token: Option<AccessTokenReport>,
   },
   PlayerAccessToken(Option<AccessTokenReport>),
 }
index 39d7c075ea5692b80943aa9e44075fb70fe25c48..9b2afc5d6cbf9b80343c1b4ecc78d9c8501067a5 100644 (file)
@@ -61,14 +61,15 @@ display_as_debug!{SpecError}
 #[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,
@@ -266,6 +267,23 @@ pub mod implementation {
     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)