chiark / gitweb /
otter cli: Provide ListAccounts
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 27 Mar 2021 11:40:38 +0000 (11:40 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 27 Mar 2021 11:42:12 +0000 (11:42 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
daemon/cmdlistener.rs
src/accounts.rs
src/bin/otter.rs
src/commands.rs
src/mgmtchannel.rs

index 708ff2275f8563af787548dfd86d7aeaa6e83471..27b1e377bd60f0d49da2539ba00d3d4e7dc5617a 100644 (file)
@@ -140,6 +140,19 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse {
       Fine
     }
 
+    MC::ListAccounts { all } => {
+      let ag = AccountsGuard::lock();
+      let names = if all == Some(true) {
+        let auth = cs.superuser.ok_or(ME::AuthorisationError)?;
+        ag.list_accounts_all(auth.into())
+      } else {
+        let AccountSpecified { notional_account, auth, .. } =
+          cs.account.as_ref().ok_or(ME::SpecifyAccount)?;
+        ag.list_accounts_scope(&notional_account.scope, *auth)
+      };
+      MR::AccountsList(names)
+    }
+
     MC::CreateGame { game, insns } => {
       let mut ag = AccountsGuard::lock();
       let mut games = games_lock();
index a04a48472b5c0e93ac2c3900547f9c90f37c6482..a5f211419cbe32f4f75d8b259724ee9f61042ee7 100644 (file)
@@ -387,6 +387,22 @@ impl AccountsGuard {
     self.save_accounts_now()?;
   }
 
+  pub fn list_accounts_all(&self, _: AuthorisationSuperuser)
+                           -> Vec<Arc<AccountName>> {
+    let accounts = self.0.as_ref().expect("loaded");
+    accounts.names.keys()
+      .cloned().collect()
+  }
+
+  pub fn list_accounts_scope(&self, scope: &AccountScope,
+                             _: Authorisation<AccountName>)
+                             -> Vec<Arc<AccountName>> {
+    let accounts = self.0.as_ref().expect("loaded");
+    accounts.names.keys()
+      .filter(|name| &name.scope == scope)
+      .cloned().collect()
+  }
+
   #[throws(AccountsSaveError)]
   pub fn save_accounts_now(&self) {
     let accounts = self.0.as_ref().expect("loaded");
index 3107160261410d269085e2c8e19199f3682ee934..9be5b1f8a93628c1b674dc1e85a97cb68b38dd3b 100644 (file)
@@ -1303,3 +1303,43 @@ mod list_pieces {
     call,
   )}
 }
+
+//---------- list-accounts ----------
+
+mod list_accounts {
+  use super::*;
+
+  #[derive(Default,Debug)]
+  struct Args {
+    all: bool,
+  }
+
+  fn subargs(sa: &mut Args) -> ArgumentParser {
+    use argparse::*;
+    let mut ap = ArgumentParser::new();
+    ap.refer(&mut sa.all)
+      .add_option(&["--all"],StoreTrue,
+                  "user superuser access to list all accounts");
+    ap
+  }
+
+  #[throws(AE)]
+  fn call(_sc: &Subcommand, ma: MainOpts, args: Vec<String>) {
+    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
+    let mut conn = connect(&ma)?;
+    let all = Some(args.all);
+    let accounts = match conn.cmd(&MC::ListAccounts { all })? {
+      MR::AccountsList(g) => g,
+      x => throw!(anyhow!("unexpected response to ListAccounts: {:?}", &x)),
+    };
+    for a in accounts {
+      println!("{:?}", a);
+    }
+  }
+
+  inventory::submit!{Subcommand(
+    "list-accounts",
+    "List accounts in your account scope",
+    call,
+  )}
+}
index c6e54136b5b847ce423844df602b8637bc712121..d62f8a540b96bf0f570415861935eb5d2acb4fab 100644 (file)
@@ -17,6 +17,7 @@ pub enum MgmtCommand {
   CreateAccount(AccountDetails),
   UpdateAccount(AccountDetails),
   DeleteAccount(AccountName),
+  ListAccounts { all: Option<bool> },
 
   SelectAccount(AccountName), // success does not mean account exists
   CheckAccount, // success *does* mean account exists and we have access
@@ -68,6 +69,7 @@ pub enum MgmtResponse {
   Fine,
   Error { error: MgmtError },
   AlterGame { error: Option<MgmtError>, responses: Vec<MgmtGameResponse> },
+  AccountsList(Vec<Arc<AccountName>>),
   GamesList(Vec<Arc<InstanceName>>),
   LibraryItems(Vec<shapelib::ItemEnquiryData>),
 }
index eac95917d15a6f49cf85dd402d7e11f96f2f79a5..9fd6f4b4917a763b5461d433dd6de04094a9b7fe 100644 (file)
@@ -68,7 +68,7 @@ impl MgmtChannel {
     self.write(&cmd).context("send command")?;
     let resp = self.read().context("read response")?;
     match &resp {
-      Fine | GamesList{..} | LibraryItems(_) => { },
+      Fine | AccountsList{..} | GamesList{..} | LibraryItems(_) => { },
       AlterGame { error: None, .. } => { },
       Error { error } => {
         Err(error.clone()).context(