diff options
| author | 2017-02-15 14:12:25 +0100 | |
|---|---|---|
| committer | 2017-02-15 14:12:25 +0100 | |
| commit | 2d097bc855dbd1ad06c7c306c05e78a198209084 (patch) | |
| tree | 67028e45792c575c25c92616633f64cc7a4a13eb /cli | |
| parent | fe293900061263a1917fc1cf18ca369c8e07cb99 (diff) | |
| parent | 5f637bd816b7323885bfe1751a1724ee59a822f6 (diff) | |
Merge remote-tracking branch 'FreshRSS/master' into dev
Diffstat (limited to 'cli')
| -rw-r--r-- | cli/.htaccess | 3 | ||||
| -rw-r--r-- | cli/README.md | 80 | ||||
| -rw-r--r-- | cli/_cli.php | 49 | ||||
| -rwxr-xr-x | cli/actualize-user.php | 23 | ||||
| -rwxr-xr-x | cli/create-user.php | 51 | ||||
| -rwxr-xr-x | cli/delete-user.php | 32 | ||||
| -rwxr-xr-x | cli/do-install.php | 101 | ||||
| -rwxr-xr-x | cli/export-opml-for-user.php | 24 | ||||
| -rwxr-xr-x | cli/export-zip-for-user.php | 30 | ||||
| -rwxr-xr-x | cli/import-for-user.php | 35 | ||||
| -rw-r--r-- | cli/index.html | 13 | ||||
| -rwxr-xr-x | cli/list-users.php | 14 | ||||
| -rwxr-xr-x | cli/user-info.php | 35 |
13 files changed, 490 insertions, 0 deletions
diff --git a/cli/.htaccess b/cli/.htaccess new file mode 100644 index 000000000..9e768397d --- /dev/null +++ b/cli/.htaccess @@ -0,0 +1,3 @@ +Order Allow,Deny +Deny from all +Satisfy all diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 000000000..e4d3409a2 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,80 @@ +* Back to [main read-me](../README.md) + +# FreshRSS Command-Line Interface (CLI) + +## Note on access rights + +When using the command-line interface, remember that your user might not be the same as the one used by your Web server. +This might create some access right problems. + +It is recommended to invoke commands using the same user as your Web server: + +```sh +cd /usr/share/FreshRSS +sudo -u www-data sh -c './cli/list-users.php' +``` + +In any case, when you are done with a series of commands, you should re-apply the access rights: + +```sh +cd /usr/share/FreshRSS +sudo chown -R :www-data . +sudo chmod -R g+r . +sudo chmod -R g+w ./data/ +``` + + +## Commands + +Options in parenthesis are optional. + + +```sh +cd /usr/share/FreshRSS + +./cli/do-install.php --default_user admin ( --auth_type form --environment production --base_url https://rss.example.net/ --title FreshRSS --allow_anonymous --api_enabled --db-type mysql --db-host localhost:3306 --db-user freshrss --db-password dbPassword123 --db-base freshrss --db-prefix freshrss ) +# --auth_type can be: 'form' (default), 'http_auth' (using the Web server access control), 'none' (dangerous) +# --db-type can be: 'sqlite' (default), 'mysql' (MySQL or MariaDB), 'pgsql' (PostgreSQL) +# --environment can be: 'production' (default), 'development' (for additional log messages) +# --db-prefix is an optional prefix in front of the names of the tables. We suggest using 'freshrss_' +# This command does not create the default user. Do that with ./cli/create-user.php + +./cli/create-user.php --user username ( --password 'password' --api-password 'api_password' --language en --email user@example.net --token 'longRandomString' --no-default-feeds ) +# --language can be: 'en' (default), 'fr', or one of the [supported languages](../app/i18n/) + +./cli/delete-user.php --user username + +./cli/list-users.php +# Return a list of users, with the default/admin user first + +./cli/actualize-user.php --user username + +./cli/import-for-user.php --user username --filename /path/to/file.ext +# The extension of the file { .json, .opml, .xml, .zip } is used to detect the type of import + +./cli/export-opml-for-user.php --user username > /path/to/file.opml.xml + +./cli/export-zip-for-user.php --user username ( --max-feed-entries 100 ) > /path/to/file.zip + +./cli/user-info.php -h --user username +# -h is to use a human-readable format +# --user can be a username, or '*' to loop on all users +# Returns a * if the user is admin, the name of the user, the date/time of last action, and the size occupied +``` + + +## Unix piping + +It is possible to invoke a command multiple times, e.g. with different usernames, thanks to the `xargs -n1` command. + +Example showing user information for all users which username starts with 'a': + +```sh +./cli/list-users.php | grep '^a' | xargs -n1 ./cli/user-info.php -h --user +``` + +Example showing all users ranked by date of last activity: + +```sh +./cli/user-info.php -h --user '*' | sort -k2 -r +``` diff --git a/cli/_cli.php b/cli/_cli.php new file mode 100644 index 000000000..7d1a7c6b2 --- /dev/null +++ b/cli/_cli.php @@ -0,0 +1,49 @@ +<?php +if (php_sapi_name() !== 'cli') { + die('FreshRSS error: This PHP script may only be invoked from command line!'); +} + +require(dirname(__FILE__) . '/../constants.php'); +require(LIB_PATH . '/lib_rss.php'); + +Minz_Configuration::register('system', + DATA_PATH . '/config.php', + DATA_PATH . '/config.default.php'); +FreshRSS_Context::$system_conf = Minz_Configuration::get('system'); +Minz_Translate::init('en'); + +FreshRSS_Context::$isCli = true; + +function fail($message) { + fwrite(STDERR, $message . "\n"); + die(1); +} + +function cliInitUser($username) { + if (!ctype_alnum($username)) { + fail('FreshRSS error: invalid username: ' . $username . "\n"); + } + + $usernames = listUsers(); + if (!in_array($username, $usernames)) { + fail('FreshRSS error: user not found: ' . $username . "\n"); + } + + FreshRSS_Context::$user_conf = get_user_configuration($username); + if (FreshRSS_Context::$user_conf == null) { + fail('FreshRSS error: invalid configuration for user: ' . $username . "\n"); + } + new Minz_ModelPdo($username); + + return $username; +} + +function accessRights() { + echo '• Remember to re-apply the appropriate access rights, such as:' , "\n", + "\t", 'sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/', "\n"; +} + +function done($ok = true) { + fwrite(STDERR, 'Result: ' . ($ok ? 'success' : 'fail') . "\n"); + exit($ok ? 0 : 1); +} diff --git a/cli/actualize-user.php b/cli/actualize-user.php new file mode 100755 index 000000000..29d51753a --- /dev/null +++ b/cli/actualize-user.php @@ -0,0 +1,23 @@ +#!/usr/bin/php +<?php +require('_cli.php'); + +$options = getopt('', array( + 'user:', + )); + +if (empty($options['user'])) { + fail('Usage: ' . basename(__FILE__) . " --user username"); +} + +$username = cliInitUser($options['user']); + +fwrite(STDERR, 'FreshRSS actualizing user “' . $username . "”…\n"); + +list($nbUpdatedFeeds, $feed) = FreshRSS_feed_Controller::actualizeFeed(0, '', true); + +echo "FreshRSS actualized $nbUpdatedFeeds feeds for $username\n"; + +invalidateHttpCache($username); + +done($nbUpdatedFeeds > 0); diff --git a/cli/create-user.php b/cli/create-user.php new file mode 100755 index 000000000..444264cc7 --- /dev/null +++ b/cli/create-user.php @@ -0,0 +1,51 @@ +#!/usr/bin/php +<?php +require('_cli.php'); + +$options = getopt('', array( + 'user:', + 'password:', + 'api-password:', + 'language:', + 'email:', + 'token:', + 'no-default-feeds', + )); + +if (empty($options['user'])) { + fail('Usage: ' . basename(__FILE__) . " --user username ( --password 'password' --api-password 'api_password'" . + " --language en --email user@example.net --token 'longRandomString --no-default-feeds' )"); +} +$username = $options['user']; +if (!ctype_alnum($username)) { + fail('FreshRSS error: invalid username “' . $username . '”'); +} + +$usernames = listUsers(); +if (preg_grep("/^$username$/i", $usernames)) { + fail('FreshRSS error: username already taken “' . $username . '”'); +} + +echo 'FreshRSS creating user “', $username, "”…\n"; + +$ok = FreshRSS_user_Controller::createUser($username, + empty($options['password']) ? '' : $options['password'], + empty($options['api-password']) ? '' : $options['api-password'], + array( + 'language' => empty($options['language']) ? '' : $options['language'], + 'token' => empty($options['token']) ? '' : $options['token'], + ), + !isset($options['no-default-feeds'])); + +if (!$ok) { + fail('FreshRSS could not create user!'); +} + +invalidateHttpCache(FreshRSS_Context::$system_conf->default_user); + +echo '• Remember to refresh the feeds of the user: ', $username , "\n", + "\t", './cli/actualize-user.php --user ', $username, "\n"; + +accessRights(); + +done($ok); diff --git a/cli/delete-user.php b/cli/delete-user.php new file mode 100755 index 000000000..6f0e86e17 --- /dev/null +++ b/cli/delete-user.php @@ -0,0 +1,32 @@ +#!/usr/bin/php +<?php +require('_cli.php'); + +$options = getopt('', array( + 'user:', + )); + +if (empty($options['user'])) { + fail('Usage: ' . basename(__FILE__) . " --user username"); +} +$username = $options['user']; +if (!ctype_alnum($username)) { + fail('FreshRSS error: invalid username “' . $username . '”'); +} + +$usernames = listUsers(); +if (!preg_grep("/^$username$/i", $usernames)) { + fail('FreshRSS error: username not found “' . $username . '”'); +} + +if (strcasecmp($username, FreshRSS_Context::$system_conf->default_user) === 0) { + fail('FreshRSS error: default user must not be deleted: “' . $username . '”'); +} + +echo 'FreshRSS deleting user “', $username, "”…\n"; + +$ok = FreshRSS_user_Controller::deleteUser($username); + +invalidateHttpCache(FreshRSS_Context::$system_conf->default_user); + +done($ok); diff --git a/cli/do-install.php b/cli/do-install.php new file mode 100755 index 000000000..100d4947f --- /dev/null +++ b/cli/do-install.php @@ -0,0 +1,101 @@ +#!/usr/bin/php +<?php +require('_cli.php'); +require(LIB_PATH . '/lib_install.php'); + +$params = array( + 'environment:', + 'base_url:', + 'title:', + 'default_user:', + 'allow_anonymous', + 'allow_anonymous_refresh', + 'auth_type:', + 'api_enabled', + 'allow_robots', + ); + +$dBparams = array( + 'db-type:', + 'db-host:', + 'db-user:', + 'db-password:', + 'db-base:', + 'db-prefix:', + ); + +$options = getopt('', array_merge($params, $dBparams)); + +if (empty($options['default_user'])) { + fail('Usage: ' . basename(__FILE__) . " --default_user admin ( --auth_type form" . + " --environment production --base_url https://rss.example.net/" . + " --title FreshRSS --allow_anonymous --api_enabled" . + " --db-type mysql --db-host localhost:3306 --db-user freshrss --db-password dbPassword123" . + " --db-base freshrss --db-prefix freshrss_ )"); +} + +fwrite(STDERR, 'FreshRSS install…' . "\n"); + +$requirements = checkRequirements(); +if ($requirements['all'] !== 'ok') { + $message = 'FreshRSS install failed requirements:' . "\n"; + foreach ($requirements as $requirement => $check) { + if ($check !== 'ok' && $requirement !== 'all') { + $message .= '• ' . $requirement . "\n"; + } + } + fail($message); +} + +if (!ctype_alnum($options['default_user'])) { + fail('FreshRSS invalid default username (must be ASCII alphanumeric): ' . $options['default_user']); +} + +if (isset($options['auth_type']) && !in_array($options['auth_type'], array('form', 'http_auth', 'none'))) { + fail('FreshRSS invalid authentication method (auth_type must be one of { form, http_auth, none }: ' . $options['auth_type']); +} + +$config = array( + 'salt' => generateSalt(), + 'db' => FreshRSS_Context::$system_conf->db, + ); + +foreach ($params as $param) { + $param = rtrim($param, ':'); + if (isset($options[$param])) { + $config[$param] = $options[$param] === false ? true : $options[$param]; + } +} + +if ((!empty($config['base_url'])) && server_is_public($config['base_url'])) { + $config['pubsubhubbub_enabled'] = true; +} + +foreach ($dBparams as $dBparam) { + $dBparam = rtrim($dBparam, ':'); + if (!empty($options[$dBparam])) { + $param = substr($dBparam, strlen('db-')); + $config['db'][$param] = $options[$dBparam]; + } +} + +if (file_put_contents(join_path(DATA_PATH, 'config.php'), "<?php\n return " . var_export($config, true) . ";\n") === false) { + fail('FreshRSS could not write configuration file!: ' . join_path(DATA_PATH, 'config.php')); +} + +$config['db']['default_user'] = $config['default_user']; +if (!checkDb($config['db'])) { + @unlink(join_path(DATA_PATH, 'config.php')); + fail('FreshRSS database error: ' . (empty($config['db']['error']) ? 'Unknown error' : $config['db']['error'])); +} + +echo '• Remember to create the default user: ', $config['default_user'] , "\n", + "\t", './cli/create-user.php --user ', $config['default_user'], " --password 'password' --more-options\n"; + +accessRights(); + +if (!deleteInstall()) { + fail('FreshRSS access right problem while deleting install file!'); +} + +done(); diff --git a/cli/export-opml-for-user.php b/cli/export-opml-for-user.php new file mode 100755 index 000000000..95b12281f --- /dev/null +++ b/cli/export-opml-for-user.php @@ -0,0 +1,24 @@ +#!/usr/bin/php +<?php +require('_cli.php'); + +$options = getopt('', array( + 'user:', + )); + +if (empty($options['user'])) { + fail('Usage: ' . basename(__FILE__) . " --user username > /path/to/file.opml.xml"); +} + +$username = cliInitUser($options['user']); + +fwrite(STDERR, 'FreshRSS exporting OPML for user “' . $username . "”…\n"); + +$importController = new FreshRSS_importExport_Controller(); + +$ok = false; +$ok = $importController->exportFile(true, false, array(), 0, $username); + +invalidateHttpCache($username); + +done($ok); diff --git a/cli/export-zip-for-user.php b/cli/export-zip-for-user.php new file mode 100755 index 000000000..92fe9bf9a --- /dev/null +++ b/cli/export-zip-for-user.php @@ -0,0 +1,30 @@ +#!/usr/bin/php +<?php +require('_cli.php'); + +$options = getopt('', array( + 'user:', + 'max-feed-entries:', + )); + +if (empty($options['user'])) { + fail('Usage: ' . basename(__FILE__) . " --user username ( --max-feed-entries 100 ) > /path/to/file.zip"); +} + +$username = cliInitUser($options['user']); + +fwrite(STDERR, 'FreshRSS exporting ZIP for user “' . $username . "”…\n"); + +$importController = new FreshRSS_importExport_Controller(); + +$ok = false; +try { + $ok = $importController->exportFile(true, true, true, + empty($options['max-feed-entries']) ? 100 : intval($options['max-feed-entries']), + $username); +} catch (FreshRSS_ZipMissing_Exception $zme) { + fail('FreshRSS error: Lacking php-zip extension!'); +} +invalidateHttpCache($username); + +done($ok); diff --git a/cli/import-for-user.php b/cli/import-for-user.php new file mode 100755 index 000000000..29084f062 --- /dev/null +++ b/cli/import-for-user.php @@ -0,0 +1,35 @@ +#!/usr/bin/php +<?php +require('_cli.php'); + +$options = getopt('', array( + 'user:', + 'filename:', + )); + +if (empty($options['user']) || empty($options['filename'])) { + fail('Usage: ' . basename(__FILE__) . " --user username --filename /path/to/file.ext"); +} + +$username = cliInitUser($options['user']); + +$filename = $options['filename']; +if (!is_readable($filename)) { + fail('FreshRSS error: file is not readable “' . $filename . '”'); +} + +echo 'FreshRSS importing ZIP/OPML/JSON for user “', $username, "”…\n"; + +$importController = new FreshRSS_importExport_Controller(); + +$ok = false; +try { + $ok = $importController->importFile($filename, $filename, $username); +} catch (FreshRSS_ZipMissing_Exception $zme) { + fail('FreshRSS error: Lacking php-zip extension!'); +} catch (FreshRSS_Zip_Exception $ze) { + fail('FreshRSS error: ZIP archive cannot be imported! Error code: ' . $ze->zipErrorCode()); +} +invalidateHttpCache($username); + +done($ok); diff --git a/cli/index.html b/cli/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/cli/index.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-GB" lang="en-GB"> +<head> +<meta charset="UTF-8" /> +<meta http-equiv="Refresh" content="0; url=/" /> +<title>Redirection</title> +<meta name="robots" content="noindex" /> +</head> + +<body> +<p><a href="/">Redirection</a></p> +</body> +</html> diff --git a/cli/list-users.php b/cli/list-users.php new file mode 100755 index 000000000..e690ff451 --- /dev/null +++ b/cli/list-users.php @@ -0,0 +1,14 @@ +#!/usr/bin/php +<?php +require('_cli.php'); + +$users = listUsers(); +sort($users); +if (FreshRSS_Context::$system_conf->default_user !== '') { + array_unshift($users, FreshRSS_Context::$system_conf->default_user); + $users = array_unique($users); +} + +foreach ($users as $user) { + echo $user, "\n"; +} diff --git a/cli/user-info.php b/cli/user-info.php new file mode 100755 index 000000000..dd38e6c7f --- /dev/null +++ b/cli/user-info.php @@ -0,0 +1,35 @@ +#!/usr/bin/php +<?php +require('_cli.php'); + +$options = getopt('h', array( + 'user:', + )); + +if (empty($options['user'])) { + fail('Usage: ' . basename(__FILE__) . " -h --user username"); +} + +$users = $options['user'] === '*' ? listUsers() : array($options['user']); + +foreach ($users as $username) { + $username = cliInitUser($username); + + $entryDAO = FreshRSS_Factory::createEntryDao($username); + + echo $username === FreshRSS_Context::$system_conf->default_user ? '*' : ' ', "\t"; + + if (isset($options['h'])) { //Human format + echo + $username, "\t", + date('c', FreshRSS_UserDAO::mtime($username)), "\t", + format_bytes($entryDAO->size()), "\t", + "\n"; + } else { + echo + $username, "\t", + FreshRSS_UserDAO::mtime($username), "\t", + $entryDAO->size(), "\t", + "\n"; + } +} |
