diff --git a/arsse.php b/arsse.php index 8214bb2..e33d618 100644 --- a/arsse.php +++ b/arsse.php @@ -18,7 +18,8 @@ if (\PHP_SAPI=="cli") { // initialize the CLI; this automatically handles --help and --version $cli = new CLI; // handle other CLI requests; some do not require configuration - $cli->dispatch(); + $exitStatus = $cli->dispatch(); + exit($exitStatus); } else { // load configuration $conf = file_exists(BASE."config.php") ? new Conf(BASE."config.php") : new Conf; diff --git a/lib/CLI.php b/lib/CLI.php index 1605efe..ab85219 100644 --- a/lib/CLI.php +++ b/lib/CLI.php @@ -6,6 +6,8 @@ declare(strict_types=1); namespace JKingWeb\Arsse; +use Docopt\Response as Opts; + class CLI { protected $args = []; @@ -15,13 +17,17 @@ class CLI { Usage: $prog daemon $prog feed refresh - $prog conf save-defaults + $prog conf save-defaults [] + $prog user [list] $prog user add [] + $prog user remove + $prog user set-pass [--oldpass=] [] + $prog user auth $prog --version $prog --help | -h The Arsse command-line interface currently allows you to start the refresh -daemon, refresh a specific feed by numeric ID, add a user, or save default +daemon, refresh a specific feed by numeric ID, manage users, or save default configuration to a sample file. USAGE_TEXT; } @@ -35,6 +41,18 @@ USAGE_TEXT; ]); } + protected function command(array $options, $args): string { + foreach ($options as $cmd) { + foreach (explode(" ", $cmd) as $part) { + if (!$args[$part]) { + continue 2; + } + } + return $cmd; + } + return ""; + } + protected function loadConf(): bool { $conf = file_exists(BASE."config.php") ? new Conf(BASE."config.php") : new Conf; Arsse::load($conf); @@ -46,27 +64,24 @@ USAGE_TEXT; public function dispatch(array $args = null): int { // act on command line $args = $args ?? $this->args; - if ($this->command("daemon", $args)) { - $this->loadConf(); - return $this->daemon(); - } elseif ($this->command("feed refresh", $args)) { - $this->loadConf(); - return $this->feedRefresh((int) $args['']); - } elseif ($this->command("conf save-defaults", $args)) { - return $this->confSaveDefaults($args['']); - } elseif ($this->command("user add", $args)) { - $this->loadConf(); - return $this->userAdd($args[''], $args['']); - } - } - - protected function command($cmd, $args): bool { - foreach (explode(" ", $cmd) as $part) { - if (!$args[$part]) { - return false; + try { + switch ($this->command(["daemon", "feed refresh", "conf save-defaults", "user"], $args)) { + case "daemon": + $this->loadConf(); + return $this->daemon(); + case "feed refresh": + $this->loadConf(); + return $this->feedRefresh((int) $args['']); + case "conf save-defaults": + return $this->confSaveDefaults($args['']); + case "user": + $this->loadConf(); + return $this->userManage($args); } + } catch (AbstractException $e) { + fwrite(STDERR, $e->getMessage().\PHP_EOL); + return $e->getCode(); } - return true; } public function daemon(bool $loop = true): int { @@ -78,15 +93,52 @@ USAGE_TEXT; return (int) !Arsse::$db->feedUpdate($id); // FIXME: exception error codes should be returned here } - public function confSaveDefaults(string $file): int { + public function confSaveDefaults(string $file = null): int { + $file = ($file=="-" ? null : $file) ?? STDOUT; return (int) !(new Conf)->exportFile($file, true); } - public function userAdd(string $user, string $password = null): int { - $passwd = Arsse::$user->add($user, $password); + public function userManage($args): int { + switch ($this->command(["add", "remove", "set-pass", "list", "auth"], $args)) { + case "add": + return $this->userAddOrSetPassword("add", $args[""], $args[""]); + case "set-pass": + return $this->userAddOrSetPassword("passwordSet", $args[""], $args[""], $args[""]); + case "remove": + return (int) !Arsse::$user->remove($args[""]); + case "auth": + return $this->userAuthenticate($args[""], $args[""]); + case "list": + case "": + return $this->userList(); + } + } + + protected function userAddOrSetPassword(string $method, string $user, string $password = null, string $oldpass = null): int { + $args = \func_get_args(); + array_shift($args); + $passwd = Arsse::$user->$method(...$args); if (is_null($password)) { echo $passwd.\PHP_EOL; } return 0; } + + protected function userList(): int { + $list = Arsse::$user->list(); + if ($list) { + echo implode(\PHP_EOL, $list).\PHP_EOL; + } + return 0; + } + + protected function userAuthenticate(string $user, string $password): int { + if (Arsse::$user->auth($user, $password)) { + echo Arsse::$lang->msg("CLI.Auth.Success").\PHP_EOL; + return 0; + } else { + echo Arsse::$lang->msg("CLI.Auth.Failure").\PHP_EOL; + return 1; + } + } } diff --git a/locale/en.php b/locale/en.php index 477f04a..d721410 100644 --- a/locale/en.php +++ b/locale/en.php @@ -4,6 +4,9 @@ * See LICENSE and AUTHORS files for details */ return [ + 'CLI.Auth.Success' => 'Authentication successful', + 'CLI.Auth.Failure' => 'Authentication failed', + 'API.TTRSS.Category.Uncategorized' => 'Uncategorized', 'API.TTRSS.Category.Special' => 'Special', 'API.TTRSS.Category.Labels' => 'Labels',