Merge pull request #570 from ArthurHoaro/config-manager
Introduce a configuration manager
This commit is contained in:
commit
649af5b501
41 changed files with 2099 additions and 1133 deletions
|
@ -132,11 +132,11 @@ public static function checkPHPVersion($minVersion, $curVersion)
|
|||
/**
|
||||
* Checks Shaarli has the proper access permissions to its resources
|
||||
*
|
||||
* @param array $globalConfig The $GLOBALS['config'] array
|
||||
* @param ConfigManager $conf Configuration Manager instance.
|
||||
*
|
||||
* @return array A list of the detected configuration issues
|
||||
*/
|
||||
public static function checkResourcePermissions($globalConfig)
|
||||
public static function checkResourcePermissions($conf)
|
||||
{
|
||||
$errors = array();
|
||||
|
||||
|
@ -145,7 +145,7 @@ public static function checkResourcePermissions($globalConfig)
|
|||
'application',
|
||||
'inc',
|
||||
'plugins',
|
||||
$globalConfig['RAINTPL_TPL']
|
||||
$conf->get('resource.raintpl_tpl'),
|
||||
) as $path) {
|
||||
if (! is_readable(realpath($path))) {
|
||||
$errors[] = '"'.$path.'" directory is not readable';
|
||||
|
@ -154,10 +154,10 @@ public static function checkResourcePermissions($globalConfig)
|
|||
|
||||
// Check cache and data directories are readable and writeable
|
||||
foreach (array(
|
||||
$globalConfig['CACHEDIR'],
|
||||
$globalConfig['DATADIR'],
|
||||
$globalConfig['PAGECACHE'],
|
||||
$globalConfig['RAINTPL_TMP']
|
||||
$conf->get('resource.thumbnails_cache'),
|
||||
$conf->get('resource.data_dir'),
|
||||
$conf->get('resource.page_cache'),
|
||||
$conf->get('resource.raintpl_tmp'),
|
||||
) as $path) {
|
||||
if (! is_readable(realpath($path))) {
|
||||
$errors[] = '"'.$path.'" directory is not readable';
|
||||
|
@ -169,11 +169,11 @@ public static function checkResourcePermissions($globalConfig)
|
|||
|
||||
// Check configuration files are readable and writeable
|
||||
foreach (array(
|
||||
$globalConfig['CONFIG_FILE'],
|
||||
$globalConfig['DATASTORE'],
|
||||
$globalConfig['IPBANS_FILENAME'],
|
||||
$globalConfig['LOG_FILE'],
|
||||
$globalConfig['UPDATECHECK_FILENAME']
|
||||
$conf->getConfigFileExt(),
|
||||
$conf->get('resource.datastore'),
|
||||
$conf->get('resource.ban_file'),
|
||||
$conf->get('resource.log'),
|
||||
$conf->get('resource.update_check'),
|
||||
) as $path) {
|
||||
if (! is_file(realpath($path))) {
|
||||
# the file may not exist yet
|
||||
|
|
|
@ -1,221 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Functions related to configuration management.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Re-write configuration file according to given array.
|
||||
* Requires mandatory fields listed in $MANDATORY_FIELDS.
|
||||
*
|
||||
* @param array $config contains all configuration fields.
|
||||
* @param bool $isLoggedIn true if user is logged in.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws MissingFieldConfigException: a mandatory field has not been provided in $config.
|
||||
* @throws UnauthorizedConfigException: user is not authorize to change configuration.
|
||||
* @throws Exception: an error occured while writing the new config file.
|
||||
*/
|
||||
function writeConfig($config, $isLoggedIn)
|
||||
{
|
||||
// These fields are required in configuration.
|
||||
$MANDATORY_FIELDS = array(
|
||||
'login', 'hash', 'salt', 'timezone', 'title', 'titleLink',
|
||||
'redirector', 'disablesessionprotection', 'privateLinkByDefault'
|
||||
);
|
||||
|
||||
if (!isset($config['config']['CONFIG_FILE'])) {
|
||||
throw new MissingFieldConfigException('CONFIG_FILE');
|
||||
}
|
||||
|
||||
// Only logged in user can alter config.
|
||||
if (is_file($config['config']['CONFIG_FILE']) && !$isLoggedIn) {
|
||||
throw new UnauthorizedConfigException();
|
||||
}
|
||||
|
||||
// Check that all mandatory fields are provided in $config.
|
||||
foreach ($MANDATORY_FIELDS as $field) {
|
||||
if (!isset($config[$field])) {
|
||||
throw new MissingFieldConfigException($field);
|
||||
}
|
||||
}
|
||||
|
||||
$configStr = '<?php '. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'login\'] = '.var_export($config['login'], true).';'. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'hash\'] = '.var_export($config['hash'], true).';'. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'salt\'] = '.var_export($config['salt'], true).'; '. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'timezone\'] = '.var_export($config['timezone'], true).';'. PHP_EOL;
|
||||
$configStr .= 'date_default_timezone_set('.var_export($config['timezone'], true).');'. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'title\'] = '.var_export($config['title'], true).';'. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'titleLink\'] = '.var_export($config['titleLink'], true).'; '. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'redirector\'] = '.var_export($config['redirector'], true).'; '. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'disablesessionprotection\'] = '.var_export($config['disablesessionprotection'], true).'; '. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'privateLinkByDefault\'] = '.var_export($config['privateLinkByDefault'], true).'; '. PHP_EOL;
|
||||
|
||||
// Store all $config['config']
|
||||
foreach ($config['config'] as $key => $value) {
|
||||
$configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($config['config'][$key], true).';'. PHP_EOL;
|
||||
}
|
||||
|
||||
if (isset($config['plugins'])) {
|
||||
foreach ($config['plugins'] as $key => $value) {
|
||||
$configStr .= '$GLOBALS[\'plugins\'][\''. $key .'\'] = '.var_export($config['plugins'][$key], true).';'. PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_put_contents($config['config']['CONFIG_FILE'], $configStr)
|
||||
|| strcmp(file_get_contents($config['config']['CONFIG_FILE']), $configStr) != 0
|
||||
) {
|
||||
throw new Exception(
|
||||
'Shaarli could not create the config file.
|
||||
Please make sure Shaarli has the right to write in the folder is it installed in.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process plugin administration form data and save it in an array.
|
||||
*
|
||||
* @param array $formData Data sent by the plugin admin form.
|
||||
*
|
||||
* @return array New list of enabled plugin, ordered.
|
||||
*
|
||||
* @throws PluginConfigOrderException Plugins can't be sorted because their order is invalid.
|
||||
*/
|
||||
function save_plugin_config($formData)
|
||||
{
|
||||
// Make sure there are no duplicates in orders.
|
||||
if (!validate_plugin_order($formData)) {
|
||||
throw new PluginConfigOrderException();
|
||||
}
|
||||
|
||||
$plugins = array();
|
||||
$newEnabledPlugins = array();
|
||||
foreach ($formData as $key => $data) {
|
||||
if (startsWith($key, 'order')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is no order, it means a disabled plugin has been enabled.
|
||||
if (isset($formData['order_' . $key])) {
|
||||
$plugins[(int) $formData['order_' . $key]] = $key;
|
||||
}
|
||||
else {
|
||||
$newEnabledPlugins[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
// New enabled plugins will be added at the end of order.
|
||||
$plugins = array_merge($plugins, $newEnabledPlugins);
|
||||
|
||||
// Sort plugins by order.
|
||||
if (!ksort($plugins)) {
|
||||
throw new PluginConfigOrderException();
|
||||
}
|
||||
|
||||
$finalPlugins = array();
|
||||
// Make plugins order continuous.
|
||||
foreach ($plugins as $plugin) {
|
||||
$finalPlugins[] = $plugin;
|
||||
}
|
||||
|
||||
return $finalPlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate plugin array submitted.
|
||||
* Will fail if there is duplicate orders value.
|
||||
*
|
||||
* @param array $formData Data from submitted form.
|
||||
*
|
||||
* @return bool true if ok, false otherwise.
|
||||
*/
|
||||
function validate_plugin_order($formData)
|
||||
{
|
||||
$orders = array();
|
||||
foreach ($formData as $key => $value) {
|
||||
// No duplicate order allowed.
|
||||
if (in_array($value, $orders)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (startsWith($key, 'order')) {
|
||||
$orders[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affect plugin parameters values into plugins array.
|
||||
*
|
||||
* @param mixed $plugins Plugins array ($plugins[<plugin_name>]['parameters']['param_name'] = <value>.
|
||||
* @param mixed $config Plugins configuration.
|
||||
*
|
||||
* @return mixed Updated $plugins array.
|
||||
*/
|
||||
function load_plugin_parameter_values($plugins, $config)
|
||||
{
|
||||
$out = $plugins;
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
if (empty($plugin['parameters'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($plugin['parameters'] as $key => $param) {
|
||||
if (!empty($config[$key])) {
|
||||
$out[$name]['parameters'][$key] = $config[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception used if a mandatory field is missing in given configuration.
|
||||
*/
|
||||
class MissingFieldConfigException extends Exception
|
||||
{
|
||||
public $field;
|
||||
|
||||
/**
|
||||
* Construct exception.
|
||||
*
|
||||
* @param string $field field name missing.
|
||||
*/
|
||||
public function __construct($field)
|
||||
{
|
||||
$this->field = $field;
|
||||
$this->message = 'Configuration value is required for '. $this->field;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception used if an unauthorized attempt to edit configuration has been made.
|
||||
*/
|
||||
class UnauthorizedConfigException extends Exception
|
||||
{
|
||||
/**
|
||||
* Construct exception.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = 'You are not authorized to alter config.';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception used if an error occur while saving plugin configuration.
|
||||
*/
|
||||
class PluginConfigOrderException extends Exception
|
||||
{
|
||||
/**
|
||||
* Construct exception.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = 'An error occurred while trying to save plugins loading order.';
|
||||
}
|
||||
}
|
|
@ -9,11 +9,13 @@ class IOException extends Exception
|
|||
/**
|
||||
* Construct a new IOException
|
||||
*
|
||||
* @param string $path path to the ressource that cannot be accessed
|
||||
* @param string $path path to the resource that cannot be accessed
|
||||
* @param string $message Custom exception message.
|
||||
*/
|
||||
public function __construct($path)
|
||||
public function __construct($path, $message = '')
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->message = 'Error accessing '.$this->path;
|
||||
$this->message = empty($message) ? 'Error accessing' : $message;
|
||||
$this->message .= PHP_EOL . $this->path;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,13 +14,21 @@ class PageBuilder
|
|||
*/
|
||||
private $tpl;
|
||||
|
||||
/**
|
||||
* @var ConfigManager $conf Configuration Manager instance.
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
/**
|
||||
* PageBuilder constructor.
|
||||
* $tpl is initialized at false for lazy loading.
|
||||
*
|
||||
* @param ConfigManager $conf Configuration Manager instance (reference).
|
||||
*/
|
||||
function __construct()
|
||||
function __construct(&$conf)
|
||||
{
|
||||
$this->tpl = false;
|
||||
$this->conf = $conf;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,17 +41,17 @@ private function initialize()
|
|||
try {
|
||||
$version = ApplicationUtils::checkUpdate(
|
||||
shaarli_version,
|
||||
$GLOBALS['config']['UPDATECHECK_FILENAME'],
|
||||
$GLOBALS['config']['UPDATECHECK_INTERVAL'],
|
||||
$GLOBALS['config']['ENABLE_UPDATECHECK'],
|
||||
$this->conf->get('resource.update_check'),
|
||||
$this->conf->get('updates.check_updates_interval'),
|
||||
$this->conf->get('updates.check_updates'),
|
||||
isLoggedIn(),
|
||||
$GLOBALS['config']['UPDATECHECK_BRANCH']
|
||||
$this->conf->get('updates.check_updates_branch')
|
||||
);
|
||||
$this->tpl->assign('newVersion', escape($version));
|
||||
$this->tpl->assign('versionError', '');
|
||||
|
||||
} catch (Exception $exc) {
|
||||
logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], $exc->getMessage());
|
||||
logm($this->conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], $exc->getMessage());
|
||||
$this->tpl->assign('newVersion', '');
|
||||
$this->tpl->assign('versionError', escape($exc->getMessage()));
|
||||
}
|
||||
|
@ -62,19 +70,24 @@ private function initialize()
|
|||
$this->tpl->assign('scripturl', index_url($_SERVER));
|
||||
$this->tpl->assign('pagetitle', 'Shaarli');
|
||||
$this->tpl->assign('privateonly', !empty($_SESSION['privateonly'])); // Show only private links?
|
||||
if (!empty($GLOBALS['title'])) {
|
||||
$this->tpl->assign('pagetitle', $GLOBALS['title']);
|
||||
if ($this->conf->exists('general.title')) {
|
||||
$this->tpl->assign('pagetitle', $this->conf->get('general.title'));
|
||||
}
|
||||
if (!empty($GLOBALS['titleLink'])) {
|
||||
$this->tpl->assign('titleLink', $GLOBALS['titleLink']);
|
||||
if ($this->conf->exists('general.header_link')) {
|
||||
$this->tpl->assign('titleLink', $this->conf->get('general.header_link'));
|
||||
}
|
||||
if (!empty($GLOBALS['pagetitle'])) {
|
||||
$this->tpl->assign('pagetitle', $GLOBALS['pagetitle']);
|
||||
if ($this->conf->exists('pagetitle')) {
|
||||
$this->tpl->assign('pagetitle', $this->conf->get('pagetitle'));
|
||||
}
|
||||
$this->tpl->assign('shaarlititle', empty($GLOBALS['title']) ? 'Shaarli': $GLOBALS['title']);
|
||||
$this->tpl->assign('shaarlititle', $this->conf->get('title', 'Shaarli'));
|
||||
$this->tpl->assign('openshaarli', $this->conf->get('security.open_shaarli', false));
|
||||
$this->tpl->assign('showatom', $this->conf->get('feed.show_atom', false));
|
||||
$this->tpl->assign('hide_timestamps', $this->conf->get('privacy.hide_timestamps', false));
|
||||
if (!empty($GLOBALS['plugin_errors'])) {
|
||||
$this->tpl->assign('plugin_errors', $GLOBALS['plugin_errors']);
|
||||
}
|
||||
// To be removed with a proper theme configuration.
|
||||
$this->tpl->assign('conf', $this->conf);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,7 +98,6 @@ private function initialize()
|
|||
*/
|
||||
public function assign($placeholder, $value)
|
||||
{
|
||||
// Lazy initialization
|
||||
if ($this->tpl === false) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
@ -101,7 +113,6 @@ public function assign($placeholder, $value)
|
|||
*/
|
||||
public function assignAll($data)
|
||||
{
|
||||
// Lazy initialization
|
||||
if ($this->tpl === false) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
@ -113,6 +124,7 @@ public function assignAll($data)
|
|||
foreach ($data as $key => $value) {
|
||||
$this->assign($key, $value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,10 +135,10 @@ public function assignAll($data)
|
|||
*/
|
||||
public function renderPage($page)
|
||||
{
|
||||
// Lazy initialization
|
||||
if ($this->tpl === false) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
$this->tpl->draw($page);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,17 +4,9 @@
|
|||
* Class PluginManager
|
||||
*
|
||||
* Use to manage, load and execute plugins.
|
||||
*
|
||||
* Using Singleton design pattern.
|
||||
*/
|
||||
class PluginManager
|
||||
{
|
||||
/**
|
||||
* PluginManager singleton instance.
|
||||
* @var PluginManager $instance
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* List of authorized plugins from configuration file.
|
||||
* @var array $authorizedPlugins
|
||||
|
@ -27,6 +19,11 @@ class PluginManager
|
|||
*/
|
||||
private $loadedPlugins = array();
|
||||
|
||||
/**
|
||||
* @var ConfigManager Configuration Manager instance.
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
/**
|
||||
* Plugins subdirectory.
|
||||
* @var string $PLUGINS_PATH
|
||||
|
@ -40,33 +37,13 @@ class PluginManager
|
|||
public static $META_EXT = 'meta';
|
||||
|
||||
/**
|
||||
* Private constructor: new instances not allowed.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloning isn't allowed either.
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
* @param ConfigManager $conf Configuration Manager instance.
|
||||
*/
|
||||
private function __clone()
|
||||
public function __construct(&$conf)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Return existing instance of PluginManager, or create it.
|
||||
*
|
||||
* @return PluginManager instance.
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (!(self::$instance instanceof self)) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
$this->conf = $conf;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,7 +99,7 @@ public function executeHooks($hook, &$data, $params = array())
|
|||
$hookFunction = $this->buildHookName($hook, $plugin);
|
||||
|
||||
if (function_exists($hookFunction)) {
|
||||
$data = call_user_func($hookFunction, $data);
|
||||
$data = call_user_func($hookFunction, $data, $this->conf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,6 +125,7 @@ private function loadPlugin($dir, $pluginName)
|
|||
throw new PluginFileNotFoundException($pluginName);
|
||||
}
|
||||
|
||||
$conf = $this->conf;
|
||||
include_once $pluginFilePath;
|
||||
|
||||
$this->loadedPlugins[] = $pluginName;
|
||||
|
|
|
@ -12,16 +12,16 @@ class Updater
|
|||
*/
|
||||
protected $doneUpdates;
|
||||
|
||||
/**
|
||||
* @var array Shaarli's configuration array.
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var LinkDB instance.
|
||||
*/
|
||||
protected $linkDB;
|
||||
|
||||
/**
|
||||
* @var ConfigManager $conf Configuration Manager instance.
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
/**
|
||||
* @var bool True if the user is logged in, false otherwise.
|
||||
*/
|
||||
|
@ -36,15 +36,15 @@ class Updater
|
|||
* Object constructor.
|
||||
*
|
||||
* @param array $doneUpdates Updates which are already done.
|
||||
* @param array $config Shaarli's configuration array.
|
||||
* @param LinkDB $linkDB LinkDB instance.
|
||||
* @oaram ConfigManager $conf Configuration Manager instance.
|
||||
* @param boolean $isLoggedIn True if the user is logged in.
|
||||
*/
|
||||
public function __construct($doneUpdates, $config, $linkDB, $isLoggedIn)
|
||||
public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn)
|
||||
{
|
||||
$this->doneUpdates = $doneUpdates;
|
||||
$this->config = $config;
|
||||
$this->linkDB = $linkDB;
|
||||
$this->conf = $conf;
|
||||
$this->isLoggedIn = $isLoggedIn;
|
||||
|
||||
// Retrieve all update methods.
|
||||
|
@ -114,19 +114,19 @@ public function getDoneUpdates()
|
|||
*/
|
||||
public function updateMethodMergeDeprecatedConfigFile()
|
||||
{
|
||||
$config_file = $this->config['config']['CONFIG_FILE'];
|
||||
|
||||
if (is_file($this->config['config']['DATADIR'].'/options.php')) {
|
||||
include $this->config['config']['DATADIR'].'/options.php';
|
||||
if (is_file($this->conf->get('resource.data_dir') . '/options.php')) {
|
||||
include $this->conf->get('resource.data_dir') . '/options.php';
|
||||
|
||||
// Load GLOBALS into config
|
||||
$allowedKeys = array_merge(ConfigPhp::$ROOT_KEYS);
|
||||
$allowedKeys[] = 'config';
|
||||
foreach ($GLOBALS as $key => $value) {
|
||||
$this->config[$key] = $value;
|
||||
if (in_array($key, $allowedKeys)) {
|
||||
$this->conf->set($key, $value);
|
||||
}
|
||||
$this->config['config']['CONFIG_FILE'] = $config_file;
|
||||
writeConfig($this->config, $this->isLoggedIn);
|
||||
|
||||
unlink($this->config['config']['DATADIR'].'/options.php');
|
||||
}
|
||||
$this->conf->write($this->isLoggedIn);
|
||||
unlink($this->conf->get('resource.data_dir').'/options.php');
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -143,7 +143,76 @@ public function updateMethodRenameDashTags()
|
|||
$link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true)));
|
||||
$this->linkDB[$link['linkdate']] = $link;
|
||||
}
|
||||
$this->linkDB->savedb($this->config['config']['PAGECACHE']);
|
||||
$this->linkDB->savedb($this->conf->get('resource.page_cache'));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move old configuration in PHP to the new config system in JSON format.
|
||||
*
|
||||
* Will rename 'config.php' into 'config.save.php' and create 'config.json.php'.
|
||||
* It will also convert legacy setting keys to the new ones.
|
||||
*/
|
||||
public function updateMethodConfigToJson()
|
||||
{
|
||||
// JSON config already exists, nothing to do.
|
||||
if ($this->conf->getConfigIO() instanceof ConfigJson) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$configPhp = new ConfigPhp();
|
||||
$configJson = new ConfigJson();
|
||||
$oldConfig = $configPhp->read($this->conf->getConfigFile() . '.php');
|
||||
rename($this->conf->getConfigFileExt(), $this->conf->getConfigFile() . '.save.php');
|
||||
$this->conf->setConfigIO($configJson);
|
||||
$this->conf->reload();
|
||||
|
||||
$legacyMap = array_flip(ConfigPhp::$LEGACY_KEYS_MAPPING);
|
||||
foreach (ConfigPhp::$ROOT_KEYS as $key) {
|
||||
$this->conf->set($legacyMap[$key], $oldConfig[$key]);
|
||||
}
|
||||
|
||||
// Set sub config keys (config and plugins)
|
||||
$subConfig = array('config', 'plugins');
|
||||
foreach ($subConfig as $sub) {
|
||||
foreach ($oldConfig[$sub] as $key => $value) {
|
||||
if (isset($legacyMap[$sub .'.'. $key])) {
|
||||
$configKey = $legacyMap[$sub .'.'. $key];
|
||||
} else {
|
||||
$configKey = $sub .'.'. $key;
|
||||
}
|
||||
$this->conf->set($configKey, $value);
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
$this->conf->write($this->isLoggedIn);
|
||||
return true;
|
||||
} catch (IOException $e) {
|
||||
error_log($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape settings which have been manually escaped in every request in previous versions:
|
||||
* - general.title
|
||||
* - general.header_link
|
||||
* - extras.redirector
|
||||
*
|
||||
* @return bool true if the update is successful, false otherwise.
|
||||
*/
|
||||
public function escapeUnescapedConfig()
|
||||
{
|
||||
try {
|
||||
$this->conf->set('general.title', escape($this->conf->get('general.title')));
|
||||
$this->conf->set('general.header_link', escape($this->conf->get('general.header_link')));
|
||||
$this->conf->set('redirector.url', escape($this->conf->get('redirector.url')));
|
||||
$this->conf->write($this->isLoggedIn);
|
||||
} catch (Exception $e) {
|
||||
error_log($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -203,7 +272,6 @@ private function buildMessage($message)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the updates file, and return already done updates.
|
||||
*
|
||||
|
|
33
application/config/ConfigIO.php
Normal file
33
application/config/ConfigIO.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Interface ConfigIO
|
||||
*
|
||||
* This describes how Config types should store their configuration.
|
||||
*/
|
||||
interface ConfigIO
|
||||
{
|
||||
/**
|
||||
* Read configuration.
|
||||
*
|
||||
* @param string $filepath Config file absolute path.
|
||||
*
|
||||
* @return array All configuration in an array.
|
||||
*/
|
||||
function read($filepath);
|
||||
|
||||
/**
|
||||
* Write configuration.
|
||||
*
|
||||
* @param string $filepath Config file absolute path.
|
||||
* @param array $conf All configuration in an array.
|
||||
*/
|
||||
function write($filepath, $conf);
|
||||
|
||||
/**
|
||||
* Get config file extension according to config type.
|
||||
*
|
||||
* @return string Config file extension.
|
||||
*/
|
||||
function getExtension();
|
||||
}
|
78
application/config/ConfigJson.php
Normal file
78
application/config/ConfigJson.php
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class ConfigJson (ConfigIO implementation)
|
||||
*
|
||||
* Handle Shaarli's JSON configuration file.
|
||||
*/
|
||||
class ConfigJson implements ConfigIO
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
function read($filepath)
|
||||
{
|
||||
if (! is_readable($filepath)) {
|
||||
return array();
|
||||
}
|
||||
$data = file_get_contents($filepath);
|
||||
$data = str_replace(self::getPhpHeaders(), '', $data);
|
||||
$data = str_replace(self::getPhpSuffix(), '', $data);
|
||||
$data = json_decode($data, true);
|
||||
if ($data === null) {
|
||||
$error = json_last_error();
|
||||
throw new Exception('An error occured while parsing JSON file: error code #'. $error);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
function write($filepath, $conf)
|
||||
{
|
||||
// JSON_PRETTY_PRINT is available from PHP 5.4.
|
||||
$print = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0;
|
||||
$data = self::getPhpHeaders() . json_encode($conf, $print) . self::getPhpSuffix();
|
||||
if (!file_put_contents($filepath, $data)) {
|
||||
throw new IOException(
|
||||
$filepath,
|
||||
'Shaarli could not create the config file.
|
||||
Please make sure Shaarli has the right to write in the folder is it installed in.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
function getExtension()
|
||||
{
|
||||
return '.json.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* The JSON data is wrapped in a PHP file for security purpose.
|
||||
* This way, even if the file is accessible, credentials and configuration won't be exposed.
|
||||
*
|
||||
* Note: this isn't a static field because concatenation isn't supported in field declaration before PHP 5.6.
|
||||
*
|
||||
* @return string PHP start tag and comment tag.
|
||||
*/
|
||||
public static function getPhpHeaders()
|
||||
{
|
||||
return '<?php /*'. PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PHP comment closing tags.
|
||||
*
|
||||
* Static method for consistency with getPhpHeaders.
|
||||
*
|
||||
* @return string PHP comment closing.
|
||||
*/
|
||||
public static function getPhpSuffix()
|
||||
{
|
||||
return PHP_EOL . '*/ ?>';
|
||||
}
|
||||
}
|
392
application/config/ConfigManager.php
Normal file
392
application/config/ConfigManager.php
Normal file
|
@ -0,0 +1,392 @@
|
|||
<?php
|
||||
|
||||
// FIXME! Namespaces...
|
||||
require_once 'ConfigIO.php';
|
||||
require_once 'ConfigJson.php';
|
||||
require_once 'ConfigPhp.php';
|
||||
|
||||
/**
|
||||
* Class ConfigManager
|
||||
*
|
||||
* Manages all Shaarli's settings.
|
||||
* See the documentation for more information on settings:
|
||||
* - doc/Shaarli-configuration.html
|
||||
* - https://github.com/shaarli/Shaarli/wiki/Shaarli-configuration
|
||||
*/
|
||||
class ConfigManager
|
||||
{
|
||||
/**
|
||||
* @var string Flag telling a setting is not found.
|
||||
*/
|
||||
protected static $NOT_FOUND = 'NOT_FOUND';
|
||||
|
||||
/**
|
||||
* @var string Config folder.
|
||||
*/
|
||||
protected $configFile;
|
||||
|
||||
/**
|
||||
* @var array Loaded config array.
|
||||
*/
|
||||
protected $loadedConfig;
|
||||
|
||||
/**
|
||||
* @var ConfigIO implementation instance.
|
||||
*/
|
||||
protected $configIO;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct($configFile = 'data/config')
|
||||
{
|
||||
$this->configFile = $configFile;
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the ConfigManager instance.
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the loaded config array from config files.
|
||||
*/
|
||||
public function reload()
|
||||
{
|
||||
$this->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the ConfigIO and loaded the conf.
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
if (file_exists($this->configFile . '.php')) {
|
||||
$this->configIO = new ConfigPhp();
|
||||
} else {
|
||||
$this->configIO = new ConfigJson();
|
||||
}
|
||||
$this->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load configuration in the ConfigurationManager.
|
||||
*/
|
||||
protected function load()
|
||||
{
|
||||
$this->loadedConfig = $this->configIO->read($this->getConfigFileExt());
|
||||
$this->setDefaultValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a setting.
|
||||
*
|
||||
* Supports nested settings with dot separated keys.
|
||||
* Eg. 'config.stuff.option' will find $conf[config][stuff][option],
|
||||
* or in JSON:
|
||||
* { "config": { "stuff": {"option": "mysetting" } } } }
|
||||
*
|
||||
* @param string $setting Asked setting, keys separated with dots.
|
||||
* @param string $default Default value if not found.
|
||||
*
|
||||
* @return mixed Found setting, or the default value.
|
||||
*/
|
||||
public function get($setting, $default = '')
|
||||
{
|
||||
// During the ConfigIO transition, map legacy settings to the new ones.
|
||||
if ($this->configIO instanceof ConfigPhp && isset(ConfigPhp::$LEGACY_KEYS_MAPPING[$setting])) {
|
||||
$setting = ConfigPhp::$LEGACY_KEYS_MAPPING[$setting];
|
||||
}
|
||||
|
||||
$settings = explode('.', $setting);
|
||||
$value = self::getConfig($settings, $this->loadedConfig);
|
||||
if ($value === self::$NOT_FOUND) {
|
||||
return $default;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a setting, and eventually write it.
|
||||
*
|
||||
* Supports nested settings with dot separated keys.
|
||||
*
|
||||
* @param string $setting Asked setting, keys separated with dots.
|
||||
* @param string $value Value to set.
|
||||
* @param bool $write Write the new setting in the config file, default false.
|
||||
* @param bool $isLoggedIn User login state, default false.
|
||||
*
|
||||
* @throws Exception Invalid
|
||||
*/
|
||||
public function set($setting, $value, $write = false, $isLoggedIn = false)
|
||||
{
|
||||
if (empty($setting) || ! is_string($setting)) {
|
||||
throw new Exception('Invalid setting key parameter. String expected, got: '. gettype($setting));
|
||||
}
|
||||
|
||||
// During the ConfigIO transition, map legacy settings to the new ones.
|
||||
if ($this->configIO instanceof ConfigPhp && isset(ConfigPhp::$LEGACY_KEYS_MAPPING[$setting])) {
|
||||
$setting = ConfigPhp::$LEGACY_KEYS_MAPPING[$setting];
|
||||
}
|
||||
|
||||
$settings = explode('.', $setting);
|
||||
self::setConfig($settings, $value, $this->loadedConfig);
|
||||
if ($write) {
|
||||
$this->write($isLoggedIn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a settings exists.
|
||||
*
|
||||
* Supports nested settings with dot separated keys.
|
||||
*
|
||||
* @param string $setting Asked setting, keys separated with dots.
|
||||
*
|
||||
* @return bool true if the setting exists, false otherwise.
|
||||
*/
|
||||
public function exists($setting)
|
||||
{
|
||||
// During the ConfigIO transition, map legacy settings to the new ones.
|
||||
if ($this->configIO instanceof ConfigPhp && isset(ConfigPhp::$LEGACY_KEYS_MAPPING[$setting])) {
|
||||
$setting = ConfigPhp::$LEGACY_KEYS_MAPPING[$setting];
|
||||
}
|
||||
|
||||
$settings = explode('.', $setting);
|
||||
$value = self::getConfig($settings, $this->loadedConfig);
|
||||
if ($value === self::$NOT_FOUND) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the config writer.
|
||||
*
|
||||
* @param bool $isLoggedIn User login state.
|
||||
*
|
||||
* @return bool True if the configuration has been successfully written, false otherwise.
|
||||
*
|
||||
* @throws MissingFieldConfigException: a mandatory field has not been provided in $conf.
|
||||
* @throws UnauthorizedConfigException: user is not authorize to change configuration.
|
||||
* @throws IOException: an error occurred while writing the new config file.
|
||||
*/
|
||||
public function write($isLoggedIn)
|
||||
{
|
||||
// These fields are required in configuration.
|
||||
$mandatoryFields = array(
|
||||
'credentials.login',
|
||||
'credentials.hash',
|
||||
'credentials.salt',
|
||||
'security.session_protection_disabled',
|
||||
'general.timezone',
|
||||
'general.title',
|
||||
'general.header_link',
|
||||
'privacy.default_private_links',
|
||||
'redirector.url',
|
||||
);
|
||||
|
||||
// Only logged in user can alter config.
|
||||
if (is_file($this->getConfigFileExt()) && !$isLoggedIn) {
|
||||
throw new UnauthorizedConfigException();
|
||||
}
|
||||
|
||||
// Check that all mandatory fields are provided in $conf.
|
||||
foreach ($mandatoryFields as $field) {
|
||||
if (! $this->exists($field)) {
|
||||
throw new MissingFieldConfigException($field);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->configIO->write($this->getConfigFileExt(), $this->loadedConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the config file path (without extension).
|
||||
*
|
||||
* @param string $configFile File path.
|
||||
*/
|
||||
public function setConfigFile($configFile)
|
||||
{
|
||||
$this->configFile = $configFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration file path (without extension).
|
||||
*
|
||||
* @return string Config path.
|
||||
*/
|
||||
public function getConfigFile()
|
||||
{
|
||||
return $this->configFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration file path with its extension.
|
||||
*
|
||||
* @return string Config file path.
|
||||
*/
|
||||
public function getConfigFileExt()
|
||||
{
|
||||
return $this->configFile . $this->configIO->getExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive function which find asked setting in the loaded config.
|
||||
*
|
||||
* @param array $settings Ordered array which contains keys to find.
|
||||
* @param array $conf Loaded settings, then sub-array.
|
||||
*
|
||||
* @return mixed Found setting or NOT_FOUND flag.
|
||||
*/
|
||||
protected static function getConfig($settings, $conf)
|
||||
{
|
||||
if (!is_array($settings) || count($settings) == 0) {
|
||||
return self::$NOT_FOUND;
|
||||
}
|
||||
|
||||
$setting = array_shift($settings);
|
||||
if (!isset($conf[$setting])) {
|
||||
return self::$NOT_FOUND;
|
||||
}
|
||||
|
||||
if (count($settings) > 0) {
|
||||
return self::getConfig($settings, $conf[$setting]);
|
||||
}
|
||||
return $conf[$setting];
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive function which find asked setting in the loaded config.
|
||||
*
|
||||
* @param array $settings Ordered array which contains keys to find.
|
||||
* @param mixed $value
|
||||
* @param array $conf Loaded settings, then sub-array.
|
||||
*
|
||||
* @return mixed Found setting or NOT_FOUND flag.
|
||||
*/
|
||||
protected static function setConfig($settings, $value, &$conf)
|
||||
{
|
||||
if (!is_array($settings) || count($settings) == 0) {
|
||||
return self::$NOT_FOUND;
|
||||
}
|
||||
|
||||
$setting = array_shift($settings);
|
||||
if (count($settings) > 0) {
|
||||
return self::setConfig($settings, $value, $conf[$setting]);
|
||||
}
|
||||
$conf[$setting] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a bunch of default values allowing Shaarli to start without a config file.
|
||||
*/
|
||||
protected function setDefaultValues()
|
||||
{
|
||||
$this->setEmpty('resource.data_dir', 'data');
|
||||
$this->setEmpty('resource.config', 'data/config.php');
|
||||
$this->setEmpty('resource.datastore', 'data/datastore.php');
|
||||
$this->setEmpty('resource.ban_file', 'data/ipbans.php');
|
||||
$this->setEmpty('resource.updates', 'data/updates.txt');
|
||||
$this->setEmpty('resource.log', 'data/log.txt');
|
||||
$this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt');
|
||||
$this->setEmpty('resource.raintpl_tpl', 'tpl/');
|
||||
$this->setEmpty('resource.raintpl_tmp', 'tmp/');
|
||||
$this->setEmpty('resource.thumbnails_cache', 'cache');
|
||||
$this->setEmpty('resource.page_cache', 'pagecache');
|
||||
|
||||
$this->setEmpty('security.ban_after', 4);
|
||||
$this->setEmpty('security.ban_duration', 1800);
|
||||
$this->setEmpty('security.session_protection_disabled', false);
|
||||
$this->setEmpty('security.open_shaarli', false);
|
||||
|
||||
$this->setEmpty('general.header_link', '?');
|
||||
$this->setEmpty('general.links_per_page', 20);
|
||||
$this->setEmpty('general.enabled_plugins', array('qrcode'));
|
||||
|
||||
$this->setEmpty('updates.check_updates', false);
|
||||
$this->setEmpty('updates.check_updates_branch', 'stable');
|
||||
$this->setEmpty('updates.check_updates_interval', 86400);
|
||||
|
||||
$this->setEmpty('feed.rss_permalinks', true);
|
||||
$this->setEmpty('feed.show_atom', false);
|
||||
|
||||
$this->setEmpty('privacy.default_private_links', false);
|
||||
$this->setEmpty('privacy.hide_public_links', false);
|
||||
$this->setEmpty('privacy.hide_timestamps', false);
|
||||
|
||||
$this->setEmpty('thumbnail.enable_thumbnails', true);
|
||||
$this->setEmpty('thumbnail.enable_localcache', true);
|
||||
|
||||
$this->setEmpty('redirector.url', '');
|
||||
$this->setEmpty('redirector.encode_url', true);
|
||||
|
||||
$this->setEmpty('plugins', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set only if the setting does not exists.
|
||||
*
|
||||
* @param string $key Setting key.
|
||||
* @param mixed $value Setting value.
|
||||
*/
|
||||
public function setEmpty($key, $value)
|
||||
{
|
||||
if (! $this->exists($key)) {
|
||||
$this->set($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ConfigIO
|
||||
*/
|
||||
public function getConfigIO()
|
||||
{
|
||||
return $this->configIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ConfigIO $configIO
|
||||
*/
|
||||
public function setConfigIO($configIO)
|
||||
{
|
||||
$this->configIO = $configIO;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception used if a mandatory field is missing in given configuration.
|
||||
*/
|
||||
class MissingFieldConfigException extends Exception
|
||||
{
|
||||
public $field;
|
||||
|
||||
/**
|
||||
* Construct exception.
|
||||
*
|
||||
* @param string $field field name missing.
|
||||
*/
|
||||
public function __construct($field)
|
||||
{
|
||||
$this->field = $field;
|
||||
$this->message = 'Configuration value is required for '. $this->field;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception used if an unauthorized attempt to edit configuration has been made.
|
||||
*/
|
||||
class UnauthorizedConfigException extends Exception
|
||||
{
|
||||
/**
|
||||
* Construct exception.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = 'You are not authorized to alter config.';
|
||||
}
|
||||
}
|
132
application/config/ConfigPhp.php
Normal file
132
application/config/ConfigPhp.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class ConfigPhp (ConfigIO implementation)
|
||||
*
|
||||
* Handle Shaarli's legacy PHP configuration file.
|
||||
* Note: this is only designed to support the transition to JSON configuration.
|
||||
*/
|
||||
class ConfigPhp implements ConfigIO
|
||||
{
|
||||
/**
|
||||
* @var array List of config key without group.
|
||||
*/
|
||||
public static $ROOT_KEYS = array(
|
||||
'login',
|
||||
'hash',
|
||||
'salt',
|
||||
'timezone',
|
||||
'title',
|
||||
'titleLink',
|
||||
'redirector',
|
||||
'disablesessionprotection',
|
||||
'privateLinkByDefault',
|
||||
);
|
||||
|
||||
/**
|
||||
* Map legacy config keys with the new ones.
|
||||
* If ConfigPhp is used, getting <newkey> will actually look for <legacykey>.
|
||||
* The Updater will use this array to transform keys when switching to JSON.
|
||||
*
|
||||
* @var array current key => legacy key.
|
||||
*/
|
||||
public static $LEGACY_KEYS_MAPPING = array(
|
||||
'credentials.login' => 'login',
|
||||
'credentials.hash' => 'hash',
|
||||
'credentials.salt' => 'salt',
|
||||
'resource.data_dir' => 'config.DATADIR',
|
||||
'resource.config' => 'config.CONFIG_FILE',
|
||||
'resource.datastore' => 'config.DATASTORE',
|
||||
'resource.updates' => 'config.UPDATES_FILE',
|
||||
'resource.log' => 'config.LOG_FILE',
|
||||
'resource.update_check' => 'config.UPDATECHECK_FILENAME',
|
||||
'resource.raintpl_tpl' => 'config.RAINTPL_TPL',
|
||||
'resource.raintpl_tmp' => 'config.RAINTPL_TMP',
|
||||
'resource.thumbnails_cache' => 'config.CACHEDIR',
|
||||
'resource.page_cache' => 'config.PAGECACHE',
|
||||
'resource.ban_file' => 'config.IPBANS_FILENAME',
|
||||
'security.session_protection_disabled' => 'disablesessionprotection',
|
||||
'security.ban_after' => 'config.BAN_AFTER',
|
||||
'security.ban_duration' => 'config.BAN_DURATION',
|
||||
'general.title' => 'title',
|
||||
'general.timezone' => 'timezone',
|
||||
'general.header_link' => 'titleLink',
|
||||
'updates.check_updates' => 'config.ENABLE_UPDATECHECK',
|
||||
'updates.check_updates_branch' => 'config.UPDATECHECK_BRANCH',
|
||||
'updates.check_updates_interval' => 'config.UPDATECHECK_INTERVAL',
|
||||
'privacy.default_private_links' => 'privateLinkByDefault',
|
||||
'feed.rss_permalinks' => 'config.ENABLE_RSS_PERMALINKS',
|
||||
'general.links_per_page' => 'config.LINKS_PER_PAGE',
|
||||
'thumbnail.enable_thumbnails' => 'config.ENABLE_THUMBNAILS',
|
||||
'thumbnail.enable_localcache' => 'config.ENABLE_LOCALCACHE',
|
||||
'general.enabled_plugins' => 'config.ENABLED_PLUGINS',
|
||||
'redirector.url' => 'redirector',
|
||||
'redirector.encode_url' => 'config.REDIRECTOR_URLENCODE',
|
||||
'feed.show_atom' => 'config.SHOW_ATOM',
|
||||
'privacy.hide_public_links' => 'config.HIDE_PUBLIC_LINKS',
|
||||
'privacy.hide_timestamps' => 'config.HIDE_TIMESTAMPS',
|
||||
'security.open_shaarli' => 'config.OPEN_SHAARLI',
|
||||
);
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
function read($filepath)
|
||||
{
|
||||
if (! file_exists($filepath) || ! is_readable($filepath)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
include $filepath;
|
||||
|
||||
$out = array();
|
||||
foreach (self::$ROOT_KEYS as $key) {
|
||||
$out[$key] = $GLOBALS[$key];
|
||||
}
|
||||
$out['config'] = $GLOBALS['config'];
|
||||
$out['plugins'] = !empty($GLOBALS['plugins']) ? $GLOBALS['plugins'] : array();
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
function write($filepath, $conf)
|
||||
{
|
||||
$configStr = '<?php '. PHP_EOL;
|
||||
foreach (self::$ROOT_KEYS as $key) {
|
||||
if (isset($conf[$key])) {
|
||||
$configStr .= '$GLOBALS[\'' . $key . '\'] = ' . var_export($conf[$key], true) . ';' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
// Store all $conf['config']
|
||||
foreach ($conf['config'] as $key => $value) {
|
||||
$configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($conf['config'][$key], true).';'. PHP_EOL;
|
||||
}
|
||||
|
||||
if (isset($conf['plugins'])) {
|
||||
foreach ($conf['plugins'] as $key => $value) {
|
||||
$configStr .= '$GLOBALS[\'plugins\'][\''. $key .'\'] = '.var_export($conf['plugins'][$key], true).';'. PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_put_contents($filepath, $configStr)
|
||||
|| strcmp(file_get_contents($filepath), $configStr) != 0
|
||||
) {
|
||||
throw new IOException(
|
||||
$filepath,
|
||||
'Shaarli could not create the config file.
|
||||
Please make sure Shaarli has the right to write in the folder is it installed in.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
function getExtension()
|
||||
{
|
||||
return '.php';
|
||||
}
|
||||
}
|
120
application/config/ConfigPlugin.php
Normal file
120
application/config/ConfigPlugin.php
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugin configuration helper functions.
|
||||
*
|
||||
* Note: no access to configuration files here.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Process plugin administration form data and save it in an array.
|
||||
*
|
||||
* @param array $formData Data sent by the plugin admin form.
|
||||
*
|
||||
* @return array New list of enabled plugin, ordered.
|
||||
*
|
||||
* @throws PluginConfigOrderException Plugins can't be sorted because their order is invalid.
|
||||
*/
|
||||
function save_plugin_config($formData)
|
||||
{
|
||||
// Make sure there are no duplicates in orders.
|
||||
if (!validate_plugin_order($formData)) {
|
||||
throw new PluginConfigOrderException();
|
||||
}
|
||||
|
||||
$plugins = array();
|
||||
$newEnabledPlugins = array();
|
||||
foreach ($formData as $key => $data) {
|
||||
if (startsWith($key, 'order')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is no order, it means a disabled plugin has been enabled.
|
||||
if (isset($formData['order_' . $key])) {
|
||||
$plugins[(int) $formData['order_' . $key]] = $key;
|
||||
}
|
||||
else {
|
||||
$newEnabledPlugins[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
// New enabled plugins will be added at the end of order.
|
||||
$plugins = array_merge($plugins, $newEnabledPlugins);
|
||||
|
||||
// Sort plugins by order.
|
||||
if (!ksort($plugins)) {
|
||||
throw new PluginConfigOrderException();
|
||||
}
|
||||
|
||||
$finalPlugins = array();
|
||||
// Make plugins order continuous.
|
||||
foreach ($plugins as $plugin) {
|
||||
$finalPlugins[] = $plugin;
|
||||
}
|
||||
|
||||
return $finalPlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate plugin array submitted.
|
||||
* Will fail if there is duplicate orders value.
|
||||
*
|
||||
* @param array $formData Data from submitted form.
|
||||
*
|
||||
* @return bool true if ok, false otherwise.
|
||||
*/
|
||||
function validate_plugin_order($formData)
|
||||
{
|
||||
$orders = array();
|
||||
foreach ($formData as $key => $value) {
|
||||
// No duplicate order allowed.
|
||||
if (in_array($value, $orders)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (startsWith($key, 'order')) {
|
||||
$orders[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affect plugin parameters values into plugins array.
|
||||
*
|
||||
* @param mixed $plugins Plugins array ($plugins[<plugin_name>]['parameters']['param_name'] = <value>.
|
||||
* @param mixed $conf Plugins configuration.
|
||||
*
|
||||
* @return mixed Updated $plugins array.
|
||||
*/
|
||||
function load_plugin_parameter_values($plugins, $conf)
|
||||
{
|
||||
$out = $plugins;
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
if (empty($plugin['parameters'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($plugin['parameters'] as $key => $param) {
|
||||
if (!empty($conf[$key])) {
|
||||
$out[$name]['parameters'][$key] = $conf[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception used if an error occur while saving plugin configuration.
|
||||
*/
|
||||
class PluginConfigOrderException extends Exception
|
||||
{
|
||||
/**
|
||||
* Construct exception.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = 'An error occurred while trying to save plugins loading order.';
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
<?php
|
||||
|
||||
$GLOBALS['plugins']['READITYOUSELF_URL'] = 'http://someurl.com';
|
|
@ -8,34 +8,31 @@
|
|||
// it seems kinda dead.
|
||||
// Not tested.
|
||||
|
||||
// don't raise unnecessary warnings
|
||||
if (is_file(PluginManager::$PLUGINS_PATH . '/readityourself/config.php')) {
|
||||
include PluginManager::$PLUGINS_PATH . '/readityourself/config.php';
|
||||
}
|
||||
|
||||
if (empty($GLOBALS['plugins']['READITYOUSELF_URL'])) {
|
||||
$riyUrl = $conf->get('plugins.READITYOUSELF_URL');
|
||||
if (empty($riyUrl)) {
|
||||
$GLOBALS['plugin_errors'][] = 'Readityourself plugin error: '.
|
||||
'Please define "$GLOBALS[\'plugins\'][\'READITYOUSELF_URL\']" '.
|
||||
'in "plugins/readityourself/config.php" or in your Shaarli config.php file.';
|
||||
'Please define the "READITYOUSELF_URL" setting in the plugin administration page.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add readityourself icon to link_plugin when rendering linklist.
|
||||
*
|
||||
* @param mixed $data - linklist data.
|
||||
* @param mixed $data Linklist data.
|
||||
* @param ConfigManager $conf Configuration Manager instance.
|
||||
*
|
||||
* @return mixed - linklist data with readityourself plugin.
|
||||
*/
|
||||
function hook_readityourself_render_linklist($data)
|
||||
function hook_readityourself_render_linklist($data, $conf)
|
||||
{
|
||||
if (!isset($GLOBALS['plugins']['READITYOUSELF_URL'])) {
|
||||
$riyUrl = $conf->get('plugins.READITYOUSELF_URL');
|
||||
if (empty($riyUrl)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$readityourself_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/readityourself/readityourself.html');
|
||||
|
||||
foreach ($data['links'] as &$value) {
|
||||
$readityourself = sprintf($readityourself_html, $GLOBALS['plugins']['READITYOUSELF_URL'], $value['url'], PluginManager::$PLUGINS_PATH);
|
||||
$readityourself = sprintf($readityourself_html, $riyUrl, $value['url'], PluginManager::$PLUGINS_PATH);
|
||||
$value['link_plugin'][] = $readityourself;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,31 +12,26 @@ The directory structure should look like:
|
|||
└── plugins
|
||||
└── wallabag
|
||||
├── README.md
|
||||
├── config.php.dist
|
||||
├── wallabag.html
|
||||
├── wallabag.meta
|
||||
├── wallabag.php
|
||||
└── wallabag.png
|
||||
├── wallabag.php
|
||||
└── WallabagInstance.php
|
||||
```
|
||||
|
||||
To enable the plugin, add `'wallabag'` to your list of enabled plugins in `data/options.php` (`PLUGINS` array).
|
||||
This should look like:
|
||||
To enable the plugin, you can either:
|
||||
|
||||
```
|
||||
$GLOBALS['config']['PLUGINS'] = array('qrcode', 'any_other_plugin', 'wallabag')
|
||||
```
|
||||
* enable it in the plugins administration page (`?do=pluginadmin`).
|
||||
* add `wallabag` to your list of enabled plugins in `data/config.json.php` (`general.enabled_plugins` section).
|
||||
|
||||
### Configuration
|
||||
|
||||
Copy `config.php.dist` into `config.php` and setup your instance.
|
||||
Go to the plugin administration page, and edit the following settings (with the plugin enabled).
|
||||
|
||||
*Wallabag instance URL*
|
||||
```
|
||||
$GLOBALS['config']['WALLABAG_URL'] = 'http://v2.wallabag.org' ;
|
||||
```
|
||||
**WALLABAG_URL**: *Wallabag instance URL*
|
||||
Example value: `http://v2.wallabag.org`
|
||||
|
||||
*Wallabag version*: either `1` (for 1.x) or `2` (for 2.x)
|
||||
```
|
||||
$GLOBALS['config']['WALLABAG_VERSION'] = 2;
|
||||
```
|
||||
**WALLABAG_VERSION**: *Wallabag version*
|
||||
Value: either `1` (for 1.x) or `2` (for 2.x)
|
||||
|
||||
> Note: these settings can also be set in `data/config.php`.
|
||||
> Note: these settings can also be set in `data/config.json.php`, in the plugins section.
|
|
@ -1,4 +0,0 @@
|
|||
<?php
|
||||
|
||||
$GLOBALS['plugins']['WALLABAG_URL'] = 'https://demo.wallabag.org';
|
||||
$GLOBALS['plugins']['WALLABAG_VERSION'] = 1;
|
|
@ -6,34 +6,29 @@
|
|||
|
||||
require_once 'WallabagInstance.php';
|
||||
|
||||
// don't raise unnecessary warnings
|
||||
if (is_file(PluginManager::$PLUGINS_PATH . '/wallabag/config.php')) {
|
||||
include PluginManager::$PLUGINS_PATH . '/wallabag/config.php';
|
||||
}
|
||||
|
||||
if (empty($GLOBALS['plugins']['WALLABAG_URL'])) {
|
||||
$wallabagUrl = $conf->get('plugins.WALLABAG_URL');
|
||||
if (empty($wallabagUrl)) {
|
||||
$GLOBALS['plugin_errors'][] = 'Wallabag plugin error: '.
|
||||
'Please define "$GLOBALS[\'plugins\'][\'WALLABAG_URL\']" '.
|
||||
'in "plugins/wallabag/config.php" or in your Shaarli config.php file.';
|
||||
'Please define the "WALLABAG_URL" setting in the plugin administration page.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add wallabag icon to link_plugin when rendering linklist.
|
||||
*
|
||||
* @param mixed $data - linklist data.
|
||||
* @param mixed $data Linklist data.
|
||||
* @param ConfigManager $conf Configuration Manager instance.
|
||||
*
|
||||
* @return mixed - linklist data with wallabag plugin.
|
||||
*/
|
||||
function hook_wallabag_render_linklist($data)
|
||||
function hook_wallabag_render_linklist($data, $conf)
|
||||
{
|
||||
if (!isset($GLOBALS['plugins']['WALLABAG_URL'])) {
|
||||
$wallabagUrl = $conf->get('plugins.WALLABAG_URL');
|
||||
if (empty($wallabagUrl)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$version = isset($GLOBALS['plugins']['WALLABAG_VERSION'])
|
||||
? $GLOBALS['plugins']['WALLABAG_VERSION']
|
||||
: '';
|
||||
$wallabagInstance = new WallabagInstance($GLOBALS['plugins']['WALLABAG_URL'], $version);
|
||||
$version = $conf->get('plugins.WALLABAG_VERSION');
|
||||
$wallabagInstance = new WallabagInstance($wallabagUrl, $version);
|
||||
|
||||
$wallabagHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/wallabag/wallabag.html');
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* ApplicationUtils' tests
|
||||
*/
|
||||
|
||||
require_once 'application/config/ConfigManager.php';
|
||||
require_once 'application/ApplicationUtils.php';
|
||||
|
||||
/**
|
||||
|
@ -59,7 +60,7 @@ public function testGetLatestGitVersionCode()
|
|||
$testTimeout
|
||||
)
|
||||
);
|
||||
$this->assertRegexp(
|
||||
$this->assertRegExp(
|
||||
self::$versionPattern,
|
||||
ApplicationUtils::getLatestGitVersionCode(
|
||||
'https://raw.githubusercontent.com/shaarli/Shaarli/'
|
||||
|
@ -275,21 +276,21 @@ public function testCheckSupportedPHPVersion52()
|
|||
*/
|
||||
public function testCheckCurrentResourcePermissions()
|
||||
{
|
||||
$config = array(
|
||||
'CACHEDIR' => 'cache',
|
||||
'CONFIG_FILE' => 'data/config.php',
|
||||
'DATADIR' => 'data',
|
||||
'DATASTORE' => 'data/datastore.php',
|
||||
'IPBANS_FILENAME' => 'data/ipbans.php',
|
||||
'LOG_FILE' => 'data/log.txt',
|
||||
'PAGECACHE' => 'pagecache',
|
||||
'RAINTPL_TMP' => 'tmp',
|
||||
'RAINTPL_TPL' => 'tpl',
|
||||
'UPDATECHECK_FILENAME' => 'data/lastupdatecheck.txt'
|
||||
);
|
||||
$conf = new ConfigManager('');
|
||||
$conf->set('resource.thumbnails_cache', 'cache');
|
||||
$conf->set('resource.config', 'data/config.php');
|
||||
$conf->set('resource.data_dir', 'data');
|
||||
$conf->set('resource.datastore', 'data/datastore.php');
|
||||
$conf->set('resource.ban_file', 'data/ipbans.php');
|
||||
$conf->set('resource.log', 'data/log.txt');
|
||||
$conf->set('resource.page_cache', 'pagecache');
|
||||
$conf->set('resource.raintpl_tmp', 'tmp');
|
||||
$conf->set('resource.raintpl_tpl', 'tpl');
|
||||
$conf->set('resource.update_check', 'data/lastupdatecheck.txt');
|
||||
|
||||
$this->assertEquals(
|
||||
array(),
|
||||
ApplicationUtils::checkResourcePermissions($config)
|
||||
ApplicationUtils::checkResourcePermissions($conf)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -298,18 +299,17 @@ public function testCheckCurrentResourcePermissions()
|
|||
*/
|
||||
public function testCheckCurrentResourcePermissionsErrors()
|
||||
{
|
||||
$config = array(
|
||||
'CACHEDIR' => 'null/cache',
|
||||
'CONFIG_FILE' => 'null/data/config.php',
|
||||
'DATADIR' => 'null/data',
|
||||
'DATASTORE' => 'null/data/store.php',
|
||||
'IPBANS_FILENAME' => 'null/data/ipbans.php',
|
||||
'LOG_FILE' => 'null/data/log.txt',
|
||||
'PAGECACHE' => 'null/pagecache',
|
||||
'RAINTPL_TMP' => 'null/tmp',
|
||||
'RAINTPL_TPL' => 'null/tpl',
|
||||
'UPDATECHECK_FILENAME' => 'null/data/lastupdatecheck.txt'
|
||||
);
|
||||
$conf = new ConfigManager('');
|
||||
$conf->set('resource.thumbnails_cache', 'null/cache');
|
||||
$conf->set('resource.config', 'null/data/config.php');
|
||||
$conf->set('resource.data_dir', 'null/data');
|
||||
$conf->set('resource.datastore', 'null/data/store.php');
|
||||
$conf->set('resource.ban_file', 'null/data/ipbans.php');
|
||||
$conf->set('resource.log', 'null/data/log.txt');
|
||||
$conf->set('resource.page_cache', 'null/pagecache');
|
||||
$conf->set('resource.raintpl_tmp', 'null/tmp');
|
||||
$conf->set('resource.raintpl_tpl', 'null/tpl');
|
||||
$conf->set('resource.update_check', 'null/data/lastupdatecheck.txt');
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'"null/tpl" directory is not readable',
|
||||
|
@ -322,7 +322,7 @@ public function testCheckCurrentResourcePermissionsErrors()
|
|||
'"null/tmp" directory is not readable',
|
||||
'"null/tmp" directory is not writable'
|
||||
),
|
||||
ApplicationUtils::checkResourcePermissions($config)
|
||||
ApplicationUtils::checkResourcePermissions($conf)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,244 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Config' tests
|
||||
*/
|
||||
|
||||
require_once 'application/Config.php';
|
||||
|
||||
/**
|
||||
* Unitary tests for Shaarli config related functions
|
||||
*/
|
||||
class ConfigTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
// Configuration input set.
|
||||
private static $configFields;
|
||||
|
||||
/**
|
||||
* Executed before each test.
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
self::$configFields = array(
|
||||
'login' => 'login',
|
||||
'hash' => 'hash',
|
||||
'salt' => 'salt',
|
||||
'timezone' => 'Europe/Paris',
|
||||
'title' => 'title',
|
||||
'titleLink' => 'titleLink',
|
||||
'redirector' => '',
|
||||
'disablesessionprotection' => false,
|
||||
'privateLinkByDefault' => false,
|
||||
'config' => array(
|
||||
'CONFIG_FILE' => 'tests/config.php',
|
||||
'DATADIR' => 'tests',
|
||||
'config1' => 'config1data',
|
||||
'config2' => 'config2data',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed after each test.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
if (is_file(self::$configFields['config']['CONFIG_FILE'])) {
|
||||
unlink(self::$configFields['config']['CONFIG_FILE']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writeConfig function, valid use case, while being logged in.
|
||||
*/
|
||||
public function testWriteConfig()
|
||||
{
|
||||
writeConfig(self::$configFields, true);
|
||||
|
||||
include self::$configFields['config']['CONFIG_FILE'];
|
||||
$this->assertEquals(self::$configFields['login'], $GLOBALS['login']);
|
||||
$this->assertEquals(self::$configFields['hash'], $GLOBALS['hash']);
|
||||
$this->assertEquals(self::$configFields['salt'], $GLOBALS['salt']);
|
||||
$this->assertEquals(self::$configFields['timezone'], $GLOBALS['timezone']);
|
||||
$this->assertEquals(self::$configFields['title'], $GLOBALS['title']);
|
||||
$this->assertEquals(self::$configFields['titleLink'], $GLOBALS['titleLink']);
|
||||
$this->assertEquals(self::$configFields['redirector'], $GLOBALS['redirector']);
|
||||
$this->assertEquals(self::$configFields['disablesessionprotection'], $GLOBALS['disablesessionprotection']);
|
||||
$this->assertEquals(self::$configFields['privateLinkByDefault'], $GLOBALS['privateLinkByDefault']);
|
||||
$this->assertEquals(self::$configFields['config']['config1'], $GLOBALS['config']['config1']);
|
||||
$this->assertEquals(self::$configFields['config']['config2'], $GLOBALS['config']['config2']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writeConfig option while logged in:
|
||||
* 1. init fields.
|
||||
* 2. update fields, add new sub config, add new root config.
|
||||
* 3. rewrite config.
|
||||
* 4. check result.
|
||||
*/
|
||||
public function testWriteConfigFieldUpdate()
|
||||
{
|
||||
writeConfig(self::$configFields, true);
|
||||
self::$configFields['title'] = 'ok';
|
||||
self::$configFields['config']['config1'] = 'ok';
|
||||
self::$configFields['config']['config_new'] = 'ok';
|
||||
self::$configFields['new'] = 'should not be saved';
|
||||
writeConfig(self::$configFields, true);
|
||||
|
||||
include self::$configFields['config']['CONFIG_FILE'];
|
||||
$this->assertEquals('ok', $GLOBALS['title']);
|
||||
$this->assertEquals('ok', $GLOBALS['config']['config1']);
|
||||
$this->assertEquals('ok', $GLOBALS['config']['config_new']);
|
||||
$this->assertFalse(isset($GLOBALS['new']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writeConfig function with an empty array.
|
||||
*
|
||||
* @expectedException MissingFieldConfigException
|
||||
*/
|
||||
public function testWriteConfigEmpty()
|
||||
{
|
||||
writeConfig(array(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writeConfig function with a missing mandatory field.
|
||||
*
|
||||
* @expectedException MissingFieldConfigException
|
||||
*/
|
||||
public function testWriteConfigMissingField()
|
||||
{
|
||||
unset(self::$configFields['login']);
|
||||
writeConfig(self::$configFields, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writeConfig function while being logged out, and there is no config file existing.
|
||||
*/
|
||||
public function testWriteConfigLoggedOutNoFile()
|
||||
{
|
||||
writeConfig(self::$configFields, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writeConfig function while being logged out, and a config file already exists.
|
||||
*
|
||||
* @expectedException UnauthorizedConfigException
|
||||
*/
|
||||
public function testWriteConfigLoggedOutWithFile()
|
||||
{
|
||||
file_put_contents(self::$configFields['config']['CONFIG_FILE'], '');
|
||||
writeConfig(self::$configFields, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test save_plugin_config with valid data.
|
||||
*
|
||||
* @throws PluginConfigOrderException
|
||||
*/
|
||||
public function testSavePluginConfigValid()
|
||||
{
|
||||
$data = array(
|
||||
'order_plugin1' => 2, // no plugin related
|
||||
'plugin2' => 0, // new - at the end
|
||||
'plugin3' => 0, // 2nd
|
||||
'order_plugin3' => 8,
|
||||
'plugin4' => 0, // 1st
|
||||
'order_plugin4' => 5,
|
||||
);
|
||||
|
||||
$expected = array(
|
||||
'plugin3',
|
||||
'plugin4',
|
||||
'plugin2',
|
||||
);
|
||||
|
||||
$out = save_plugin_config($data);
|
||||
$this->assertEquals($expected, $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test save_plugin_config with invalid data.
|
||||
*
|
||||
* @expectedException PluginConfigOrderException
|
||||
*/
|
||||
public function testSavePluginConfigInvalid()
|
||||
{
|
||||
$data = array(
|
||||
'plugin2' => 0,
|
||||
'plugin3' => 0,
|
||||
'order_plugin3' => 0,
|
||||
'plugin4' => 0,
|
||||
'order_plugin4' => 0,
|
||||
);
|
||||
|
||||
save_plugin_config($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test save_plugin_config without data.
|
||||
*/
|
||||
public function testSavePluginConfigEmpty()
|
||||
{
|
||||
$this->assertEquals(array(), save_plugin_config(array()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validate_plugin_order with valid data.
|
||||
*/
|
||||
public function testValidatePluginOrderValid()
|
||||
{
|
||||
$data = array(
|
||||
'order_plugin1' => 2,
|
||||
'plugin2' => 0,
|
||||
'plugin3' => 0,
|
||||
'order_plugin3' => 1,
|
||||
'plugin4' => 0,
|
||||
'order_plugin4' => 5,
|
||||
);
|
||||
|
||||
$this->assertTrue(validate_plugin_order($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validate_plugin_order with invalid data.
|
||||
*/
|
||||
public function testValidatePluginOrderInvalid()
|
||||
{
|
||||
$data = array(
|
||||
'order_plugin1' => 2,
|
||||
'order_plugin3' => 1,
|
||||
'order_plugin4' => 1,
|
||||
);
|
||||
|
||||
$this->assertFalse(validate_plugin_order($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test load_plugin_parameter_values.
|
||||
*/
|
||||
public function testLoadPluginParameterValues()
|
||||
{
|
||||
$plugins = array(
|
||||
'plugin_name' => array(
|
||||
'parameters' => array(
|
||||
'param1' => true,
|
||||
'param2' => false,
|
||||
'param3' => '',
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$parameters = array(
|
||||
'param1' => 'value1',
|
||||
'param2' => 'value2',
|
||||
);
|
||||
|
||||
$result = load_plugin_parameter_values($plugins, $parameters);
|
||||
$this->assertEquals('value1', $result['plugin_name']['parameters']['param1']);
|
||||
$this->assertEquals('value2', $result['plugin_name']['parameters']['param2']);
|
||||
$this->assertEquals('', $result['plugin_name']['parameters']['param3']);
|
||||
}
|
||||
}
|
|
@ -76,7 +76,7 @@ public function testRSSBuildData()
|
|||
// Test headers (RSS)
|
||||
$this->assertEquals(self::$RSS_LANGUAGE, $data['language']);
|
||||
$this->assertEmpty($data['pubsubhub_url']);
|
||||
$this->assertEquals('Tue, 10 Mar 2015 11:46:51 +0100', $data['last_update']);
|
||||
$this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $data['last_update']);
|
||||
$this->assertEquals(true, $data['show_dates']);
|
||||
$this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']);
|
||||
$this->assertEquals('http://host.tld/', $data['index_url']);
|
||||
|
@ -88,7 +88,7 @@ public function testRSSBuildData()
|
|||
$this->assertEquals('20150310_114651', $link['linkdate']);
|
||||
$this->assertEquals('http://host.tld/?WDWyig', $link['guid']);
|
||||
$this->assertEquals('http://host.tld/?WDWyig', $link['url']);
|
||||
$this->assertEquals('Tue, 10 Mar 2015 11:46:51 +0100', $link['iso_date']);
|
||||
$this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $link['iso_date']);
|
||||
$this->assertContains('Stallman has a beard', $link['description']);
|
||||
$this->assertContains('Permalink', $link['description']);
|
||||
$this->assertContains('http://host.tld/?WDWyig', $link['description']);
|
||||
|
@ -113,7 +113,7 @@ public function testAtomBuildData()
|
|||
$data = $feedBuilder->buildData();
|
||||
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
|
||||
$link = array_shift($data['links']);
|
||||
$this->assertEquals('2015-03-10T11:46:51+01:00', $link['iso_date']);
|
||||
$this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:+\d{2}/', $link['iso_date']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -101,7 +101,7 @@ public function testConstructLoggedOut()
|
|||
* Attempt to instantiate a LinkDB whereas the datastore is not writable
|
||||
*
|
||||
* @expectedException IOException
|
||||
* @expectedExceptionMessageRegExp /Error accessing null/
|
||||
* @expectedExceptionMessageRegExp /Error accessing\nnull/
|
||||
*/
|
||||
public function testConstructDatastoreNotWriteable()
|
||||
{
|
||||
|
|
|
@ -23,6 +23,17 @@ class PluginManagerTest extends PHPUnit_Framework_TestCase
|
|||
*/
|
||||
private static $pluginName = 'test';
|
||||
|
||||
/**
|
||||
* @var PluginManager $pluginManager Plugin Mananger instance.
|
||||
*/
|
||||
protected $pluginManager;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$conf = new ConfigManager('');
|
||||
$this->pluginManager = new PluginManager($conf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test plugin loading and hook execution.
|
||||
*
|
||||
|
@ -30,23 +41,21 @@ class PluginManagerTest extends PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testPlugin()
|
||||
{
|
||||
$pluginManager = PluginManager::getInstance();
|
||||
|
||||
PluginManager::$PLUGINS_PATH = self::$pluginPath;
|
||||
$pluginManager->load(array(self::$pluginName));
|
||||
$this->pluginManager->load(array(self::$pluginName));
|
||||
|
||||
$this->assertTrue(function_exists('hook_test_random'));
|
||||
|
||||
$data = array(0 => 'woot');
|
||||
$pluginManager->executeHooks('random', $data);
|
||||
$this->pluginManager->executeHooks('random', $data);
|
||||
$this->assertEquals('woot', $data[1]);
|
||||
|
||||
$data = array(0 => 'woot');
|
||||
$pluginManager->executeHooks('random', $data, array('target' => 'test'));
|
||||
$this->pluginManager->executeHooks('random', $data, array('target' => 'test'));
|
||||
$this->assertEquals('page test', $data[1]);
|
||||
|
||||
$data = array(0 => 'woot');
|
||||
$pluginManager->executeHooks('random', $data, array('loggedin' => true));
|
||||
$this->pluginManager->executeHooks('random', $data, array('loggedin' => true));
|
||||
$this->assertEquals('loggedin', $data[1]);
|
||||
}
|
||||
|
||||
|
@ -57,11 +66,8 @@ public function testPlugin()
|
|||
*/
|
||||
public function testPluginNotFound()
|
||||
{
|
||||
$pluginManager = PluginManager::getInstance();
|
||||
|
||||
$pluginManager->load(array());
|
||||
|
||||
$pluginManager->load(array('nope', 'renope'));
|
||||
$this->pluginManager->load(array());
|
||||
$this->pluginManager->load(array('nope', 'renope'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,16 +75,14 @@ public function testPluginNotFound()
|
|||
*/
|
||||
public function testGetPluginsMeta()
|
||||
{
|
||||
$pluginManager = PluginManager::getInstance();
|
||||
|
||||
PluginManager::$PLUGINS_PATH = self::$pluginPath;
|
||||
$pluginManager->load(array(self::$pluginName));
|
||||
$this->pluginManager->load(array(self::$pluginName));
|
||||
|
||||
$expectedParameters = array(
|
||||
'pop' => '',
|
||||
'hip' => '',
|
||||
);
|
||||
$meta = $pluginManager->getPluginsMeta();
|
||||
$meta = $this->pluginManager->getPluginsMeta();
|
||||
$this->assertEquals('test plugin', $meta[self::$pluginName]['description']);
|
||||
$this->assertEquals($expectedParameters, $meta[self::$pluginName]['parameters']);
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ class DummyUpdater extends Updater
|
|||
* Object constructor.
|
||||
*
|
||||
* @param array $doneUpdates Updates which are already done.
|
||||
* @param array $config Shaarli's configuration array.
|
||||
* @param LinkDB $linkDB LinkDB instance.
|
||||
* @param ConfigManager $conf Configuration Manager instance.
|
||||
* @param boolean $isLoggedIn True if the user is logged in.
|
||||
*/
|
||||
public function __construct($doneUpdates, $config, $linkDB, $isLoggedIn)
|
||||
public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn)
|
||||
{
|
||||
parent::__construct($doneUpdates, $config, $linkDB, $isLoggedIn);
|
||||
parent::__construct($doneUpdates, $linkDB, $conf, $isLoggedIn);
|
||||
|
||||
// Retrieve all update methods.
|
||||
// For unit test, only retrieve final methods,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
require_once 'application/config/ConfigManager.php';
|
||||
require_once 'tests/Updater/DummyUpdater.php';
|
||||
|
||||
/**
|
||||
|
@ -8,59 +9,27 @@
|
|||
*/
|
||||
class UpdaterTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var array Configuration input set.
|
||||
*/
|
||||
private static $configFields;
|
||||
|
||||
/**
|
||||
* @var string Path to test datastore.
|
||||
*/
|
||||
protected static $testDatastore = 'sandbox/datastore.php';
|
||||
|
||||
/**
|
||||
* @var string Config file path (without extension).
|
||||
*/
|
||||
protected static $configFile = 'tests/utils/config/configJson';
|
||||
|
||||
/**
|
||||
* @var ConfigManager
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
/**
|
||||
* Executed before each test.
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
self::$configFields = array(
|
||||
'login' => 'login',
|
||||
'hash' => 'hash',
|
||||
'salt' => 'salt',
|
||||
'timezone' => 'Europe/Paris',
|
||||
'title' => 'title',
|
||||
'titleLink' => 'titleLink',
|
||||
'redirector' => '',
|
||||
'disablesessionprotection' => false,
|
||||
'privateLinkByDefault' => false,
|
||||
'config' => array(
|
||||
'CONFIG_FILE' => 'tests/Updater/config.php',
|
||||
'DATADIR' => 'tests/Updater',
|
||||
'PAGECACHE' => 'sandbox/pagecache',
|
||||
'config1' => 'config1data',
|
||||
'config2' => 'config2data',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed after each test.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
if (is_file(self::$configFields['config']['CONFIG_FILE'])) {
|
||||
unlink(self::$configFields['config']['CONFIG_FILE']);
|
||||
}
|
||||
|
||||
if (is_file(self::$configFields['config']['DATADIR'] . '/options.php')) {
|
||||
unlink(self::$configFields['config']['DATADIR'] . '/options.php');
|
||||
}
|
||||
|
||||
if (is_file(self::$configFields['config']['DATADIR'] . '/updates.json')) {
|
||||
unlink(self::$configFields['config']['DATADIR'] . '/updates.json');
|
||||
}
|
||||
$this->conf = new ConfigManager(self::$configFile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,9 +38,10 @@ public function tearDown()
|
|||
public function testReadEmptyUpdatesFile()
|
||||
{
|
||||
$this->assertEquals(array(), read_updates_file(''));
|
||||
$updatesFile = self::$configFields['config']['DATADIR'] . '/updates.json';
|
||||
$updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
|
||||
touch($updatesFile);
|
||||
$this->assertEquals(array(), read_updates_file($updatesFile));
|
||||
unlink($updatesFile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,7 +49,7 @@ public function testReadEmptyUpdatesFile()
|
|||
*/
|
||||
public function testReadWriteUpdatesFile()
|
||||
{
|
||||
$updatesFile = self::$configFields['config']['DATADIR'] . '/updates.json';
|
||||
$updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
|
||||
$updatesMethods = array('m1', 'm2', 'm3');
|
||||
|
||||
write_updates_file($updatesFile, $updatesMethods);
|
||||
|
@ -91,6 +61,7 @@ public function testReadWriteUpdatesFile()
|
|||
write_updates_file($updatesFile, $updatesMethods);
|
||||
$readMethods = read_updates_file($updatesFile);
|
||||
$this->assertEquals($readMethods, $updatesMethods);
|
||||
unlink($updatesFile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,10 +83,15 @@ public function testWriteEmptyUpdatesFile()
|
|||
*/
|
||||
public function testWriteUpdatesFileNotWritable()
|
||||
{
|
||||
$updatesFile = self::$configFields['config']['DATADIR'] . '/updates.json';
|
||||
$updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
|
||||
touch($updatesFile);
|
||||
chmod($updatesFile, 0444);
|
||||
try {
|
||||
@write_updates_file($updatesFile, array('test'));
|
||||
} catch (Exception $e) {
|
||||
unlink($updatesFile);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -131,10 +107,10 @@ public function testNoUpdates()
|
|||
'updateMethodDummy3',
|
||||
'updateMethodException',
|
||||
);
|
||||
$updater = new DummyUpdater($updates, array(), array(), true);
|
||||
$updater = new DummyUpdater($updates, array(), $this->conf, true);
|
||||
$this->assertEquals(array(), $updater->update());
|
||||
|
||||
$updater = new DummyUpdater(array(), array(), array(), false);
|
||||
$updater = new DummyUpdater(array(), array(), $this->conf, false);
|
||||
$this->assertEquals(array(), $updater->update());
|
||||
}
|
||||
|
||||
|
@ -149,7 +125,7 @@ public function testUpdatesFirstTime()
|
|||
'updateMethodDummy2',
|
||||
'updateMethodDummy3',
|
||||
);
|
||||
$updater = new DummyUpdater($updates, array(), array(), true);
|
||||
$updater = new DummyUpdater($updates, array(), $this->conf, true);
|
||||
$this->assertEquals($expectedUpdates, $updater->update());
|
||||
}
|
||||
|
||||
|
@ -165,7 +141,7 @@ public function testOneUpdate()
|
|||
);
|
||||
$expectedUpdate = array('updateMethodDummy2');
|
||||
|
||||
$updater = new DummyUpdater($updates, array(), array(), true);
|
||||
$updater = new DummyUpdater($updates, array(), $this->conf, true);
|
||||
$this->assertEquals($expectedUpdate, $updater->update());
|
||||
}
|
||||
|
||||
|
@ -182,7 +158,7 @@ public function testUpdateFailed()
|
|||
'updateMethodDummy3',
|
||||
);
|
||||
|
||||
$updater = new DummyUpdater($updates, array(), array(), true);
|
||||
$updater = new DummyUpdater($updates, array(), $this->conf, true);
|
||||
$updater->update();
|
||||
}
|
||||
|
||||
|
@ -195,26 +171,28 @@ public function testUpdateFailed()
|
|||
*/
|
||||
public function testUpdateMergeDeprecatedConfig()
|
||||
{
|
||||
// init
|
||||
writeConfig(self::$configFields, true);
|
||||
$configCopy = self::$configFields;
|
||||
$invert = !$configCopy['privateLinkByDefault'];
|
||||
$configCopy['privateLinkByDefault'] = $invert;
|
||||
$this->conf->setConfigFile('tests/utils/config/configPhp');
|
||||
$this->conf->reset();
|
||||
|
||||
// Use writeConfig to create a options.php
|
||||
$configCopy['config']['CONFIG_FILE'] = 'tests/Updater/options.php';
|
||||
writeConfig($configCopy, true);
|
||||
$optionsFile = 'tests/Updater/options.php';
|
||||
$options = '<?php
|
||||
$GLOBALS[\'privateLinkByDefault\'] = true;';
|
||||
file_put_contents($optionsFile, $options);
|
||||
|
||||
$this->assertTrue(is_file($configCopy['config']['CONFIG_FILE']));
|
||||
// tmp config file.
|
||||
$this->conf->setConfigFile('tests/Updater/config');
|
||||
|
||||
// merge configs
|
||||
$updater = new Updater(array(), self::$configFields, array(), true);
|
||||
$updater = new Updater(array(), array(), $this->conf, true);
|
||||
// This writes a new config file in tests/Updater/config.php
|
||||
$updater->updateMethodMergeDeprecatedConfigFile();
|
||||
|
||||
// make sure updated field is changed
|
||||
include self::$configFields['config']['CONFIG_FILE'];
|
||||
$this->assertEquals($invert, $GLOBALS['privateLinkByDefault']);
|
||||
$this->assertFalse(is_file($configCopy['config']['CONFIG_FILE']));
|
||||
$this->conf->reload();
|
||||
$this->assertTrue($this->conf->get('privacy.default_private_links'));
|
||||
$this->assertFalse(is_file($optionsFile));
|
||||
// Delete the generated file.
|
||||
unlink($this->conf->getConfigFileExt());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -222,23 +200,67 @@ public function testUpdateMergeDeprecatedConfig()
|
|||
*/
|
||||
public function testMergeDeprecatedConfigNoFile()
|
||||
{
|
||||
writeConfig(self::$configFields, true);
|
||||
|
||||
$updater = new Updater(array(), self::$configFields, array(), true);
|
||||
$updater = new Updater(array(), array(), $this->conf, true);
|
||||
$updater->updateMethodMergeDeprecatedConfigFile();
|
||||
|
||||
include self::$configFields['config']['CONFIG_FILE'];
|
||||
$this->assertEquals(self::$configFields['login'], $GLOBALS['login']);
|
||||
$this->assertEquals('root', $this->conf->get('credentials.login'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test renameDashTags update method.
|
||||
*/
|
||||
public function testRenameDashTags()
|
||||
{
|
||||
$refDB = new ReferenceLinkDB();
|
||||
$refDB->write(self::$testDatastore);
|
||||
$linkDB = new LinkDB(self::$testDatastore, true, false);
|
||||
$this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude')));
|
||||
$updater = new Updater(array(), self::$configFields, $linkDB, true);
|
||||
$updater = new Updater(array(), $linkDB, $this->conf, true);
|
||||
$updater->updateMethodRenameDashTags();
|
||||
$this->assertNotEmpty($linkDB->filterSearch(array('searchtags' => 'exclude')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert old PHP config file to JSON config.
|
||||
*/
|
||||
public function testConfigToJson()
|
||||
{
|
||||
$configFile = 'tests/utils/config/configPhp';
|
||||
$this->conf->setConfigFile($configFile);
|
||||
$this->conf->reset();
|
||||
|
||||
// The ConfigIO is initialized with ConfigPhp.
|
||||
$this->assertTrue($this->conf->getConfigIO() instanceof ConfigPhp);
|
||||
|
||||
$updater = new Updater(array(), array(), $this->conf, false);
|
||||
$done = $updater->updateMethodConfigToJson();
|
||||
$this->assertTrue($done);
|
||||
|
||||
// The ConfigIO has been updated to ConfigJson.
|
||||
$this->assertTrue($this->conf->getConfigIO() instanceof ConfigJson);
|
||||
$this->assertTrue(file_exists($this->conf->getConfigFileExt()));
|
||||
|
||||
// Check JSON config data.
|
||||
$this->conf->reload();
|
||||
$this->assertEquals('root', $this->conf->get('credentials.login'));
|
||||
$this->assertEquals('lala', $this->conf->get('redirector.url'));
|
||||
$this->assertEquals('data/datastore.php', $this->conf->get('resource.datastore'));
|
||||
$this->assertEquals('1', $this->conf->get('plugins.WALLABAG_VERSION'));
|
||||
|
||||
rename($configFile . '.save.php', $configFile . '.php');
|
||||
unlink($this->conf->getConfigFileExt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch config conversion update with an existing JSON file => nothing to do.
|
||||
*/
|
||||
public function testConfigToJsonNothingToDo()
|
||||
{
|
||||
$filetime = filemtime($this->conf->getConfigFileExt());
|
||||
$updater = new Updater(array(), array(), $this->conf, false);
|
||||
$done = $updater->updateMethodConfigToJson();
|
||||
$this->assertTrue($done);
|
||||
$expected = filemtime($this->conf->getConfigFileExt());
|
||||
$this->assertEquals($expected, $filetime);
|
||||
}
|
||||
}
|
||||
|
|
133
tests/config/ConfigJsonTest.php
Normal file
133
tests/config/ConfigJsonTest.php
Normal file
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
|
||||
require_once 'application/config/ConfigJson.php';
|
||||
|
||||
/**
|
||||
* Class ConfigJsonTest
|
||||
*/
|
||||
class ConfigJsonTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var ConfigJson
|
||||
*/
|
||||
protected $configIO;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->configIO = new ConfigJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a simple existing config file.
|
||||
*/
|
||||
public function testRead()
|
||||
{
|
||||
$conf = $this->configIO->read('tests/utils/config/configJson.json.php');
|
||||
$this->assertEquals('root', $conf['credentials']['login']);
|
||||
$this->assertEquals('lala', $conf['redirector']['url']);
|
||||
$this->assertEquals('tests/utils/config/datastore.php', $conf['resource']['datastore']);
|
||||
$this->assertEquals('1', $conf['plugins']['WALLABAG_VERSION']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a non existent config file -> empty array.
|
||||
*/
|
||||
public function testReadNonExistent()
|
||||
{
|
||||
$this->assertEquals(array(), $this->configIO->read('nope'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a non existent config file -> empty array.
|
||||
*
|
||||
* @expectedException Exception
|
||||
* @expectedExceptionMessage An error occured while parsing JSON file: error code #4
|
||||
*/
|
||||
public function testReadInvalidJson()
|
||||
{
|
||||
$this->configIO->read('tests/utils/config/configInvalid.json.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new config file.
|
||||
*/
|
||||
public function testWriteNew()
|
||||
{
|
||||
$dataFile = 'tests/utils/config/configWrite.json.php';
|
||||
$data = array(
|
||||
'credentials' => array(
|
||||
'login' => 'root',
|
||||
),
|
||||
'resource' => array(
|
||||
'datastore' => 'data/datastore.php',
|
||||
),
|
||||
'redirector' => array(
|
||||
'url' => 'lala',
|
||||
),
|
||||
'plugins' => array(
|
||||
'WALLABAG_VERSION' => '1',
|
||||
)
|
||||
);
|
||||
$this->configIO->write($dataFile, $data);
|
||||
// PHP 5.3 doesn't support json pretty print.
|
||||
if (defined('JSON_PRETTY_PRINT')) {
|
||||
$expected = '{
|
||||
"credentials": {
|
||||
"login": "root"
|
||||
},
|
||||
"resource": {
|
||||
"datastore": "data\/datastore.php"
|
||||
},
|
||||
"redirector": {
|
||||
"url": "lala"
|
||||
},
|
||||
"plugins": {
|
||||
"WALLABAG_VERSION": "1"
|
||||
}
|
||||
}';
|
||||
} else {
|
||||
$expected = '{"credentials":{"login":"root"},"resource":{"datastore":"data\/datastore.php"},"redirector":{"url":"lala"},"plugins":{"WALLABAG_VERSION":"1"}}';
|
||||
}
|
||||
$expected = ConfigJson::getPhpHeaders() . $expected . ConfigJson::getPhpSuffix();
|
||||
$this->assertEquals($expected, file_get_contents($dataFile));
|
||||
unlink($dataFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite an existing setting.
|
||||
*/
|
||||
public function testOverwrite()
|
||||
{
|
||||
$source = 'tests/utils/config/configJson.json.php';
|
||||
$dest = 'tests/utils/config/configOverwrite.json.php';
|
||||
copy($source, $dest);
|
||||
$conf = $this->configIO->read($dest);
|
||||
$conf['redirector']['url'] = 'blabla';
|
||||
$this->configIO->write($dest, $conf);
|
||||
$conf = $this->configIO->read($dest);
|
||||
$this->assertEquals('blabla', $conf['redirector']['url']);
|
||||
unlink($dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to invalid path.
|
||||
*
|
||||
* @expectedException IOException
|
||||
*/
|
||||
public function testWriteInvalidArray()
|
||||
{
|
||||
$conf = array('conf' => 'value');
|
||||
@$this->configIO->write(array(), $conf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to invalid path.
|
||||
*
|
||||
* @expectedException IOException
|
||||
*/
|
||||
public function testWriteInvalidBlank()
|
||||
{
|
||||
$conf = array('conf' => 'value');
|
||||
@$this->configIO->write('', $conf);
|
||||
}
|
||||
}
|
172
tests/config/ConfigManagerTest.php
Normal file
172
tests/config/ConfigManagerTest.php
Normal file
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Unit tests for Class ConfigManagerTest
|
||||
*
|
||||
* Note: it only test the manager with ConfigJson,
|
||||
* ConfigPhp is only a workaround to handle the transition to JSON type.
|
||||
*/
|
||||
class ConfigManagerTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var ConfigManager
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple config test:
|
||||
* 1. Set settings.
|
||||
* 2. Check settings value.
|
||||
*/
|
||||
public function testSetGet()
|
||||
{
|
||||
$this->conf->set('paramInt', 42);
|
||||
$this->conf->set('paramString', 'value1');
|
||||
$this->conf->set('paramBool', false);
|
||||
$this->conf->set('paramArray', array('foo' => 'bar'));
|
||||
$this->conf->set('paramNull', null);
|
||||
|
||||
$this->assertEquals(42, $this->conf->get('paramInt'));
|
||||
$this->assertEquals('value1', $this->conf->get('paramString'));
|
||||
$this->assertFalse($this->conf->get('paramBool'));
|
||||
$this->assertEquals(array('foo' => 'bar'), $this->conf->get('paramArray'));
|
||||
$this->assertEquals(null, $this->conf->get('paramNull'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set/write/get config test:
|
||||
* 1. Set settings.
|
||||
* 2. Write it to the config file.
|
||||
* 3. Read the file.
|
||||
* 4. Check settings value.
|
||||
*/
|
||||
public function testSetWriteGet()
|
||||
{
|
||||
$this->conf->set('paramInt', 42);
|
||||
$this->conf->set('paramString', 'value1');
|
||||
$this->conf->set('paramBool', false);
|
||||
$this->conf->set('paramArray', array('foo' => 'bar'));
|
||||
$this->conf->set('paramNull', null);
|
||||
|
||||
$this->conf->setConfigFile('tests/utils/config/configTmp');
|
||||
$this->conf->write(true);
|
||||
$this->conf->reload();
|
||||
unlink($this->conf->getConfigFileExt());
|
||||
|
||||
$this->assertEquals(42, $this->conf->get('paramInt'));
|
||||
$this->assertEquals('value1', $this->conf->get('paramString'));
|
||||
$this->assertFalse($this->conf->get('paramBool'));
|
||||
$this->assertEquals(array('foo' => 'bar'), $this->conf->get('paramArray'));
|
||||
$this->assertEquals(null, $this->conf->get('paramNull'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test set/write/get with nested keys.
|
||||
*/
|
||||
public function testSetWriteGetNested()
|
||||
{
|
||||
$this->conf->set('foo.bar.key.stuff', 'testSetWriteGetNested');
|
||||
|
||||
$this->conf->setConfigFile('tests/utils/config/configTmp');
|
||||
$this->conf->write(true);
|
||||
$this->conf->reload();
|
||||
unlink($this->conf->getConfigFileExt());
|
||||
|
||||
$this->assertEquals('testSetWriteGetNested', $this->conf->get('foo.bar.key.stuff'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set with an empty key.
|
||||
*
|
||||
* @expectedException Exception
|
||||
* @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
|
||||
*/
|
||||
public function testSetEmptyKey()
|
||||
{
|
||||
$this->conf->set('', 'stuff');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set with an array key.
|
||||
*
|
||||
* @expectedException Exception
|
||||
* @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
|
||||
*/
|
||||
public function testSetArrayKey()
|
||||
{
|
||||
$this->conf->set(array('foo' => 'bar'), 'stuff');
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to write the config without mandatory parameter (e.g. 'login').
|
||||
*
|
||||
* @expectedException MissingFieldConfigException
|
||||
*/
|
||||
public function testWriteMissingParameter()
|
||||
{
|
||||
$this->conf->setConfigFile('tests/utils/config/configTmp');
|
||||
$this->assertFalse(file_exists($this->conf->getConfigFileExt()));
|
||||
$this->conf->reload();
|
||||
|
||||
$this->conf->write(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get non existent config keys.
|
||||
*/
|
||||
public function testGetNonExistent()
|
||||
{
|
||||
$this->assertEquals('', $this->conf->get('nope.test'));
|
||||
$this->assertEquals('default', $this->conf->get('nope.test', 'default'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the 'exists' method with existent values.
|
||||
*/
|
||||
public function testExistsOk()
|
||||
{
|
||||
$this->assertTrue($this->conf->exists('credentials.login'));
|
||||
$this->assertTrue($this->conf->exists('config.foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the 'exists' method with non existent or invalid values.
|
||||
*/
|
||||
public function testExistsKo()
|
||||
{
|
||||
$this->assertFalse($this->conf->exists('nope'));
|
||||
$this->assertFalse($this->conf->exists('nope.nope'));
|
||||
$this->assertFalse($this->conf->exists(''));
|
||||
$this->assertFalse($this->conf->exists(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the ConfigManager instance.
|
||||
*/
|
||||
public function testReset()
|
||||
{
|
||||
$confIO = $this->conf->getConfigIO();
|
||||
$this->conf->reset();
|
||||
$this->assertFalse($confIO === $this->conf->getConfigIO());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the config from file.
|
||||
*/
|
||||
public function testReload()
|
||||
{
|
||||
$this->conf->setConfigFile('tests/utils/config/configTmp');
|
||||
$newConf = ConfigJson::getPhpHeaders() . '{ "key": "value" }';
|
||||
file_put_contents($this->conf->getConfigFileExt(), $newConf);
|
||||
$this->conf->reload();
|
||||
unlink($this->conf->getConfigFileExt());
|
||||
// Previous conf no longer exists, and new values have been loaded.
|
||||
$this->assertFalse($this->conf->exists('credentials.login'));
|
||||
$this->assertEquals('value', $this->conf->get('key'));
|
||||
}
|
||||
}
|
82
tests/config/ConfigPhpTest.php
Normal file
82
tests/config/ConfigPhpTest.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
require_once 'application/config/ConfigPhp.php';
|
||||
|
||||
/**
|
||||
* Class ConfigPhpTest
|
||||
*/
|
||||
class ConfigPhpTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var ConfigPhp
|
||||
*/
|
||||
protected $configIO;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->configIO = new ConfigPhp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a simple existing config file.
|
||||
*/
|
||||
public function testRead()
|
||||
{
|
||||
$conf = $this->configIO->read('tests/utils/config/configPhp.php');
|
||||
$this->assertEquals('root', $conf['login']);
|
||||
$this->assertEquals('lala', $conf['redirector']);
|
||||
$this->assertEquals('data/datastore.php', $conf['config']['DATASTORE']);
|
||||
$this->assertEquals('1', $conf['plugins']['WALLABAG_VERSION']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a non existent config file -> empty array.
|
||||
*/
|
||||
public function testReadNonExistent()
|
||||
{
|
||||
$this->assertEquals(array(), $this->configIO->read('nope'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new config file.
|
||||
*/
|
||||
public function testWriteNew()
|
||||
{
|
||||
$dataFile = 'tests/utils/config/configWrite.php';
|
||||
$data = array(
|
||||
'login' => 'root',
|
||||
'redirector' => 'lala',
|
||||
'config' => array(
|
||||
'DATASTORE' => 'data/datastore.php',
|
||||
),
|
||||
'plugins' => array(
|
||||
'WALLABAG_VERSION' => '1',
|
||||
)
|
||||
);
|
||||
$this->configIO->write($dataFile, $data);
|
||||
$expected = '<?php
|
||||
$GLOBALS[\'login\'] = \'root\';
|
||||
$GLOBALS[\'redirector\'] = \'lala\';
|
||||
$GLOBALS[\'config\'][\'DATASTORE\'] = \'data/datastore.php\';
|
||||
$GLOBALS[\'plugins\'][\'WALLABAG_VERSION\'] = \'1\';
|
||||
';
|
||||
$this->assertEquals($expected, file_get_contents($dataFile));
|
||||
unlink($dataFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite an existing setting.
|
||||
*/
|
||||
public function testOverwrite()
|
||||
{
|
||||
$source = 'tests/utils/config/configPhp.php';
|
||||
$dest = 'tests/utils/config/configOverwrite.php';
|
||||
copy($source, $dest);
|
||||
$conf = $this->configIO->read($dest);
|
||||
$conf['redirector'] = 'blabla';
|
||||
$this->configIO->write($dest, $conf);
|
||||
$conf = $this->configIO->read($dest);
|
||||
$this->assertEquals('blabla', $conf['redirector']);
|
||||
unlink($dest);
|
||||
}
|
||||
}
|
121
tests/config/ConfigPluginTest.php
Normal file
121
tests/config/ConfigPluginTest.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
/**
|
||||
* Config' tests
|
||||
*/
|
||||
|
||||
require_once 'application/config/ConfigPlugin.php';
|
||||
|
||||
/**
|
||||
* Unitary tests for Shaarli config related functions
|
||||
*/
|
||||
class ConfigPluginTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Test save_plugin_config with valid data.
|
||||
*
|
||||
* @throws PluginConfigOrderException
|
||||
*/
|
||||
public function testSavePluginConfigValid()
|
||||
{
|
||||
$data = array(
|
||||
'order_plugin1' => 2, // no plugin related
|
||||
'plugin2' => 0, // new - at the end
|
||||
'plugin3' => 0, // 2nd
|
||||
'order_plugin3' => 8,
|
||||
'plugin4' => 0, // 1st
|
||||
'order_plugin4' => 5,
|
||||
);
|
||||
|
||||
$expected = array(
|
||||
'plugin3',
|
||||
'plugin4',
|
||||
'plugin2',
|
||||
);
|
||||
|
||||
$out = save_plugin_config($data);
|
||||
$this->assertEquals($expected, $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test save_plugin_config with invalid data.
|
||||
*
|
||||
* @expectedException PluginConfigOrderException
|
||||
*/
|
||||
public function testSavePluginConfigInvalid()
|
||||
{
|
||||
$data = array(
|
||||
'plugin2' => 0,
|
||||
'plugin3' => 0,
|
||||
'order_plugin3' => 0,
|
||||
'plugin4' => 0,
|
||||
'order_plugin4' => 0,
|
||||
);
|
||||
|
||||
save_plugin_config($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test save_plugin_config without data.
|
||||
*/
|
||||
public function testSavePluginConfigEmpty()
|
||||
{
|
||||
$this->assertEquals(array(), save_plugin_config(array()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validate_plugin_order with valid data.
|
||||
*/
|
||||
public function testValidatePluginOrderValid()
|
||||
{
|
||||
$data = array(
|
||||
'order_plugin1' => 2,
|
||||
'plugin2' => 0,
|
||||
'plugin3' => 0,
|
||||
'order_plugin3' => 1,
|
||||
'plugin4' => 0,
|
||||
'order_plugin4' => 5,
|
||||
);
|
||||
|
||||
$this->assertTrue(validate_plugin_order($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validate_plugin_order with invalid data.
|
||||
*/
|
||||
public function testValidatePluginOrderInvalid()
|
||||
{
|
||||
$data = array(
|
||||
'order_plugin1' => 2,
|
||||
'order_plugin3' => 1,
|
||||
'order_plugin4' => 1,
|
||||
);
|
||||
|
||||
$this->assertFalse(validate_plugin_order($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test load_plugin_parameter_values.
|
||||
*/
|
||||
public function testLoadPluginParameterValues()
|
||||
{
|
||||
$plugins = array(
|
||||
'plugin_name' => array(
|
||||
'parameters' => array(
|
||||
'param1' => true,
|
||||
'param2' => false,
|
||||
'param3' => '',
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$parameters = array(
|
||||
'param1' => 'value1',
|
||||
'param2' => 'value2',
|
||||
);
|
||||
|
||||
$result = load_plugin_parameter_values($plugins, $parameters);
|
||||
$this->assertEquals('value1', $result['plugin_name']['parameters']['param1']);
|
||||
$this->assertEquals('value2', $result['plugin_name']['parameters']['param2']);
|
||||
$this->assertEquals('', $result['plugin_name']['parameters']['param3']);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@
|
|||
* PluginReadityourselfTest.php.php
|
||||
*/
|
||||
|
||||
// FIXME! add an init method.
|
||||
$conf = new ConfigManager('');
|
||||
require_once 'plugins/readityourself/readityourself.php';
|
||||
|
||||
/**
|
||||
|
@ -25,7 +27,8 @@ function setUp()
|
|||
*/
|
||||
function testReadityourselfLinklist()
|
||||
{
|
||||
$GLOBALS['plugins']['READITYOUSELF_URL'] = 'value';
|
||||
$conf = new ConfigManager('');
|
||||
$conf->set('plugins.READITYOUSELF_URL', 'value');
|
||||
$str = 'http://randomstr.com/test';
|
||||
$data = array(
|
||||
'title' => $str,
|
||||
|
@ -36,7 +39,7 @@ function testReadityourselfLinklist()
|
|||
)
|
||||
);
|
||||
|
||||
$data = hook_readityourself_render_linklist($data);
|
||||
$data = hook_readityourself_render_linklist($data, $conf);
|
||||
$link = $data['links'][0];
|
||||
// data shouldn't be altered
|
||||
$this->assertEquals($str, $data['title']);
|
||||
|
@ -52,7 +55,8 @@ function testReadityourselfLinklist()
|
|||
*/
|
||||
function testReadityourselfLinklistWithoutConfig()
|
||||
{
|
||||
unset($GLOBALS['plugins']['READITYOUSELF_URL']);
|
||||
$conf = new ConfigManager('');
|
||||
$conf->set('plugins.READITYOUSELF_URL', null);
|
||||
$str = 'http://randomstr.com/test';
|
||||
$data = array(
|
||||
'title' => $str,
|
||||
|
@ -63,7 +67,7 @@ function testReadityourselfLinklistWithoutConfig()
|
|||
)
|
||||
);
|
||||
|
||||
$data = hook_readityourself_render_linklist($data);
|
||||
$data = hook_readityourself_render_linklist($data, $conf);
|
||||
$link = $data['links'][0];
|
||||
// data shouldn't be altered
|
||||
$this->assertEquals($str, $data['title']);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
* PluginWallabagTest.php.php
|
||||
*/
|
||||
|
||||
// FIXME! add an init method.
|
||||
$conf = new ConfigManager('');
|
||||
require_once 'plugins/wallabag/wallabag.php';
|
||||
|
||||
/**
|
||||
|
@ -25,7 +27,8 @@ function setUp()
|
|||
*/
|
||||
function testWallabagLinklist()
|
||||
{
|
||||
$GLOBALS['plugins']['WALLABAG_URL'] = 'value';
|
||||
$conf = new ConfigManager('');
|
||||
$conf->set('plugins.WALLABAG_URL', 'value');
|
||||
$str = 'http://randomstr.com/test';
|
||||
$data = array(
|
||||
'title' => $str,
|
||||
|
@ -36,7 +39,7 @@ function testWallabagLinklist()
|
|||
)
|
||||
);
|
||||
|
||||
$data = hook_wallabag_render_linklist($data);
|
||||
$data = hook_wallabag_render_linklist($data, $conf);
|
||||
$link = $data['links'][0];
|
||||
// data shouldn't be altered
|
||||
$this->assertEquals($str, $data['title']);
|
||||
|
@ -45,7 +48,6 @@ function testWallabagLinklist()
|
|||
// plugin data
|
||||
$this->assertEquals(1, count($link['link_plugin']));
|
||||
$this->assertNotFalse(strpos($link['link_plugin'][0], urlencode($str)));
|
||||
$this->assertNotFalse(strpos($link['link_plugin'][0], $GLOBALS['plugins']['WALLABAG_URL']));
|
||||
$this->assertNotFalse(strpos($link['link_plugin'][0], $conf->get('plugins.WALLABAG_URL')));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
5
tests/utils/config/configInvalid.json.php
Normal file
5
tests/utils/config/configInvalid.json.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php /*
|
||||
{
|
||||
bad: bad,
|
||||
}
|
||||
*/ ?>
|
34
tests/utils/config/configJson.json.php
Normal file
34
tests/utils/config/configJson.json.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php /*
|
||||
{
|
||||
"credentials": {
|
||||
"login":"root",
|
||||
"hash":"hash",
|
||||
"salt":"salt"
|
||||
},
|
||||
"security": {
|
||||
"session_protection_disabled":false
|
||||
},
|
||||
"general": {
|
||||
"timezone":"Europe\/Paris",
|
||||
"title": "Shaarli",
|
||||
"header_link": "?"
|
||||
},
|
||||
"privacy": {
|
||||
"default_private_links":true
|
||||
},
|
||||
"redirector": {
|
||||
"url":"lala"
|
||||
},
|
||||
"config": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"resource": {
|
||||
"datastore": "tests\/utils\/config\/datastore.php",
|
||||
"data_dir": "tests\/utils\/config"
|
||||
},
|
||||
"plugins": {
|
||||
"WALLABAG_VERSION": 1
|
||||
}
|
||||
}
|
||||
*/ ?>
|
||||
|
14
tests/utils/config/configPhp.php
Normal file
14
tests/utils/config/configPhp.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
$GLOBALS['login'] = 'root';
|
||||
$GLOBALS['hash'] = 'hash';
|
||||
$GLOBALS['salt'] = 'salt';
|
||||
$GLOBALS['timezone'] = 'Europe/Paris';
|
||||
$GLOBALS['title'] = 'title';
|
||||
$GLOBALS['titleLink'] = 'titleLink';
|
||||
$GLOBALS['redirector'] = 'lala';
|
||||
$GLOBALS['disablesessionprotection'] = false;
|
||||
$GLOBALS['privateLinkByDefault'] = false;
|
||||
$GLOBALS['config']['DATADIR'] = 'tests/Updater';
|
||||
$GLOBALS['config']['PAGECACHE'] = 'sandbox/pagecache';
|
||||
$GLOBALS['config']['DATASTORE'] = 'data/datastore.php';
|
||||
$GLOBALS['plugins']['WALLABAG_VERSION'] = '1';
|
|
@ -9,40 +9,82 @@
|
|||
<input type="hidden" name="token" value="{$token}">
|
||||
<table id="configuration_table">
|
||||
|
||||
<tr><td><b>Page title:</b></td><td><input type="text" name="title" id="title" size="50" value="{$title}"></td></tr>
|
||||
<tr>
|
||||
<td><b>Page title:</b></td>
|
||||
<td><input type="text" name="title" id="title" size="50" value="{$title}"></td>
|
||||
</tr>
|
||||
|
||||
<tr><td><b>Title link:</b></td><td><input type="text" name="titleLink" id="titleLink" size="50" value="{$titleLink}"><br/><label for="titleLink">(default value is: ?)</label></td></tr>
|
||||
<tr><td><b>Timezone:</b></td><td>{$timezone_form}</td></tr>
|
||||
<tr>
|
||||
<td><b>Title link:</b></td>
|
||||
<td><input type="text" name="titleLink" id="titleLink" size="50" value="{$titleLink}"><br/><label
|
||||
for="titleLink">(default value is: ?)</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Timezone:</b></td>
|
||||
<td>{$timezone_form}</td>
|
||||
</tr>
|
||||
|
||||
<tr><td><b>Redirector</b></td><td><input type="text" name="redirector" id="redirector" size="50" value="{$redirector}"><br>(e.g. <i>http://anonym.to/?</i> will mask the HTTP_REFERER)</td></tr>
|
||||
<tr>
|
||||
<td><b>Redirector</b></td>
|
||||
<td>
|
||||
<input type="text" name="redirector" id="redirector" size="50" value="{$redirector}"><br>
|
||||
(e.g. <i>http://anonym.to/?</i> will mask the HTTP_REFERER)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td><b>Security:</b></td><td><input type="checkbox" name="disablesessionprotection" id="disablesessionprotection" {if="!empty($GLOBALS['disablesessionprotection'])"}checked{/if}><label for="disablesessionprotection"> Disable session cookie hijacking protection (Check this if you get disconnected often or if your IP address changes often.)</label></td></tr>
|
||||
<tr>
|
||||
<td><b>Security:</b></td>
|
||||
<td>
|
||||
<input type="checkbox" name="disablesessionprotection" id="disablesessionprotection"
|
||||
{if="$private_links_default"}checked{/if}>
|
||||
<label
|
||||
for="disablesessionprotection"> Disable session cookie hijacking protection (Check this if you get
|
||||
disconnected often or if your IP address changes often.)</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td valign="top"><b>New link:</b></td><td>
|
||||
<input type="checkbox" name="privateLinkByDefault" id="privateLinkByDefault" {if="!empty($GLOBALS['privateLinkByDefault'])"}checked{/if}/><label for="privateLinkByDefault"> All new links are private by default</label></td>
|
||||
<tr>
|
||||
<td valign="top"><b>New link:</b></td>
|
||||
<td>
|
||||
<input type="checkbox" name="privateLinkByDefault" id="privateLinkByDefault"
|
||||
{if="$private_links_default"}checked{/if}/>
|
||||
<label for="privateLinkByDefault">
|
||||
All new links are private by default
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>RSS direct links</b></td>
|
||||
<td>
|
||||
<input type="checkbox" name="enableRssPermalinks" id="enableRssPermalinks" {if="!empty($GLOBALS['config']['ENABLE_RSS_PERMALINKS'])"}checked{/if}/>
|
||||
<input type="checkbox" name="enableRssPermalinks" id="enableRssPermalinks"
|
||||
{if="$enable_rss_permalinks"}checked{/if}/>
|
||||
<label for="enableRssPermalinks">
|
||||
Disable it to use permalinks in RSS feed instead of direct links to your shaared links. Currently <b>{if="$GLOBALS['config']['ENABLE_RSS_PERMALINKS']"}enabled{else}disabled{/if}.</b>
|
||||
Disable it to use permalinks in RSS feed instead of direct links to your shaared links. Currently <b>
|
||||
{if="$enable_rss_permalinks"}enabled{else}disabled{/if}.</b>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Hide public links</b></td>
|
||||
<td>
|
||||
<input type="checkbox" name="hidePublicLinks" id="hidePublicLinks" {if="!empty($GLOBALS['config']['HIDE_PUBLIC_LINKS'])"}checked{/if}/><label for="hidePublicLinks">
|
||||
Do not show any links if the user is not logged in.</label>
|
||||
<input type="checkbox" name="hidePublicLinks" id="hidePublicLinks"
|
||||
{if="$hide_public_links"}checked{/if}/>
|
||||
<label for="hidePublicLinks"> Do not show any links if the user is not logged in.</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td valign="top"><b>Update:</b></td><td>
|
||||
<input type="checkbox" name="updateCheck" id="updateCheck" {if="!empty($GLOBALS['config']['ENABLE_UPDATECHECK'])"}checked{/if}/>
|
||||
<label for="updateCheck"> Notify me when a new release is ready</label></td>
|
||||
<tr>
|
||||
<td valign="top"><b>Update:</b></td>
|
||||
<td>
|
||||
<input type="checkbox" name="updateCheck" id="updateCheck"
|
||||
{if="$enable_update_check"}checked{/if}/>
|
||||
<label for="updateCheck"> Notify me when a new release is ready</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td></td><td class="right"><input type="submit" name="Save" value="Save config" class="bigbutton"></td></tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="right"><input type="submit" name="Save" value="Save config" class="bigbutton"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink">
|
||||
</a>
|
||||
</div>
|
||||
{if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"}
|
||||
{if="!$hide_timestamps || isLoggedIn()"}
|
||||
<div class="dailyEntryLinkdate">
|
||||
<a href="?{$link.linkdate|smallHash}">{function="strftime('%c', $link.timestamp)"}</a>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<description><![CDATA[
|
||||
{loop="links"}
|
||||
<h3><a href="{$value.url}">{$value.title}</a></h3>
|
||||
<small>{if="!$GLOBALS['config']['HIDE_TIMESTAMPS']"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
|
||||
<small>{if="!$hide_timestamps"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
|
||||
{$value.url}</small><br>
|
||||
{if="$value.thumbnail"}{$value.thumbnail}{/if}<br>
|
||||
{if="$value.description"}{$value.formatedDescription}{/if}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
{$value}
|
||||
{/loop}
|
||||
|
||||
{if="($link_is_new && $GLOBALS['privateLinkByDefault']==true) || $link.private == true"}
|
||||
{if="($link_is_new && $default_private_links) || $link.private == true"}
|
||||
<input type="checkbox" checked="checked" name="lf_private" id="lf_private">
|
||||
<label for="lf_private"><i>Private</i></label><br>
|
||||
{else}
|
||||
|
@ -43,12 +43,10 @@
|
|||
{if="$source !== 'firefoxsocialapi'"}
|
||||
{include="page.footer"}
|
||||
{/if}
|
||||
{if="($GLOBALS['config']['OPEN_SHAARLI'] || isLoggedIn())"}
|
||||
<script src="inc/awesomplete.min.js#"></script>
|
||||
<script src="inc/awesomplete-multiple-tags.js#"></script>
|
||||
<script>
|
||||
awesompleteUniqueTag('#lf_tags');
|
||||
</script>
|
||||
{/if}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
</span>
|
||||
<br>
|
||||
{if="$value.description"}<div class="linkdescription">{$value.description}</div>{/if}
|
||||
{if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"}
|
||||
{if="!$hide_timestamps || isLoggedIn()"}
|
||||
<span class="linkdate" title="Permalink"><a href="?{$value.linkdate|smallHash}">{function="strftime('%c', $value.timestamp)"} - permalink</a> - </span>
|
||||
{else}
|
||||
<span class="linkdate" title="Short link here"><a href="?{$value.shorturl}">permalink</a> - </span>
|
||||
|
|
|
@ -21,14 +21,14 @@
|
|||
<li><a href="?do=logout">Logout</a></li>
|
||||
<li><a href="?do=tools">Tools</a></li>
|
||||
<li><a href="?do=addlink">Add link</a></li>
|
||||
{elseif="$GLOBALS['config']['OPEN_SHAARLI']"}
|
||||
{elseif="$openshaarli"}
|
||||
<li><a href="?do=tools">Tools</a></li>
|
||||
<li><a href="?do=addlink">Add link</a></li>
|
||||
{else}
|
||||
<li><a href="?do=login">Login</a></li>
|
||||
{/if}
|
||||
<li><a href="{$feedurl}?do=rss{$searchcrits}" class="nomobile">RSS Feed</a></li>
|
||||
{if="$GLOBALS['config']['SHOW_ATOM']"}
|
||||
{if="$showatom"}
|
||||
<li><a href="{$feedurl}?do=atom{$searchcrits}" class="nomobile">ATOM Feed</a></li>
|
||||
{/if}
|
||||
<li><a href="?do=tagcloud">Tag cloud</a></li>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<br><br>
|
||||
<a href="?do=pluginadmin"><b>Plugin administration</b><span>: Enable, disable and configure plugins.</span></a>
|
||||
<br><br>
|
||||
{if="!$GLOBALS['config']['OPEN_SHAARLI']"}<a href="?do=changepasswd"><b>Change password</b><span>: Change your password.</span></a>
|
||||
{if="$openshaarli"}<a href="?do=changepasswd"><b>Change password</b><span>: Change your password.</span></a>
|
||||
<br><br>{/if}
|
||||
<a href="?do=changetag"><b>Rename/delete tags</b><span>: Rename or delete a tag in all links</span></a>
|
||||
<br><br>
|
||||
|
|
Loading…
Reference in a new issue