]> git.mxchange.org Git - friendica.git/commitdiff
Merge pull request #5314 from MrPetovan/task/4889-fix-tests
authorMichael Vogel <icarus@dabo.de>
Fri, 6 Jul 2018 20:14:01 +0000 (22:14 +0200)
committerGitHub <noreply@github.com>
Fri, 6 Jul 2018 20:14:01 +0000 (22:14 +0200)
Fix tests after enabling PHP Notices

35 files changed:
boot.php
mod/admin.php
src/Core/Cache.php
src/Core/Cache/AbstractCacheDriver.php [new file with mode: 0644]
src/Core/Cache/ArrayCache.php [new file with mode: 0644]
src/Core/Cache/CacheDriverFactory.php [new file with mode: 0644]
src/Core/Cache/DatabaseCacheDriver.php
src/Core/Cache/ICacheDriver.php
src/Core/Cache/IMemoryCacheDriver.php [new file with mode: 0644]
src/Core/Cache/MemcacheCacheDriver.php
src/Core/Cache/MemcachedCacheDriver.php
src/Core/Cache/RedisCacheDriver.php
src/Core/Cache/TraitCompareDelete.php [new file with mode: 0644]
src/Core/Cache/TraitCompareSet.php [new file with mode: 0644]
src/Core/Lock.php [new file with mode: 0644]
src/Core/Lock/AbstractLockDriver.php [new file with mode: 0644]
src/Core/Lock/CacheLockDriver.php [new file with mode: 0644]
src/Core/Lock/DatabaseLockDriver.php [new file with mode: 0644]
src/Core/Lock/ILockDriver.php [new file with mode: 0644]
src/Core/Lock/SemaphoreLockDriver.php [new file with mode: 0644]
src/Core/Worker.php
src/Database/DBStructure.php
src/Model/Event.php
src/Model/Item.php
src/Model/User.php
src/Object/Post.php
src/Protocol/OStatus.php
src/Util/Lock.php [deleted file]
tests/src/Core/Lock/CacheLockDriverTest.php [new file with mode: 0644]
tests/src/Core/Lock/DatabaseLockDriverTest.php [new file with mode: 0644]
tests/src/Core/Lock/LockTest.php [new file with mode: 0644]
tests/src/Core/Lock/SemaphoreLockDriverTest.php [new file with mode: 0644]
view/lang/cs/messages.po
view/lang/cs/strings.php
view/templates/admin/site.tpl

index e876d25a3f9495a7803c6088927ab54e0aa4ca53..b58e1bbc0dfbed27f9a7deb180e9f72472a32268 100644 (file)
--- a/boot.php
+++ b/boot.php
@@ -41,7 +41,7 @@ define('FRIENDICA_PLATFORM',     'Friendica');
 define('FRIENDICA_CODENAME',     'The Tazmans Flax-lily');
 define('FRIENDICA_VERSION',      '2018.08-dev');
 define('DFRN_PROTOCOL_VERSION',  '2.23');
-define('DB_UPDATE_VERSION',      1274);
+define('DB_UPDATE_VERSION',      1275);
 define('NEW_UPDATE_ROUTINE_VERSION', 1170);
 
 /**
index b43baa44331fa6432fce0321c7165b801d702b0f..f12ec5e3b2578ecace5959d0ee1f503f9b15875d 100644 (file)
@@ -975,6 +975,7 @@ function admin_page_site_post(App $a)
 
        $allowed_sites          =       ((x($_POST,'allowed_sites'))            ? notags(trim($_POST['allowed_sites']))         : '');
        $allowed_email          =       ((x($_POST,'allowed_email'))            ? notags(trim($_POST['allowed_email']))         : '');
+       $forbidden_nicknames    =       ((x($_POST,'forbidden_nicknames'))      ? strtolower(notags(trim($_POST['forbidden_nicknames'])))               : '');
        $no_oembed_rich_content = x($_POST,'no_oembed_rich_content');
        $allowed_oembed         =       ((x($_POST,'allowed_oembed'))           ? notags(trim($_POST['allowed_oembed']))                : '');
        $block_public           =       ((x($_POST,'block_public'))             ? True                                          : False);
@@ -1143,6 +1144,7 @@ function admin_page_site_post(App $a)
        Config::set('config', 'register_text', $register_text);
        Config::set('system', 'allowed_sites', $allowed_sites);
        Config::set('system', 'allowed_email', $allowed_email);
+       Config::set('system', 'forbidden_nicknames', $forbidden_nicknames);
        Config::set('system', 'no_oembed_rich_content', $no_oembed_rich_content);
        Config::set('system', 'allowed_oembed', $allowed_oembed);
        Config::set('system', 'block_public', $block_public);
@@ -1349,6 +1351,8 @@ function admin_page_site(App $a)
        if ($optimize_max_tablesize <= 0) {
                $optimize_max_tablesize = -1;
        }
+       // Default list of forbidden names, classic role names from RFC 2142
+       $default_forbidden_nicknames = 'info, marketing, sales, support, abuse, noc, security, postmaster, hostmaster, usenet, news, webmaster, www, uucp, ftp, root, sysop';
 
        $t = get_markup_template('admin/site.tpl');
        return replace_macros($t, [
@@ -1388,6 +1392,7 @@ function admin_page_site(App $a)
                '$register_policy'      => ['register_policy', L10n::t("Register policy"), $a->config['register_policy'], "", $register_choices],
                '$daily_registrations'  => ['max_daily_registrations', L10n::t("Maximum Daily Registrations"), Config::get('system', 'max_daily_registrations'), L10n::t("If registration is permitted above, this sets the maximum number of new user registrations to accept per day.  If register is set to closed, this setting has no effect.")],
                '$register_text'        => ['register_text', L10n::t("Register text"), $a->config['register_text'], L10n::t("Will be displayed prominently on the registration page. You can use BBCode here.")],
+               '$forbidden_nicknames' => ['forbidden_nicknames', L10n::t('Forbidden Nicknames'), Config::get('system', 'forbidden_nicknames', $default_forbidden_nicknames), L10n::t('Comma separated list of nicknames that are forbidden from registration. Preset is a list of role names according RFC 2142.')],
                '$abandon_days'         => ['abandon_days', L10n::t('Accounts abandoned after x days'), Config::get('system','account_abandon_days'), L10n::t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')],
                '$allowed_sites'        => ['allowed_sites', L10n::t("Allowed friend domains"), Config::get('system','allowed_sites'), L10n::t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")],
                '$allowed_email'        => ['allowed_email', L10n::t("Allowed email domains"), Config::get('system','allowed_email'), L10n::t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")],
index 4202db325c411c38b7852321af769bfb0f09d33c..cc77d9bfd0dc7e35598130af672287454ffdd25c 100644 (file)
@@ -4,8 +4,7 @@
  */
 namespace Friendica\Core;
 
-use Friendica\Core\Cache;
-use Friendica\Core\Config;
+use Friendica\Core\Cache\CacheDriverFactory;
 
 /**
  * @brief Class for storing data for a short time
@@ -24,31 +23,13 @@ class Cache extends \Friendica\BaseObject
        /**
         * @var Cache\ICacheDriver
         */
-       static $driver = null;
+       private static $driver = null;
 
        public static function init()
        {
-               switch(Config::get('system', 'cache_driver', 'database')) {
-                       case 'memcache':
-                               $memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
-                               $memcache_port = Config::get('system', 'memcache_port', 11211);
-
-                               self::$driver = new Cache\MemcacheCacheDriver($memcache_host, $memcache_port);
-                               break;
-                       case 'memcached':
-                               $memcached_hosts = Config::get('system', 'memcached_hosts', [['127.0.0.1', 11211]]);
-
-                               self::$driver = new Cache\MemcachedCacheDriver($memcached_hosts);
-                               break;
-                       case 'redis':
-                               $redis_host = Config::get('system', 'redis_host', '127.0.0.1');
-                               $redis_port = Config::get('system', 'redis_port', 6379);
-
-                               self::$driver = new Cache\RedisCacheDriver($redis_host, $redis_port);
-                               break;
-                       default:
-                               self::$driver = new Cache\DatabaseCacheDriver();
-               }
+               $driver_name = Config::get('system', 'cache_driver', 'database');
+
+               self::$driver = CacheDriverFactory::create($driver_name);
        }
 
        /**
diff --git a/src/Core/Cache/AbstractCacheDriver.php b/src/Core/Cache/AbstractCacheDriver.php
new file mode 100644 (file)
index 0000000..417accd
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+
+namespace Friendica\Core\Cache;
+use Friendica\BaseObject;
+
+
+/**
+ * Abstract class for common used functions
+ *
+ * Class AbstractCacheDriver
+ *
+ * @package Friendica\Core\Cache
+ */
+abstract class AbstractCacheDriver extends BaseObject
+{
+       /**
+        * @param string $key   The original key
+        * @return string               The cache key used for the cache
+        */
+       protected function getCacheKey($key) {
+               return self::getApp()->get_hostname() . ":" . $key;
+       }
+}
diff --git a/src/Core/Cache/ArrayCache.php b/src/Core/Cache/ArrayCache.php
new file mode 100644 (file)
index 0000000..ec9f3a2
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+
+namespace Friendica\Core\Cache;
+
+
+use Friendica\Core\Cache;
+
+/**
+ * Implementation of the IMemoryCacheDriver mainly for testing purpose
+ *
+ * Class ArrayCache
+ *
+ * @package Friendica\Core\Cache
+ */
+class ArrayCache extends AbstractCacheDriver implements IMemoryCacheDriver
+{
+       use TraitCompareDelete;
+
+       /** @var array Array with the cached data */
+       protected $cachedData = array();
+
+       /**
+        * (@inheritdoc)
+        */
+       public function get($key)
+       {
+               if (isset($this->cachedData[$key])) {
+                       return $this->cachedData[$key];
+               }
+               return null;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
+       {
+               $this->cachedData[$key] = $value;
+               return true;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function delete($key)
+       {
+               unset($this->cachedData[$key]);
+               return true;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function clear()
+       {
+               $this->cachedData = [];
+               return true;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
+       {
+               if (isset($this->cachedData[$key])) {
+                       return false;
+               } else {
+                       return $this->set($key, $value, $ttl);
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES)
+       {
+               if ($this->get($key) === $oldValue) {
+                       return $this->set($key, $newValue);
+               } else {
+                       return false;
+               }
+       }
+}
diff --git a/src/Core/Cache/CacheDriverFactory.php b/src/Core/Cache/CacheDriverFactory.php
new file mode 100644 (file)
index 0000000..8fbdc15
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+
+namespace Friendica\Core\Cache;
+
+use Friendica\Core\Config;
+
+/**
+ * Class CacheDriverFactory
+ *
+ * @package Friendica\Core\Cache
+ *
+ * A basic class to generate a CacheDriver
+ */
+class CacheDriverFactory
+{
+       /**
+        * This method creates a CacheDriver for the given cache driver name
+        *
+        * @param string $driver The name of the cache driver
+        * @return ICacheDriver  The instance of the CacheDriver
+        * @throws \Exception    The exception if something went wrong during the CacheDriver creation
+        */
+       public static function create($driver) {
+
+               switch ($driver) {
+                       case 'memcache':
+                               $memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
+                               $memcache_port = Config::get('system', 'memcache_port', 11211);
+
+                               return new MemcacheCacheDriver($memcache_host, $memcache_port);
+                               break;
+
+                       case 'memcached':
+                               $memcached_hosts = Config::get('system', 'memcached_hosts', [['127.0.0.1', 11211]]);
+
+                               return new MemcachedCacheDriver($memcached_hosts);
+                               break;
+                       case 'redis':
+                               $redis_host = Config::get('system', 'redis_host', '127.0.0.1');
+                               $redis_port = Config::get('system', 'redis_port', 6379);
+
+                               return new RedisCacheDriver($redis_host, $redis_port);
+                               break;
+                       default:
+                               return new DatabaseCacheDriver();
+               }
+       }
+}
index 7248e0b349c2eaf1aecc76767cda0ca9e59113d4..5c71fb19623cab9f3ce3ecf2b0e9a4e8bf99f71e 100644 (file)
@@ -12,7 +12,7 @@ use Friendica\Util\DateTimeFormat;
  *
  * @author Hypolite Petovan <mrpetovan@gmail.com>
  */
-class DatabaseCacheDriver implements ICacheDriver
+class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver
 {
        public function get($key)
        {
@@ -33,11 +33,11 @@ class DatabaseCacheDriver implements ICacheDriver
                return null;
        }
 
-       public function set($key, $value, $duration = Cache::MONTH)
+       public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
        {
                $fields = [
                        'v'       => serialize($value),
-                       'expires' => DateTimeFormat::utc('now + ' . $duration . ' seconds'),
+                       'expires' => DateTimeFormat::utc('now + ' . $ttl . ' seconds'),
                        'updated' => DateTimeFormat::utcNow()
                ];
 
index be896edf7f8d53e23347d26785edc5e2097464e8..ced7b4e2168b935ab72467631df50581fd3f0e1a 100644 (file)
@@ -25,17 +25,16 @@ interface ICacheDriver
         *
         * @param string  $key      The cache key
         * @param mixed   $value    The value to store
-        * @param integer $duration The cache lifespan, must be one of the Cache constants
+        * @param integer $ttl The cache lifespan, must be one of the Cache constants
         *
         * @return bool
         */
-       public function set($key, $value, $duration = Cache::MONTH);
-
+       public function set($key, $value, $ttl = Cache::FIVE_MINUTES);
 
        /**
         * Delete a key from the cache
         *
-        * @param string $key
+        * @param string $key      The cache key
         *
         * @return bool
         */
diff --git a/src/Core/Cache/IMemoryCacheDriver.php b/src/Core/Cache/IMemoryCacheDriver.php
new file mode 100644 (file)
index 0000000..a50e2d1
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+namespace Friendica\Core\Cache;
+use Friendica\Core\Cache;
+
+/**
+ * This interface defines methods for Memory-Caches only
+ *
+ * Interface IMemoryCacheDriver
+ *
+ * @package Friendica\Core\Cache
+ */
+interface IMemoryCacheDriver extends ICacheDriver
+{
+       /**
+        * Sets a value if it's not already stored
+        *
+        * @param string $key      The cache key
+        * @param mixed  $value    The old value we know from the cache
+        * @param int    $ttl      The cache lifespan, must be one of the Cache constants
+        * @return bool
+        */
+       public function add($key, $value, $ttl = Cache::FIVE_MINUTES);
+
+       /**
+        * Compares if the old value is set and sets the new value
+        *
+        * @param string $key         The cache key
+        * @param mixed  $oldValue    The old value we know from the cache
+        * @param mixed  $newValue    The new value we want to set
+        * @param int    $ttl              The cache lifespan, must be one of the Cache constants
+        *
+        * @return bool
+        */
+       public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES);
+
+       /**
+        * Compares if the old value is set and removes it
+        *
+        * @param string $key          The cache key
+        * @param mixed  $value        The old value we know and want to delete
+        * @return bool
+        */
+       public function compareDelete($key, $value);
+}
index 1537be25b202a1e96515362a76dc9260c18d98a6..af7e5ab0e226df58e0289ec862a27cac04b43a9d 100644 (file)
@@ -2,7 +2,6 @@
 
 namespace Friendica\Core\Cache;
 
-use Friendica\BaseObject;
 use Friendica\Core\Cache;
 
 /**
@@ -10,10 +9,13 @@ use Friendica\Core\Cache;
  *
  * @author Hypolite Petovan <mrpetovan@gmail.com>
  */
-class MemcacheCacheDriver extends BaseObject implements ICacheDriver
+class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver
 {
+       use TraitCompareSet;
+       use TraitCompareDelete;
+
        /**
-        * @var Memcache
+        * @var \Memcache
         */
        private $memcache;
 
@@ -30,12 +32,16 @@ class MemcacheCacheDriver extends BaseObject implements ICacheDriver
                }
        }
 
+       /**
+        * (@inheritdoc)
+        */
        public function get($key)
        {
                $return = null;
+               $cachekey = $this->getCacheKey($key);
 
                // We fetch with the hostname as key to avoid problems with other applications
-               $cached = $this->memcache->get(self::getApp()->get_hostname() . ':' . $key);
+               $cached = $this->memcache->get($cachekey);
 
                // @see http://php.net/manual/en/memcache.get.php#84275
                if (is_bool($cached) || is_double($cached) || is_long($cached)) {
@@ -54,24 +60,53 @@ class MemcacheCacheDriver extends BaseObject implements ICacheDriver
                return $return;
        }
 
-       public function set($key, $value, $duration = Cache::MONTH)
+       /**
+        * (@inheritdoc)
+        */
+       public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
        {
+               $cachekey = $this->getCacheKey($key);
+
                // We store with the hostname as key to avoid problems with other applications
-               return $this->memcache->set(
-                       self::getApp()->get_hostname() . ":" . $key,
-                       serialize($value),
-                       MEMCACHE_COMPRESSED,
-                       time() + $duration
-               );
+               if ($ttl > 0) {
+                       return $this->memcache->set(
+                               $cachekey,
+                               serialize($value),
+                               MEMCACHE_COMPRESSED,
+                               time() + $ttl
+                       );
+               } else {
+                       return $this->memcache->set(
+                               $cachekey,
+                               serialize($value),
+                               MEMCACHE_COMPRESSED
+                       );
+               }
        }
 
+       /**
+        * (@inheritdoc)
+        */
        public function delete($key)
        {
-               return $this->memcache->delete($key);
+               $cachekey = $this->getCacheKey($key);
+               return $this->memcache->delete($cachekey);
        }
 
+       /**
+        * (@inheritdoc)
+        */
        public function clear()
        {
-               return true;
+               return $this->memcache->flush();
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+               return $this->memcache->add($cachekey, $value, $ttl);
        }
 }
index 78a4a6bdfe28c8fd477afd5f8ac37ad23be61337..819cf71c5c6fba73676137f6d04a359b922d6e09 100644 (file)
@@ -2,7 +2,6 @@
 
 namespace Friendica\Core\Cache;
 
-use Friendica\BaseObject;
 use Friendica\Core\Cache;
 
 /**
@@ -10,10 +9,13 @@ use Friendica\Core\Cache;
  *
  * @author Hypolite Petovan <mrpetovan@gmail.com>
  */
-class MemcachedCacheDriver extends BaseObject implements ICacheDriver
+class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver
 {
+       use TraitCompareSet;
+       use TraitCompareDelete;
+
        /**
-        * @var Memcached
+        * @var \Memcached
         */
        private $memcached;
 
@@ -35,9 +37,10 @@ class MemcachedCacheDriver extends BaseObject implements ICacheDriver
        public function get($key)
        {
                $return = null;
+               $cachekey = $this->getCacheKey($key);
 
                // We fetch with the hostname as key to avoid problems with other applications
-               $value = $this->memcached->get(self::getApp()->get_hostname() . ':' . $key);
+               $value = $this->memcached->get($cachekey);
 
                if ($this->memcached->getResultCode() === \Memcached::RES_SUCCESS) {
                        $return = $value;
@@ -46,25 +49,48 @@ class MemcachedCacheDriver extends BaseObject implements ICacheDriver
                return $return;
        }
 
-       public function set($key, $value, $duration = Cache::MONTH)
+       public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
        {
+               $cachekey = $this->getCacheKey($key);
+
                // We store with the hostname as key to avoid problems with other applications
-               return $this->memcached->set(
-                       self::getApp()->get_hostname() . ':' . $key,
-                       $value,
-                       time() + $duration
-               );
+               if ($ttl > 0) {
+                       return $this->memcached->set(
+                               $cachekey,
+                               $value,
+                               time() + $ttl
+                       );
+               } else {
+                       return $this->memcached->set(
+                               $cachekey,
+                               $value
+                       );
+               }
+
        }
 
        public function delete($key)
        {
-               $return = $this->memcached->delete(self::getApp()->get_hostname() . ':' . $key);
-
-               return $return;
+               $cachekey = $this->getCacheKey($key);
+               return $this->memcached->delete($cachekey);
        }
 
        public function clear()
        {
                return true;
        }
+
+       /**
+        * @brief Sets a value if it's not already stored
+        *
+        * @param string $key      The cache key
+        * @param mixed  $value    The old value we know from the cache
+        * @param int    $ttl      The cache lifespan, must be one of the Cache constants
+        * @return bool
+        */
+       public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+               return $this->memcached->add($cachekey, $value, $ttl);
+       }
 }
index fa98842da0e686f39ad4b862a50898fd873bfadb..67df8e8fee21904dee1583074c411a91fb8a0376 100644 (file)
@@ -2,7 +2,6 @@
 
 namespace Friendica\Core\Cache;
 
-use Friendica\BaseObject;
 use Friendica\Core\Cache;
 
 /**
@@ -11,10 +10,10 @@ use Friendica\Core\Cache;
  * @author Hypolite Petovan <mrpetovan@gmail.com>
  * @author Roland Haeder <roland@mxchange.org>
  */
-class RedisCacheDriver extends BaseObject implements ICacheDriver
+class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver
 {
        /**
-        * @var Redis
+        * @var \Redis
         */
        private $redis;
 
@@ -34,9 +33,10 @@ class RedisCacheDriver extends BaseObject implements ICacheDriver
        public function get($key)
        {
                $return = null;
+               $cachekey = $this->getCacheKey($key);
 
                // We fetch with the hostname as key to avoid problems with other applications
-               $cached = $this->redis->get(self::getApp()->get_hostname() . ':' . $key);
+               $cached = $this->redis->get($cachekey);
 
                // @see http://php.net/manual/en/redis.get.php#84275
                if (is_bool($cached) || is_double($cached) || is_long($cached)) {
@@ -55,14 +55,23 @@ class RedisCacheDriver extends BaseObject implements ICacheDriver
                return $return;
        }
 
-       public function set($key, $value, $duration = Cache::MONTH)
+       public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
        {
+               $cachekey = $this->getCacheKey($key);
+
                // We store with the hostname as key to avoid problems with other applications
-               return $this->redis->set(
-                       self::getApp()->get_hostname() . ":" . $key,
-                       serialize($value),
-                       time() + $duration
-               );
+               if ($ttl > 0) {
+                       return $this->redis->setex(
+                               $cachekey,
+                               time() + $ttl,
+                               serialize($value)
+                       );
+               } else {
+                       return $this->redis->set(
+                               $cachekey,
+                               serialize($value)
+                       );
+               }
        }
 
        public function delete($key)
@@ -74,4 +83,66 @@ class RedisCacheDriver extends BaseObject implements ICacheDriver
        {
                return true;
        }
+
+
+       /**
+        * (@inheritdoc)
+        */
+       public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+
+               if (!is_int($value)) {
+                       $value = serialize($value);
+               }
+
+               return $this->redis->setnx($cachekey, $value);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES)
+       {
+               $cachekey = $this->getCacheKey($key);
+
+               if (!is_int($newValue)) {
+                       $newValue = serialize($newValue);
+               }
+
+               $this->redis->watch($cachekey);
+               // If the old value isn't what we expected, somebody else changed the key meanwhile
+               if ($this->get($cachekey) === $oldValue) {
+                       if ($ttl > 0) {
+                               $result = $this->redis->multi()
+                                       ->setex($cachekey, $ttl, $newValue)
+                                       ->exec();
+                       } else {
+                               $result = $this->redis->multi()
+                                       ->set($cachekey, $newValue)
+                                       ->exec();
+                       }
+                       return $result !== false;
+               }
+               $this->redis->unwatch();
+               return false;
+       }
+       /**
+        * (@inheritdoc)
+        */
+       public function compareDelete($key, $value)
+       {
+               $cachekey = $this->getCacheKey($key);
+
+               $this->redis->watch($cachekey);
+               // If the old value isn't what we expected, somebody else changed the key meanwhile
+               if ($this->get($key) === $value) {
+                       $result = $this->redis->multi()
+                               ->del($cachekey)
+                               ->exec();
+                       return $result !== false;
+               }
+               $this->redis->unwatch();
+               return false;
+       }
 }
diff --git a/src/Core/Cache/TraitCompareDelete.php b/src/Core/Cache/TraitCompareDelete.php
new file mode 100644 (file)
index 0000000..ef59f69
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+namespace Friendica\Core\Cache;
+
+use Friendica\Core\Cache;
+
+/**
+ * Trait TraitCompareSetDelete
+ *
+ * This Trait is to compensate non native "exclusive" sets/deletes in caches
+ *
+ * @package Friendica\Core\Cache
+ */
+trait TraitCompareDelete
+{
+       abstract public function get($key);
+
+       abstract public function set($key, $value, $ttl = Cache::FIVE_MINUTES);
+
+       abstract public function delete($key);
+
+       abstract public function add($key, $value, $ttl = Cache::FIVE_MINUTES);
+
+       /**
+        * NonNative - Compares if the old value is set and removes it
+        *
+        * @param string $key          The cache key
+        * @param mixed  $value        The old value we know and want to delete
+        * @return bool
+        */
+       public function compareDelete($key, $value) {
+               if ($this->add($key . "_lock", true)) {
+                       if ($this->get($key) === $value) {
+                               $this->delete($key);
+                               $this->delete($key . "_lock");
+                               return true;
+                       } else {
+                               $this->delete($key . "_lock");
+                               return false;
+                       }
+               } else {
+                       return false;
+               }
+       }
+}
diff --git a/src/Core/Cache/TraitCompareSet.php b/src/Core/Cache/TraitCompareSet.php
new file mode 100644 (file)
index 0000000..77a6028
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+
+namespace Friendica\Core\Cache;
+
+use Friendica\Core\Cache;
+
+/**
+ * Trait TraitCompareSetDelete
+ *
+ * This Trait is to compensate non native "exclusive" sets/deletes in caches
+ *
+ * @package Friendica\Core\Cache
+ */
+trait TraitCompareSet
+{
+       abstract public function get($key);
+
+       abstract public function set($key, $value, $ttl = Cache::FIVE_MINUTES);
+
+       abstract public function delete($key);
+
+       abstract public function add($key, $value, $ttl = Cache::FIVE_MINUTES);
+
+       /**
+        * NonNative - Compares if the old value is set and sets the new value
+        *
+        * @param string $key         The cache key
+        * @param mixed  $oldValue    The old value we know from the cache
+        * @param mixed  $newValue    The new value we want to set
+        * @param int    $ttl      The cache lifespan, must be one of the Cache constants
+        *
+        * @return bool
+        */
+       public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES) {
+               if ($this->add($key . "_lock", true)) {
+                       if ($this->get($key) === $oldValue) {
+                               $this->set($key, $newValue, $ttl);
+                               $this->delete($key . "_lock");
+                               return true;
+                       } else {
+                               $this->delete($key . "_lock");
+                               return false;
+                       }
+               } else {
+                       return false;
+               }
+       }
+}
diff --git a/src/Core/Lock.php b/src/Core/Lock.php
new file mode 100644 (file)
index 0000000..9892f1f
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+
+namespace Friendica\Core;
+
+/**
+ * @file src/Core/Lock.php
+ * @brief Functions for preventing parallel execution of functions
+ */
+
+use Friendica\Core\Cache\CacheDriverFactory;
+use Friendica\Core\Cache\IMemoryCacheDriver;
+
+/**
+ * @brief This class contain Functions for preventing parallel execution of functions
+ */
+class Lock
+{
+       /**
+        * @var Lock\ILockDriver;
+        */
+       static $driver = null;
+
+       public static function init()
+       {
+               $lock_driver = Config::get('system', 'lock_driver', 'default');
+
+               try {
+                       switch ($lock_driver) {
+                               case 'memcache':
+                               case 'memcached':
+                               case 'redis':
+                                       $cache_driver = CacheDriverFactory::create($lock_driver);
+                                       if ($cache_driver instanceof IMemoryCacheDriver) {
+                                               self::$driver = new Lock\CacheLockDriver($cache_driver);
+                                       }
+                                       break;
+
+                               case 'database':
+                                       self::$driver = new Lock\DatabaseLockDriver();
+                                       break;
+
+                               case 'semaphore':
+                                       self::$driver = new Lock\SemaphoreLockDriver();
+                                       break;
+
+                               default:
+                                       self::useAutoDriver();
+                       }
+               } catch (\Exception $exception) {
+                       logger ('Driver \'' . $lock_driver . '\' failed - Fallback to \'useAutoDriver()\'');
+                       self::useAutoDriver();
+               }
+       }
+
+       /**
+        * @brief This method tries to find the best - local - locking method for Friendica
+        *
+        * The following sequence will be tried:
+        * 1. Semaphore Locking
+        * 2. Cache Locking
+        * 3. Database Locking
+        *
+        */
+       private static function useAutoDriver() {
+
+               // 1. Try to use Semaphores for - local - locking
+               if (function_exists('sem_get')) {
+                       try {
+                               self::$driver = new Lock\SemaphoreLockDriver();
+                               return;
+                       } catch (\Exception $exception) {
+                               logger ('Using Semaphore driver for locking failed: ' . $exception->getMessage());
+                       }
+               }
+
+               // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!)
+               $cache_driver = Config::get('system', 'cache_driver', 'database');
+               if ($cache_driver != 'database') {
+                       try {
+                               $lock_driver = CacheDriverFactory::create($cache_driver);
+                               if ($lock_driver instanceof IMemoryCacheDriver) {
+                                       self::$driver = new Lock\CacheLockDriver($lock_driver);
+                               }
+                               return;
+                       } catch (\Exception $exception) {
+                               logger('Using Cache driver for locking failed: ' . $exception->getMessage());
+                       }
+               }
+
+               // 3. Use Database Locking as a Fallback
+               self::$driver = new Lock\DatabaseLockDriver();
+       }
+
+       /**
+        * Returns the current cache driver
+        *
+        * @return Lock\ILockDriver;
+        */
+       private static function getDriver()
+       {
+               if (self::$driver === null) {
+                       self::init();
+               }
+
+               return self::$driver;
+       }
+
+       /**
+        * @brief Acquires a lock for a given name
+        *
+        * @param string  $key Name of the lock
+        * @param integer $timeout Seconds until we give up
+        *
+        * @return boolean Was the lock successful?
+        */
+       public static function acquire($key, $timeout = 120)
+       {
+               return self::getDriver()->acquireLock($key, $timeout);
+       }
+
+       /**
+        * @brief Releases a lock if it was set by us
+        *
+        * @param string $key Name of the lock
+        * @return void
+        */
+       public static function release($key)
+       {
+               self::getDriver()->releaseLock($key);
+       }
+
+       /**
+        * @brief Releases all lock that were set by us
+        * @return void
+        */
+       public static function releaseAll()
+       {
+               self::getDriver()->releaseAll();
+       }
+}
diff --git a/src/Core/Lock/AbstractLockDriver.php b/src/Core/Lock/AbstractLockDriver.php
new file mode 100644 (file)
index 0000000..033d6f3
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+
+namespace Friendica\Core\Lock;
+use Friendica\BaseObject;
+
+/**
+ * Class AbstractLockDriver
+ *
+ * @package Friendica\Core\Lock
+ *
+ * Basic class for Locking with common functions (local acquired locks, releaseAll, ..)
+ */
+abstract class AbstractLockDriver extends BaseObject implements ILockDriver
+{
+       /**
+        * @var array The local acquired locks
+        */
+       protected $acquiredLocks = [];
+
+       /**
+        * Check if we've locally acquired a lock
+        *
+        * @param string key The Name of the lock
+        * @return bool      Returns true if the lock is set
+        */
+       protected function hasAcquiredLock($key) {
+               return isset($this->acquireLock[$key]) && $this->acquiredLocks[$key] === true;
+       }
+
+       /**
+        * Mark a locally acquired lock
+        *
+        * @param string $key The Name of the lock
+        */
+       protected function markAcquire($key) {
+               $this->acquiredLocks[$key] = true;
+       }
+
+       /**
+        * Mark a release of a locally acquired lock
+        *
+        * @param string $key The Name of the lock
+        */
+       protected function markRelease($key) {
+               unset($this->acquiredLocks[$key]);
+       }
+
+       /**
+        * Releases all lock that were set by us
+        *
+        * @return void
+        */
+       public function releaseAll() {
+               foreach ($this->acquiredLocks as $acquiredLock => $hasLock) {
+                       $this->releaseLock($acquiredLock);
+               }
+       }
+}
diff --git a/src/Core/Lock/CacheLockDriver.php b/src/Core/Lock/CacheLockDriver.php
new file mode 100644 (file)
index 0000000..ccbbb8a
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+
+namespace Friendica\Core\Lock;
+
+use Friendica\Core\Cache\IMemoryCacheDriver;
+
+class CacheLockDriver extends AbstractLockDriver
+{
+       /**
+        * @var \Friendica\Core\Cache\ICacheDriver;
+        */
+       private $cache;
+
+       /**
+        * CacheLockDriver constructor.
+        *
+        * @param IMemoryCacheDriver $cache The CacheDriver for this type of lock
+        */
+       public function __construct(IMemoryCacheDriver $cache)
+       {
+               $this->cache = $cache;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function acquireLock($key, $timeout = 120)
+       {
+               $got_lock = false;
+               $start = time();
+
+               $cachekey = self::getLockKey($key);
+
+               do {
+                       $lock = $this->cache->get($cachekey);
+                       // When we do want to lock something that was already locked by us.
+                       if ((int)$lock == getmypid()) {
+                               $got_lock = true;
+                       }
+
+                       // When we do want to lock something new
+                       if (is_null($lock)) {
+                               // At first initialize it with "0"
+                               $this->cache->add($cachekey, 0);
+                               // Now the value has to be "0" because otherwise the key was used by another process meanwhile
+                               if ($this->cache->compareSet($cachekey, 0, getmypid(), 300)) {
+                                       $got_lock = true;
+                                       $this->markAcquire($key);
+                               }
+                       }
+
+                       if (!$got_lock && ($timeout > 0)) {
+                               usleep(rand(10000, 200000));
+                       }
+               } while (!$got_lock && ((time() - $start) < $timeout));
+
+               return $got_lock;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function releaseLock($key)
+       {
+               $cachekey = self::getLockKey($key);
+
+               $this->cache->compareDelete($cachekey, getmypid());
+               $this->markRelease($key);
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function isLocked($key)
+       {
+               $cachekey = self::getLockKey($key);
+               $lock = $this->cache->get($cachekey);
+               return isset($lock) && ($lock !== false);
+       }
+
+       /**
+        * @param string $key   The original key
+        * @return string               The cache key used for the cache
+        */
+       private static function getLockKey($key) {
+               return "lock:" . $key;
+       }
+}
diff --git a/src/Core/Lock/DatabaseLockDriver.php b/src/Core/Lock/DatabaseLockDriver.php
new file mode 100644 (file)
index 0000000..6f4b942
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+
+namespace Friendica\Core\Lock;
+
+use dba;
+use Friendica\Database\DBM;
+use Friendica\Util\DateTimeFormat;
+
+/**
+ * Locking driver that stores the locks in the database
+ */
+class DatabaseLockDriver extends AbstractLockDriver
+{
+       /**
+        * (@inheritdoc)
+        */
+       public function acquireLock($key, $timeout = 120)
+       {
+               $got_lock = false;
+               $start = time();
+
+               do {
+                       dba::lock('locks');
+                       $lock = dba::selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
+
+                       if (DBM::is_result($lock)) {
+                               if ($lock['locked']) {
+                                       // We want to lock something that was already locked by us? So we got the lock.
+                                       if ($lock['pid'] == getmypid()) {
+                                               $got_lock = true;
+                                               $this->markAcquire($key);
+                                       }
+                               }
+                               if (!$lock['locked']) {
+                                       dba::update('locks', ['locked' => true, 'pid' => getmypid(), 'expires' => DateTimeFormat::utc('now + 300seconds')], ['name' => $key]);
+                                       $got_lock = true;
+                                       $this->markAcquire($key);
+                               }
+                       } else {
+                               dba::insert('locks', ['name' => $key, 'locked' => true, 'pid' => getmypid(), 'expires' => DateTimeFormat::utc('now + 300seconds')]);
+                               $got_lock = true;
+                               $this->markAcquire($key);
+                       }
+
+                       dba::unlock();
+
+                       if (!$got_lock && ($timeout > 0)) {
+                               usleep(rand(100000, 2000000));
+                       }
+               } while (!$got_lock && ((time() - $start) < $timeout));
+
+               return $got_lock;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function releaseLock($key)
+       {
+               dba::delete('locks', ['name' => $key, 'pid' => getmypid()]);
+
+               $this->markRelease($key);
+
+               return;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function releaseAll()
+       {
+               dba::delete('locks', ['pid' => getmypid()]);
+
+               $this->acquiredLocks = [];
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function isLocked($key)
+       {
+               $lock = dba::selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
+
+               if (DBM::is_result($lock)) {
+                       return $lock['locked'] !== false;
+               } else {
+                       return false;
+               }
+       }
+}
diff --git a/src/Core/Lock/ILockDriver.php b/src/Core/Lock/ILockDriver.php
new file mode 100644 (file)
index 0000000..cd54cc0
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+namespace Friendica\Core\Lock;
+
+/**
+ * Lock Driver Interface
+ *
+ * @author Philipp Holzer <admin@philipp.info>
+ */
+interface ILockDriver
+{
+       /**
+        * Checks, if a key is currently locked to a or my process
+        *
+        * @param string $key           The name of the lock
+        * @return bool
+        */
+       public function isLocked($key);
+
+       /**
+        *
+        * Acquires a lock for a given name
+        *
+        * @param string  $key      The Name of the lock
+        * @param integer $timeout  Seconds until we give up
+        *
+        * @return boolean Was the lock successful?
+        */
+       public function acquireLock($key, $timeout = 120);
+
+       /**
+        * Releases a lock if it was set by us
+        *
+        * @param string $key The Name of the lock
+        *
+        * @return void
+        */
+       public function releaseLock($key);
+
+       /**
+        * Releases all lock that were set by us
+        *
+        * @return void
+        */
+       public function releaseAll();
+}
diff --git a/src/Core/Lock/SemaphoreLockDriver.php b/src/Core/Lock/SemaphoreLockDriver.php
new file mode 100644 (file)
index 0000000..d032d46
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+
+namespace Friendica\Core\Lock;
+
+class SemaphoreLockDriver extends AbstractLockDriver
+{
+       private static $semaphore = [];
+
+       public function __construct()
+       {
+               if (!function_exists('sem_get')) {
+                       throw new \Exception('Semaphore lock not supported');
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       private static function semaphoreKey($key)
+       {
+               $temp = get_temppath();
+
+               $file = $temp . '/' . $key . '.sem';
+
+               if (!file_exists($file)) {
+                       file_put_contents($file, $key);
+               }
+
+               return ftok($file, 'f');
+       }
+
+       /**
+        *
+        * (@inheritdoc)
+        */
+       public function acquireLock($key, $timeout = 120)
+       {
+               self::$semaphore[$key] = sem_get(self::semaphoreKey($key));
+               if (self::$semaphore[$key]) {
+                       if (sem_acquire(self::$semaphore[$key], ($timeout == 0))) {
+                               $this->markAcquire($key);
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function releaseLock($key)
+       {
+               if (empty(self::$semaphore[$key])) {
+                       return false;
+               } else {
+                       $success = @sem_release(self::$semaphore[$key]);
+                       unset(self::$semaphore[$key]);
+                       $this->markRelease($key);
+                       return $success;
+               }
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function isLocked($key)
+       {
+               return isset(self::$semaphore[$key]);
+       }
+}
index c965e05830adee089e5d928dc14eb9ad164efd40..c4c91bbf8b48f420fcef8c8e9451ce4ccbe5891a 100644 (file)
@@ -4,15 +4,11 @@
  */
 namespace Friendica\Core;
 
-use Friendica\Core\Addon;
-use Friendica\Core\Config;
-use Friendica\Core\System;
+use dba;
 use Friendica\Database\DBM;
 use Friendica\Model\Process;
 use Friendica\Util\DateTimeFormat;
-use Friendica\Util\Lock;
 use Friendica\Util\Network;
-use dba;
 
 require_once 'include/dba.php';
 
@@ -108,16 +104,16 @@ class Worker
                                }
 
                                // If possible we will fetch new jobs for this worker
-                               if (!$refetched && Lock::set('worker_process', 0)) {
+                               if (!$refetched && Lock::acquire('worker_process', 0)) {
                                        $stamp = (float)microtime(true);
                                        $refetched = self::findWorkerProcesses($passing_slow);
                                        self::$db_duration += (microtime(true) - $stamp);
-                                       Lock::remove('worker_process');
+                                       Lock::release('worker_process');
                                }
                        }
 
                        // To avoid the quitting of multiple workers only one worker at a time will execute the check
-                       if (Lock::set('worker', 0)) {
+                       if (Lock::acquire('worker', 0)) {
                                $stamp = (float)microtime(true);
                                // Count active workers and compare them with a maximum value that depends on the load
                                if (self::tooMuchWorkers()) {
@@ -130,7 +126,7 @@ class Worker
                                        logger('Memory limit reached, quitting.', LOGGER_DEBUG);
                                        return;
                                }
-                               Lock::remove('worker');
+                               Lock::release('worker');
                                self::$db_duration += (microtime(true) - $stamp);
                        }
 
@@ -883,7 +879,7 @@ class Worker
                dba::close($r);
 
                $stamp = (float)microtime(true);
-               if (!Lock::set('worker_process')) {
+               if (!Lock::acquire('worker_process')) {
                        return false;
                }
                self::$lock_duration = (microtime(true) - $stamp);
@@ -892,7 +888,7 @@ class Worker
                $found = self::findWorkerProcesses($passing_slow);
                self::$db_duration += (microtime(true) - $stamp);
 
-               Lock::remove('worker_process');
+               Lock::release('worker_process');
 
                if ($found) {
                        $r = dba::select('workerqueue', [], ['pid' => getmypid(), 'done' => false]);
@@ -1097,13 +1093,13 @@ class Worker
                }
 
                // If there is a lock then we don't have to check for too much worker
-               if (!Lock::set('worker', 0)) {
+               if (!Lock::acquire('worker', 0)) {
                        return true;
                }
 
                // If there are already enough workers running, don't fork another one
                $quit = self::tooMuchWorkers();
-               Lock::remove('worker');
+               Lock::release('worker');
 
                if ($quit) {
                        return true;
index d4cb9cf58b017e4394b02df4679fe89c6ac2619c..7bb9b18aec798335a89798d8ca205497ceeea464 100644 (file)
@@ -4,10 +4,9 @@
  */
 namespace Friendica\Database;
 
+use dba;
 use Friendica\Core\Config;
 use Friendica\Core\L10n;
-use Friendica\Database\DBM;
-use dba;
 
 require_once 'boot.php';
 require_once 'include/dba.php';
@@ -1283,9 +1282,11 @@ class DBStructure
                                                "name" => ["type" => "varchar(128)", "not null" => "1", "default" => "", "comment" => ""],
                                                "locked" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "pid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => "Process ID"],
-                                               ],
+                                               "expires" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "datetime of cache expiration"],
+                               ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
+                                               "name_expires" => ["name", "expires"]
                                                ]
                                ];
                $database["mail"] = [
index 9b258960e6264ceded8d1bbb616678169ef98e81..49d759585a20bc513d865014dd21e383638f42eb 100644 (file)
@@ -268,9 +268,9 @@ class Event extends BaseObject
                if ($event['id']) {
                        // has the event actually changed?
                        $existing_event = dba::selectFirst('event', ['edited'], ['id' => $event['id'], 'uid' => $event['uid']]);
-                       if ((! DBM::is_result($existing_event)) || ($existing_event['edited'] === $event['edited'])) {
+                       if (!DBM::is_result($existing_event) || ($existing_event['edited'] === $event['edited'])) {
 
-                               $item = dba::selectFirst('item', [], ['event-id' => $event['id'], 'uid' => $event['uid']]);
+                               $item = Item::selectFirst(['id'], ['event-id' => $event['id'], 'uid' => $event['uid']]);
 
                                return DBM::is_result($item) ? $item['id'] : 0;
                        }
@@ -289,7 +289,7 @@ class Event extends BaseObject
 
                        dba::update('event', $updated_fields, ['id' => $event['id'], 'uid' => $event['uid']]);
 
-                       $item = dba::selectFirst('item', ['id'], ['event-id' => $event['id'], 'uid' => $event['uid']]);
+                       $item = Item::selectFirst(['id'], ['event-id' => $event['id'], 'uid' => $event['uid']]);
                        if (DBM::is_result($item)) {
                                $object = '<object><type>' . xmlify(ACTIVITY_OBJ_EVENT) . '</type><title></title><id>' . xmlify($event['uri']) . '</id>';
                                $object .= '<content>' . xmlify(self::getBBCode($event)) . '</content>';
@@ -464,8 +464,7 @@ class Event extends BaseObject
                }
 
                // Query for the event by event id
-               $r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
-                               `item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
+               $r = q("SELECT `event`.*, `item`.`id` AS `itemid` FROM `event`
                        LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
                        WHERE `event`.`uid` = %d AND `event`.`id` = %d $sql_extra",
                        intval($owner_uid),
@@ -505,8 +504,7 @@ class Event extends BaseObject
 
                // Query for the event by date.
                // @todo Slow query (518 seconds to run), to be optimzed
-               $r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
-                                       `item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
+               $r = q("SELECT `event`.*, `item`.`id` AS `itemid` FROM `event`
                                LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
                                WHERE `event`.`uid` = %d AND event.ignore = %d
                                AND ((`adjust` = 0 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s')
@@ -542,6 +540,11 @@ class Event extends BaseObject
                $last_date = '';
                $fmt = L10n::t('l, F j');
                foreach ($event_result as $event) {
+                       $item = Item::selectFirst(['plink', 'author-name', 'author-avatar', 'author-link'], ['id' => $event['itemid']]);
+                       if (DBM::is_result($item)) {
+                               $event = array_merge($event, $item);
+                       }
+
                        $start = $event['adjust'] ? DateTimeFormat::local($event['start'], 'c')  : DateTimeFormat::utc($event['start'], 'c');
                        $j     = $event['adjust'] ? DateTimeFormat::local($event['start'], 'j')  : DateTimeFormat::utc($event['start'], 'j');
                        $day   = $event['adjust'] ? DateTimeFormat::local($event['start'], $fmt) : DateTimeFormat::utc($event['start'], $fmt);
index 052d402127cc7338ac54003b039f523fb4d12307..664a8e9b291de096eac2840297cc2759545d18d1 100644 (file)
@@ -6,26 +6,22 @@
 
 namespace Friendica\Model;
 
+use dba;
 use Friendica\BaseObject;
 use Friendica\Content\Text;
 use Friendica\Core\Addon;
 use Friendica\Core\Config;
 use Friendica\Core\L10n;
+use Friendica\Core\Lock;
 use Friendica\Core\PConfig;
 use Friendica\Core\System;
 use Friendica\Core\Worker;
 use Friendica\Database\DBM;
-use Friendica\Model\Contact;
-use Friendica\Model\Conversation;
-use Friendica\Model\Group;
-use Friendica\Model\Term;
 use Friendica\Object\Image;
 use Friendica\Protocol\Diaspora;
 use Friendica\Protocol\OStatus;
 use Friendica\Util\DateTimeFormat;
 use Friendica\Util\XML;
-use Friendica\Util\Lock;
-use dba;
 use Text_LanguageDetect;
 
 require_once 'boot.php';
@@ -279,7 +275,7 @@ class Item extends BaseObject
 
                $param_string = self::addTablesToFields(dba::buildParameter($params), $fields);
 
-               $table = "`item` " . self::constructJoins($uid, $select_fields . $condition_string . $param_string, false);
+               $table = "`item` " . self::constructJoins($uid, $select_fields . $condition_string . $param_string, false, $usermode);
 
                $sql = "SELECT " . $select_fields . " FROM " . $table . $condition_string . $param_string;
 
@@ -394,7 +390,7 @@ class Item extends BaseObject
                $param_string = self::addTablesToFields($param_string, $threadfields);
                $param_string = self::addTablesToFields($param_string, $fields);
 
-               $table = "`thread` " . self::constructJoins($uid, $select_fields . $condition_string . $param_string, true);
+               $table = "`thread` " . self::constructJoins($uid, $select_fields . $condition_string . $param_string, true, $usermode);
 
                $sql = "SELECT " . $select_fields . " FROM " . $table . $condition_string . $param_string;
 
@@ -473,7 +469,7 @@ class Item extends BaseObject
         *
         * @return string The SQL joins for the "select" functions
         */
-       private static function constructJoins($uid, $sql_commands, $thread_mode)
+       private static function constructJoins($uid, $sql_commands, $thread_mode, $user_mode)
        {
                if ($thread_mode) {
                        $master_table = "`thread`";
@@ -485,14 +481,26 @@ class Item extends BaseObject
                        $joins = '';
                }
 
-               $joins .= sprintf("STRAIGHT_JOIN `contact` ON `contact`.`id` = $master_table.`contact-id`
-                       AND NOT `contact`.`blocked`
-                       AND ((NOT `contact`.`readonly` AND NOT `contact`.`pending` AND (`contact`.`rel` IN (%s, %s)))
-                       OR `contact`.`self` OR (`item`.`id` != `item`.`parent`) OR `contact`.`uid` = 0)
-                       STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = $master_table.`author-id` AND NOT `author`.`blocked`
-                       STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = $master_table.`owner-id` AND NOT `owner`.`blocked`
-                       LEFT JOIN `user-item` ON `user-item`.`iid` = $master_table_key AND `user-item`.`uid` = %d",
-                       CONTACT_IS_SHARING, CONTACT_IS_FRIEND, intval($uid));
+               if ($user_mode) {
+                       $joins .= sprintf("STRAIGHT_JOIN `contact` ON `contact`.`id` = $master_table.`contact-id`
+                               AND NOT `contact`.`blocked`
+                               AND ((NOT `contact`.`readonly` AND NOT `contact`.`pending` AND (`contact`.`rel` IN (%s, %s)))
+                               OR `contact`.`self` OR (`item`.`id` != `item`.`parent`) OR `contact`.`uid` = 0)
+                               STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = $master_table.`author-id` AND NOT `author`.`blocked`
+                               STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = $master_table.`owner-id` AND NOT `owner`.`blocked`
+                               LEFT JOIN `user-item` ON `user-item`.`iid` = $master_table_key AND `user-item`.`uid` = %d",
+                               CONTACT_IS_SHARING, CONTACT_IS_FRIEND, intval($uid));
+               } else {
+                       if (strpos($sql_commands, "`contact`.") !== false) {
+                               $joins .= "STRAIGHT_JOIN `contact` ON `contact`.`id` = $master_table.`contact-id`";
+                       }
+                       if (strpos($sql_commands, "`author`.") !== false) {
+                               $joins .= " STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = $master_table.`author-id`";
+                       }
+                       if (strpos($sql_commands, "`owner`.") !== false) {
+                               $joins .= " STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = $master_table.`owner-id`";
+                       }
+               }
 
                if (strpos($sql_commands, "`group_member`.") !== false) {
                        $joins .= " STRAIGHT_JOIN `group_member` ON `group_member`.`contact-id` = $master_table.`contact-id`";
@@ -1585,7 +1593,7 @@ class Item extends BaseObject
                }
 
                // To avoid timing problems, we are using locks.
-               $locked = Lock::set('item_insert_content');
+               $locked = Lock::acquire('item_insert_content');
                if (!$locked) {
                        logger("Couldn't acquire lock for URI " . $item['uri'] . " - proceeding anyway.");
                }
@@ -1605,7 +1613,7 @@ class Item extends BaseObject
                        logger('Could not insert content for URI ' . $item['uri'] . ' - trying asynchronously');
                }
                if ($locked) {
-                       Lock::remove('item_insert_content');
+                       Lock::release('item_insert_content');
                }
        }
 
@@ -2685,7 +2693,7 @@ class Item extends BaseObject
                }
 
                $base_condition = ['verb' => $verbs, 'deleted' => false, 'gravity' => GRAVITY_ACTIVITY,
-                       'author-id' => $author_contact['id'], 'uid' => item['uid']];
+                       'author-id' => $author_contact['id'], 'uid' => $item['uid']];
 
                $condition = array_merge($base_condition, ['parent' => $item_id]);
                $like_item = self::selectFirst(['id', 'guid', 'verb'], $condition);
index 6754f220702704ecda759107902e4a12cb1299e4..dc5702b6055214cafd68241b196414845b430c73 100644 (file)
@@ -304,6 +304,33 @@ class User
                return dba::update('user', $fields, ['uid' => $uid]);
        }
 
+       /**
+        * @brief Checks if a nickname is in the list of the forbidden nicknames
+        *
+        * Check if a nickname is forbidden from registration on the node by the
+        * admin. Forbidden nicknames (e.g. role namess) can be configured in the
+        * admin panel.
+        *
+        * @param string $nickname The nickname that should be checked
+        * @return boolean True is the nickname is blocked on the node
+        */
+       public static function isNicknameBlocked($nickname)
+       {
+               $forbidden_nicknames = Config::get('system', 'forbidden_nicknames', '');
+               // if the config variable is empty return false
+               if (!x($forbidden_nicknames)) {
+                       return false;
+               }
+               // check if the nickname is in the list of blocked nicknames
+               $forbidden = explode(',', $forbidden_nicknames);
+               $forbidden = array_map('trim', $forbidden);
+               if (in_array(strtolower($nickname), $forbidden)) {
+                       return true;
+               }
+               // else return false
+               return false;
+       }
+
        /**
         * @brief Catch-all user creation function
         *
@@ -417,6 +444,9 @@ class User
                if (!valid_email($email) || !Network::isEmailDomainValid($email)) {
                        throw new Exception(L10n::t('Not a valid email address.'));
                }
+               if (self::isNicknameBlocked($nickname)) {
+                       throw new Exception(L10n::t('The nickname was blocked from registration by the nodes admin.'));
+               }
 
                if (Config::get('system', 'block_extended_register', false) && dba::exists('user', ['email' => $email])) {
                        throw new Exception(L10n::t('Cannot use that email.'));
index 7a65c8afc9feefd47f81929702c88952bbfa8aac..b131246fd4e1a3f7a909d566506c291d0d0d1a62 100644 (file)
@@ -859,7 +859,7 @@ class Post extends BaseObject
 
                                                $owner = ['uid' => 0, 'id' => $this->getDataValue('owner-id'),
                                                        'network' => $this->getDataValue('owner-network'),
-                                                       'url' => $this->getDataValue('ownerr-link')];
+                                                       'url' => $this->getDataValue('owner-link')];
                                                $this->owner_url = Contact::magicLinkbyContact($owner);
                                        }
                                }
index 4538d36dfa11676844c858661493d1ddf81c0c89..dadc19dcca27691af4f36fbe941eeefe16f080a5 100644 (file)
@@ -4,11 +4,15 @@
  */
 namespace Friendica\Protocol;
 
+use dba;
+use DOMDocument;
+use DOMXPath;
 use Friendica\Content\Text\BBCode;
 use Friendica\Content\Text\HTML;
 use Friendica\Core\Cache;
 use Friendica\Core\Config;
 use Friendica\Core\L10n;
+use Friendica\Core\Lock;
 use Friendica\Core\System;
 use Friendica\Database\DBM;
 use Friendica\Model\Contact;
@@ -19,12 +23,8 @@ use Friendica\Model\User;
 use Friendica\Network\Probe;
 use Friendica\Object\Image;
 use Friendica\Util\DateTimeFormat;
-use Friendica\Util\Lock;
 use Friendica\Util\Network;
 use Friendica\Util\XML;
-use dba;
-use DOMDocument;
-use DOMXPath;
 
 require_once 'include/dba.php';
 require_once 'include/items.php';
@@ -341,7 +341,7 @@ class OStatus
                $header["type"] = "remote";
                $header["wall"] = 0;
                $header["origin"] = 0;
-               $header["gravity"] = GRAVITY_PARENT;
+               $header["gravity"] = GRAVITY_COMMENT;
 
                $first_child = $doc->firstChild->tagName;
 
@@ -513,9 +513,9 @@ class OStatus
                                                        logger("Item with uri ".$item["uri"]." is from a blocked contact.", LOGGER_DEBUG);
                                                } else {
                                                        // We are having duplicated entries. Hopefully this solves it.
-                                                       if (Lock::set('ostatus_process_item_insert')) {
+                                                       if (Lock::acquire('ostatus_process_item_insert')) {
                                                                $ret = Item::insert($item);
-                                                               Lock::remove('ostatus_process_item_insert');
+                                                               Lock::release('ostatus_process_item_insert');
                                                                logger("Item with uri ".$item["uri"]." for user ".$importer["uid"].' stored. Return value: '.$ret);
                                                        } else {
                                                                $ret = Item::insert($item);
@@ -683,9 +683,9 @@ class OStatus
                        }
 
                        $item["type"] = 'remote-comment';
-                       $item["gravity"] = GRAVITY_COMMENT;
                } else {
                        $item["parent-uri"] = $item["uri"];
+                       $item["gravity"] = GRAVITY_PARENT;
                }
 
                if (($item['author-link'] != '') && !empty($item['protocol'])) {
diff --git a/src/Util/Lock.php b/src/Util/Lock.php
deleted file mode 100644 (file)
index eba264a..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-<?php
-/**
- * @file src/Util/Lock.php
- */
-namespace Friendica\Util;
-
-/**
- * @file src/Util/Lock.php
- * @brief Functions for preventing parallel execution of functions
- */
-
-use Friendica\Core\Config;
-use Friendica\Database\DBM;
-use Memcache;
-use dba;
-
-require_once 'include/dba.php';
-
-/**
- * @brief This class contain Functions for preventing parallel execution of functions
- */
-class Lock
-{
-       private static $semaphore = [];
-
-       /**
-        * @brief Check for memcache and open a connection if configured
-        *
-        * @return object|boolean The memcache object - or "false" if not successful
-        */
-       private static function connectMemcache()
-       {
-               if (!function_exists('memcache_connect')) {
-                       return false;
-               }
-
-               if (!Config::get('system', 'memcache')) {
-                       return false;
-               }
-
-               $memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
-               $memcache_port = Config::get('system', 'memcache_port', 11211);
-
-               $memcache = new Memcache;
-
-               if (!$memcache->connect($memcache_host, $memcache_port)) {
-                       return false;
-               }
-
-               return $memcache;
-       }
-
-       /**
-        * @brief Creates a semaphore key
-        *
-        * @param string $fn_name Name of the lock
-        *
-        * @return ressource the semaphore key
-        */
-       private static function semaphoreKey($fn_name)
-       {
-               $temp = get_temppath();
-
-               $file = $temp.'/'.$fn_name.'.sem';
-
-               if (!file_exists($file)) {
-                       file_put_contents($file, $fn_name);
-               }
-
-               return ftok($file, 'f');
-       }
-
-       /**
-        * @brief Sets a lock for a given name
-        *
-        * @param string  $fn_name Name of the lock
-        * @param integer $timeout Seconds until we give up
-        *
-        * @return boolean Was the lock successful?
-        */
-       public static function set($fn_name, $timeout = 120)
-       {
-               $got_lock = false;
-               $start = time();
-
-               // The second parameter for "sem_acquire" doesn't exist before 5.6.1
-               if (function_exists('sem_get') && version_compare(PHP_VERSION, '5.6.1', '>=')) {
-                       self::$semaphore[$fn_name] = sem_get(self::semaphoreKey($fn_name));
-                       if (self::$semaphore[$fn_name]) {
-                               return sem_acquire(self::$semaphore[$fn_name], ($timeout == 0));
-                       }
-               }
-
-               $memcache = self::connectMemcache();
-               if (is_object($memcache)) {
-                       $cachekey = get_app()->get_hostname().";lock:".$fn_name;
-
-                       do {
-                               // We only lock to be sure that nothing happens at exactly the same time
-                               dba::lock('locks');
-                               $lock = $memcache->get($cachekey);
-
-                               if (!is_bool($lock)) {
-                                       $pid = (int)$lock;
-
-                                       // When the process id isn't used anymore, we can safely claim the lock for us.
-                                       // Or we do want to lock something that was already locked by us.
-                                       if (!posix_kill($pid, 0) || ($pid == getmypid())) {
-                                               $lock = false;
-                                       }
-                               }
-                               if (is_bool($lock)) {
-                                       $memcache->set($cachekey, getmypid(), MEMCACHE_COMPRESSED, 300);
-                                       $got_lock = true;
-                               }
-
-                               dba::unlock();
-
-                               if (!$got_lock && ($timeout > 0)) {
-                                       usleep(rand(10000, 200000));
-                               }
-                       } while (!$got_lock && ((time() - $start) < $timeout));
-
-                       return $got_lock;
-               }
-
-               do {
-                       dba::lock('locks');
-                       $lock = dba::selectFirst('locks', ['locked', 'pid'], ['name' => $fn_name]);
-
-                       if (DBM::is_result($lock)) {
-                               if ($lock['locked']) {
-                                       // When the process id isn't used anymore, we can safely claim the lock for us.
-                                       if (!posix_kill($lock['pid'], 0)) {
-                                               $lock['locked'] = false;
-                                       }
-                                       // We want to lock something that was already locked by us? So we got the lock.
-                                       if ($lock['pid'] == getmypid()) {
-                                               $got_lock = true;
-                                       }
-                               }
-                               if (!$lock['locked']) {
-                                       dba::update('locks', ['locked' => true, 'pid' => getmypid()], ['name' => $fn_name]);
-                                       $got_lock = true;
-                               }
-                       } elseif (!DBM::is_result($lock)) {
-                               dba::insert('locks', ['name' => $fn_name, 'locked' => true, 'pid' => getmypid()]);
-                               $got_lock = true;
-                       }
-
-                       dba::unlock();
-
-                       if (!$got_lock && ($timeout > 0)) {
-                               usleep(rand(100000, 2000000));
-                       }
-               } while (!$got_lock && ((time() - $start) < $timeout));
-
-               return $got_lock;
-       }
-
-       /**
-        * @brief Removes a lock if it was set by us
-        *
-        * @param string $fn_name Name of the lock
-        * @return mixed
-        */
-       public static function remove($fn_name)
-       {
-               if (function_exists('sem_get') && version_compare(PHP_VERSION, '5.6.1', '>=')) {
-                       if (empty(self::$semaphore[$fn_name])) {
-                               return false;
-                       } else {
-                               $success = @sem_release(self::$semaphore[$fn_name]);
-                               unset(self::$semaphore[$fn_name]);
-                               return $success;
-                       }
-               }
-
-               $memcache = self::connectMemcache();
-               if (is_object($memcache)) {
-                       $cachekey = get_app()->get_hostname().";lock:".$fn_name;
-                       $lock = $memcache->get($cachekey);
-
-                       if (!is_bool($lock)) {
-                               if ((int)$lock == getmypid()) {
-                                       $memcache->delete($cachekey);
-                               }
-                       }
-                       return;
-               }
-
-               dba::update('locks', ['locked' => false, 'pid' => 0], ['name' => $fn_name, 'pid' => getmypid()]);
-               return;
-       }
-
-       /**
-        * @brief Removes all lock that were set by us
-        * @return void
-        */
-       public static function removeAll()
-       {
-               $memcache = self::connectMemcache();
-               if (is_object($memcache)) {
-                       // We cannot delete all cache entries, but this doesn't matter with memcache
-                       return;
-               }
-
-               dba::update('locks', ['locked' => false, 'pid' => 0], ['pid' => getmypid()]);
-               return;
-       }
-}
diff --git a/tests/src/Core/Lock/CacheLockDriverTest.php b/tests/src/Core/Lock/CacheLockDriverTest.php
new file mode 100644 (file)
index 0000000..a089059
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+namespace Friendica\Test\src\Core\Lock;
+
+
+use Friendica\Core\Cache\ArrayCache;
+use Friendica\Core\Lock\CacheLockDriver;
+
+class CacheLockDriverTest extends LockTest
+{
+       /**
+        * @var \Friendica\Core\Cache\IMemoryCacheDriver
+        */
+       private $cache;
+
+       protected function getInstance()
+       {
+               $this->cache = new ArrayCache();
+               return new CacheLockDriver($this->cache);
+       }
+
+       public function tearDown()
+       {
+               $this->cache->clear();
+               parent::tearDown();
+       }
+}
\ No newline at end of file
diff --git a/tests/src/Core/Lock/DatabaseLockDriverTest.php b/tests/src/Core/Lock/DatabaseLockDriverTest.php
new file mode 100644 (file)
index 0000000..a80ff4c
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+
+namespace Friendica\Test\src\Core\Lock;
+
+use dba;
+use Friendica\Core\Lock\DatabaseLockDriver;
+use Friendica\Database\DBStructure;
+use PHPUnit\DbUnit\DataSet\YamlDataSet;
+use PHPUnit\DbUnit\TestCaseTrait;
+use PHPUnit_Extensions_Database_DB_IDatabaseConnection;
+
+class DatabaseLockDriverTest extends LockTest
+{
+       use TestCaseTrait;
+
+       /**
+        * Get database connection.
+        *
+        * This function is executed before each test in order to get a database connection that can be used by tests.
+        * If no prior connection is available, it tries to create one using the USER, PASS and DB environment variables.
+        *
+        * If it could not connect to the database, the test is skipped.
+        *
+        * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
+        * @see https://phpunit.de/manual/5.7/en/database.html
+        */
+       protected function getConnection()
+       {
+               if (!dba::$connected) {
+                       dba::connect('localhost', getenv('USER'), getenv('PASS'), getenv('DB'));
+
+                       if (dba::$connected) {
+                               $app = get_app();
+                               // We need to do this in order to disable logging
+                               $app->module = 'install';
+
+                               // Create database structure
+                               DBStructure::update(false, true, true);
+                       } else {
+                               $this->markTestSkipped('Could not connect to the database.');
+                       }
+               }
+
+               return $this->createDefaultDBConnection(dba::get_db(), getenv('DB'));
+       }
+
+       /**
+        * Get dataset to populate the database with.
+        * @return YamlDataSet
+        * @see https://phpunit.de/manual/5.7/en/database.html
+        */
+       protected function getDataSet()
+       {
+               return new YamlDataSet(__DIR__ . '/../../../datasets/api.yml');
+       }
+
+       protected function getInstance()
+       {
+               return new DatabaseLockDriver();
+       }
+
+       public function tearDown()
+       {
+               dba::delete('locks', [ 'id > 0']);
+               parent::tearDown();
+       }
+}
\ No newline at end of file
diff --git a/tests/src/Core/Lock/LockTest.php b/tests/src/Core/Lock/LockTest.php
new file mode 100644 (file)
index 0000000..c8c0c32
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+
+namespace Friendica\Test\src\Core\Lock;
+
+use Friendica\App;
+use Friendica\Core\Config;
+use PHPUnit\Framework\TestCase;
+
+abstract class LockTest extends TestCase
+{
+       /**
+        * @var \Friendica\Core\Lock\ILockDriver
+        */
+       protected $instance;
+
+       abstract protected function getInstance();
+
+       protected function setUp()
+       {
+               global $a;
+               parent::setUp();
+               $this->instance = $this->getInstance();
+
+               // Reusable App object
+               $this->app = new App(__DIR__.'/../');
+               $a = $this->app;
+
+               // Default config
+               Config::set('config', 'hostname', 'localhost');
+               Config::set('system', 'throttle_limit_day', 100);
+               Config::set('system', 'throttle_limit_week', 100);
+               Config::set('system', 'throttle_limit_month', 100);
+               Config::set('system', 'theme', 'system_theme');
+       }
+
+       public function testLock() {
+               $this->instance->acquireLock('foo', 1);
+               $this->assertTrue($this->instance->isLocked('foo'));
+               $this->assertFalse($this->instance->isLocked('bar'));
+       }
+
+       public function testDoubleLock() {
+               $this->instance->acquireLock('foo', 1);
+               $this->assertTrue($this->instance->isLocked('foo'));
+               // We already locked it
+               $this->assertTrue($this->instance->acquireLock('foo', 1));
+       }
+
+       public function testReleaseLock() {
+               $this->instance->acquireLock('foo', 1);
+               $this->assertTrue($this->instance->isLocked('foo'));
+               $this->instance->releaseLock('foo');
+               $this->assertFalse($this->instance->isLocked('foo'));
+       }
+
+       public function testReleaseAll() {
+               $this->instance->acquireLock('foo', 1);
+               $this->instance->acquireLock('bar', 1);
+               $this->instance->acquireLock('nice', 1);
+
+               $this->instance->releaseAll();
+
+               $this->assertFalse($this->instance->isLocked('foo'));
+               $this->assertFalse($this->instance->isLocked('bar'));
+               $this->assertFalse($this->instance->isLocked('nice'));
+       }
+
+       public function testReleaseAfterUnlock() {
+               $this->instance->acquireLock('foo', 1);
+               $this->instance->acquireLock('bar', 1);
+               $this->instance->acquireLock('nice', 1);
+
+               $this->instance->releaseLock('foo');
+
+               $this->instance->releaseAll();
+
+               $this->assertFalse($this->instance->isLocked('bar'));
+               $this->assertFalse($this->instance->isLocked('#/$%§'));
+       }
+}
\ No newline at end of file
diff --git a/tests/src/Core/Lock/SemaphoreLockDriverTest.php b/tests/src/Core/Lock/SemaphoreLockDriverTest.php
new file mode 100644 (file)
index 0000000..56c9645
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+namespace Friendica\Test\src\Core\Lock;
+
+
+use Friendica\Core\Lock\SemaphoreLockDriver;
+
+class SemaphoreLockDriverTest extends LockTest
+{
+       /**
+        * @var \Friendica\Core\Lock\SemaphoreLockDriver
+        */
+       private $semaphoreLockDriver;
+
+       protected function getInstance()
+       {
+               $this->semaphoreLockDriver = new SemaphoreLockDriver();
+               return $this->semaphoreLockDriver;
+       }
+
+       public function tearDown()
+       {
+               $this->semaphoreLockDriver->releaseAll();
+               parent::tearDown();
+       }
+}
\ No newline at end of file
index 7984a34e669ee27e4ed80a8e75507d5fd67c5c7d..07aad54e2073dfb7db3d970168966898e0aed480 100644 (file)
@@ -13,7 +13,7 @@ msgstr ""
 "Project-Id-Version: friendica\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2018-06-30 17:33+0200\n"
-"PO-Revision-Date: 2018-07-01 23:15+0000\n"
+"PO-Revision-Date: 2018-07-06 02:27+0000\n"
 "Last-Translator: Aditoo\n"
 "Language-Team: Czech (http://www.transifex.com/Friendica/friendica/language/cs/)\n"
 "MIME-Version: 1.0\n"
@@ -158,12 +158,12 @@ msgstr "fotka"
 #: src/Protocol/Diaspora.php:1945
 #, php-format
 msgid "%1$s likes %2$s's %3$s"
-msgstr "%1$s se líbí %3$s %2$s"
+msgstr "Uživateli %1$s se líbí %3$s %2$s"
 
 #: include/conversation.php:170 src/Model/Item.php:2535
 #, php-format
 msgid "%1$s doesn't like %2$s's %3$s"
-msgstr "%1$s se nelíbí %3$s %2$s"
+msgstr "Uživateli %1$s se nelíbí %3$s %2$s"
 
 #: include/conversation.php:172
 #, php-format
@@ -206,11 +206,11 @@ msgstr "uživatel %1$s označil %3$s %2$s jako oblíbené"
 
 #: include/conversation.php:504 mod/profiles.php:355 mod/photos.php:1464
 msgid "Likes"
-msgstr "Libí se mi"
+msgstr "Libí se"
 
 #: include/conversation.php:504 mod/profiles.php:359 mod/photos.php:1464
 msgid "Dislikes"
-msgstr "Nelibí se mi"
+msgstr "Nelibí se"
 
 #: include/conversation.php:505 include/conversation.php:1455
 #: mod/photos.php:1465
@@ -320,12 +320,12 @@ msgstr "Připojit / Následovat"
 #: include/conversation.php:969
 #, php-format
 msgid "%s likes this."
-msgstr "%s se to líbí."
+msgstr "Uživateli %s se tohle líbí."
 
 #: include/conversation.php:972
 #, php-format
 msgid "%s doesn't like this."
-msgstr "%s se to nelíbí."
+msgstr "Uživateli %s se tohle nelíbí."
 
 #: include/conversation.php:975
 #, php-format
@@ -354,22 +354,22 @@ msgstr "a dalších %d lidí"
 #: include/conversation.php:1007
 #, php-format
 msgid "<span  %1$s>%2$d people</span> like this"
-msgstr "<span  %1$s>%2$d lidem</span> se to líbí"
+msgstr "<span  %1$s>%2$d lidem</span> se tohle líbí"
 
 #: include/conversation.php:1008
 #, php-format
 msgid "%s like this."
-msgstr "%s se tohle líbí."
+msgstr "Uživatelům %s se tohle líbí."
 
 #: include/conversation.php:1011
 #, php-format
 msgid "<span  %1$s>%2$d people</span> don't like this"
-msgstr "<span  %1$s>%2$d lidem</span> se to nelíbí"
+msgstr "<span  %1$s>%2$d lidem</span> se tohle nelíbí"
 
 #: include/conversation.php:1012
 #, php-format
 msgid "%s don't like this."
-msgstr "%s se tohle nelíbí."
+msgstr "Uživatelům %s se tohle nelíbí."
 
 #: include/conversation.php:1015
 #, php-format
@@ -596,12 +596,12 @@ msgstr "Děkujeme, "
 #: include/enotify.php:38
 #, php-format
 msgid "%s Administrator"
-msgstr "%s administrátor"
+msgstr "Administrátor %s"
 
 #: include/enotify.php:40
 #, php-format
 msgid "%1$s, %2$s Administrator"
-msgstr "%1$s, %2$s administrátor"
+msgstr "%1$s, administrátor %2$s"
 
 #: include/enotify.php:96
 #, php-format
@@ -740,12 +740,12 @@ msgstr "[Friendica:Oznámení] Obdrženo představení"
 #: include/enotify.php:262
 #, php-format
 msgid "You've received an introduction from '%1$s' at %2$s"
-msgstr "Obdržel/a jste představení od \"%1$s\" na %2$s"
+msgstr "Obdržel/a jste představení od uživatele \"%1$s\" na %2$s"
 
 #: include/enotify.php:263
 #, php-format
 msgid "You've received [url=%1$s]an introduction[/url] from %2$s."
-msgstr "Obdržel/a jste [url=%1$s]představení[/url] od %2$s."
+msgstr "Obdržel/a jste [url=%1$s]představení[/url] od uživatele %2$s."
 
 #: include/enotify.php:268 include/enotify.php:314
 #, php-format
@@ -782,13 +782,13 @@ msgstr "[Friendica:Oznámení] Obdržen návrh pro přátelství"
 #: include/enotify.php:305
 #, php-format
 msgid "You've received a friend suggestion from '%1$s' at %2$s"
-msgstr "Obdržel jste návrh pro přátelství od '%1$s' na %2$s"
+msgstr "Obdržel/a jste návrh pro přátelství od uživatele \"%1$s\" na %2$s"
 
 #: include/enotify.php:306
 #, php-format
 msgid ""
 "You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s."
-msgstr "Obdržel jste [url=%1$s]návrh pro přátelství[/url] s %2$s from %3$s."
+msgstr "Obdržel/a jste [url=%1$s]návrh pro přátelství[/url] s uživatelem %2$s od uživatele %3$s."
 
 #: include/enotify.php:312
 msgid "Name:"
@@ -810,12 +810,12 @@ msgstr "[Friendica:Oznámení] Spojení akceptováno"
 #: include/enotify.php:326 include/enotify.php:341
 #, php-format
 msgid "'%1$s' has accepted your connection request at %2$s"
-msgstr "\"%1$s\" akceptoval váš požadavek na spojení na %2$s"
+msgstr "\"%1$s\" akceptoval/a Váš požadavek na spojení na %2$s"
 
 #: include/enotify.php:327 include/enotify.php:342
 #, php-format
 msgid "%2$s has accepted your [url=%1$s]connection request[/url]."
-msgstr "%2$s akceptoval váš [url=%1$s]požadavek na spojení[/url]."
+msgstr "%2$s akceptoval/a Váš [url=%1$s]požadavek na spojení[/url]."
 
 #: include/enotify.php:332
 msgid ""
@@ -860,12 +860,12 @@ msgstr "žádost o registraci"
 #: include/enotify.php:363
 #, php-format
 msgid "You've received a registration request from '%1$s' at %2$s"
-msgstr "Obdržel jste žádost o registraci od '%1$s' na %2$s"
+msgstr "Obdržel/a jste žádost o registraci od uživatele \"%1$s\" na %2$s"
 
 #: include/enotify.php:364
 #, php-format
 msgid "You've received a [url=%1$s]registration request[/url] from %2$s."
-msgstr "Obdržel jste [url=%1$s]žádost o registraci[/url] od '%2$s'."
+msgstr "Obdržel/a jste [url=%1$s]žádost o registraci[/url] od uživatele \"%2$s\"."
 
 #: include/enotify.php:369
 #, php-format
@@ -972,7 +972,7 @@ msgstr "šťouchnout"
 
 #: include/text.php:1043
 msgid "poked"
-msgstr "šťouchnul"
+msgstr "šťouchnul/a"
 
 #: include/text.php:1044
 msgid "ping"
@@ -980,7 +980,7 @@ msgstr "cinknout"
 
 #: include/text.php:1044
 msgid "pinged"
-msgstr "cinknul"
+msgstr "cinknul/a"
 
 #: include/text.php:1045
 msgid "prod"
@@ -988,7 +988,7 @@ msgstr "dloubnout"
 
 #: include/text.php:1045
 msgid "prodded"
-msgstr "dloubnul"
+msgstr "dloubnul/a"
 
 #: include/text.php:1046
 msgid "slap"
@@ -996,15 +996,15 @@ msgstr "uhodit"
 
 #: include/text.php:1046
 msgid "slapped"
-msgstr "uhodil"
+msgstr "uhodil/a"
 
 #: include/text.php:1047
 msgid "finger"
-msgstr "osahávat"
+msgstr "osahat"
 
 #: include/text.php:1047
 msgid "fingered"
-msgstr "osahal"
+msgstr "osahal/a"
 
 #: include/text.php:1048
 msgid "rebuff"
@@ -1012,7 +1012,7 @@ msgstr "odmítnout"
 
 #: include/text.php:1048
 msgid "rebuffed"
-msgstr "odmítnul"
+msgstr "odmítnul/a"
 
 #: include/text.php:1062 mod/settings.php:935 src/Model/Event.php:379
 msgid "Monday"
@@ -1361,7 +1361,7 @@ msgid ""
 "On your <em>Settings</em> page -  change your initial password. Also make a "
 "note of your Identity Address. This looks just like an email address - and "
 "will be useful in making friends on the free social web."
-msgstr "Na Vaší stránce <em>Nastavení</em> si změňte Vaše první heslo.\nVěnujte také svou pozornost k adrese Identity. Vypadá jako emailová adresa a bude Vám užitečná pro navazování přátelství na svobodném sociálním webu."
+msgstr "Na Vaší stránce <em>Nastavení</em> si změňte Vaše první heslo. Věnujte také svou pozornost k adrese Identity. Vypadá jako emailová adresa a bude Vám užitečná pro navazování přátelství na svobodném sociálním webu."
 
 #: mod/newmember.php:22
 msgid ""
@@ -2089,7 +2089,7 @@ msgstr "Odpovězte, prosím, následující:"
 #: mod/follow.php:150 mod/dfrn_request.php:647
 #, php-format
 msgid "Does %s know you?"
-msgstr "Zná Vás uživatel %s ?"
+msgstr "Zná Vás %s ?"
 
 #: mod/follow.php:151 mod/dfrn_request.php:648
 msgid "Add a personal note:"
@@ -2607,7 +2607,7 @@ msgstr "Vaše databáze Friendica  byla nainstalována."
 msgid ""
 "You may need to import the file \"database.sql\" manually using phpmyadmin "
 "or mysql."
-msgstr "Pravděpodobně budete muset manuálně importovat soubor \"database.sql\" pomocí phpMyAdmin či MySQL."
+msgstr "Nejspíše budete muset manuálně importovat soubor \"database.sql\" pomocí phpMyAdmin či MySQL."
 
 #: mod/install.php:109 mod/install.php:155 mod/install.php:267
 msgid "Please see the file \"INSTALL.txt\"."
@@ -2639,7 +2639,7 @@ msgstr "Pro instalaci Friendica potřeujeme znát připojení k Vaší databázi
 msgid ""
 "Please contact your hosting provider or site administrator if you have "
 "questions about these settings."
-msgstr "Pokud máte otázky k následujícím nastavením, obraťte se na svého poskytovatele hostingu nebo administrátora serveru"
+msgstr "Pokud máte otázky k následujícím nastavením, obraťte se na svého poskytovatele hostingu nebo administrátora serveru."
 
 #: mod/install.php:180
 msgid ""
@@ -4150,7 +4150,7 @@ msgstr "Jste označen v příspěvku"
 
 #: mod/settings.php:1249
 msgid "You are poked/prodded/etc. in a post"
-msgstr "Byl jste šťouchnut(a)/dloubnut(a)/apod. v příspěvku"
+msgstr "Byl/a jste šťouchnut(a)/dloubnut(a)/apod. v příspěvku"
 
 #: mod/settings.php:1251
 msgid "Activate desktop notifications"
@@ -4319,7 +4319,7 @@ msgstr "vyzkoušet webfinger"
 
 #: mod/admin.php:223 src/Content/Nav.php:218
 msgid "Admin"
-msgstr "Administrace"
+msgstr "Administrátor"
 
 #: mod/admin.php:224
 msgid "Addon Features"
@@ -5678,7 +5678,7 @@ msgid ""
 "\n"
 "\t\t\tDear %1$s,\n"
 "\t\t\t\tthe administrator of %2$s has set up an account for you."
-msgstr "\n\t\t\tVážený/á%1$s,\n\t\t\t\tadministrátor %2$s pro Vás vytvořil/a uživatelský účet."
+msgstr "\n\t\t\tVážený/á%1$s,\n\t\t\t\tadministrátor %2$s pro Vás vytvořil uživatelský účet."
 
 #: mod/admin.php:1597
 #, php-format
@@ -5809,7 +5809,7 @@ msgstr "Odmítnout"
 
 #: mod/admin.php:1835
 msgid "Site admin"
-msgstr "Site administrátor"
+msgstr "Administrátor webu"
 
 #: mod/admin.php:1836
 msgid "Account expired"
index fc89a8a571b2594274e2c1ad5dc1352053a96a36..9bdcd2ad275a62f3f6cdef6c139bffba458e4ff5 100644 (file)
@@ -34,8 +34,8 @@ $a->strings["Profile Photos"] = "Profilové fotky";
 $a->strings["event"] = "událost";
 $a->strings["status"] = "stav";
 $a->strings["photo"] = "fotka";
-$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s se líbí %3\$s %2\$s";
-$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "%1\$s se nelíbí %3\$s %2\$s";
+$a->strings["%1\$s likes %2\$s's %3\$s"] = "Uživateli %1\$s se líbí %3\$s %2\$s";
+$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "Uživateli %1\$s se nelíbí %3\$s %2\$s";
 $a->strings["%1\$s attends %2\$s's %3\$s"] = "%1\$s se účastní %3\$s %2\$s";
 $a->strings["%1\$s doesn't attend %2\$s's %3\$s"] = "%1\$s se neúčastní %3\$s %2\$s";
 $a->strings["%1\$s attends maybe %2\$s's %3\$s"] = "%1\$s se možná účastní %3\$s %2\$s";
@@ -44,8 +44,8 @@ $a->strings["%1\$s poked %2\$s"] = "%1\$s šťouchnul %2\$s";
 $a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s označil %3\$s %2\$s s %4\$s";
 $a->strings["post/item"] = "příspěvek/položka";
 $a->strings["%1\$s marked %2\$s's %3\$s as favorite"] = "uživatel %1\$s označil %3\$s %2\$s jako oblíbené";
-$a->strings["Likes"] = "Libí se mi";
-$a->strings["Dislikes"] = "Nelibí se mi";
+$a->strings["Likes"] = "Libí se";
+$a->strings["Dislikes"] = "Nelibí se";
 $a->strings["Attending"] = [
        0 => "Účastní se",
        1 => "Účastní se",
@@ -73,17 +73,17 @@ $a->strings["View Contact"] = "Zobrazit kontakt";
 $a->strings["Send PM"] = "Poslat soukromou zprávu";
 $a->strings["Poke"] = "Šťouchnout";
 $a->strings["Connect/Follow"] = "Připojit / Následovat";
-$a->strings["%s likes this."] = "%s se to líbí.";
-$a->strings["%s doesn't like this."] = "%s se to nelíbí.";
+$a->strings["%s likes this."] = "Uživateli %s se tohle líbí.";
+$a->strings["%s doesn't like this."] = "Uživateli %s se tohle nelíbí.";
 $a->strings["%s attends."] = "%s se účastní.";
 $a->strings["%s doesn't attend."] = "%s se neúčastní.";
 $a->strings["%s attends maybe."] = "%s se možná účastní.";
 $a->strings["and"] = "a";
 $a->strings["and %d other people"] = "a dalších %d lidí";
-$a->strings["<span  %1\$s>%2\$d people</span> like this"] = "<span  %1\$s>%2\$d lidem</span> se to líbí";
-$a->strings["%s like this."] = "%s se tohle líbí.";
-$a->strings["<span  %1\$s>%2\$d people</span> don't like this"] = "<span  %1\$s>%2\$d lidem</span> se to nelíbí";
-$a->strings["%s don't like this."] = "%s se tohle nelíbí.";
+$a->strings["<span  %1\$s>%2\$d people</span> like this"] = "<span  %1\$s>%2\$d lidem</span> se tohle líbí";
+$a->strings["%s like this."] = "Uživatelům %s se tohle líbí.";
+$a->strings["<span  %1\$s>%2\$d people</span> don't like this"] = "<span  %1\$s>%2\$d lidem</span> se tohle nelíbí";
+$a->strings["%s don't like this."] = "Uživatelům %s se tohle nelíbí.";
 $a->strings["<span  %1\$s>%2\$d people</span> attend"] = "<span  %1\$s>%2\$d lidí</span> se účastní";
 $a->strings["%s attend."] = "%s se účastní.";
 $a->strings["<span  %1\$s>%2\$d people</span> don't attend"] = "<span  %1\$s>%2\$d lidí</span> se neúčastní";
@@ -152,8 +152,8 @@ $a->strings["Undecided"] = [
 ];
 $a->strings["Friendica Notification"] = "Oznámení Friendica";
 $a->strings["Thank You,"] = "Děkujeme, ";
-$a->strings["%s Administrator"] = "%s administrátor";
-$a->strings["%1\$s, %2\$s Administrator"] = "%1\$s, %2\$s administrátor";
+$a->strings["%s Administrator"] = "Administrátor %s";
+$a->strings["%1\$s, %2\$s Administrator"] = "%1\$s, administrátor %2\$s";
 $a->strings["[Friendica:Notify] New mail received at %s"] = "[Friendica:Oznámení] Obdržena nová zpráva na %s";
 $a->strings["%1\$s sent you a new private message at %2\$s."] = "%1\$s Vám poslal/a novou soukromou zprávu na %2\$s.";
 $a->strings["a private message"] = "soukromou zprávu";
@@ -181,8 +181,8 @@ $a->strings["[Friendica:Notify] %s tagged your post"] = "[Friendica:Oznámení]
 $a->strings["%1\$s tagged your post at %2\$s"] = "%1\$s označil/a Váš příspěvek na%2\$s";
 $a->strings["%1\$s tagged [url=%2\$s]your post[/url]"] = "%1\$s označil/a [url=%2\$s]Váš příspěvek[/url]";
 $a->strings["[Friendica:Notify] Introduction received"] = "[Friendica:Oznámení] Obdrženo představení";
-$a->strings["You've received an introduction from '%1\$s' at %2\$s"] = "Obdržel/a jste představení od \"%1\$s\" na %2\$s";
-$a->strings["You've received [url=%1\$s]an introduction[/url] from %2\$s."] = "Obdržel/a jste [url=%1\$s]představení[/url] od %2\$s.";
+$a->strings["You've received an introduction from '%1\$s' at %2\$s"] = "Obdržel/a jste představení od uživatele \"%1\$s\" na %2\$s";
+$a->strings["You've received [url=%1\$s]an introduction[/url] from %2\$s."] = "Obdržel/a jste [url=%1\$s]představení[/url] od uživatele %2\$s.";
 $a->strings["You may visit their profile at %s"] = "Můžete navštívit jejich profil na %s";
 $a->strings["Please visit %s to approve or reject the introduction."] = "Prosím navštivte %s pro schválení či zamítnutí představení.";
 $a->strings["[Friendica:Notify] A new person is sharing with you"] = "[Friendica:Oznámení] Nový člověk s vámi sdílí";
@@ -190,14 +190,14 @@ $a->strings["%1\$s is sharing with you at %2\$s"] = "Uživatel %1\$s s vámi sd
 $a->strings["[Friendica:Notify] You have a new follower"] = "[Friendica:Oznámení] Máte nového sledovatele";
 $a->strings["You have a new follower at %2\$s : %1\$s"] = "Máte nového sledovatele na %2\$s : %1\$s";
 $a->strings["[Friendica:Notify] Friend suggestion received"] = "[Friendica:Oznámení] Obdržen návrh pro přátelství";
-$a->strings["You've received a friend suggestion from '%1\$s' at %2\$s"] = "Obdržel jste návrh pro přátelství od '%1\$s' na %2\$s";
-$a->strings["You've received [url=%1\$s]a friend suggestion[/url] for %2\$s from %3\$s."] = "Obdržel jste [url=%1\$s]návrh pro přátelství[/url] s %2\$s from %3\$s.";
+$a->strings["You've received a friend suggestion from '%1\$s' at %2\$s"] = "Obdržel/a jste návrh pro přátelství od uživatele \"%1\$s\" na %2\$s";
+$a->strings["You've received [url=%1\$s]a friend suggestion[/url] for %2\$s from %3\$s."] = "Obdržel/a jste [url=%1\$s]návrh pro přátelství[/url] s uživatelem %2\$s od uživatele %3\$s.";
 $a->strings["Name:"] = "Jméno:";
 $a->strings["Photo:"] = "Foto:";
 $a->strings["Please visit %s to approve or reject the suggestion."] = "Prosím navštivte %s pro schválení či zamítnutí doporučení.";
 $a->strings["[Friendica:Notify] Connection accepted"] = "[Friendica:Oznámení] Spojení akceptováno";
-$a->strings["'%1\$s' has accepted your connection request at %2\$s"] = "\"%1\$s\" akceptoval váš požadavek na spojení na %2\$s";
-$a->strings["%2\$s has accepted your [url=%1\$s]connection request[/url]."] = "%2\$s akceptoval váš [url=%1\$s]požadavek na spojení[/url].";
+$a->strings["'%1\$s' has accepted your connection request at %2\$s"] = "\"%1\$s\" akceptoval/a Váš požadavek na spojení na %2\$s";
+$a->strings["%2\$s has accepted your [url=%1\$s]connection request[/url]."] = "%2\$s akceptoval/a Váš [url=%1\$s]požadavek na spojení[/url].";
 $a->strings["You are now mutual friends and may exchange status updates, photos, and email without restriction."] = "Jste nyní vzájemní přátelé a můžete si vyměňovat aktualizace stavu, fotky a e-maily bez omezení.";
 $a->strings["Please visit %s if you wish to make any changes to this relationship."] = "Pokud chcete provést změny s tímto vztahem, prosím navštivte %s.";
 $a->strings["'%1\$s' has chosen to accept you a fan, which restricts some forms of communication - such as private messaging and some profile interactions. If this is a celebrity or community page, these settings were applied automatically."] = "\"%1\$s\" se rozhodl/a Vás přijmout jako fanouška, což omezuje některé formy komunikace - například soukoromé zprávy a některé interakce s profily. Pokud je toto stránka celebrity či komunity, byla tato nastavení aplikována automaticky.";
@@ -205,8 +205,8 @@ $a->strings["'%1\$s' may choose to extend this into a two-way or more permissive
 $a->strings["Please visit %s  if you wish to make any changes to this relationship."] = "Prosím navštivte %s  pokud chcete změnit tento vztah.";
 $a->strings["[Friendica System Notify]"] = "[Oznámení systému Friendica]";
 $a->strings["registration request"] = "žádost o registraci";
-$a->strings["You've received a registration request from '%1\$s' at %2\$s"] = "Obdržel jste žádost o registraci od '%1\$s' na %2\$s";
-$a->strings["You've received a [url=%1\$s]registration request[/url] from %2\$s."] = "Obdržel jste [url=%1\$s]žádost o registraci[/url] od '%2\$s'.";
+$a->strings["You've received a registration request from '%1\$s' at %2\$s"] = "Obdržel/a jste žádost o registraci od uživatele \"%1\$s\" na %2\$s";
+$a->strings["You've received a [url=%1\$s]registration request[/url] from %2\$s."] = "Obdržel/a jste [url=%1\$s]žádost o registraci[/url] od uživatele \"%2\$s\".";
 $a->strings["Full Name:\t%s\nSite Location:\t%s\nLogin Name:\t%s (%s)"] = "Celé jméno:\t\t%s\nAdresa stránky:\t\t%s\nPřihlašovací jméno:\t%s (%s)";
 $a->strings["Please visit %s to approve or reject the request."] = "Prosím navštivte %s k odsouhlasení nebo k zamítnutí požadavku.";
 $a->strings["newer"] = "novější";
@@ -234,17 +234,17 @@ $a->strings["Tags"] = "Štítky:";
 $a->strings["Contacts"] = "Kontakty";
 $a->strings["Forums"] = "Fóra";
 $a->strings["poke"] = "šťouchnout";
-$a->strings["poked"] = "šťouchnul";
+$a->strings["poked"] = "šťouchnul/a";
 $a->strings["ping"] = "cinknout";
-$a->strings["pinged"] = "cinknul";
+$a->strings["pinged"] = "cinknul/a";
 $a->strings["prod"] = "dloubnout";
-$a->strings["prodded"] = "dloubnul";
+$a->strings["prodded"] = "dloubnul/a";
 $a->strings["slap"] = "uhodit";
-$a->strings["slapped"] = "uhodil";
-$a->strings["finger"] = "osahávat";
-$a->strings["fingered"] = "osahal";
+$a->strings["slapped"] = "uhodil/a";
+$a->strings["finger"] = "osahat";
+$a->strings["fingered"] = "osahal/a";
 $a->strings["rebuff"] = "odmítnout";
-$a->strings["rebuffed"] = "odmítnul";
+$a->strings["rebuffed"] = "odmítnul/a";
 $a->strings["Monday"] = "Pondělí";
 $a->strings["Tuesday"] = "Úterý";
 $a->strings["Wednesday"] = "Středa";
@@ -328,7 +328,7 @@ $a->strings["Friendica Walk-Through"] = "Prohlídka Friendica ";
 $a->strings["On your <em>Quick Start</em> page - find a brief introduction to your profile and network tabs, make some new connections, and find some groups to join."] = "Na Vaší stránce <em>Rychlý Start</em> najděte stručné představení k Vašemu profilu a síťovým záložkám, spojte ses novými kontakty a jděte skupiny, ke kterým se můžete připojit.";
 $a->strings["Settings"] = "Nastavení";
 $a->strings["Go to Your Settings"] = "Navštivte své nastavení";
-$a->strings["On your <em>Settings</em> page -  change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web."] = "Na Vaší stránce <em>Nastavení</em> si změňte Vaše první heslo.\nVěnujte také svou pozornost k adrese Identity. Vypadá jako emailová adresa a bude Vám užitečná pro navazování přátelství na svobodném sociálním webu.";
+$a->strings["On your <em>Settings</em> page -  change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web."] = "Na Vaší stránce <em>Nastavení</em> si změňte Vaše první heslo. Věnujte také svou pozornost k adrese Identity. Vypadá jako emailová adresa a bude Vám užitečná pro navazování přátelství na svobodném sociálním webu.";
 $a->strings["Review the other settings, particularly the privacy settings. An unpublished directory listing is like having an unlisted phone number. In general, you should probably publish your listing - unless all of your friends and potential friends know exactly how to find you."] = "Prohlédněte si další nastavení, a to zejména nastavení soukromí. Nezveřejnění svého účtu v adresáři je jako mít nezveřejněné telefonní číslo. Obecně platí, že je lepší mít svůj účet zveřejněný, leda by všichni vaši přátelé a potenciální přátelé věděli, jak vás přesně najít.";
 $a->strings["Profile"] = "Profil";
 $a->strings["Upload Profile Photo"] = "Nahrát profilovou fotografii";
@@ -484,7 +484,7 @@ $a->strings["Diaspora support isn't enabled. Contact can't be added."] = "Podpor
 $a->strings["OStatus support is disabled. Contact can't be added."] = "Podpora pro OStatus je vypnnuta. Kontakt nemůže být přidán.";
 $a->strings["The network type couldn't be detected. Contact can't be added."] = "Typ sítě nemohl být detekován. Kontakt nemůže být přidán.";
 $a->strings["Please answer the following:"] = "Odpovězte, prosím, následující:";
-$a->strings["Does %s know you?"] = "Zná Vás uživatel %s ?";
+$a->strings["Does %s know you?"] = "Zná Vás %s ?";
 $a->strings["Add a personal note:"] = "Přidat osobní poznámku:";
 $a->strings["Your Identity Address:"] = "Verze PHP pro příkazový řádek na Vašem systému nemá povolen \"register_argc_argv\".";
 $a->strings["Profile URL"] = "URL profilu";
@@ -594,14 +594,14 @@ $a->strings["Friendica Communications Server - Setup"] = "Friendica Komunikačn
 $a->strings["Could not connect to database."] = "Nelze se připojit k databázi.";
 $a->strings["Could not create table."] = "Nelze vytvořit tabulku.";
 $a->strings["Your Friendica site database has been installed."] = "Vaše databáze Friendica  byla nainstalována.";
-$a->strings["You may need to import the file \"database.sql\" manually using phpmyadmin or mysql."] = "Pravděpodobně budete muset manuálně importovat soubor \"database.sql\" pomocí phpMyAdmin či MySQL.";
+$a->strings["You may need to import the file \"database.sql\" manually using phpmyadmin or mysql."] = "Nejspíše budete muset manuálně importovat soubor \"database.sql\" pomocí phpMyAdmin či MySQL.";
 $a->strings["Please see the file \"INSTALL.txt\"."] = "Přečtěte si prosím informace v souboru \"INSTALL.txt\".";
 $a->strings["Database already in use."] = "Databáze se již používá.";
 $a->strings["System check"] = "Testování systému";
 $a->strings["Check again"] = "Otestovat znovu";
 $a->strings["Database connection"] = "Databázové spojení";
 $a->strings["In order to install Friendica we need to know how to connect to your database."] = "Pro instalaci Friendica potřeujeme znát připojení k Vaší databázi.";
-$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Pokud máte otázky k následujícím nastavením, obraťte se na svého poskytovatele hostingu nebo administrátora serveru";
+$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Pokud máte otázky k následujícím nastavením, obraťte se na svého poskytovatele hostingu nebo administrátora serveru.";
 $a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "Databáze, kterou uvedete níže, by již měla existovat. Pokud to tak není, prosíme, vytvořte ji před pokračováním.";
 $a->strings["Database Server Name"] = "Jméno databázového serveru";
 $a->strings["Database Login Name"] = "Přihlašovací jméno k databázi";
@@ -954,7 +954,7 @@ $a->strings["Someone writes a followup comment"] = "někdo Vám napíše násled
 $a->strings["You receive a private message"] = "obdržíte soukromou zprávu";
 $a->strings["You receive a friend suggestion"] = "Obdržel jste návrh přátelství";
 $a->strings["You are tagged in a post"] = "Jste označen v příspěvku";
-$a->strings["You are poked/prodded/etc. in a post"] = "Byl jste šťouchnut(a)/dloubnut(a)/apod. v příspěvku";
+$a->strings["You are poked/prodded/etc. in a post"] = "Byl/a jste šťouchnut(a)/dloubnut(a)/apod. v příspěvku";
 $a->strings["Activate desktop notifications"] = "Aktivovat upozornění na desktopu";
 $a->strings["Show desktop popup on new notifications"] = "Zobrazit dektopové zprávy nových upozornění.";
 $a->strings["Text-only notification emails"] = "Pouze textové notifikační e-maily";
@@ -995,7 +995,7 @@ $a->strings["Diagnostics"] = "Diagnostica";
 $a->strings["PHP Info"] = "Info o PHP";
 $a->strings["probe address"] = "vyzkoušet adresu";
 $a->strings["check webfinger"] = "vyzkoušet webfinger";
-$a->strings["Admin"] = "Administrace";
+$a->strings["Admin"] = "Administrátor";
 $a->strings["Addon Features"] = "Vlastnosti doplňků";
 $a->strings["User registrations waiting for confirmation"] = "Registrace uživatele čeká na potvrzení";
 $a->strings["Administration"] = "Administrace";
@@ -1290,7 +1290,7 @@ $a->strings["Failed Updates"] = "Neúspěšné aktualizace";
 $a->strings["This does not include updates prior to 1139, which did not return a status."] = "To nezahrnuje aktualizace do verze 1139, které nevracejí žádný status.";
 $a->strings["Mark success (if update was manually applied)"] = "Označit za úspěšné (pokud byla aktualizace aplikována manuálně)";
 $a->strings["Attempt to execute this update step automatically"] = "Pokusit se provést tuto aktualizaci automaticky.";
-$a->strings["\n\t\t\tDear %1\$s,\n\t\t\t\tthe administrator of %2\$s has set up an account for you."] = "\n\t\t\tVážený/á%1\$s,\n\t\t\t\tadministrátor %2\$s pro Vás vytvořil/a uživatelský účet.";
+$a->strings["\n\t\t\tDear %1\$s,\n\t\t\t\tthe administrator of %2\$s has set up an account for you."] = "\n\t\t\tVážený/á%1\$s,\n\t\t\t\tadministrátor %2\$s pro Vás vytvořil uživatelský účet.";
 $a->strings["\n\t\t\tThe login details are as follows:\n\n\t\t\tSite Location:\t%1\$s\n\t\t\tLogin Name:\t\t%2\$s\n\t\t\tPassword:\t\t%3\$s\n\n\t\t\tYou may change your password from your account \"Settings\" page after logging\n\t\t\tin.\n\n\t\t\tPlease take a few moments to review the other account settings on that page.\n\n\t\t\tYou may also wish to add some basic information to your default profile\n\t\t\t(on the \"Profiles\" page) so that other people can easily find you.\n\n\t\t\tWe recommend setting your full name, adding a profile photo,\n\t\t\tadding some profile \"keywords\" (very useful in making new friends) - and\n\t\t\tperhaps what country you live in; if you do not wish to be more specific\n\t\t\tthan that.\n\n\t\t\tWe fully respect your right to privacy, and none of these items are necessary.\n\t\t\tIf you are new and do not know anybody here, they may help\n\t\t\tyou to make some new and interesting friends.\n\n\t\t\tIf you ever want to delete your account, you can do so at %1\$s/removeme\n\n\t\t\tThank you and welcome to %4\$s."] = "\n\t\t\tZde jsou vaše přihlašovací detaily:\n\n\t\t\tAdresa stránky:\t\t%1\$s\n\t\t\tPřihlašovací jméno:\t%2\$s\n\t\t\tHeslo:\t\t\t%3\$s\n\n\t\t\tSvé heslo si po přihlášení můžete změnit na stránce \"Nastavení\" vašeho\n\t\t\túčtu.\n\n\t\t\tProsím, prohlédněte si na chvilku ostatní nastavení účtu na té stránce.\n\n\t\t\tMožná byste si také přáli přidat pár základních informací na svůj výchozí\n\t\t\tprofil (na stránce \"Profily\") aby vás další lidé mohli snadno najít.\n\t\t\tDoporučujeme nastavit si vaše celé jméno, přidat profilovou fotku,\n\t\t\tpřidat pár \"klíčových slov\" k profilu (velmi užitečné při získávání nových\n\t\t\tpřátel) - a možná v jaké zemi žijete; pokud nechcete být konkrétnější.\n\n\t\t\tZcela respektujeme vaše právo na soukromí a žádnou z těchto položek\n\t\t\tnení potřeba vyplňovat. Pokud jste zde nový/á a nikoho zde neznáte, mohou vám\n\t\t\tpomoci si získat nové a zajímavé přátele.\n\t\t\tPokud byste si někdy přál/a smazat účet, může tak učinit na stránce\n\t\t\t%1\$s/removeme.\n\n\t\t\tDěkujeme vám a vítáme vás na %4\$s.";
 $a->strings["Registration details for %s"] = "Registrační údaje pro %s";
 $a->strings["%s user blocked/unblocked"] = [
@@ -1322,7 +1322,7 @@ $a->strings["No registrations."] = "Žádné registrace.";
 $a->strings["Note from the user"] = "Poznámka od uživatele";
 $a->strings["Approve"] = "Schválit";
 $a->strings["Deny"] = "Odmítnout";
-$a->strings["Site admin"] = "Site administrátor";
+$a->strings["Site admin"] = "Administrátor webu";
 $a->strings["Account expired"] = "Účtu vypršela platnost";
 $a->strings["New User"] = "Nový uživatel";
 $a->strings["Deleted since"] = "Smazán od";
index 0b46aa9919d83839be4471f7e2643370ec75df7d..31b3b68ca294ec7862bc7c34018681768ee180de 100644 (file)
@@ -78,6 +78,7 @@
        <h3>{{$corporate}}</h3>
        {{include file="field_input.tpl" field=$allowed_sites}}
        {{include file="field_input.tpl" field=$allowed_email}}
+       {{include file="field_input.tpl" field=$forbidden_nicknames}}
        {{include file="field_checkbox.tpl" field=$no_oembed_rich_content}}
        {{include file="field_input.tpl" field=$allowed_oembed}}
        {{include file="field_checkbox.tpl" field=$block_public}}