Merge remote-tracking branch 'upstream/develop' into inverted
This commit is contained in:
commit
6ccf038053
55 changed files with 1834 additions and 709 deletions
|
@ -1,6 +1,6 @@
|
||||||
-- ------------------------------------------
|
-- ------------------------------------------
|
||||||
-- Friendica 2020.03-dev (Dalmatian Bellflower)
|
-- Friendica 2020.03-dev (Dalmatian Bellflower)
|
||||||
-- DB_UPDATE_VERSION 1329
|
-- DB_UPDATE_VERSION 1330
|
||||||
-- ------------------------------------------
|
-- ------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,22 +17,24 @@ namespace Friendica\Model\Storage;
|
||||||
```php
|
```php
|
||||||
interface IStorage
|
interface IStorage
|
||||||
{
|
{
|
||||||
public static function get($ref);
|
public function get(string $reference);
|
||||||
public static function put($data, $ref = "");
|
public function put(string $data, string $reference = '');
|
||||||
public static function delete($ref);
|
public function delete(string $reference);
|
||||||
public static function getOptions();
|
public function getOptions();
|
||||||
public static function saveOptions($data);
|
public function saveOptions(array $data);
|
||||||
|
public function __toString();
|
||||||
|
public static function getName();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- `get($ref)` returns data pointed by `$ref`
|
- `get(string $reference)` returns data pointed by `$reference`
|
||||||
- `put($data, $ref)` saves data in `$data` to position `$ref`, or a new position if `$ref` is empty.
|
- `put(string $data, string $reference)` saves data in `$data` to position `$reference`, or a new position if `$reference` is empty.
|
||||||
- `delete($ref)` delete data pointed by `$ref`
|
- `delete(string $reference)` delete data pointed by `$reference`
|
||||||
|
|
||||||
Each storage backend can have options the admin can set in admin page.
|
Each storage backend can have options the admin can set in admin page.
|
||||||
|
|
||||||
- `getOptions()` returns an array with details about each option to build the interface.
|
- `getOptions()` returns an array with details about each option to build the interface.
|
||||||
- `saveOptions($data)` get `$data` from admin page, validate it and save it.
|
- `saveOptions(array $data)` get `$data` from admin page, validate it and save it.
|
||||||
|
|
||||||
The array returned by `getOptions()` is defined as:
|
The array returned by `getOptions()` is defined as:
|
||||||
|
|
||||||
|
@ -84,11 +86,38 @@ See doxygen documentation of `IStorage` interface for details about each method.
|
||||||
|
|
||||||
Each backend must be registered in the system when the plugin is installed, to be aviable.
|
Each backend must be registered in the system when the plugin is installed, to be aviable.
|
||||||
|
|
||||||
`Friendica\Core\StorageManager::register($name, $class)` is used to register the backend class.
|
`DI::facStorage()->register(string $class)` is used to register the backend class.
|
||||||
The `$name` must be univocal and will be shown to admin.
|
|
||||||
|
|
||||||
When the plugin is uninstalled, registered backends must be unregistered using
|
When the plugin is uninstalled, registered backends must be unregistered using
|
||||||
`Friendica\Core\StorageManager::unregister($class)`.
|
`DI::facStorage()->unregister(string $class)`.
|
||||||
|
|
||||||
|
You have to register a new hook in your addon, listening on `storage_instance(App $a, array $data)`.
|
||||||
|
In case `$data['name']` is your storage class name, you have to instance a new instance of your `Friendica\Model\Storage\IStorage` class.
|
||||||
|
Set the instance of your class as `$data['storage']` to pass it back to the backend.
|
||||||
|
|
||||||
|
This is necessary because it isn't always clear, if you need further construction arguments.
|
||||||
|
|
||||||
|
## Adding tests
|
||||||
|
|
||||||
|
**Currently testing is limited to core Friendica only, this shows theoretically how tests should work in the future**
|
||||||
|
|
||||||
|
Each new Storage class should be added to the test-environment at [Storage Tests](https://github.com/friendica/friendica/tree/develop/tests/src/Model/Storage/).
|
||||||
|
|
||||||
|
Add a new test class which's naming convention is `StorageClassTest`, which extend the `StorageTest` in the same directory.
|
||||||
|
|
||||||
|
Override the two necessary instances:
|
||||||
|
```php
|
||||||
|
use Friendica\Model\Storage\IStorage;
|
||||||
|
|
||||||
|
abstract class StorageTest
|
||||||
|
{
|
||||||
|
// returns an instance of your newly created storage class
|
||||||
|
abstract protected function getInstance();
|
||||||
|
|
||||||
|
// Assertion for the option array you return for your new StorageClass
|
||||||
|
abstract protected function assertOption(IStorage $storage);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
|
@ -112,60 +141,91 @@ use Friendica\Core\L10n;
|
||||||
|
|
||||||
class SampleStorageBackend implements IStorage
|
class SampleStorageBackend implements IStorage
|
||||||
{
|
{
|
||||||
public static function get($ref)
|
const NAME = 'Sample Storage';
|
||||||
|
|
||||||
|
/** @var Config\IConfiguration */
|
||||||
|
private $config;
|
||||||
|
/** @var L10n\L10n */
|
||||||
|
private $l10n;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SampleStorageBackend constructor.
|
||||||
|
* @param Config\IConfiguration $config The configuration of Friendica
|
||||||
|
*
|
||||||
|
* You can add here every dynamic class as dependency you like and add them to a private field
|
||||||
|
* Friendica automatically creates these classes and passes them as argument to the constructor
|
||||||
|
*/
|
||||||
|
public function __construct(Config\IConfiguration $config, L10n\L10n $l10n)
|
||||||
{
|
{
|
||||||
// we return alwais the same image data. Which file we load is defined by
|
$this->config = $config;
|
||||||
|
$this->l10n = $l10n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $reference)
|
||||||
|
{
|
||||||
|
// we return always the same image data. Which file we load is defined by
|
||||||
// a config key
|
// a config key
|
||||||
$filename = Config::get("storage", "samplestorage", "sample.jpg");
|
$filename = $this->config->get('storage', 'samplestorage', 'sample.jpg');
|
||||||
return file_get_contents($filename);
|
return file_get_contents($filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function put($data, $ref = "")
|
public function put(string $data, string $reference = '')
|
||||||
{
|
{
|
||||||
if ($ref === "") {
|
if ($reference === '') {
|
||||||
$ref = "sample";
|
$reference = 'sample';
|
||||||
}
|
}
|
||||||
// we don't save $data !
|
// we don't save $data !
|
||||||
return $ref;
|
return $reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function delete($ref)
|
public function delete(string $reference)
|
||||||
{
|
{
|
||||||
// we pretend to delete the data
|
// we pretend to delete the data
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getOptions()
|
public function getOptions()
|
||||||
{
|
{
|
||||||
$filename = Config::get("storage", "samplestorage", "sample.jpg");
|
$filename = $this->config->get('storage', 'samplestorage', 'sample.jpg');
|
||||||
return [
|
return [
|
||||||
"filename" => [
|
'filename' => [
|
||||||
"input", // will use a simple text input
|
'input', // will use a simple text input
|
||||||
L10n::t("The file to return"), // the label
|
$this->l10n->t('The file to return'), // the label
|
||||||
$filename, // the current value
|
$filename, // the current value
|
||||||
L10n::t("Enter the path to a file"), // the help text
|
$this->l10n->t('Enter the path to a file'), // the help text
|
||||||
// no extra data for "input" type..
|
// no extra data for 'input' type..
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function saveOptions($data)
|
public function saveOptions(array $data)
|
||||||
{
|
{
|
||||||
// the keys in $data are the same keys we defined in getOptions()
|
// the keys in $data are the same keys we defined in getOptions()
|
||||||
$newfilename = trim($data["filename"]);
|
$newfilename = trim($data['filename']);
|
||||||
|
|
||||||
// this function should always validate the data.
|
// this function should always validate the data.
|
||||||
// in this example we check if file exists
|
// in this example we check if file exists
|
||||||
if (!file_exists($newfilename)) {
|
if (!file_exists($newfilename)) {
|
||||||
// in case of error we return an array with
|
// in case of error we return an array with
|
||||||
// ["optionname" => "error message"]
|
// ['optionname' => 'error message']
|
||||||
return ["filename" => "The file doesn't exists"];
|
return ['filename' => 'The file doesn\'t exists'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::set("storage", "samplestorage", $newfilename);
|
$this->config->set('storage', 'samplestorage', $newfilename);
|
||||||
|
|
||||||
// no errors, return empty array
|
// no errors, return empty array
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getName()
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -182,23 +242,59 @@ The file is `addon/samplestorage/samplestorage.php`
|
||||||
* Author: Alice <https://alice.social/~alice>
|
* Author: Alice <https://alice.social/~alice>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Friendica\Core\StorageManager;
|
|
||||||
use Friendica\Addon\samplestorage\SampleStorageBackend;
|
use Friendica\Addon\samplestorage\SampleStorageBackend;
|
||||||
|
use Friendica\DI;
|
||||||
|
|
||||||
function samplestorage_install()
|
function samplestorage_install()
|
||||||
{
|
{
|
||||||
// on addon install, we register our class with name "Sample Storage".
|
// on addon install, we register our class with name "Sample Storage".
|
||||||
// note: we use `::class` property, which returns full class name as string
|
// note: we use `::class` property, which returns full class name as string
|
||||||
// this save us the problem of correctly escape backslashes in class name
|
// this save us the problem of correctly escape backslashes in class name
|
||||||
StorageManager::register("Sample Storage", SampleStorageBackend::class);
|
DI::storageManager()->register(SampleStorageBackend::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
function samplestorage_unistall()
|
function samplestorage_unistall()
|
||||||
{
|
{
|
||||||
// when the plugin is uninstalled, we unregister the backend.
|
// when the plugin is uninstalled, we unregister the backend.
|
||||||
StorageManager::unregister("Sample Storage");
|
DI::storageManager()->unregister(SampleStorageBackend::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
function samplestorage_storage_instance(\Friendica\App $a, array $data)
|
||||||
|
{
|
||||||
|
if ($data['name'] === SampleStorageBackend::getName()) {
|
||||||
|
// instance a new sample storage instance and pass it back to the core for usage
|
||||||
|
$data['storage'] = new SampleStorageBackend(DI::config(), DI::l10n(), DI::cache());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Theoretically - until tests for Addons are enabled too - create a test class with the name `addon/tests/SampleStorageTest.php`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Friendica\Model\Storage\IStorage;
|
||||||
|
use Friendica\Test\src\Model\Storage\StorageTest;
|
||||||
|
|
||||||
|
class SampleStorageTest extends StorageTest
|
||||||
|
{
|
||||||
|
// returns an instance of your newly created storage class
|
||||||
|
protected function getInstance()
|
||||||
|
{
|
||||||
|
// create a new SampleStorageBackend instance with all it's dependencies
|
||||||
|
// Have a look at DatabaseStorageTest or FilesystemStorageTest for further insights
|
||||||
|
return new SampleStorageBackend();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assertion for the option array you return for your new StorageClass
|
||||||
|
protected function assertOption(IStorage $storage)
|
||||||
|
{
|
||||||
|
$this->assertEquals([
|
||||||
|
'filename' => [
|
||||||
|
'input',
|
||||||
|
'The file to return',
|
||||||
|
'sample.jpg',
|
||||||
|
'Enter the path to a file'
|
||||||
|
],
|
||||||
|
], $storage->getOptions());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -706,6 +706,14 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
|
||||||
Hook::callAll('page_header', DI::page()['nav']);
|
Hook::callAll('page_header', DI::page()['nav']);
|
||||||
Hook::callAll('nav_info', $nav);
|
Hook::callAll('nav_info', $nav);
|
||||||
|
|
||||||
|
### src/Core/Authentication.php
|
||||||
|
|
||||||
|
Hook::callAll('logged_in', $a->user);
|
||||||
|
|
||||||
|
### src/Core/StorageManager
|
||||||
|
|
||||||
|
Hook::callAll('storage_instance', $data);
|
||||||
|
|
||||||
### src/Worker/Directory.php
|
### src/Worker/Directory.php
|
||||||
|
|
||||||
Hook::callAll('globaldir_update', $arr);
|
Hook::callAll('globaldir_update', $arr);
|
||||||
|
|
|
@ -425,6 +425,10 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap
|
||||||
|
|
||||||
Hook::callAll('logged_in', $a->user);
|
Hook::callAll('logged_in', $a->user);
|
||||||
|
|
||||||
|
### src/Core/StorageManager
|
||||||
|
|
||||||
|
Hook::callAll('storage_instance', $data);
|
||||||
|
|
||||||
### src/Worker/Directory.php
|
### src/Worker/Directory.php
|
||||||
|
|
||||||
Hook::callAll('globaldir_update', $arr);
|
Hook::callAll('globaldir_update', $arr);
|
||||||
|
|
|
@ -427,8 +427,16 @@ function events_content(App $a)
|
||||||
|
|
||||||
// Passed parameters overrides anything found in the DB
|
// Passed parameters overrides anything found in the DB
|
||||||
if (in_array($mode, ['edit', 'new', 'copy'])) {
|
if (in_array($mode, ['edit', 'new', 'copy'])) {
|
||||||
|
$share_checked = '';
|
||||||
|
$share_disabled = '';
|
||||||
|
|
||||||
if (empty($orig_event)) {
|
if (empty($orig_event)) {
|
||||||
$orig_event = User::getById(local_user(), ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']);;
|
$orig_event = User::getById(local_user(), ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']);;
|
||||||
|
} elseif ($orig_event['allow_cid'] !== '<' . local_user() . '>'
|
||||||
|
|| $orig_event['allow_gid']
|
||||||
|
|| $orig_event['deny_cid']
|
||||||
|
|| $orig_event['deny_gid']) {
|
||||||
|
$share_checked = ' checked="checked" ';
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case of an error the browser is redirected back here, with these parameters filled in with the previous values
|
// In case of an error the browser is redirected back here, with these parameters filled in with the previous values
|
||||||
|
@ -450,20 +458,8 @@ function events_content(App $a)
|
||||||
$cid = !empty($orig_event) ? $orig_event['cid'] : 0;
|
$cid = !empty($orig_event) ? $orig_event['cid'] : 0;
|
||||||
$uri = !empty($orig_event) ? $orig_event['uri'] : '';
|
$uri = !empty($orig_event) ? $orig_event['uri'] : '';
|
||||||
|
|
||||||
$sh_disabled = '';
|
|
||||||
$sh_checked = '';
|
|
||||||
|
|
||||||
if (!empty($orig_event)
|
|
||||||
&& ($orig_event['allow_cid'] !== '<' . local_user() . '>'
|
|
||||||
|| $orig_event['allow_gid']
|
|
||||||
|| $orig_event['deny_cid']
|
|
||||||
|| $orig_event['deny_gid']))
|
|
||||||
{
|
|
||||||
$sh_checked = ' checked="checked" ';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cid || $mode === 'edit') {
|
if ($cid || $mode === 'edit') {
|
||||||
$sh_disabled = 'disabled="disabled"';
|
$share_disabled = 'disabled="disabled"';
|
||||||
}
|
}
|
||||||
|
|
||||||
$sdt = !empty($orig_event) ? $orig_event['start'] : 'now';
|
$sdt = !empty($orig_event) ? $orig_event['start'] : 'now';
|
||||||
|
@ -547,8 +543,8 @@ function events_content(App $a)
|
||||||
'$t_orig' => $t_orig,
|
'$t_orig' => $t_orig,
|
||||||
'$summary' => ['summary', L10n::t('Title:'), $t_orig, '', '*'],
|
'$summary' => ['summary', L10n::t('Title:'), $t_orig, '', '*'],
|
||||||
'$sh_text' => L10n::t('Share this event'),
|
'$sh_text' => L10n::t('Share this event'),
|
||||||
'$share' => ['share', L10n::t('Share this event'), $sh_checked, '', $sh_disabled],
|
'$share' => ['share', L10n::t('Share this event'), $share_checked, '', $share_disabled],
|
||||||
'$sh_checked' => $sh_checked,
|
'$sh_checked' => $share_checked,
|
||||||
'$nofinish' => ['nofinish', L10n::t('Finish date/time is not known or not relevant'), $n_checked],
|
'$nofinish' => ['nofinish', L10n::t('Finish date/time is not known or not relevant'), $n_checked],
|
||||||
'$adjust' => ['adjust', L10n::t('Adjust for viewer timezone'), $a_checked],
|
'$adjust' => ['adjust', L10n::t('Adjust for viewer timezone'), $a_checked],
|
||||||
'$preview' => L10n::t('Preview'),
|
'$preview' => L10n::t('Preview'),
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
use Friendica\App;
|
use Friendica\App;
|
||||||
use Friendica\Content\ForumManager;
|
use Friendica\Content\ForumManager;
|
||||||
use Friendica\Content\Text\BBCode;
|
use Friendica\Content\Text\BBCode;
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\Hook;
|
use Friendica\Core\Hook;
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n;
|
||||||
|
@ -197,7 +197,7 @@ function ping_init(App $a)
|
||||||
}
|
}
|
||||||
|
|
||||||
$cachekey = "ping_init:".local_user();
|
$cachekey = "ping_init:".local_user();
|
||||||
$ev = Cache::get($cachekey);
|
$ev = DI::cache()->get($cachekey);
|
||||||
if (is_null($ev)) {
|
if (is_null($ev)) {
|
||||||
$ev = q(
|
$ev = q(
|
||||||
"SELECT type, start, adjust FROM `event`
|
"SELECT type, start, adjust FROM `event`
|
||||||
|
@ -208,7 +208,7 @@ function ping_init(App $a)
|
||||||
DBA::escape(DateTimeFormat::utcNow())
|
DBA::escape(DateTimeFormat::utcNow())
|
||||||
);
|
);
|
||||||
if (DBA::isResult($ev)) {
|
if (DBA::isResult($ev)) {
|
||||||
Cache::set($cachekey, $ev, Cache::HOUR);
|
DI::cache()->set($cachekey, $ev, Cache::HOUR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,12 @@
|
||||||
|
|
||||||
use Friendica\App;
|
use Friendica\App;
|
||||||
use Friendica\Content\Text\BBCode;
|
use Friendica\Content\Text\BBCode;
|
||||||
use Friendica\Core\Cache;
|
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Core\Protocol;
|
use Friendica\Core\Protocol;
|
||||||
use Friendica\Core\Renderer;
|
use Friendica\Core\Renderer;
|
||||||
use Friendica\Core\System;
|
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
|
use Friendica\DI;
|
||||||
use Friendica\Protocol\PortableContact;
|
use Friendica\Protocol\PortableContact;
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
use Friendica\Util\Strings;
|
use Friendica\Util\Strings;
|
||||||
|
@ -255,10 +254,10 @@ function poco_init(App $a) {
|
||||||
if (isset($contact['account-type'])) {
|
if (isset($contact['account-type'])) {
|
||||||
$contact['contact-type'] = $contact['account-type'];
|
$contact['contact-type'] = $contact['account-type'];
|
||||||
}
|
}
|
||||||
$about = Cache::get("about:" . $contact['updated'] . ":" . $contact['nurl']);
|
$about = DI::cache()->get("about:" . $contact['updated'] . ":" . $contact['nurl']);
|
||||||
if (is_null($about)) {
|
if (is_null($about)) {
|
||||||
$about = BBCode::convert($contact['about'], false);
|
$about = BBCode::convert($contact['about'], false);
|
||||||
Cache::set("about:" . $contact['updated'] . ":" . $contact['nurl'], $about);
|
DI::cache()->set("about:" . $contact['updated'] . ":" . $contact['nurl'], $about);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non connected persons can only see the keywords of a Diaspora account
|
// Non connected persons can only see the keywords of a Diaspora account
|
||||||
|
|
|
@ -13,6 +13,19 @@ class Storage extends \Asika\SimpleConsole\Console
|
||||||
{
|
{
|
||||||
protected $helpOptions = ['h', 'help', '?'];
|
protected $helpOptions = ['h', 'help', '?'];
|
||||||
|
|
||||||
|
/** @var StorageManager */
|
||||||
|
private $storageManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param StorageManager $storageManager
|
||||||
|
*/
|
||||||
|
public function __construct(StorageManager $storageManager, array $argv = [])
|
||||||
|
{
|
||||||
|
parent::__construct($argv);
|
||||||
|
|
||||||
|
$this->storageManager = $storageManager;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getHelp()
|
protected function getHelp()
|
||||||
{
|
{
|
||||||
$help = <<<HELP
|
$help = <<<HELP
|
||||||
|
@ -69,11 +82,11 @@ HELP;
|
||||||
protected function doList()
|
protected function doList()
|
||||||
{
|
{
|
||||||
$rowfmt = ' %-3s | %-20s';
|
$rowfmt = ' %-3s | %-20s';
|
||||||
$current = StorageManager::getBackend();
|
$current = $this->storageManager->getBackend();
|
||||||
$this->out(sprintf($rowfmt, 'Sel', 'Name'));
|
$this->out(sprintf($rowfmt, 'Sel', 'Name'));
|
||||||
$this->out('-----------------------');
|
$this->out('-----------------------');
|
||||||
$isregisterd = false;
|
$isregisterd = false;
|
||||||
foreach (StorageManager::listBackends() as $name => $class) {
|
foreach ($this->storageManager->listBackends() as $name => $class) {
|
||||||
$issel = ' ';
|
$issel = ' ';
|
||||||
if ($current === $class) {
|
if ($current === $class) {
|
||||||
$issel = '*';
|
$issel = '*';
|
||||||
|
@ -100,14 +113,14 @@ HELP;
|
||||||
}
|
}
|
||||||
|
|
||||||
$name = $this->args[1];
|
$name = $this->args[1];
|
||||||
$class = StorageManager::getByName($name);
|
$class = $this->storageManager->getByName($name);
|
||||||
|
|
||||||
if ($class === '') {
|
if ($class === '') {
|
||||||
$this->out($name . ' is not a registered backend.');
|
$this->out($name . ' is not a registered backend.');
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StorageManager::setBackend($class)) {
|
if (!$this->storageManager->setBackend($class)) {
|
||||||
$this->out($class . ' is not a valid backend storage class.');
|
$this->out($class . ' is not a valid backend storage class.');
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -130,11 +143,11 @@ HELP;
|
||||||
$tables = [$table];
|
$tables = [$table];
|
||||||
}
|
}
|
||||||
|
|
||||||
$current = StorageManager::getBackend();
|
$current = $this->storageManager->getBackend();
|
||||||
$total = 0;
|
$total = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
$moved = StorageManager::move($current, $tables, $this->getOption('n', 5000));
|
$moved = $this->storageManager->move($current, $tables, $this->getOption('n', 5000));
|
||||||
if ($moved) {
|
if ($moved) {
|
||||||
$this->out(date('[Y-m-d H:i:s] ') . sprintf('Moved %d files', $moved));
|
$this->out(date('[Y-m-d H:i:s] ') . sprintf('Moved %d files', $moved));
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use DOMNode;
|
||||||
use DOMText;
|
use DOMText;
|
||||||
use DOMXPath;
|
use DOMXPath;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\Hook;
|
use Friendica\Core\Hook;
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n;
|
||||||
|
@ -66,7 +66,7 @@ class OEmbed
|
||||||
if (DBA::isResult($oembed_record)) {
|
if (DBA::isResult($oembed_record)) {
|
||||||
$json_string = $oembed_record['content'];
|
$json_string = $oembed_record['content'];
|
||||||
} else {
|
} else {
|
||||||
$json_string = Cache::get($cache_key);
|
$json_string = DI::cache()->get($cache_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// These media files should now be caught in bbcode.php
|
// These media files should now be caught in bbcode.php
|
||||||
|
@ -125,7 +125,7 @@ class OEmbed
|
||||||
$cache_ttl = Cache::FIVE_MINUTES;
|
$cache_ttl = Cache::FIVE_MINUTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache::set($cache_key, $json_string, $cache_ttl);
|
DI::cache()->set($cache_key, $json_string, $cache_ttl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oembed->type == 'error') {
|
if ($oembed->type == 'error') {
|
||||||
|
|
|
@ -10,7 +10,6 @@ use DOMXPath;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Friendica\Content\OEmbed;
|
use Friendica\Content\OEmbed;
|
||||||
use Friendica\Content\Smilies;
|
use Friendica\Content\Smilies;
|
||||||
use Friendica\Core\Cache;
|
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\Hook;
|
use Friendica\Core\Hook;
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n;
|
||||||
|
@ -1070,7 +1069,7 @@ class BBCode
|
||||||
private static function removePictureLinksCallback($match)
|
private static function removePictureLinksCallback($match)
|
||||||
{
|
{
|
||||||
$cache_key = 'remove:' . $match[1];
|
$cache_key = 'remove:' . $match[1];
|
||||||
$text = Cache::get($cache_key);
|
$text = DI::cache()->get($cache_key);
|
||||||
|
|
||||||
if (is_null($text)) {
|
if (is_null($text)) {
|
||||||
$a = DI::app();
|
$a = DI::app();
|
||||||
|
@ -1112,7 +1111,7 @@ class BBCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cache::set($cache_key, $text);
|
DI::cache()->set($cache_key, $text);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $text;
|
return $text;
|
||||||
|
@ -1143,7 +1142,7 @@ class BBCode
|
||||||
}
|
}
|
||||||
|
|
||||||
$cache_key = 'clean:' . $match[1];
|
$cache_key = 'clean:' . $match[1];
|
||||||
$text = Cache::get($cache_key);
|
$text = DI::cache()->get($cache_key);
|
||||||
if (!is_null($text)) {
|
if (!is_null($text)) {
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
@ -1194,7 +1193,7 @@ class BBCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cache::set($cache_key, $text);
|
DI::cache()->set($cache_key, $text);
|
||||||
|
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
|
|
||||||
namespace Friendica\Content\Widget;
|
namespace Friendica\Content\Widget;
|
||||||
|
|
||||||
use Friendica\Core\Cache;
|
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n;
|
||||||
use Friendica\Core\Renderer;
|
use Friendica\Core\Renderer;
|
||||||
use Friendica\Database\DBA;
|
|
||||||
use Friendica\Model\Term;
|
use Friendica\Model\Term;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @file src/Core/Cache.php
|
|
||||||
*/
|
|
||||||
namespace Friendica\Core;
|
|
||||||
|
|
||||||
use Friendica\Core\Cache\Cache as CacheClass;
|
|
||||||
use Friendica\DI;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Class for storing data for a short time
|
|
||||||
*/
|
|
||||||
class Cache
|
|
||||||
{
|
|
||||||
/** @deprecated Use CacheClass::MONTH */
|
|
||||||
const MONTH = CacheClass::MONTH;
|
|
||||||
/** @deprecated Use CacheClass::WEEK */
|
|
||||||
const WEEK = CacheClass::WEEK;
|
|
||||||
/** @deprecated Use CacheClass::DAY */
|
|
||||||
const DAY = CacheClass::DAY;
|
|
||||||
/** @deprecated Use CacheClass::HOUR */
|
|
||||||
const HOUR = CacheClass::HOUR;
|
|
||||||
/** @deprecated Use CacheClass::HALF_HOUR */
|
|
||||||
const HALF_HOUR = CacheClass::HALF_HOUR;
|
|
||||||
/** @deprecated Use CacheClass::QUARTER_HOUR */
|
|
||||||
const QUARTER_HOUR = CacheClass::QUARTER_HOUR;
|
|
||||||
/** @deprecated Use CacheClass::FIVE_MINUTES */
|
|
||||||
const FIVE_MINUTES = CacheClass::FIVE_MINUTES;
|
|
||||||
/** @deprecated Use CacheClass::MINUTE */
|
|
||||||
const MINUTE = CacheClass::MINUTE;
|
|
||||||
/** @deprecated Use CacheClass::INFINITE */
|
|
||||||
const INFINITE = CacheClass::INFINITE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns all the cache keys sorted alphabetically
|
|
||||||
*
|
|
||||||
* @param string $prefix Prefix of the keys (optional)
|
|
||||||
*
|
|
||||||
* @return array Empty if the driver doesn't support this feature
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public static function getAllKeys($prefix = null)
|
|
||||||
{
|
|
||||||
return DI::cache()->getAllKeys($prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Fetch cached data according to the key
|
|
||||||
*
|
|
||||||
* @param string $key The key to the cached data
|
|
||||||
*
|
|
||||||
* @return mixed Cached $value or "null" if not found
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public static function get($key)
|
|
||||||
{
|
|
||||||
return DI::cache()->get($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Put data in the cache according to the key
|
|
||||||
*
|
|
||||||
* The input $value can have multiple formats.
|
|
||||||
*
|
|
||||||
* @param string $key The key to the cached data
|
|
||||||
* @param mixed $value The value that is about to be stored
|
|
||||||
* @param integer $duration The cache lifespan
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public static function set($key, $value, $duration = CacheClass::MONTH)
|
|
||||||
{
|
|
||||||
return DI::cache()->set($key, $value, $duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Delete a value from the cache
|
|
||||||
*
|
|
||||||
* @param string $key The key to the cached data
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public static function delete($key)
|
|
||||||
{
|
|
||||||
return DI::cache()->delete($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Remove outdated data from the cache
|
|
||||||
*
|
|
||||||
* @param boolean $outdated just remove outdated values
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public static function clear($outdated = true)
|
|
||||||
{
|
|
||||||
return DI::cache()->clear($outdated);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Friendica\Core\Lock;
|
namespace Friendica\Core\Lock;
|
||||||
|
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Database\Database;
|
use Friendica\Database\Database;
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,12 @@
|
||||||
|
|
||||||
namespace Friendica\Core;
|
namespace Friendica\Core;
|
||||||
|
|
||||||
use Friendica\Database\DBA;
|
use Exception;
|
||||||
use Friendica\Model\Storage\IStorage;
|
use Friendica\Core\Config\IConfiguration;
|
||||||
|
use Friendica\Core\L10n\L10n;
|
||||||
|
use Friendica\Database\Database;
|
||||||
|
use Friendica\Model\Storage;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,59 +18,146 @@ use Friendica\Model\Storage\IStorage;
|
||||||
*/
|
*/
|
||||||
class StorageManager
|
class StorageManager
|
||||||
{
|
{
|
||||||
private static $default_backends = [
|
// Default tables to look for data
|
||||||
'Filesystem' => \Friendica\Model\Storage\Filesystem::class,
|
const TABLES = ['photo', 'attach'];
|
||||||
'Database' => \Friendica\Model\Storage\Database::class,
|
|
||||||
|
// Default storage backends
|
||||||
|
const DEFAULT_BACKENDS = [
|
||||||
|
Storage\Filesystem::NAME => Storage\Filesystem::class,
|
||||||
|
Storage\Database::NAME => Storage\Database::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
private static $backends = [];
|
private $backends = [];
|
||||||
|
|
||||||
private static function setup()
|
/**
|
||||||
|
* @var Storage\IStorage[] A local cache for storage instances
|
||||||
|
*/
|
||||||
|
private $backendInstances = [];
|
||||||
|
|
||||||
|
/** @var Database */
|
||||||
|
private $dba;
|
||||||
|
/** @var IConfiguration */
|
||||||
|
private $config;
|
||||||
|
/** @var LoggerInterface */
|
||||||
|
private $logger;
|
||||||
|
/** @var L10n */
|
||||||
|
private $l10n;
|
||||||
|
|
||||||
|
/** @var Storage\IStorage */
|
||||||
|
private $currentBackend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Database $dba
|
||||||
|
* @param IConfiguration $config
|
||||||
|
* @param LoggerInterface $logger
|
||||||
|
* @param L10n $l10n
|
||||||
|
*/
|
||||||
|
public function __construct(Database $dba, IConfiguration $config, LoggerInterface $logger, L10n $l10n)
|
||||||
{
|
{
|
||||||
if (count(self::$backends) == 0) {
|
$this->dba = $dba;
|
||||||
self::$backends = Config::get('storage', 'backends', self::$default_backends);
|
$this->config = $config;
|
||||||
}
|
$this->logger = $logger;
|
||||||
|
$this->l10n = $l10n;
|
||||||
|
$this->backends = $config->get('storage', 'backends', self::DEFAULT_BACKENDS);
|
||||||
|
|
||||||
|
$currentName = $this->config->get('storage', 'name', '');
|
||||||
|
|
||||||
|
$this->currentBackend = $this->getByName($currentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return current storage backend class
|
* @brief Return current storage backend class
|
||||||
*
|
*
|
||||||
* @return string
|
* @return Storage\IStorage|null
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
|
||||||
*/
|
*/
|
||||||
public static function getBackend()
|
public function getBackend()
|
||||||
{
|
{
|
||||||
return Config::get('storage', 'class', '');
|
return $this->currentBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return storage backend class by registered name
|
* @brief Return storage backend class by registered name
|
||||||
*
|
*
|
||||||
* @param string $name Backend name
|
* @param string|null $name Backend name
|
||||||
* @return string Empty if no backend registered at $name exists
|
* @param boolean $userBackend Just return instances in case it's a user backend (e.g. not SystemResource)
|
||||||
|
*
|
||||||
|
* @return Storage\IStorage|null null if no backend registered at $name
|
||||||
|
*
|
||||||
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
*/
|
*/
|
||||||
public static function getByName($name)
|
public function getByName(string $name = null, $userBackend = true)
|
||||||
{
|
{
|
||||||
self::setup();
|
// If there's no cached instance create a new instance
|
||||||
return self::$backends[$name] ?? '';
|
if (!isset($this->backendInstances[$name])) {
|
||||||
|
// If the current name isn't a valid backend (or the SystemResource instance) create it
|
||||||
|
if ($this->isValidBackend($name, $userBackend)) {
|
||||||
|
switch ($name) {
|
||||||
|
// Try the filesystem backend
|
||||||
|
case Storage\Filesystem::getName():
|
||||||
|
$this->backendInstances[$name] = new Storage\Filesystem($this->config, $this->logger, $this->l10n);
|
||||||
|
break;
|
||||||
|
// try the database backend
|
||||||
|
case Storage\Database::getName():
|
||||||
|
$this->backendInstances[$name] = new Storage\Database($this->dba, $this->logger, $this->l10n);
|
||||||
|
break;
|
||||||
|
// at least, try if there's an addon for the backend
|
||||||
|
case Storage\SystemResource::getName():
|
||||||
|
$this->backendInstances[$name] = new Storage\SystemResource();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$data = [
|
||||||
|
'name' => $name,
|
||||||
|
'storage' => null,
|
||||||
|
];
|
||||||
|
Hook::callAll('storage_instance', $data);
|
||||||
|
if (($data['storage'] ?? null) instanceof Storage\IStorage) {
|
||||||
|
$this->backendInstances[$data['name'] ?? $name] = $data['storage'];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->backendInstances[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks, if the storage is a valid backend
|
||||||
|
*
|
||||||
|
* @param string|null $name The name or class of the backend
|
||||||
|
* @param boolean $userBackend True, if just user backend should get returned (e.g. not SystemResource)
|
||||||
|
*
|
||||||
|
* @return boolean True, if the backend is a valid backend
|
||||||
|
*/
|
||||||
|
public function isValidBackend(string $name = null, bool $userBackend = true)
|
||||||
|
{
|
||||||
|
return array_key_exists($name, $this->backends) ||
|
||||||
|
(!$userBackend && $name === Storage\SystemResource::getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set current storage backend class
|
* @brief Set current storage backend class
|
||||||
*
|
*
|
||||||
* @param string $class Backend class name
|
* @param string $name Backend class name
|
||||||
* @return bool
|
*
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
* @return boolean True, if the set was successful
|
||||||
*/
|
*/
|
||||||
public static function setBackend($class)
|
public function setBackend(string $name = null)
|
||||||
{
|
{
|
||||||
if (!in_array('Friendica\Model\Storage\IStorage', class_implements($class))) {
|
if (!$this->isValidBackend($name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::set('storage', 'class', $class);
|
if ($this->config->set('storage', 'name', $name)) {
|
||||||
|
$this->currentBackend = $this->getByName($name);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,42 +165,63 @@ class StorageManager
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function listBackends()
|
public function listBackends()
|
||||||
{
|
{
|
||||||
self::setup();
|
return $this->backends;
|
||||||
return self::$backends;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register a storage backend class
|
* Register a storage backend class
|
||||||
|
*
|
||||||
|
* You have to register the hook "storage_instance" as well to make this class work!
|
||||||
*
|
*
|
||||||
* @param string $name User readable backend name
|
|
||||||
* @param string $class Backend class name
|
* @param string $class Backend class name
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
*
|
||||||
|
* @return boolean True, if the registration was successful
|
||||||
*/
|
*/
|
||||||
public static function register($name, $class)
|
public function register(string $class)
|
||||||
{
|
{
|
||||||
/// @todo Check that $class implements IStorage
|
if (is_subclass_of($class, Storage\IStorage::class)) {
|
||||||
self::setup();
|
/** @var Storage\IStorage $class */
|
||||||
self::$backends[$name] = $class;
|
|
||||||
Config::set('storage', 'backends', self::$backends);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$backends = $this->backends;
|
||||||
|
$backends[$class::getName()] = $class;
|
||||||
|
|
||||||
|
if ($this->config->set('storage', 'backends', $backends)) {
|
||||||
|
$this->backends = $backends;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unregister a storage backend class
|
* @brief Unregister a storage backend class
|
||||||
*
|
*
|
||||||
* @param string $name User readable backend name
|
* @param string $class Backend class name
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
*
|
||||||
|
* @return boolean True, if unregistering was successful
|
||||||
*/
|
*/
|
||||||
public static function unregister($name)
|
public function unregister(string $class)
|
||||||
{
|
{
|
||||||
self::setup();
|
if (is_subclass_of($class, Storage\IStorage::class)) {
|
||||||
unset(self::$backends[$name]);
|
/** @var Storage\IStorage $class */
|
||||||
Config::set('storage', 'backends', self::$backends);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
unset($this->backends[$class::getName()]);
|
||||||
|
|
||||||
|
if ($this->currentBackend instanceof $class) {
|
||||||
|
$this->config->set('storage', 'name', null);
|
||||||
|
$this->currentBackend = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->config->set('storage', 'backends', $this->backends);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Move up to 5000 resources to storage $dest
|
* @brief Move up to 5000 resources to storage $dest
|
||||||
|
@ -117,64 +229,60 @@ class StorageManager
|
||||||
* Copy existing data to destination storage and delete from source.
|
* Copy existing data to destination storage and delete from source.
|
||||||
* This method cannot move to legacy in-table `data` field.
|
* This method cannot move to legacy in-table `data` field.
|
||||||
*
|
*
|
||||||
* @param string $destination Storage class name
|
* @param Storage\IStorage $destination Destination storage class name
|
||||||
* @param array|null $tables Tables to look in for resources. Optional, defaults to ['photo', 'attach']
|
* @param array $tables Tables to look in for resources. Optional, defaults to ['photo', 'attach']
|
||||||
* @param int $limit Limit of the process batch size, defaults to 5000
|
* @param int $limit Limit of the process batch size, defaults to 5000
|
||||||
|
*
|
||||||
* @return int Number of moved resources
|
* @return int Number of moved resources
|
||||||
* @throws \Exception
|
* @throws Storage\StorageException
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function move($destination, $tables = null, $limit = 5000)
|
public function move(Storage\IStorage $destination, array $tables = self::TABLES, int $limit = 5000)
|
||||||
{
|
{
|
||||||
if (empty($destination)) {
|
if ($destination === null) {
|
||||||
throw new \Exception('Can\'t move to NULL storage backend');
|
throw new Storage\StorageException('Can\'t move to NULL storage backend');
|
||||||
}
|
|
||||||
|
|
||||||
if (is_null($tables)) {
|
|
||||||
$tables = ['photo', 'attach'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$moved = 0;
|
$moved = 0;
|
||||||
foreach ($tables as $table) {
|
foreach ($tables as $table) {
|
||||||
// Get the rows where backend class is not the destination backend class
|
// Get the rows where backend class is not the destination backend class
|
||||||
$resources = DBA::select(
|
$resources = $this->dba->select(
|
||||||
$table,
|
$table,
|
||||||
['id', 'data', 'backend-class', 'backend-ref'],
|
['id', 'data', 'backend-class', 'backend-ref'],
|
||||||
['`backend-class` IS NULL or `backend-class` != ?', $destination],
|
['`backend-class` IS NULL or `backend-class` != ?', $destination::getName()],
|
||||||
['limit' => $limit]
|
['limit' => $limit]
|
||||||
);
|
);
|
||||||
|
|
||||||
while ($resource = DBA::fetch($resources)) {
|
while ($resource = $this->dba->fetch($resources)) {
|
||||||
$id = $resource['id'];
|
$id = $resource['id'];
|
||||||
$data = $resource['data'];
|
$data = $resource['data'];
|
||||||
/** @var IStorage $backendClass */
|
$source = $this->getByName($resource['backend-class']);
|
||||||
$backendClass = $resource['backend-class'];
|
$sourceRef = $resource['backend-ref'];
|
||||||
$backendRef = $resource['backend-ref'];
|
|
||||||
if (!empty($backendClass)) {
|
if (!empty($source)) {
|
||||||
Logger::log("get data from old backend " . $backendClass . " : " . $backendRef);
|
$this->logger->info('Get data from old backend.', ['oldBackend' => $source, 'oldReference' => $sourceRef]);
|
||||||
$data = $backendClass::get($backendRef);
|
$data = $source->get($sourceRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::log("save data to new backend " . $destination);
|
$this->logger->info('Save data to new backend.', ['newBackend' => $destination]);
|
||||||
/** @var IStorage $destination */
|
$destinationRef = $destination->put($data);
|
||||||
$ref = $destination::put($data);
|
$this->logger->info('Saved data.', ['newReference' => $destinationRef]);
|
||||||
Logger::log("saved data as " . $ref);
|
|
||||||
|
|
||||||
if ($ref !== '') {
|
if ($destinationRef !== '') {
|
||||||
Logger::log("update row");
|
$this->logger->info('update row');
|
||||||
if (DBA::update($table, ['backend-class' => $destination, 'backend-ref' => $ref, 'data' => ''], ['id' => $id])) {
|
if ($this->dba->update($table, ['backend-class' => $destination, 'backend-ref' => $destinationRef, 'data' => ''], ['id' => $id])) {
|
||||||
if (!empty($backendClass)) {
|
if (!empty($source)) {
|
||||||
Logger::log("delete data from old backend " . $backendClass . " : " . $backendRef);
|
$this->logger->info('Delete data from old backend.', ['oldBackend' => $source, 'oldReference' => $sourceRef]);
|
||||||
$backendClass::delete($backendRef);
|
$source->delete($sourceRef);
|
||||||
}
|
}
|
||||||
$moved++;
|
$moved++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DBA::close($resources);
|
$this->dba->close($resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $moved;
|
return $moved;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ use Friendica\Database\DBA;
|
||||||
use Friendica\Database\DBStructure;
|
use Friendica\Database\DBStructure;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Util\Strings;
|
use Friendica\Util\Strings;
|
||||||
|
use Friendica\Core\Cache\Cache;
|
||||||
|
|
||||||
class Update
|
class Update
|
||||||
{
|
{
|
||||||
|
|
64
src/DI.php
64
src/DI.php
|
@ -27,6 +27,7 @@ use Psr\Log\LoggerInterface;
|
||||||
* @method static Core\L10n\L10n l10n()
|
* @method static Core\L10n\L10n l10n()
|
||||||
* @method static Core\Process process()
|
* @method static Core\Process process()
|
||||||
* @method static Core\Session\ISession session()
|
* @method static Core\Session\ISession session()
|
||||||
|
* @method static Core\StorageManager storageManager()
|
||||||
* @method static Database\Database dba()
|
* @method static Database\Database dba()
|
||||||
* @method static Factory\Mastodon\Account mstdnAccount()
|
* @method static Factory\Mastodon\Account mstdnAccount()
|
||||||
* @method static Factory\Mastodon\FollowRequest mstdnFollowRequest()
|
* @method static Factory\Mastodon\FollowRequest mstdnFollowRequest()
|
||||||
|
@ -34,6 +35,7 @@ use Psr\Log\LoggerInterface;
|
||||||
* @method static Model\User\Cookie cookie()
|
* @method static Model\User\Cookie cookie()
|
||||||
* @method static Model\Notify notify()
|
* @method static Model\Notify notify()
|
||||||
* @method static Repository\Introduction intro()
|
* @method static Repository\Introduction intro()
|
||||||
|
* @method static Model\Storage\IStorage storage()
|
||||||
* @method static Protocol\Activity activity()
|
* @method static Protocol\Activity activity()
|
||||||
* @method static Util\ACLFormatter aclFormatter()
|
* @method static Util\ACLFormatter aclFormatter()
|
||||||
* @method static Util\DateTimeFormat dtFormat()
|
* @method static Util\DateTimeFormat dtFormat()
|
||||||
|
@ -47,38 +49,40 @@ use Psr\Log\LoggerInterface;
|
||||||
abstract class DI
|
abstract class DI
|
||||||
{
|
{
|
||||||
const CLASS_MAPPING = [
|
const CLASS_MAPPING = [
|
||||||
'app' => App::class,
|
'app' => App::class,
|
||||||
'auth' => App\Authentication::class,
|
'auth' => App\Authentication::class,
|
||||||
'args' => App\Arguments::class,
|
'args' => App\Arguments::class,
|
||||||
'baseUrl' => App\BaseURL::class,
|
'baseUrl' => App\BaseURL::class,
|
||||||
'mode' => App\Mode::class,
|
'mode' => App\Mode::class,
|
||||||
'module' => App\Module::class,
|
'module' => App\Module::class,
|
||||||
'page' => App\Page::class,
|
'page' => App\Page::class,
|
||||||
'router' => App\Router::class,
|
'router' => App\Router::class,
|
||||||
'contentItem' => Content\Item::class,
|
'contentItem' => Content\Item::class,
|
||||||
'bbCodeVideo' => Content\Text\BBCode\Video::class,
|
'bbCodeVideo' => Content\Text\BBCode\Video::class,
|
||||||
'cache' => Core\Cache\ICache::class,
|
'cache' => Core\Cache\ICache::class,
|
||||||
'config' => Core\Config\IConfiguration::class,
|
'config' => Core\Config\IConfiguration::class,
|
||||||
'pConfig' => Core\Config\IPConfiguration::class,
|
'pConfig' => Core\Config\IPConfiguration::class,
|
||||||
'l10n' => Core\L10n\L10n::class,
|
'l10n' => Core\L10n\L10n::class,
|
||||||
'lock' => Core\Lock\ILock::class,
|
'lock' => Core\Lock\ILock::class,
|
||||||
'process' => Core\Process::class,
|
'process' => Core\Process::class,
|
||||||
'session' => Core\Session\ISession::class,
|
'session' => Core\Session\ISession::class,
|
||||||
'dba' => Database\Database::class,
|
'storageManager' => Core\StorageManager::class,
|
||||||
'mstdnAccount' => Factory\Mastodon\Account::class,
|
'dba' => Database\Database::class,
|
||||||
|
'mstdnAccount' => Factory\Mastodon\Account::class,
|
||||||
'mstdnFollowRequest' => Factory\Mastodon\FollowRequest::class,
|
'mstdnFollowRequest' => Factory\Mastodon\FollowRequest::class,
|
||||||
'mstdnRelationship' => Factory\Mastodon\Relationship::class,
|
'mstdnRelationship' => Factory\Mastodon\Relationship::class,
|
||||||
'cookie' => Model\User\Cookie::class,
|
'cookie' => Model\User\Cookie::class,
|
||||||
'notify' => Model\Notify::class,
|
'notify' => Model\Notify::class,
|
||||||
'intro' => Repository\Introduction::class,
|
'storage' => Model\Storage\IStorage::class,
|
||||||
'activity' => Protocol\Activity::class,
|
'intro' => Repository\Introduction::class,
|
||||||
'aclFormatter' => Util\ACLFormatter::class,
|
'activity' => Protocol\Activity::class,
|
||||||
'dtFormat' => Util\DateTimeFormat::class,
|
'aclFormatter' => Util\ACLFormatter::class,
|
||||||
'fs' => Util\FileSystem::class,
|
'dtFormat' => Util\DateTimeFormat::class,
|
||||||
'workerLogger' => Util\Logger\WorkerLogger::class,
|
'fs' => Util\FileSystem::class,
|
||||||
'profiler' => Util\Profiler::class,
|
'workerLogger' => Util\Logger\WorkerLogger::class,
|
||||||
'logger' => LoggerInterface::class,
|
'profiler' => Util\Profiler::class,
|
||||||
'devLogger' => '$devLogger',
|
'logger' => LoggerInterface::class,
|
||||||
|
'devLogger' => '$devLogger',
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var Dice */
|
/** @var Dice */
|
||||||
|
|
|
@ -6,12 +6,10 @@
|
||||||
*/
|
*/
|
||||||
namespace Friendica\Model;
|
namespace Friendica\Model;
|
||||||
|
|
||||||
use Friendica\Core\StorageManager;
|
|
||||||
use Friendica\Core\System;
|
use Friendica\Core\System;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\Database\DBStructure;
|
use Friendica\Database\DBStructure;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Model\Storage\IStorage;
|
|
||||||
use Friendica\Object\Image;
|
use Friendica\Object\Image;
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
use Friendica\Util\Mimetype;
|
use Friendica\Util\Mimetype;
|
||||||
|
@ -146,7 +144,8 @@ class Attach
|
||||||
*/
|
*/
|
||||||
public static function getData($item)
|
public static function getData($item)
|
||||||
{
|
{
|
||||||
if ($item['backend-class'] == '') {
|
$backendClass = DI::storageManager()->getByName($photo['backend-class'] ?? '');
|
||||||
|
if ($backendClass === null) {
|
||||||
// legacy data storage in 'data' column
|
// legacy data storage in 'data' column
|
||||||
$i = self::selectFirst(['data'], ['id' => $item['id']]);
|
$i = self::selectFirst(['data'], ['id' => $item['id']]);
|
||||||
if ($i === false) {
|
if ($i === false) {
|
||||||
|
@ -154,9 +153,8 @@ class Attach
|
||||||
}
|
}
|
||||||
return $i['data'];
|
return $i['data'];
|
||||||
} else {
|
} else {
|
||||||
$backendClass = $item['backend-class'];
|
|
||||||
$backendRef = $item['backend-ref'];
|
$backendRef = $item['backend-ref'];
|
||||||
return $backendClass::get($backendRef);
|
return $backendClass->get($backendRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,13 +184,8 @@ class Attach
|
||||||
$filesize = strlen($data);
|
$filesize = strlen($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var IStorage $backend_class */
|
$backend_ref = DI::storage()->put($data);
|
||||||
$backend_class = StorageManager::getBackend();
|
$data = '';
|
||||||
$backend_ref = '';
|
|
||||||
if ($backend_class !== '') {
|
|
||||||
$backend_ref = $backend_class::put($data);
|
|
||||||
$data = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$hash = System::createGUID(64);
|
$hash = System::createGUID(64);
|
||||||
$created = DateTimeFormat::utcNow();
|
$created = DateTimeFormat::utcNow();
|
||||||
|
@ -210,7 +203,7 @@ class Attach
|
||||||
'allow_gid' => $allow_gid,
|
'allow_gid' => $allow_gid,
|
||||||
'deny_cid' => $deny_cid,
|
'deny_cid' => $deny_cid,
|
||||||
'deny_gid' => $deny_gid,
|
'deny_gid' => $deny_gid,
|
||||||
'backend-class' => $backend_class,
|
'backend-class' => (string)DI::storage(),
|
||||||
'backend-ref' => $backend_ref
|
'backend-ref' => $backend_ref
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -266,10 +259,9 @@ class Attach
|
||||||
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
|
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
|
||||||
|
|
||||||
foreach($items as $item) {
|
foreach($items as $item) {
|
||||||
/** @var IStorage $backend_class */
|
$backend_class = DI::storageManager()->getByName($item['backend-class'] ?? '');
|
||||||
$backend_class = (string)$item['backend-class'];
|
if ($backend_class !== null) {
|
||||||
if ($backend_class !== '') {
|
$fields['backend-ref'] = $backend_class->put($img->asString(), $item['backend-ref'] ?? '');
|
||||||
$fields['backend-ref'] = $backend_class::put($img->asString(), $item['backend-ref']);
|
|
||||||
} else {
|
} else {
|
||||||
$fields['data'] = $img->asString();
|
$fields['data'] = $img->asString();
|
||||||
}
|
}
|
||||||
|
@ -299,10 +291,9 @@ class Attach
|
||||||
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
|
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
|
||||||
|
|
||||||
foreach($items as $item) {
|
foreach($items as $item) {
|
||||||
/** @var IStorage $backend_class */
|
$backend_class = DI::storageManager()->getByName($item['backend-class'] ?? '');
|
||||||
$backend_class = (string)$item['backend-class'];
|
if ($backend_class !== null) {
|
||||||
if ($backend_class !== '') {
|
$backend_class->delete($item['backend-ref'] ?? '');
|
||||||
$backend_class::delete($item['backend-ref']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1896,6 +1896,14 @@ class Contact
|
||||||
$data = [$contact["photo"], $contact["thumb"], $contact["micro"]];
|
$data = [$contact["photo"], $contact["thumb"], $contact["micro"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($data as $image_uri) {
|
||||||
|
$image_rid = Photo::ridFromURI($image_uri);
|
||||||
|
if ($image_rid && !Photo::exists(['resource-id' => $image_rid, 'uid' => $uid])) {
|
||||||
|
Logger::info('Regenerating avatar', ['contact uid' => $uid, 'cid' => $cid, 'missing photo' => $image_rid, 'avatar' => $contact['avatar']]);
|
||||||
|
$force = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (($contact["avatar"] != $avatar) || $force) {
|
if (($contact["avatar"] != $avatar) || $force) {
|
||||||
$photos = Photo::importProfilePhoto($avatar, $uid, $cid, true);
|
$photos = Photo::importProfilePhoto($avatar, $uid, $cid, true);
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,7 @@ class GServer
|
||||||
$serverdata = self::analyseRootBody($curlResult, $serverdata, $url);
|
$serverdata = self::analyseRootBody($curlResult, $serverdata, $url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$curlResult->isSuccess() || empty($curlResult->getBody())) {
|
if (!$curlResult->isSuccess() || empty($curlResult->getBody()) || self::invalidBody($curlResult->getBody())) {
|
||||||
DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow()], ['nurl' => Strings::normaliseLink($url)]);
|
DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow()], ['nurl' => Strings::normaliseLink($url)]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1061,6 +1061,7 @@ class GServer
|
||||||
$serverdata['platform'] = 'gnusocial';
|
$serverdata['platform'] = 'gnusocial';
|
||||||
// Remove junk that some GNU Social servers return
|
// Remove junk that some GNU Social servers return
|
||||||
$serverdata['version'] = str_replace(chr(239) . chr(187) . chr(191), '', $curlResult->getBody());
|
$serverdata['version'] = str_replace(chr(239) . chr(187) . chr(191), '', $curlResult->getBody());
|
||||||
|
$serverdata['version'] = str_replace(["\r", "\n", "\t"], '', $serverdata['version']);
|
||||||
$serverdata['version'] = trim($serverdata['version'], '"');
|
$serverdata['version'] = trim($serverdata['version'], '"');
|
||||||
$serverdata['network'] = Protocol::OSTATUS;
|
$serverdata['network'] = Protocol::OSTATUS;
|
||||||
return $serverdata;
|
return $serverdata;
|
||||||
|
@ -1070,11 +1071,20 @@ class GServer
|
||||||
$curlResult = Network::curl($url . '/api/statusnet/version.json');
|
$curlResult = Network::curl($url . '/api/statusnet/version.json');
|
||||||
if ($curlResult->isSuccess() && ($curlResult->getBody() != '{"error":"not implemented"}') &&
|
if ($curlResult->isSuccess() && ($curlResult->getBody() != '{"error":"not implemented"}') &&
|
||||||
($curlResult->getBody() != '') && (strlen($curlResult->getBody()) < 30)) {
|
($curlResult->getBody() != '') && (strlen($curlResult->getBody()) < 30)) {
|
||||||
$serverdata['platform'] = 'statusnet';
|
|
||||||
// Remove junk that some GNU Social servers return
|
// Remove junk that some GNU Social servers return
|
||||||
$serverdata['version'] = str_replace(chr(239).chr(187).chr(191), '', $curlResult->getBody());
|
$serverdata['version'] = str_replace(chr(239).chr(187).chr(191), '', $curlResult->getBody());
|
||||||
|
$serverdata['version'] = str_replace(["\r", "\n", "\t"], '', $serverdata['version']);
|
||||||
$serverdata['version'] = trim($serverdata['version'], '"');
|
$serverdata['version'] = trim($serverdata['version'], '"');
|
||||||
$serverdata['network'] = Protocol::OSTATUS;
|
|
||||||
|
if (!empty($serverdata['version']) && strtolower(substr($serverdata['version'], 0, 7)) == 'pleroma') {
|
||||||
|
$serverdata['platform'] = 'pleroma';
|
||||||
|
$serverdata['version'] = trim(str_ireplace('pleroma', '', $serverdata['version']));
|
||||||
|
$serverdata['network'] = Protocol::ACTIVITYPUB;
|
||||||
|
} else {
|
||||||
|
$serverdata['platform'] = 'statusnet';
|
||||||
|
$serverdata['network'] = Protocol::OSTATUS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $serverdata;
|
return $serverdata;
|
||||||
|
@ -1285,7 +1295,6 @@ class GServer
|
||||||
$serverdata['platform'] = 'diaspora';
|
$serverdata['platform'] = 'diaspora';
|
||||||
$serverdata['network'] = $network = Protocol::DIASPORA;
|
$serverdata['network'] = $network = Protocol::DIASPORA;
|
||||||
$serverdata['version'] = $curlResult->getHeader('x-diaspora-version');
|
$serverdata['version'] = $curlResult->getHeader('x-diaspora-version');
|
||||||
|
|
||||||
} elseif ($curlResult->inHeader('x-friendica-version')) {
|
} elseif ($curlResult->inHeader('x-friendica-version')) {
|
||||||
$serverdata['platform'] = 'friendica';
|
$serverdata['platform'] = 'friendica';
|
||||||
$serverdata['network'] = $network = Protocol::DFRN;
|
$serverdata['network'] = $network = Protocol::DFRN;
|
||||||
|
@ -1294,6 +1303,19 @@ class GServer
|
||||||
return $serverdata;
|
return $serverdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if the body contains valid content
|
||||||
|
*
|
||||||
|
* @param string $body
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
private static function invalidBody(string $body)
|
||||||
|
{
|
||||||
|
// Currently we only test for a HTML element.
|
||||||
|
// Possibly we enhance this in the future.
|
||||||
|
return !strpos($body, '>');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the user directory of a given gserver record
|
* Update the user directory of a given gserver record
|
||||||
*
|
*
|
||||||
|
|
|
@ -215,12 +215,10 @@ class Mail
|
||||||
$images = $match[1];
|
$images = $match[1];
|
||||||
if (count($images)) {
|
if (count($images)) {
|
||||||
foreach ($images as $image) {
|
foreach ($images as $image) {
|
||||||
if (!stristr($image, DI::baseUrl() . '/photo/')) {
|
$image_rid = Photo::ridFromURI($image);
|
||||||
continue;
|
if (!empty($image_rid)) {
|
||||||
|
Photo::update(['allow-cid' => '<' . $recipient . '>'], ['resource-id' => $image_rid, 'album' => 'Wall Photos', 'uid' => local_user()]);
|
||||||
}
|
}
|
||||||
$image_uri = substr($image, strrpos($image, '/') + 1);
|
|
||||||
$image_uri = substr($image_uri, 0, strpos($image_uri, '-'));
|
|
||||||
Photo::update(['allow-cid' => '<' . $recipient . '>'], ['resource-id' => $image_uri, 'album' => 'Wall Photos', 'uid' => local_user()]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,12 +52,15 @@ class Nodeinfo
|
||||||
|
|
||||||
$logger->debug('user statistics', $userStats);
|
$logger->debug('user statistics', $userStats);
|
||||||
|
|
||||||
$local_posts = DBA::count('thread', ["`wall` AND NOT `deleted` AND `uid` != 0"]);
|
$items = DBA::p("SELECT COUNT(*) AS `total`, `gravity` FROM `item` WHERE `origin` AND NOT `deleted` AND `uid` != 0 AND `gravity` IN (?, ?) GROUP BY `gravity`",
|
||||||
$config->set('nodeinfo', 'local_posts', $local_posts);
|
GRAVITY_PARENT, GRAVITY_COMMENT);
|
||||||
$logger->debug('thread statistics', ['local_posts' => $local_posts]);
|
while ($item = DBA::fetch($items)) {
|
||||||
|
if ($item['gravity'] == GRAVITY_PARENT) {
|
||||||
$local_comments = DBA::count('item', ["`origin` AND `id` != `parent` AND NOT `deleted` AND `uid` != 0"]);
|
$config->set('nodeinfo', 'local_posts', $item['total']);
|
||||||
$config->set('nodeinfo', 'local_comments', $local_comments);
|
} elseif ($item['gravity'] == GRAVITY_COMMENT) {
|
||||||
$logger->debug('item statistics', ['local_comments' => $local_comments]);
|
$config->set('nodeinfo', 'local_comments', $item['total']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBA::close($items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,15 @@
|
||||||
*/
|
*/
|
||||||
namespace Friendica\Model;
|
namespace Friendica\Model;
|
||||||
|
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Core\StorageManager;
|
|
||||||
use Friendica\Core\System;
|
use Friendica\Core\System;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\Database\DBStructure;
|
use Friendica\Database\DBStructure;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Model\Storage\IStorage;
|
use Friendica\Model\Storage\SystemResource;
|
||||||
use Friendica\Object\Image;
|
use Friendica\Object\Image;
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
use Friendica\Util\Images;
|
use Friendica\Util\Images;
|
||||||
|
@ -172,26 +171,24 @@ class Photo
|
||||||
*/
|
*/
|
||||||
public static function getImageForPhoto(array $photo)
|
public static function getImageForPhoto(array $photo)
|
||||||
{
|
{
|
||||||
$data = "";
|
$backendClass = DI::storageManager()->getByName($photo['backend-class'] ?? '');
|
||||||
|
if ($backendClass === null) {
|
||||||
if ($photo["backend-class"] == "") {
|
|
||||||
// legacy data storage in "data" column
|
// legacy data storage in "data" column
|
||||||
$i = self::selectFirst(["data"], ["id" => $photo["id"]]);
|
$i = self::selectFirst(['data'], ['id' => $photo['id']]);
|
||||||
if ($i === false) {
|
if ($i === false) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$data = $i["data"];
|
$data = $i['data'];
|
||||||
} else {
|
} else {
|
||||||
$backendClass = $photo["backend-class"];
|
$backendRef = $photo['backend-ref'] ?? '';
|
||||||
$backendRef = $photo["backend-ref"];
|
$data = $backendClass->get($backendRef);
|
||||||
$data = $backendClass::get($backendRef);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($data === "") {
|
if (empty($data)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Image($data, $photo["type"]);
|
return new Image($data, $photo['type']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -222,11 +219,11 @@ class Photo
|
||||||
$fields = self::getFields();
|
$fields = self::getFields();
|
||||||
$values = array_fill(0, count($fields), "");
|
$values = array_fill(0, count($fields), "");
|
||||||
|
|
||||||
$photo = array_combine($fields, $values);
|
$photo = array_combine($fields, $values);
|
||||||
$photo["backend-class"] = Storage\SystemResource::class;
|
$photo['backend-class'] = SystemResource::NAME;
|
||||||
$photo["backend-ref"] = $filename;
|
$photo['backend-ref'] = $filename;
|
||||||
$photo["type"] = $mimetype;
|
$photo['type'] = $mimetype;
|
||||||
$photo["cacheable"] = false;
|
$photo['cacheable'] = false;
|
||||||
|
|
||||||
return $photo;
|
return $photo;
|
||||||
}
|
}
|
||||||
|
@ -273,18 +270,17 @@ class Photo
|
||||||
$data = "";
|
$data = "";
|
||||||
$backend_ref = "";
|
$backend_ref = "";
|
||||||
|
|
||||||
/** @var IStorage $backend_class */
|
|
||||||
if (DBA::isResult($existing_photo)) {
|
if (DBA::isResult($existing_photo)) {
|
||||||
$backend_ref = (string)$existing_photo["backend-ref"];
|
$backend_ref = (string)$existing_photo["backend-ref"];
|
||||||
$backend_class = (string)$existing_photo["backend-class"];
|
$storage = DI::storageManager()->getByName($existing_photo["backend-class"] ?? '');
|
||||||
} else {
|
} else {
|
||||||
$backend_class = StorageManager::getBackend();
|
$storage = DI::storage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($backend_class === "") {
|
if ($storage === null) {
|
||||||
$data = $Image->asString();
|
$data = $Image->asString();
|
||||||
} else {
|
} else {
|
||||||
$backend_ref = $backend_class::put($Image->asString(), $backend_ref);
|
$backend_ref = $storage->put($Image->asString(), $backend_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -309,7 +305,7 @@ class Photo
|
||||||
"deny_cid" => $deny_cid,
|
"deny_cid" => $deny_cid,
|
||||||
"deny_gid" => $deny_gid,
|
"deny_gid" => $deny_gid,
|
||||||
"desc" => $desc,
|
"desc" => $desc,
|
||||||
"backend-class" => $backend_class,
|
"backend-class" => (string)$storage,
|
||||||
"backend-ref" => $backend_ref
|
"backend-ref" => $backend_ref
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -340,10 +336,9 @@ class Photo
|
||||||
$photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions);
|
$photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions);
|
||||||
|
|
||||||
foreach($photos as $photo) {
|
foreach($photos as $photo) {
|
||||||
/** @var IStorage $backend_class */
|
$backend_class = DI::storageManager()->getByName($photo['backend-class'] ?? '');
|
||||||
$backend_class = (string)$photo["backend-class"];
|
if ($backend_class !== null) {
|
||||||
if ($backend_class !== "") {
|
$backend_class->delete($photo["backend-ref"] ?? '');
|
||||||
$backend_class::delete($photo["backend-ref"]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,10 +365,9 @@ class Photo
|
||||||
$photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions);
|
$photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions);
|
||||||
|
|
||||||
foreach($photos as $photo) {
|
foreach($photos as $photo) {
|
||||||
/** @var IStorage $backend_class */
|
$backend_class = DI::storageManager()->getByName($photo['backend-class'] ?? '');
|
||||||
$backend_class = (string)$photo["backend-class"];
|
if ($backend_class !== null) {
|
||||||
if ($backend_class !== "") {
|
$fields["backend-ref"] = $backend_class->put($img->asString(), $photo['backend-ref']);
|
||||||
$fields["backend-ref"] = $backend_class::put($img->asString(), $photo["backend-ref"]);
|
|
||||||
} else {
|
} else {
|
||||||
$fields["data"] = $img->asString();
|
$fields["data"] = $img->asString();
|
||||||
}
|
}
|
||||||
|
@ -546,7 +540,7 @@ class Photo
|
||||||
$sql_extra = Security::getPermissionsSQLByUserId($uid);
|
$sql_extra = Security::getPermissionsSQLByUserId($uid);
|
||||||
|
|
||||||
$key = "photo_albums:".$uid.":".local_user().":".remote_user();
|
$key = "photo_albums:".$uid.":".local_user().":".remote_user();
|
||||||
$albums = Cache::get($key);
|
$albums = DI::cache()->get($key);
|
||||||
if (is_null($albums) || $update) {
|
if (is_null($albums) || $update) {
|
||||||
if (!Config::get("system", "no_count", false)) {
|
if (!Config::get("system", "no_count", false)) {
|
||||||
/// @todo This query needs to be renewed. It is really slow
|
/// @todo This query needs to be renewed. It is really slow
|
||||||
|
@ -569,7 +563,7 @@ class Photo
|
||||||
DBA::escape(L10n::t("Contact Photos"))
|
DBA::escape(L10n::t("Contact Photos"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Cache::set($key, $albums, Cache::DAY);
|
DI::cache()->set($key, $albums, Cache::DAY);
|
||||||
}
|
}
|
||||||
return $albums;
|
return $albums;
|
||||||
}
|
}
|
||||||
|
@ -582,7 +576,7 @@ class Photo
|
||||||
public static function clearAlbumCache($uid)
|
public static function clearAlbumCache($uid)
|
||||||
{
|
{
|
||||||
$key = "photo_albums:".$uid.":".local_user().":".remote_user();
|
$key = "photo_albums:".$uid.":".local_user().":".remote_user();
|
||||||
Cache::set($key, null, Cache::DAY);
|
DI::cache()->set($key, null, Cache::DAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -596,6 +590,25 @@ class Photo
|
||||||
return System::createGUID(32, false);
|
return System::createGUID(32, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the rid from a local photo URI
|
||||||
|
*
|
||||||
|
* @param string $image_uri The URI of the photo
|
||||||
|
* @return string The rid of the photo, or an empty string if the URI is not local
|
||||||
|
*/
|
||||||
|
public static function ridFromURI(string $image_uri)
|
||||||
|
{
|
||||||
|
if (!stristr($image_uri, DI::baseUrl() . '/photo/')) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$image_uri = substr($image_uri, strrpos($image_uri, '/') + 1);
|
||||||
|
$image_uri = substr($image_uri, 0, strpos($image_uri, '-'));
|
||||||
|
if (!strlen($image_uri)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return $image_uri;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes photo permissions that had been embedded in a post
|
* Changes photo permissions that had been embedded in a post
|
||||||
*
|
*
|
||||||
|
@ -622,12 +635,8 @@ class Photo
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($images as $image) {
|
foreach ($images as $image) {
|
||||||
if (!stristr($image, DI::baseUrl() . '/photo/')) {
|
$image_rid = self::ridFromURI($image);
|
||||||
continue;
|
if (empty($image_rid)) {
|
||||||
}
|
|
||||||
$image_uri = substr($image,strrpos($image,'/') + 1);
|
|
||||||
$image_uri = substr($image_uri,0, strpos($image_uri,'-'));
|
|
||||||
if (!strlen($image_uri)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,7 +645,7 @@ class Photo
|
||||||
|
|
||||||
$condition = [
|
$condition = [
|
||||||
'allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '',
|
'allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '',
|
||||||
'resource-id' => $image_uri, 'uid' => $uid
|
'resource-id' => $image_rid, 'uid' => $uid
|
||||||
];
|
];
|
||||||
if (!Photo::exists($condition)) {
|
if (!Photo::exists($condition)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -646,7 +655,7 @@ class Photo
|
||||||
|
|
||||||
$fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow,
|
$fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow,
|
||||||
'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny];
|
'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny];
|
||||||
$condition = ['resource-id' => $image_uri, 'uid' => $uid];
|
$condition = ['resource-id' => $image_rid, 'uid' => $uid];
|
||||||
Logger::info('Set permissions', ['condition' => $condition, 'permissions' => $fields]);
|
Logger::info('Set permissions', ['condition' => $condition, 'permissions' => $fields]);
|
||||||
Photo::update($fields, $condition);
|
Photo::update($fields, $condition);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use Friendica\Content\ForumManager;
|
||||||
use Friendica\Content\Text\BBCode;
|
use Friendica\Content\Text\BBCode;
|
||||||
use Friendica\Content\Text\HTML;
|
use Friendica\Content\Text\HTML;
|
||||||
use Friendica\Content\Widget\ContactBlock;
|
use Friendica\Content\Widget\ContactBlock;
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\Hook;
|
use Friendica\Core\Hook;
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n;
|
||||||
|
@ -586,7 +586,7 @@ class Profile
|
||||||
$bd_short = L10n::t('F d');
|
$bd_short = L10n::t('F d');
|
||||||
|
|
||||||
$cachekey = 'get_birthdays:' . local_user();
|
$cachekey = 'get_birthdays:' . local_user();
|
||||||
$r = Cache::get($cachekey);
|
$r = DI::cache()->get($cachekey);
|
||||||
if (is_null($r)) {
|
if (is_null($r)) {
|
||||||
$s = DBA::p(
|
$s = DBA::p(
|
||||||
"SELECT `event`.*, `event`.`id` AS `eid`, `contact`.* FROM `event`
|
"SELECT `event`.*, `event`.`id` AS `eid`, `contact`.* FROM `event`
|
||||||
|
@ -608,7 +608,7 @@ class Profile
|
||||||
);
|
);
|
||||||
if (DBA::isResult($s)) {
|
if (DBA::isResult($s)) {
|
||||||
$r = DBA::toArray($s);
|
$r = DBA::toArray($s);
|
||||||
Cache::set($cachekey, $r, Cache::HOUR);
|
DI::cache()->set($cachekey, $r, Cache::HOUR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1066,11 +1066,11 @@ class Profile
|
||||||
|
|
||||||
// Avoid endless loops
|
// Avoid endless loops
|
||||||
$cachekey = 'zrlInit:' . $my_url;
|
$cachekey = 'zrlInit:' . $my_url;
|
||||||
if (Cache::get($cachekey)) {
|
if (DI::cache()->get($cachekey)) {
|
||||||
Logger::log('URL ' . $my_url . ' already tried to authenticate.', Logger::DEBUG);
|
Logger::log('URL ' . $my_url . ' already tried to authenticate.', Logger::DEBUG);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Cache::set($cachekey, true, Cache::MINUTE);
|
DI::cache()->set($cachekey, true, Cache::MINUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::log('Not authenticated. Invoking reverse magic-auth for ' . $my_url, Logger::DEBUG);
|
Logger::log('Not authenticated. Invoking reverse magic-auth for ' . $my_url, Logger::DEBUG);
|
||||||
|
|
32
src/Model/Storage/AbstractStorage.php
Normal file
32
src/Model/Storage/AbstractStorage.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Model\Storage;
|
||||||
|
|
||||||
|
use Friendica\Core\L10n\L10n;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A general storage class which loads common dependencies and implements common methods
|
||||||
|
*/
|
||||||
|
abstract class AbstractStorage implements IStorage
|
||||||
|
{
|
||||||
|
/** @var L10n */
|
||||||
|
protected $l10n;
|
||||||
|
/** @var LoggerInterface */
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param L10n $l10n
|
||||||
|
* @param LoggerInterface $logger
|
||||||
|
*/
|
||||||
|
public function __construct(L10n $l10n, LoggerInterface $logger)
|
||||||
|
{
|
||||||
|
$this->l10n = $l10n;
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return static::getName();
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,58 +6,100 @@
|
||||||
|
|
||||||
namespace Friendica\Model\Storage;
|
namespace Friendica\Model\Storage;
|
||||||
|
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\L10n\L10n;
|
||||||
use Friendica\Core\L10n;
|
use Psr\Log\LoggerInterface;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\Database as DBA;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Database based storage system
|
* @brief Database based storage system
|
||||||
*
|
*
|
||||||
* This class manage data stored in database table.
|
* This class manage data stored in database table.
|
||||||
*/
|
*/
|
||||||
class Database implements IStorage
|
class Database extends AbstractStorage
|
||||||
{
|
{
|
||||||
public static function get($ref)
|
const NAME = 'Database';
|
||||||
|
|
||||||
|
/** @var DBA */
|
||||||
|
private $dba;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DBA $dba
|
||||||
|
* @param LoggerInterface $logger
|
||||||
|
* @param L10n $l10n
|
||||||
|
*/
|
||||||
|
public function __construct(DBA $dba, LoggerInterface $logger, L10n $l10n)
|
||||||
{
|
{
|
||||||
$r = DBA::selectFirst('storage', ['data'], ['id' => $ref]);
|
parent::__construct($l10n, $logger);
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
|
$this->dba = $dba;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get(string $reference)
|
||||||
|
{
|
||||||
|
$result = $this->dba->selectFirst('storage', ['data'], ['id' => $reference]);
|
||||||
|
if (!$this->dba->isResult($result)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $r['data'];
|
return $result['data'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function put($data, $ref = '')
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function put(string $data, string $reference = '')
|
||||||
{
|
{
|
||||||
if ($ref !== '') {
|
if ($reference !== '') {
|
||||||
$r = DBA::update('storage', ['data' => $data], ['id' => $ref]);
|
$result = $this->dba->update('storage', ['data' => $data], ['id' => $reference]);
|
||||||
if ($r === false) {
|
if ($result === false) {
|
||||||
Logger::log('Failed to update data with id ' . $ref . ': ' . DBA::errorNo() . ' : ' . DBA::errorMessage());
|
$this->logger->warning('Failed to update data.', ['id' => $reference, 'errorCode' => $this->dba->errorNo(), 'errorMessage' => $this->dba->errorMessage()]);
|
||||||
throw new StorageException(L10n::t('Database storage failed to update %s', $ref));
|
throw new StorageException($this->l10n->t('Database storage failed to update %s', $reference));
|
||||||
}
|
|
||||||
return $ref;
|
|
||||||
} else {
|
|
||||||
$r = DBA::insert('storage', ['data' => $data]);
|
|
||||||
if ($r === false) {
|
|
||||||
Logger::log('Failed to insert data: ' . DBA::errorNo() . ' : ' . DBA::errorMessage());
|
|
||||||
throw new StorageException(L10n::t('Database storage failed to insert data'));
|
|
||||||
}
|
}
|
||||||
return DBA::lastInsertId();
|
|
||||||
|
return $reference;
|
||||||
|
} else {
|
||||||
|
$result = $this->dba->insert('storage', ['data' => $data]);
|
||||||
|
if ($result === false) {
|
||||||
|
$this->logger->warning('Failed to insert data.', ['errorCode' => $this->dba->errorNo(), 'errorMessage' => $this->dba->errorMessage()]);
|
||||||
|
throw new StorageException($this->l10n->t('Database storage failed to insert data'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->dba->lastInsertId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function delete($ref)
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function delete(string $reference)
|
||||||
{
|
{
|
||||||
return DBA::delete('storage', ['id' => $ref]);
|
return $this->dba->delete('storage', ['id' => $reference]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getOptions()
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getOptions()
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function saveOptions($data)
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function saveOptions(array $data)
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public static function getName()
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
namespace Friendica\Model\Storage;
|
namespace Friendica\Model\Storage;
|
||||||
|
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config\IConfiguration;
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n\L10n;
|
||||||
use Friendica\Core\Logger;
|
|
||||||
use Friendica\Util\Strings;
|
use Friendica\Util\Strings;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Filesystem based storage backend
|
* @brief Filesystem based storage backend
|
||||||
|
@ -21,52 +21,72 @@ use Friendica\Util\Strings;
|
||||||
* Each new resource gets a value as reference and is saved in a
|
* Each new resource gets a value as reference and is saved in a
|
||||||
* folder tree stucture created from that value.
|
* folder tree stucture created from that value.
|
||||||
*/
|
*/
|
||||||
class Filesystem implements IStorage
|
class Filesystem extends AbstractStorage
|
||||||
{
|
{
|
||||||
|
const NAME = 'Filesystem';
|
||||||
|
|
||||||
// Default base folder
|
// Default base folder
|
||||||
const DEFAULT_BASE_FOLDER = 'storage';
|
const DEFAULT_BASE_FOLDER = 'storage';
|
||||||
|
|
||||||
private static function getBasePath()
|
/** @var IConfiguration */
|
||||||
|
private $config;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $basePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filesystem constructor.
|
||||||
|
*
|
||||||
|
* @param IConfiguration $config
|
||||||
|
* @param LoggerInterface $logger
|
||||||
|
* @param L10n $l10n
|
||||||
|
*/
|
||||||
|
public function __construct(IConfiguration $config, LoggerInterface $logger, L10n $l10n)
|
||||||
{
|
{
|
||||||
$path = Config::get('storage', 'filesystem_path', self::DEFAULT_BASE_FOLDER);
|
parent::__construct($l10n, $logger);
|
||||||
return rtrim($path, '/');
|
|
||||||
|
$this->config = $config;
|
||||||
|
|
||||||
|
$path = $this->config->get('storage', 'filesystem_path', self::DEFAULT_BASE_FOLDER);
|
||||||
|
$this->basePath = rtrim($path, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Split data ref and return file path
|
* @brief Split data ref and return file path
|
||||||
* @param string $ref Data reference
|
*
|
||||||
|
* @param string $reference Data reference
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private static function pathForRef($ref)
|
private function pathForRef(string $reference)
|
||||||
{
|
{
|
||||||
$base = self::getBasePath();
|
$fold1 = substr($reference, 0, 2);
|
||||||
$fold1 = substr($ref, 0, 2);
|
$fold2 = substr($reference, 2, 2);
|
||||||
$fold2 = substr($ref, 2, 2);
|
$file = substr($reference, 4);
|
||||||
$file = substr($ref, 4);
|
|
||||||
|
|
||||||
return implode('/', [$base, $fold1, $fold2, $file]);
|
return implode('/', [$this->basePath, $fold1, $fold2, $file]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create dirctory tree to store file, with .htaccess and index.html files
|
* @brief Create dirctory tree to store file, with .htaccess and index.html files
|
||||||
|
*
|
||||||
* @param string $file Path and filename
|
* @param string $file Path and filename
|
||||||
|
*
|
||||||
* @throws StorageException
|
* @throws StorageException
|
||||||
*/
|
*/
|
||||||
private static function createFoldersForFile($file)
|
private function createFoldersForFile(string $file)
|
||||||
{
|
{
|
||||||
$path = dirname($file);
|
$path = dirname($file);
|
||||||
|
|
||||||
if (!is_dir($path)) {
|
if (!is_dir($path)) {
|
||||||
if (!mkdir($path, 0770, true)) {
|
if (!mkdir($path, 0770, true)) {
|
||||||
Logger::log('Failed to create dirs ' . $path);
|
$this->logger->warning('Failed to create dir.', ['path' => $path]);
|
||||||
throw new StorageException(L10n::t('Filesystem storage failed to create "%s". Check you write permissions.', $path));
|
throw new StorageException($this->l10n->t('Filesystem storage failed to create "%s". Check you write permissions.', $path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$base = self::getBasePath();
|
while ($path !== $this->basePath) {
|
||||||
|
|
||||||
while ($path !== $base) {
|
|
||||||
if (!is_file($path . '/index.html')) {
|
if (!is_file($path . '/index.html')) {
|
||||||
file_put_contents($path . '/index.html', '');
|
file_put_contents($path . '/index.html', '');
|
||||||
}
|
}
|
||||||
|
@ -80,9 +100,12 @@ class Filesystem implements IStorage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function get($ref)
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get(string $reference)
|
||||||
{
|
{
|
||||||
$file = self::pathForRef($ref);
|
$file = $this->pathForRef($reference);
|
||||||
if (!is_file($file)) {
|
if (!is_file($file)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -90,27 +113,33 @@ class Filesystem implements IStorage
|
||||||
return file_get_contents($file);
|
return file_get_contents($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function put($data, $ref = '')
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function put(string $data, string $reference = '')
|
||||||
{
|
{
|
||||||
if ($ref === '') {
|
if ($reference === '') {
|
||||||
$ref = Strings::getRandomHex();
|
$reference = Strings::getRandomHex();
|
||||||
}
|
}
|
||||||
$file = self::pathForRef($ref);
|
$file = $this->pathForRef($reference);
|
||||||
|
|
||||||
self::createFoldersForFile($file);
|
$this->createFoldersForFile($file);
|
||||||
|
|
||||||
$r = file_put_contents($file, $data);
|
if (!file_put_contents($file, $data)) {
|
||||||
if ($r === FALSE) {
|
$this->logger->warning('Failed to write data.', ['file' => $file]);
|
||||||
Logger::log('Failed to write data to ' . $file);
|
throw new StorageException($this->l10n->t('Filesystem storage failed to save data to "%s". Check your write permissions', $file));
|
||||||
throw new StorageException(L10n::t('Filesystem storage failed to save data to "%s". Check your write permissions', $file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chmod($file, 0660);
|
chmod($file, 0660);
|
||||||
return $ref;
|
return $reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function delete($ref)
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function delete(string $reference)
|
||||||
{
|
{
|
||||||
$file = self::pathForRef($ref);
|
$file = $this->pathForRef($reference);
|
||||||
// return true if file doesn't exists. we want to delete it: success with zero work!
|
// return true if file doesn't exists. we want to delete it: success with zero work!
|
||||||
if (!is_file($file)) {
|
if (!is_file($file)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -118,28 +147,42 @@ class Filesystem implements IStorage
|
||||||
return unlink($file);
|
return unlink($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getOptions()
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getOptions()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'storagepath' => [
|
'storagepath' => [
|
||||||
'input',
|
'input',
|
||||||
L10n::t('Storage base path'),
|
$this->l10n->t('Storage base path'),
|
||||||
self::getBasePath(),
|
$this->basePath,
|
||||||
L10n::t('Folder where uploaded files are saved. For maximum security, This should be a path outside web server folder tree')
|
$this->l10n->t('Folder where uploaded files are saved. For maximum security, This should be a path outside web server folder tree')
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function saveOptions($data)
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function saveOptions(array $data)
|
||||||
{
|
{
|
||||||
$storagepath = $data['storagepath'] ?? '';
|
$storagePath = $data['storagepath'] ?? '';
|
||||||
if ($storagepath === '' || !is_dir($storagepath)) {
|
if ($storagePath === '' || !is_dir($storagePath)) {
|
||||||
return [
|
return [
|
||||||
'storagepath' => L10n::t('Enter a valid existing folder')
|
'storagepath' => $this->l10n->t('Enter a valid existing folder')
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
Config::set('storage', 'filesystem_path', $storagepath);
|
$this->config->set('storage', 'filesystem_path', $storagePath);
|
||||||
|
$this->basePath = $storagePath;
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public static function getName()
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,25 +13,31 @@ interface IStorage
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @brief Get data from backend
|
* @brief Get data from backend
|
||||||
* @param string $ref Data reference
|
*
|
||||||
|
* @param string $reference Data reference
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function get($ref);
|
public function get(string $reference);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Put data in backend as $ref. If $ref is not defined a new reference is created.
|
* @brief Put data in backend as $ref. If $ref is not defined a new reference is created.
|
||||||
* @param string $data Data to save
|
*
|
||||||
* @param string $ref Data referece. Optional.
|
* @param string $data Data to save
|
||||||
* @return string Saved data referece
|
* @param string $reference Data reference. Optional.
|
||||||
|
*
|
||||||
|
* @return string Saved data reference
|
||||||
*/
|
*/
|
||||||
public static function put($data, $ref = "");
|
public function put(string $data, string $reference = "");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Remove data from backend
|
* @brief Remove data from backend
|
||||||
* @param string $ref Data referece
|
*
|
||||||
|
* @param string $reference Data reference
|
||||||
|
*
|
||||||
* @return boolean True on success
|
* @return boolean True on success
|
||||||
*/
|
*/
|
||||||
public static function delete($ref);
|
public function delete(string $reference);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get info about storage options
|
* @brief Get info about storage options
|
||||||
|
@ -71,19 +77,30 @@ interface IStorage
|
||||||
*
|
*
|
||||||
* See https://github.com/friendica/friendica/wiki/Quick-Template-Guide
|
* See https://github.com/friendica/friendica/wiki/Quick-Template-Guide
|
||||||
*/
|
*/
|
||||||
public static function getOptions();
|
public function getOptions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Validate and save options
|
* @brief Validate and save options
|
||||||
*
|
*
|
||||||
* @param array $data Array [optionname => value] to be saved
|
* @param array $data Array [optionname => value] to be saved
|
||||||
*
|
*
|
||||||
* @return array Validation errors: [optionname => error message]
|
* @return array Validation errors: [optionname => error message]
|
||||||
*
|
*
|
||||||
* Return array must be empty if no error.
|
* Return array must be empty if no error.
|
||||||
*/
|
*/
|
||||||
public static function saveOptions($data);
|
public function saveOptions(array $data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the backend
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the backend
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,15 @@ use \BadMethodCallException;
|
||||||
*/
|
*/
|
||||||
class SystemResource implements IStorage
|
class SystemResource implements IStorage
|
||||||
{
|
{
|
||||||
|
const NAME = 'SystemResource';
|
||||||
|
|
||||||
// Valid folders to look for resources
|
// Valid folders to look for resources
|
||||||
const VALID_FOLDERS = ["images"];
|
const VALID_FOLDERS = ["images"];
|
||||||
|
|
||||||
public static function get($filename)
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get(string $filename)
|
||||||
{
|
{
|
||||||
$folder = dirname($filename);
|
$folder = dirname($filename);
|
||||||
if (!in_array($folder, self::VALID_FOLDERS)) {
|
if (!in_array($folder, self::VALID_FOLDERS)) {
|
||||||
|
@ -31,25 +36,48 @@ class SystemResource implements IStorage
|
||||||
return file_get_contents($filename);
|
return file_get_contents($filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
public static function put($data, $filename = "")
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function put(string $data, string $filename = '')
|
||||||
{
|
{
|
||||||
throw new BadMethodCallException();
|
throw new BadMethodCallException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function delete($filename)
|
public function delete(string $filename)
|
||||||
{
|
{
|
||||||
throw new BadMethodCallException();
|
throw new BadMethodCallException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getOptions()
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getOptions()
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function saveOptions($data)
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function saveOptions(array $data)
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public static function getName()
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
namespace Friendica\Model;
|
namespace Friendica\Model;
|
||||||
|
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
|
@ -57,7 +57,7 @@ class Term
|
||||||
*/
|
*/
|
||||||
public static function getGlobalTrendingHashtags(int $period, $limit = 10)
|
public static function getGlobalTrendingHashtags(int $period, $limit = 10)
|
||||||
{
|
{
|
||||||
$tags = Cache::get('global_trending_tags');
|
$tags = DI::cache()->get('global_trending_tags');
|
||||||
|
|
||||||
if (!$tags) {
|
if (!$tags) {
|
||||||
$tagsStmt = DBA::p("SELECT t.`term`, COUNT(*) AS `score`
|
$tagsStmt = DBA::p("SELECT t.`term`, COUNT(*) AS `score`
|
||||||
|
@ -84,7 +84,7 @@ class Term
|
||||||
|
|
||||||
if (DBA::isResult($tagsStmt)) {
|
if (DBA::isResult($tagsStmt)) {
|
||||||
$tags = DBA::toArray($tagsStmt);
|
$tags = DBA::toArray($tagsStmt);
|
||||||
Cache::set('global_trending_tags', $tags, Cache::HOUR);
|
DI::cache()->set('global_trending_tags', $tags, Cache::HOUR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ class Term
|
||||||
*/
|
*/
|
||||||
public static function getLocalTrendingHashtags(int $period, $limit = 10)
|
public static function getLocalTrendingHashtags(int $period, $limit = 10)
|
||||||
{
|
{
|
||||||
$tags = Cache::get('local_trending_tags');
|
$tags = DI::cache()->get('local_trending_tags');
|
||||||
|
|
||||||
if (!$tags) {
|
if (!$tags) {
|
||||||
$tagsStmt = DBA::p("SELECT t.`term`, COUNT(*) AS `score`
|
$tagsStmt = DBA::p("SELECT t.`term`, COUNT(*) AS `score`
|
||||||
|
@ -129,7 +129,7 @@ class Term
|
||||||
|
|
||||||
if (DBA::isResult($tagsStmt)) {
|
if (DBA::isResult($tagsStmt)) {
|
||||||
$tags = DBA::toArray($tagsStmt);
|
$tags = DBA::toArray($tagsStmt);
|
||||||
Cache::set('local_trending_tags', $tags, Cache::HOUR);
|
DI::cache()->set('local_trending_tags', $tags, Cache::HOUR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,168 +14,103 @@ class Federation extends BaseAdminModule
|
||||||
{
|
{
|
||||||
parent::content($parameters);
|
parent::content($parameters);
|
||||||
|
|
||||||
// get counts on active friendica, diaspora, redmatrix, hubzilla, gnu
|
// get counts on active federation systems this node is knowing
|
||||||
// social and statusnet nodes this node is knowing
|
// We list the more common systems by name. The rest is counted as "other"
|
||||||
//
|
$systems = [
|
||||||
// We are looking for the following platforms in the DB, "Red" should find
|
'Friendica' => ['name' => 'Friendica', 'color' => '#ffc018'], // orange from the logo
|
||||||
// all variants of that platform ID string as the q() function is stripping
|
'diaspora' => ['name' => 'Diaspora', 'color' => '#a1a1a1'], // logo is black and white, makes a gray
|
||||||
// off one % two of them are needed in the query
|
'funkwhale' => ['name' => 'Funkwhale', 'color' => '#4082B4'], // From the homepage
|
||||||
// Add more platforms if you like, when one returns 0 known nodes it is not
|
'gnusocial' => ['name' => 'GNU Social/Statusnet', 'color' => '#a22430'], // dark red from the logo
|
||||||
// displayed on the stats page.
|
'hubzilla' => ['name' => 'Hubzilla/Red Matrix', 'color' => '#43488a'], // blue from the logo
|
||||||
$platforms = ['Friendi%%a', 'Diaspora', '%%red%%', 'Hubzilla', 'BlaBlaNet', 'GNU Social', 'StatusNet', 'Mastodon', 'Pleroma', 'socialhome', 'ganggo'];
|
'mastodon' => ['name' => 'Mastodon', 'color' => '#1a9df9'], // blue from the Mastodon logo
|
||||||
$colors = [
|
'misskey' => ['name' => 'Misskey', 'color' => '#ccfefd'], // Font color of the homepage
|
||||||
'Friendi%%a' => '#ffc018', // orange from the logo
|
'peertube' => ['name' => 'Peertube', 'color' => '#ffad5c'], // One of the logo colors
|
||||||
'Diaspora' => '#a1a1a1', // logo is black and white, makes a gray
|
'pixelfed' => ['name' => 'Pixelfed', 'color' => '#11da47'], // One of the logo colors
|
||||||
'%%red%%' => '#c50001', // fire red from the logo
|
'pleroma' => ['name' => 'Pleroma', 'color' => '#E46F0F'], // Orange from the text that is used on Pleroma instances
|
||||||
'Hubzilla' => '#43488a', // blue from the logo
|
'plume' => ['name' => 'Plume', 'color' => '#7765e3'], // From the homepage
|
||||||
'BlaBlaNet' => '#3B5998', // blue from the navbar at blablanet-dot-com
|
'socialhome' => ['name' => 'SocialHome', 'color' => '#52056b'], // lilac from the Django Image used at the Socialhome homepage
|
||||||
'GNU Social' => '#a22430', // dark red from the logo
|
'wordpress' => ['name' => 'WordPress', 'color' => '#016087'], // Background color of the homepage
|
||||||
'StatusNet' => '#789240', // the green from the logo (red and blue have already others
|
'writefreely' => ['name' => 'WriteFreely', 'color' => '#292929'], // Font color of the homepage
|
||||||
'Mastodon' => '#1a9df9', // blue from the Mastodon logo
|
'other' => ['name' => L10n::t('Other'), 'color' => '#F1007E'], // ActivityPub main color
|
||||||
'Pleroma' => '#E46F0F', // Orange from the text that is used on Pleroma instances
|
|
||||||
'socialhome' => '#52056b', // lilac from the Django Image used at the Socialhome homepage
|
|
||||||
'ganggo' => '#69d7e2', // from the favicon
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$platforms = array_keys($systems);
|
||||||
|
|
||||||
$counts = [];
|
$counts = [];
|
||||||
|
foreach ($platforms as $platform) {
|
||||||
|
$counts[$platform] = [];
|
||||||
|
}
|
||||||
|
|
||||||
$total = 0;
|
$total = 0;
|
||||||
$users = 0;
|
$users = 0;
|
||||||
|
|
||||||
foreach ($platforms as $platform) {
|
$gservers = DBA::p("SELECT COUNT(*) AS `total`, SUM(`registered-users`) AS `users`, `platform`,
|
||||||
// get a total count for the platform, the name and version of the
|
ANY_VALUE(`network`) AS `network`, MAX(`version`) AS `version`
|
||||||
// highest version and the protocol tpe
|
FROM `gserver` WHERE `last_contact` >= `last_failure` GROUP BY `platform`");
|
||||||
$platformCount = DBA::fetchFirst('SELECT
|
while ($gserver = DBA::fetch($gservers)) {
|
||||||
COUNT(*) AS `total`,
|
$total += $gserver['total'];
|
||||||
SUM(`registered-users`) AS `users`,
|
$users += $gserver['users'];
|
||||||
ANY_VALUE(`platform`) AS `platform`,
|
|
||||||
ANY_VALUE(`network`) AS `network`,
|
|
||||||
MAX(`version`) AS `version` FROM `gserver`
|
|
||||||
WHERE `platform` LIKE ?
|
|
||||||
AND `last_contact` >= `last_failure`
|
|
||||||
ORDER BY `version` ASC', $platform);
|
|
||||||
$total += $platformCount['total'];
|
|
||||||
$users += $platformCount['users'];
|
|
||||||
|
|
||||||
// what versions for that platform do we know at all?
|
|
||||||
// again only the active nodes
|
|
||||||
$versionCountsStmt = DBA::p('SELECT
|
|
||||||
COUNT(*) AS `total`,
|
|
||||||
`version` FROM `gserver`
|
|
||||||
WHERE `last_contact` >= `last_failure`
|
|
||||||
AND `platform` LIKE ?
|
|
||||||
GROUP BY `version`
|
|
||||||
ORDER BY `version`;', $platform);
|
|
||||||
$versionCounts = DBA::toArray($versionCountsStmt);
|
|
||||||
|
|
||||||
//
|
|
||||||
// clean up version numbers
|
|
||||||
//
|
|
||||||
// some platforms do not provide version information, add a unkown there
|
|
||||||
// to the version string for the displayed list.
|
|
||||||
foreach ($versionCounts as $key => $value) {
|
|
||||||
if ($versionCounts[$key]['version'] == '') {
|
|
||||||
$versionCounts[$key] = ['total' => $versionCounts[$key]['total'], 'version' => L10n::t('unknown')];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reformat and compact version numbers
|
|
||||||
if ($platform == 'Pleroma') {
|
|
||||||
$compacted = [];
|
|
||||||
foreach ($versionCounts as $key => $value) {
|
|
||||||
$version = $versionCounts[$key]['version'];
|
|
||||||
$parts = explode(' ', trim($version));
|
|
||||||
do {
|
|
||||||
$part = array_pop($parts);
|
|
||||||
} while (!empty($parts) && ((strlen($part) >= 40) || (strlen($part) <= 3)));
|
|
||||||
// only take the x.x.x part of the version, not the "release" after the dash
|
|
||||||
if (!empty($part) && strpos($part, '-')) {
|
|
||||||
$part = explode('-', $part)[0];
|
|
||||||
}
|
|
||||||
if (!empty($part)) {
|
|
||||||
if (empty($compacted[$part])) {
|
|
||||||
$compacted[$part] = $versionCounts[$key]['total'];
|
|
||||||
} else {
|
|
||||||
$compacted[$part] += $versionCounts[$key]['total'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$versionCounts = [];
|
|
||||||
foreach ($compacted as $version => $pl_total) {
|
|
||||||
$versionCounts[] = ['version' => $version, 'total' => $pl_total];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// in the DB the Diaspora versions have the format x.x.x.x-xx the last
|
|
||||||
// part (-xx) should be removed to clean up the versions from the "head
|
|
||||||
// commit" information and combined into a single entry for x.x.x.x
|
|
||||||
if ($platform == 'Diaspora') {
|
|
||||||
$newV = [];
|
|
||||||
$newVv = [];
|
|
||||||
foreach ($versionCounts as $vv) {
|
|
||||||
$newVC = $vv['total'];
|
|
||||||
$newVV = $vv['version'];
|
|
||||||
$posDash = strpos($newVV, '-');
|
|
||||||
if ($posDash) {
|
|
||||||
$newVV = substr($newVV, 0, $posDash);
|
|
||||||
}
|
|
||||||
if (isset($newV[$newVV])) {
|
|
||||||
$newV[$newVV] += $newVC;
|
|
||||||
} else {
|
|
||||||
$newV[$newVV] = $newVC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach ($newV as $key => $value) {
|
|
||||||
array_push($newVv, ['total' => $value, 'version' => $key]);
|
|
||||||
}
|
|
||||||
$versionCounts = $newVv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// early friendica versions have the format x.x.xxxx where xxxx is the
|
|
||||||
// DB version stamp; those should be operated out and versions be
|
|
||||||
// conbined
|
|
||||||
if ($platform == 'Friendi%%a') {
|
|
||||||
$newV = [];
|
|
||||||
$newVv = [];
|
|
||||||
foreach ($versionCounts as $vv) {
|
|
||||||
$newVC = $vv['total'];
|
|
||||||
$newVV = $vv['version'];
|
|
||||||
$lastDot = strrpos($newVV, '.');
|
|
||||||
$len = strlen($newVV) - 1;
|
|
||||||
if (($lastDot == $len - 4) && (!strrpos($newVV, '-rc') == $len - 3)) {
|
|
||||||
$newVV = substr($newVV, 0, $lastDot);
|
|
||||||
}
|
|
||||||
if (isset($newV[$newVV])) {
|
|
||||||
$newV[$newVV] += $newVC;
|
|
||||||
} else {
|
|
||||||
$newV[$newVV] = $newVC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach ($newV as $key => $value) {
|
|
||||||
array_push($newVv, ['total' => $value, 'version' => $key]);
|
|
||||||
}
|
|
||||||
$versionCounts = $newVv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assure that the versions are sorted correctly
|
|
||||||
$v2 = [];
|
|
||||||
$versions = [];
|
|
||||||
foreach ($versionCounts as $vv) {
|
|
||||||
$version = trim(strip_tags($vv["version"]));
|
|
||||||
$v2[$version] = $vv;
|
|
||||||
$versions[] = $version;
|
|
||||||
}
|
|
||||||
|
|
||||||
usort($versions, 'version_compare');
|
|
||||||
|
|
||||||
$versionCounts = [];
|
$versionCounts = [];
|
||||||
foreach ($versions as $version) {
|
$versions = DBA::p("SELECT COUNT(*) AS `total`, `version` FROM `gserver`
|
||||||
$versionCounts[] = $v2[$version];
|
WHERE `last_contact` >= `last_failure` AND `platform` = ?
|
||||||
|
GROUP BY `version` ORDER BY `version`", $gserver['platform']);
|
||||||
|
while ($version = DBA::fetch($versions)) {
|
||||||
|
$version['version'] = str_replace(["\n", "\r", "\t"], " ", $version['version']);
|
||||||
|
|
||||||
|
if (in_array($gserver['platform'], ['Red Matrix', 'redmatrix', 'red'])) {
|
||||||
|
$version['version'] = 'Red ' . $version['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$versionCounts[] = $version;
|
||||||
|
}
|
||||||
|
DBA::close($versions);
|
||||||
|
|
||||||
|
$platform = $gserver['platform'];
|
||||||
|
|
||||||
|
if ($platform == 'Friendika') {
|
||||||
|
$platform = 'Friendica';
|
||||||
|
} elseif (in_array($platform, ['Red Matrix', 'redmatrix', 'red'])) {
|
||||||
|
$platform = 'hubzilla';
|
||||||
|
} elseif(stristr($platform, 'pleroma')) {
|
||||||
|
$platform = 'pleroma';
|
||||||
|
} elseif(stristr($platform, 'statusnet')) {
|
||||||
|
$platform = 'gnusocial';
|
||||||
|
} elseif(stristr($platform, 'wordpress')) {
|
||||||
|
$platform = 'wordpress';
|
||||||
|
} elseif (!in_array($platform, $platforms)) {
|
||||||
|
$platform = 'other';
|
||||||
}
|
}
|
||||||
|
|
||||||
// the 3rd array item is needed for the JavaScript graphs as JS does
|
if ($platform != $gserver['platform']) {
|
||||||
// not like some characters in the names of variables...
|
if ($platform == 'other') {
|
||||||
$counts[$platform] = [$platformCount, $versionCounts, str_replace([' ', '%'], '', $platform), $colors[$platform]];
|
$versionCounts = $counts[$platform][1] ?? [];
|
||||||
|
$versionCounts[] = ['version' => $gserver['platform'] ?: L10n::t('unknown'), 'total' => $gserver['total']];
|
||||||
|
$gserver['version'] = '';
|
||||||
|
} else {
|
||||||
|
$versionCounts = array_merge($versionCounts, $counts[$platform][1] ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
|
$gserver['platform'] = $platform;
|
||||||
|
$gserver['total'] += $counts[$platform][0]['total'] ?? 0;
|
||||||
|
$gserver['users'] += $counts[$platform][0]['users'] ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($platform == 'Friendica') {
|
||||||
|
$versionCounts = self::reformaFriendicaVersions($versionCounts);
|
||||||
|
} elseif ($platform == 'pleroma') {
|
||||||
|
$versionCounts = self::reformaPleromaVersions($versionCounts);
|
||||||
|
} elseif ($platform == 'diaspora') {
|
||||||
|
$versionCounts = self::reformaDiasporaVersions($versionCounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
$versionCounts = self::sortVersion($versionCounts);
|
||||||
|
|
||||||
|
$gserver['platform'] = $systems[$platform]['name'];
|
||||||
|
|
||||||
|
$counts[$platform] = [$gserver, $versionCounts, str_replace([' ', '%'], '', $platform), $systems[$platform]['color']];
|
||||||
}
|
}
|
||||||
|
DBA::close($gserver);
|
||||||
|
|
||||||
// some helpful text
|
// some helpful text
|
||||||
$intro = L10n::t('This page offers you some numbers to the known part of the federated social network your Friendica node is part of. These numbers are not complete but only reflect the part of the network your node is aware of.');
|
$intro = L10n::t('This page offers you some numbers to the known part of the federated social network your Friendica node is part of. These numbers are not complete but only reflect the part of the network your node is aware of.');
|
||||||
|
@ -194,4 +129,144 @@ class Federation extends BaseAdminModule
|
||||||
'$legendtext' => L10n::t('Currently this node is aware of %d nodes with %d registered users from the following platforms:', $total, $users),
|
'$legendtext' => L10n::t('Currently this node is aware of %d nodes with %d registered users from the following platforms:', $total, $users),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* early friendica versions have the format x.x.xxxx where xxxx is the
|
||||||
|
* DB version stamp; those should be operated out and versions be combined
|
||||||
|
*
|
||||||
|
* @param array $versionCounts list of version numbers
|
||||||
|
* @return array with cleaned version numbers
|
||||||
|
*/
|
||||||
|
private static function reformaFriendicaVersions(array $versionCounts)
|
||||||
|
{
|
||||||
|
$newV = [];
|
||||||
|
$newVv = [];
|
||||||
|
foreach ($versionCounts as $vv) {
|
||||||
|
$newVC = $vv['total'];
|
||||||
|
$newVV = $vv['version'];
|
||||||
|
$lastDot = strrpos($newVV, '.');
|
||||||
|
$len = strlen($newVV) - 1;
|
||||||
|
if (($lastDot == $len - 4) && (!strrpos($newVV, '-rc') == $len - 3)) {
|
||||||
|
$newVV = substr($newVV, 0, $lastDot);
|
||||||
|
}
|
||||||
|
if (isset($newV[$newVV])) {
|
||||||
|
$newV[$newVV] += $newVC;
|
||||||
|
} else {
|
||||||
|
$newV[$newVV] = $newVC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($newV as $key => $value) {
|
||||||
|
array_push($newVv, ['total' => $value, 'version' => $key]);
|
||||||
|
}
|
||||||
|
$versionCounts = $newVv;
|
||||||
|
|
||||||
|
return $versionCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* in the DB the Diaspora versions have the format x.x.x.x-xx the last
|
||||||
|
* part (-xx) should be removed to clean up the versions from the "head
|
||||||
|
* commit" information and combined into a single entry for x.x.x.x
|
||||||
|
*
|
||||||
|
* @param array $versionCounts list of version numbers
|
||||||
|
* @return array with cleaned version numbers
|
||||||
|
*/
|
||||||
|
private static function reformaDiasporaVersions(array $versionCounts)
|
||||||
|
{
|
||||||
|
$newV = [];
|
||||||
|
$newVv = [];
|
||||||
|
foreach ($versionCounts as $vv) {
|
||||||
|
$newVC = $vv['total'];
|
||||||
|
$newVV = $vv['version'];
|
||||||
|
$posDash = strpos($newVV, '-');
|
||||||
|
if ($posDash) {
|
||||||
|
$newVV = substr($newVV, 0, $posDash);
|
||||||
|
}
|
||||||
|
if (isset($newV[$newVV])) {
|
||||||
|
$newV[$newVV] += $newVC;
|
||||||
|
} else {
|
||||||
|
$newV[$newVV] = $newVC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($newV as $key => $value) {
|
||||||
|
array_push($newVv, ['total' => $value, 'version' => $key]);
|
||||||
|
}
|
||||||
|
$versionCounts = $newVv;
|
||||||
|
|
||||||
|
return $versionCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up Pleroma version numbers
|
||||||
|
*
|
||||||
|
* @param array $versionCounts list of version numbers
|
||||||
|
* @return array with cleaned version numbers
|
||||||
|
*/
|
||||||
|
private static function reformaPleromaVersions(array $versionCounts)
|
||||||
|
{
|
||||||
|
$compacted = [];
|
||||||
|
foreach ($versionCounts as $key => $value) {
|
||||||
|
$version = $versionCounts[$key]['version'];
|
||||||
|
$parts = explode(' ', trim($version));
|
||||||
|
do {
|
||||||
|
$part = array_pop($parts);
|
||||||
|
} while (!empty($parts) && ((strlen($part) >= 40) || (strlen($part) <= 3)));
|
||||||
|
// only take the x.x.x part of the version, not the "release" after the dash
|
||||||
|
if (!empty($part) && strpos($part, '-')) {
|
||||||
|
$part = explode('-', $part)[0];
|
||||||
|
}
|
||||||
|
if (!empty($part)) {
|
||||||
|
if (empty($compacted[$part])) {
|
||||||
|
$compacted[$part] = $versionCounts[$key]['total'];
|
||||||
|
} else {
|
||||||
|
$compacted[$part] += $versionCounts[$key]['total'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$versionCounts = [];
|
||||||
|
foreach ($compacted as $version => $pl_total) {
|
||||||
|
$versionCounts[] = ['version' => $version, 'total' => $pl_total];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $versionCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reformat, sort and compact version numbers
|
||||||
|
*
|
||||||
|
* @param array $versionCounts list of version numbers
|
||||||
|
* @return array with reformatted version numbers
|
||||||
|
*/
|
||||||
|
private static function sortVersion(array $versionCounts)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// clean up version numbers
|
||||||
|
//
|
||||||
|
// some platforms do not provide version information, add a unkown there
|
||||||
|
// to the version string for the displayed list.
|
||||||
|
foreach ($versionCounts as $key => $value) {
|
||||||
|
if ($versionCounts[$key]['version'] == '') {
|
||||||
|
$versionCounts[$key] = ['total' => $versionCounts[$key]['total'], 'version' => L10n::t('unknown')];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assure that the versions are sorted correctly
|
||||||
|
$v2 = [];
|
||||||
|
$versions = [];
|
||||||
|
foreach ($versionCounts as $vv) {
|
||||||
|
$version = trim(strip_tags($vv["version"]));
|
||||||
|
$v2[$version] = $vv;
|
||||||
|
$versions[] = $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
usort($versions, 'version_compare');
|
||||||
|
|
||||||
|
$versionCounts = [];
|
||||||
|
foreach ($versions as $version) {
|
||||||
|
$versionCounts[] = $v2[$version];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $versionCounts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,42 +199,37 @@ class Site extends BaseAdminModule
|
||||||
$relay_user_tags = !empty($_POST['relay_user_tags']);
|
$relay_user_tags = !empty($_POST['relay_user_tags']);
|
||||||
$active_panel = (!empty($_POST['active_panel']) ? "#" . Strings::escapeTags(trim($_POST['active_panel'])) : '');
|
$active_panel = (!empty($_POST['active_panel']) ? "#" . Strings::escapeTags(trim($_POST['active_panel'])) : '');
|
||||||
|
|
||||||
/**
|
|
||||||
* @var $storagebackend \Friendica\Model\Storage\IStorage
|
|
||||||
*/
|
|
||||||
$storagebackend = Strings::escapeTags(trim($_POST['storagebackend'] ?? ''));
|
$storagebackend = Strings::escapeTags(trim($_POST['storagebackend'] ?? ''));
|
||||||
|
|
||||||
// save storage backend form
|
// save storage backend form
|
||||||
if (!is_null($storagebackend) && $storagebackend != "") {
|
if (DI::storageManager()->setBackend($storagebackend)) {
|
||||||
if (StorageManager::setBackend($storagebackend)) {
|
$storage_opts = DI::storage()->getOptions();
|
||||||
$storage_opts = $storagebackend::getOptions();
|
$storage_form_prefix = preg_replace('|[^a-zA-Z0-9]|', '', $storagebackend);
|
||||||
$storage_form_prefix = preg_replace('|[^a-zA-Z0-9]|', '', $storagebackend);
|
$storage_opts_data = [];
|
||||||
$storage_opts_data = [];
|
foreach ($storage_opts as $name => $info) {
|
||||||
foreach ($storage_opts as $name => $info) {
|
$fieldname = $storage_form_prefix . '_' . $name;
|
||||||
$fieldname = $storage_form_prefix . '_' . $name;
|
switch ($info[0]) { // type
|
||||||
switch ($info[0]) { // type
|
case 'checkbox':
|
||||||
case 'checkbox':
|
case 'yesno':
|
||||||
case 'yesno':
|
$value = !empty($_POST[$fieldname]);
|
||||||
$value = !empty($_POST[$fieldname]);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
$value = $_POST[$fieldname] ?? '';
|
||||||
$value = $_POST[$fieldname] ?? '';
|
|
||||||
}
|
|
||||||
$storage_opts_data[$name] = $value;
|
|
||||||
}
|
}
|
||||||
unset($name);
|
$storage_opts_data[$name] = $value;
|
||||||
unset($info);
|
|
||||||
|
|
||||||
$storage_form_errors = $storagebackend::saveOptions($storage_opts_data);
|
|
||||||
if (count($storage_form_errors)) {
|
|
||||||
foreach ($storage_form_errors as $name => $err) {
|
|
||||||
notice('Storage backend, ' . $storage_opts[$name][1] . ': ' . $err);
|
|
||||||
}
|
|
||||||
DI::baseUrl()->redirect('admin/site' . $active_panel);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
info(L10n::t('Invalid storage backend setting value.'));
|
|
||||||
}
|
}
|
||||||
|
unset($name);
|
||||||
|
unset($info);
|
||||||
|
|
||||||
|
$storage_form_errors = DI::storage()->saveOptions($storage_opts_data);
|
||||||
|
if (count($storage_form_errors)) {
|
||||||
|
foreach ($storage_form_errors as $name => $err) {
|
||||||
|
notice('Storage backend, ' . $storage_opts[$name][1] . ': ' . $err);
|
||||||
|
}
|
||||||
|
DI::baseUrl()->redirect('admin/site' . $active_panel);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info(L10n::t('Invalid storage backend setting value.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has the directory url changed? If yes, then resubmit the existing profiles there
|
// Has the directory url changed? If yes, then resubmit the existing profiles there
|
||||||
|
@ -530,29 +525,25 @@ class Site extends BaseAdminModule
|
||||||
$optimize_max_tablesize = -1;
|
$optimize_max_tablesize = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$storage_backends = StorageManager::listBackends();
|
$current_storage_backend = DI::storage();
|
||||||
/** @var $current_storage_backend \Friendica\Model\Storage\IStorage */
|
|
||||||
$current_storage_backend = StorageManager::getBackend();
|
|
||||||
|
|
||||||
$available_storage_backends = [];
|
$available_storage_backends = [];
|
||||||
|
|
||||||
// show legacy option only if it is the current backend:
|
// show legacy option only if it is the current backend:
|
||||||
// once changed can't be selected anymore
|
// once changed can't be selected anymore
|
||||||
if ($current_storage_backend == '') {
|
if ($current_storage_backend == null) {
|
||||||
$available_storage_backends[''] = L10n::t('Database (legacy)');
|
$available_storage_backends[''] = L10n::t('Database (legacy)');
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($storage_backends as $name => $class) {
|
foreach (DI::storageManager()->listBackends() as $name => $class) {
|
||||||
$available_storage_backends[$class] = $name;
|
$available_storage_backends[$name] = $name;
|
||||||
}
|
}
|
||||||
unset($storage_backends);
|
|
||||||
|
|
||||||
// build storage config form,
|
// build storage config form,
|
||||||
$storage_form_prefix = preg_replace('|[^a-zA-Z0-9]|' ,'', $current_storage_backend);
|
$storage_form_prefix = preg_replace('|[^a-zA-Z0-9]|' ,'', $current_storage_backend);
|
||||||
|
|
||||||
$storage_form = [];
|
$storage_form = [];
|
||||||
if (!is_null($current_storage_backend) && $current_storage_backend != '') {
|
if (!is_null($current_storage_backend) && $current_storage_backend != '') {
|
||||||
foreach ($current_storage_backend::getOptions() as $name => $info) {
|
foreach ($current_storage_backend->getOptions() as $name => $info) {
|
||||||
$type = $info[0];
|
$type = $info[0];
|
||||||
$info[0] = $storage_form_prefix . '_' . $name;
|
$info[0] = $storage_form_prefix . '_' . $name;
|
||||||
$info['type'] = $type;
|
$info['type'] = $type;
|
||||||
|
|
|
@ -2,13 +2,10 @@
|
||||||
|
|
||||||
namespace Friendica\Module\Search;
|
namespace Friendica\Module\Search;
|
||||||
|
|
||||||
use Friendica\App\Arguments;
|
|
||||||
use Friendica\App\BaseURL;
|
|
||||||
use Friendica\Content\Nav;
|
use Friendica\Content\Nav;
|
||||||
use Friendica\Content\Pager;
|
use Friendica\Content\Pager;
|
||||||
use Friendica\Content\Text\HTML;
|
use Friendica\Content\Text\HTML;
|
||||||
use Friendica\Content\Widget;
|
use Friendica\Content\Widget;
|
||||||
use Friendica\Core\Cache;
|
|
||||||
use Friendica\Core\Cache\Cache as CacheClass;
|
use Friendica\Core\Cache\Cache as CacheClass;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n;
|
||||||
|
@ -53,15 +50,15 @@ class Index extends BaseSearchModule
|
||||||
$crawl_permit_period = 10;
|
$crawl_permit_period = 10;
|
||||||
|
|
||||||
$remote = $_SERVER['REMOTE_ADDR'];
|
$remote = $_SERVER['REMOTE_ADDR'];
|
||||||
$result = Cache::get('remote_search:' . $remote);
|
$result = DI::cache()->get('remote_search:' . $remote);
|
||||||
if (!is_null($result)) {
|
if (!is_null($result)) {
|
||||||
$resultdata = json_decode($result);
|
$resultdata = json_decode($result);
|
||||||
if (($resultdata->time > (time() - $crawl_permit_period)) && ($resultdata->accesses > $free_crawls)) {
|
if (($resultdata->time > (time() - $crawl_permit_period)) && ($resultdata->accesses > $free_crawls)) {
|
||||||
throw new HTTPException\TooManyRequestsException(L10n::t('Only one search per minute is permitted for not logged in users.'));
|
throw new HTTPException\TooManyRequestsException(L10n::t('Only one search per minute is permitted for not logged in users.'));
|
||||||
}
|
}
|
||||||
Cache::set('remote_search:' . $remote, json_encode(['time' => time(), 'accesses' => $resultdata->accesses + 1]), CacheClass::HOUR);
|
DI::cache()->set('remote_search:' . $remote, json_encode(['time' => time(), 'accesses' => $resultdata->accesses + 1]), CacheClass::HOUR);
|
||||||
} else {
|
} else {
|
||||||
Cache::set('remote_search:' . $remote, json_encode(['time' => time(), 'accesses' => 1]), CacheClass::HOUR);
|
DI::cache()->set('remote_search:' . $remote, json_encode(['time' => time(), 'accesses' => 1]), CacheClass::HOUR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Friendica\Network;
|
||||||
|
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
use DomXPath;
|
use DomXPath;
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Core\Protocol;
|
use Friendica\Core\Protocol;
|
||||||
|
@ -332,7 +332,7 @@ class Probe
|
||||||
public static function uri($uri, $network = '', $uid = -1, $cache = true)
|
public static function uri($uri, $network = '', $uid = -1, $cache = true)
|
||||||
{
|
{
|
||||||
if ($cache) {
|
if ($cache) {
|
||||||
$result = Cache::get('Probe::uri:' . $network . ':' . $uri);
|
$result = DI::cache()->get('Probe::uri:' . $network . ':' . $uri);
|
||||||
if (!is_null($result)) {
|
if (!is_null($result)) {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
@ -409,7 +409,7 @@ class Probe
|
||||||
|
|
||||||
// Only store into the cache if the value seems to be valid
|
// Only store into the cache if the value seems to be valid
|
||||||
if (!in_array($data['network'], [Protocol::PHANTOM, Protocol::MAIL])) {
|
if (!in_array($data['network'], [Protocol::PHANTOM, Protocol::MAIL])) {
|
||||||
Cache::set('Probe::uri:' . $network . ':' . $uri, $data, Cache::DAY);
|
DI::cache()->set('Probe::uri:' . $network . ':' . $uri, $data, Cache::DAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace Friendica\Protocol\ActivityPub;
|
||||||
use Friendica\Content\Feature;
|
use Friendica\Content\Feature;
|
||||||
use Friendica\Content\Text\BBCode;
|
use Friendica\Content\Text\BBCode;
|
||||||
use Friendica\Content\Text\Plaintext;
|
use Friendica\Content\Text\Plaintext;
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Core\Protocol;
|
use Friendica\Core\Protocol;
|
||||||
|
@ -819,7 +819,7 @@ class Transmitter
|
||||||
$cachekey = 'APDelivery:createActivity:' . $item_id;
|
$cachekey = 'APDelivery:createActivity:' . $item_id;
|
||||||
|
|
||||||
if (!$force) {
|
if (!$force) {
|
||||||
$data = Cache::get($cachekey);
|
$data = DI::cache()->get($cachekey);
|
||||||
if (!is_null($data)) {
|
if (!is_null($data)) {
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
@ -827,7 +827,7 @@ class Transmitter
|
||||||
|
|
||||||
$data = ActivityPub\Transmitter::createActivityFromItem($item_id);
|
$data = ActivityPub\Transmitter::createActivityFromItem($item_id);
|
||||||
|
|
||||||
Cache::set($cachekey, $data, Cache::QUARTER_HOUR);
|
DI::cache()->set($cachekey, $data, Cache::QUARTER_HOUR);
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Friendica\Protocol;
|
||||||
use Friendica\Content\Feature;
|
use Friendica\Content\Feature;
|
||||||
use Friendica\Content\Text\BBCode;
|
use Friendica\Content\Text\BBCode;
|
||||||
use Friendica\Content\Text\Markdown;
|
use Friendica\Content\Text\Markdown;
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
|
@ -3246,7 +3246,7 @@ class Diaspora
|
||||||
|
|
||||||
$cachekey = "diaspora:sendParticipation:".$item['guid'];
|
$cachekey = "diaspora:sendParticipation:".$item['guid'];
|
||||||
|
|
||||||
$result = Cache::get($cachekey);
|
$result = DI::cache()->get($cachekey);
|
||||||
if (!is_null($result)) {
|
if (!is_null($result)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3272,7 +3272,7 @@ class Diaspora
|
||||||
Logger::log("Send participation for ".$item["guid"]." by ".$author, Logger::DEBUG);
|
Logger::log("Send participation for ".$item["guid"]." by ".$author, Logger::DEBUG);
|
||||||
|
|
||||||
// It doesn't matter what we store, we only want to avoid sending repeated notifications for the same item
|
// It doesn't matter what we store, we only want to avoid sending repeated notifications for the same item
|
||||||
Cache::set($cachekey, $item["guid"], Cache::QUARTER_HOUR);
|
DI::cache()->set($cachekey, $item["guid"], Cache::QUARTER_HOUR);
|
||||||
|
|
||||||
return self::buildAndTransmit($owner, $contact, "participation", $message);
|
return self::buildAndTransmit($owner, $contact, "participation", $message);
|
||||||
}
|
}
|
||||||
|
@ -3524,7 +3524,7 @@ class Diaspora
|
||||||
{
|
{
|
||||||
$cachekey = "diaspora:buildStatus:".$item['guid'];
|
$cachekey = "diaspora:buildStatus:".$item['guid'];
|
||||||
|
|
||||||
$result = Cache::get($cachekey);
|
$result = DI::cache()->get($cachekey);
|
||||||
if (!is_null($result)) {
|
if (!is_null($result)) {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
@ -3628,7 +3628,7 @@ class Diaspora
|
||||||
|
|
||||||
$msg = ["type" => $type, "message" => $message];
|
$msg = ["type" => $type, "message" => $message];
|
||||||
|
|
||||||
Cache::set($cachekey, $msg, Cache::QUARTER_HOUR);
|
DI::cache()->set($cachekey, $msg, Cache::QUARTER_HOUR);
|
||||||
|
|
||||||
return $msg;
|
return $msg;
|
||||||
}
|
}
|
||||||
|
@ -3749,7 +3749,7 @@ class Diaspora
|
||||||
{
|
{
|
||||||
$cachekey = "diaspora:constructComment:".$item['guid'];
|
$cachekey = "diaspora:constructComment:".$item['guid'];
|
||||||
|
|
||||||
$result = Cache::get($cachekey);
|
$result = DI::cache()->get($cachekey);
|
||||||
if (!is_null($result)) {
|
if (!is_null($result)) {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
@ -3798,7 +3798,7 @@ class Diaspora
|
||||||
$comment['thread_parent_guid'] = $thread_parent_item['guid'];
|
$comment['thread_parent_guid'] = $thread_parent_item['guid'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache::set($cachekey, $comment, Cache::QUARTER_HOUR);
|
DI::cache()->set($cachekey, $comment, Cache::QUARTER_HOUR);
|
||||||
|
|
||||||
return($comment);
|
return($comment);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use DOMDocument;
|
||||||
use DOMXPath;
|
use DOMXPath;
|
||||||
use Friendica\Content\Text\BBCode;
|
use Friendica\Content\Text\BBCode;
|
||||||
use Friendica\Content\Text\HTML;
|
use Friendica\Content\Text\HTML;
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\L10n;
|
use Friendica\Core\L10n;
|
||||||
use Friendica\Core\Lock;
|
use Friendica\Core\Lock;
|
||||||
|
@ -2185,7 +2185,7 @@ class OStatus
|
||||||
|
|
||||||
// Don't cache when the last item was posted less then 15 minutes ago (Cache duration)
|
// Don't cache when the last item was posted less then 15 minutes ago (Cache duration)
|
||||||
if ((time() - strtotime($owner['last-item'])) < 15*60) {
|
if ((time() - strtotime($owner['last-item'])) < 15*60) {
|
||||||
$result = Cache::get($cachekey);
|
$result = DI::cache()->get($cachekey);
|
||||||
if (!$nocache && !is_null($result)) {
|
if (!$nocache && !is_null($result)) {
|
||||||
Logger::log('Feed duration: ' . number_format(microtime(true) - $stamp, 3) . ' - ' . $owner_nick . ' - ' . $filter . ' - ' . $previous_created . ' (cached)', Logger::DEBUG);
|
Logger::log('Feed duration: ' . number_format(microtime(true) - $stamp, 3) . ' - ' . $owner_nick . ' - ' . $filter . ' - ' . $previous_created . ' (cached)', Logger::DEBUG);
|
||||||
$last_update = $result['last_update'];
|
$last_update = $result['last_update'];
|
||||||
|
@ -2246,7 +2246,7 @@ class OStatus
|
||||||
$feeddata = trim($doc->saveXML());
|
$feeddata = trim($doc->saveXML());
|
||||||
|
|
||||||
$msg = ['feed' => $feeddata, 'last_update' => $last_update];
|
$msg = ['feed' => $feeddata, 'last_update' => $last_update];
|
||||||
Cache::set($cachekey, $msg, Cache::QUARTER_HOUR);
|
DI::cache()->set($cachekey, $msg, Cache::QUARTER_HOUR);
|
||||||
|
|
||||||
Logger::log('Feed duration: ' . number_format(microtime(true) - $stamp, 3) . ' - ' . $owner_nick . ' - ' . $filter . ' - ' . $previous_created, Logger::DEBUG);
|
Logger::log('Feed duration: ' . number_format(microtime(true) - $stamp, 3) . ' - ' . $owner_nick . ' - ' . $filter . ' - ' . $previous_created, Logger::DEBUG);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace Friendica\Util;
|
namespace Friendica\Util;
|
||||||
|
|
||||||
use Friendica\Core\Cache;
|
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Core\System;
|
use Friendica\Core\System;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
|
@ -125,12 +124,12 @@ class Images
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = Cache::get($url);
|
$data = DI::cache()->get($url);
|
||||||
|
|
||||||
if (empty($data) || !is_array($data)) {
|
if (empty($data) || !is_array($data)) {
|
||||||
$data = self::getInfoFromURL($url);
|
$data = self::getInfoFromURL($url);
|
||||||
|
|
||||||
Cache::set($url, $data);
|
DI::cache()->set($url, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
*/
|
*/
|
||||||
namespace Friendica\Util;
|
namespace Friendica\Util;
|
||||||
|
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Friendica\DI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This class contain methods to work with JsonLD data
|
* @brief This class contain methods to work with JsonLD data
|
||||||
|
@ -39,13 +40,13 @@ class JsonLD
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = Cache::get('documentLoader:' . $url);
|
$result = DI::cache()->get('documentLoader:' . $url);
|
||||||
if (!is_null($result)) {
|
if (!is_null($result)) {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = jsonld_default_document_loader($url);
|
$data = jsonld_default_document_loader($url);
|
||||||
Cache::set('documentLoader:' . $url, $data, Cache::DAY);
|
DI::cache()->set('documentLoader:' . $url, $data, Cache::DAY);
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,8 @@ class Cron
|
||||||
// check upstream version?
|
// check upstream version?
|
||||||
Worker::add(PRIORITY_LOW, 'CheckVersion');
|
Worker::add(PRIORITY_LOW, 'CheckVersion');
|
||||||
|
|
||||||
|
self::checkdeletedContacts();
|
||||||
|
|
||||||
Config::set('system', 'last_expire_day', $d2);
|
Config::set('system', 'last_expire_day', $d2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +123,19 @@ class Cron
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for contacts that are about to be deleted and ensures that they are removed.
|
||||||
|
* This should be done automatically in the "remove" function. This here is a cleanup job.
|
||||||
|
*/
|
||||||
|
private static function checkdeletedContacts()
|
||||||
|
{
|
||||||
|
$contacts = DBA::select('contact', ['id'], ['deleted' => true]);
|
||||||
|
while ($contact = DBA::fetch($contacts)) {
|
||||||
|
Worker::add(PRIORITY_MEDIUM, 'RemoveContact', $contact['id']);
|
||||||
|
}
|
||||||
|
DBA::close($contacts);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update public contacts
|
* @brief Update public contacts
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
namespace Friendica\Worker;
|
namespace Friendica\Worker;
|
||||||
|
|
||||||
use Friendica\App;
|
use Friendica\App;
|
||||||
use Friendica\Core\Cache;
|
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Core\Protocol;
|
use Friendica\Core\Protocol;
|
||||||
|
@ -154,7 +153,7 @@ class CronJobs
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear old cache
|
// clear old cache
|
||||||
Cache::clear();
|
DI::cache()->clear();
|
||||||
|
|
||||||
// clear old item cache files
|
// clear old item cache files
|
||||||
clear_cache();
|
clear_cache();
|
||||||
|
@ -324,8 +323,8 @@ class CronJobs
|
||||||
*/
|
*/
|
||||||
private static function moveStorage()
|
private static function moveStorage()
|
||||||
{
|
{
|
||||||
$current = StorageManager::getBackend();
|
$current = DI::storage();
|
||||||
$moved = StorageManager::move($current);
|
$moved = DI::storageManager()->move($current);
|
||||||
|
|
||||||
if ($moved) {
|
if ($moved) {
|
||||||
Worker::add(PRIORITY_LOW, "CronJobs", "move_storage");
|
Worker::add(PRIORITY_LOW, "CronJobs", "move_storage");
|
||||||
|
|
|
@ -197,6 +197,11 @@ class Delivery
|
||||||
$contact['network'] = Protocol::DIASPORA;
|
$contact['network'] = Protocol::DIASPORA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that local contacts are delivered locally
|
||||||
|
if (Model\Contact::isLocal($contact['url'])) {
|
||||||
|
$contact['network'] = Protocol::DFRN;
|
||||||
|
}
|
||||||
|
|
||||||
Logger::notice('Delivering', ['cmd' => $cmd, 'target' => $target_id, 'followup' => $followup, 'network' => $contact['network']]);
|
Logger::notice('Delivering', ['cmd' => $cmd, 'target' => $target_id, 'followup' => $followup, 'network' => $contact['network']]);
|
||||||
|
|
||||||
switch ($contact['network']) {
|
switch ($contact['network']) {
|
||||||
|
@ -287,11 +292,8 @@ class Delivery
|
||||||
|
|
||||||
Logger::debug('Notifier entry: ' . $contact["url"] . ' ' . (($target_item['guid'] ?? '') ?: $target_item['id']) . ' entry: ' . $atom);
|
Logger::debug('Notifier entry: ' . $contact["url"] . ' ' . (($target_item['guid'] ?? '') ?: $target_item['id']) . ' entry: ' . $atom);
|
||||||
|
|
||||||
$basepath = implode('/', array_slice(explode('/', $contact['url']), 0, 3));
|
|
||||||
|
|
||||||
// perform local delivery if we are on the same site
|
// perform local delivery if we are on the same site
|
||||||
|
if (Model\Contact::isLocal($contact['url'])) {
|
||||||
if (Strings::compareLink($basepath, DI::baseUrl())) {
|
|
||||||
$condition = ['nurl' => Strings::normaliseLink($contact['url']), 'self' => true];
|
$condition = ['nurl' => Strings::normaliseLink($contact['url']), 'self' => true];
|
||||||
$target_self = DBA::selectFirst('contact', ['uid'], $condition);
|
$target_self = DBA::selectFirst('contact', ['uid'], $condition);
|
||||||
if (!DBA::isResult($target_self)) {
|
if (!DBA::isResult($target_self)) {
|
||||||
|
|
|
@ -444,6 +444,11 @@ class Notifier
|
||||||
|
|
||||||
if (DBA::isResult($r)) {
|
if (DBA::isResult($r)) {
|
||||||
foreach ($r as $rr) {
|
foreach ($r as $rr) {
|
||||||
|
// Ensure that local contacts are delivered via DFRN
|
||||||
|
if (Contact::isLocal($rr['url'])) {
|
||||||
|
$contact['network'] = Protocol::DFRN;
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($rr['addr']) && ($rr['network'] == Protocol::ACTIVITYPUB) && !DBA::exists('fcontact', ['addr' => $rr['addr']])) {
|
if (!empty($rr['addr']) && ($rr['network'] == Protocol::ACTIVITYPUB) && !DBA::exists('fcontact', ['addr' => $rr['addr']])) {
|
||||||
Logger::info('Contact is AP omly', ['target' => $target_id, 'contact' => $rr['url']]);
|
Logger::info('Contact is AP omly', ['target' => $target_id, 'contact' => $rr['url']]);
|
||||||
continue;
|
continue;
|
||||||
|
@ -489,6 +494,11 @@ class Notifier
|
||||||
|
|
||||||
// delivery loop
|
// delivery loop
|
||||||
while ($contact = DBA::fetch($delivery_contacts_stmt)) {
|
while ($contact = DBA::fetch($delivery_contacts_stmt)) {
|
||||||
|
// Ensure that local contacts are delivered via DFRN
|
||||||
|
if (Contact::isLocal($contact['url'])) {
|
||||||
|
$contact['network'] = Protocol::DFRN;
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($contact['addr']) && ($contact['network'] == Protocol::ACTIVITYPUB) && !DBA::exists('fcontact', ['addr' => $contact['addr']])) {
|
if (!empty($contact['addr']) && ($contact['network'] == Protocol::ACTIVITYPUB) && !DBA::exists('fcontact', ['addr' => $contact['addr']])) {
|
||||||
Logger::info('Contact is AP omly', ['target' => $target_id, 'contact' => $contact['url']]);
|
Logger::info('Contact is AP omly', ['target' => $target_id, 'contact' => $contact['url']]);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -13,8 +13,7 @@ class RemoveContact {
|
||||||
public static function execute($id) {
|
public static function execute($id) {
|
||||||
|
|
||||||
// Only delete if the contact is to be deleted
|
// Only delete if the contact is to be deleted
|
||||||
$condition = ['network' => Protocol::PHANTOM, 'id' => $id];
|
$contact = DBA::selectFirst('contact', ['uid'], ['deleted' => true]);
|
||||||
$contact = DBA::selectFirst('contact', ['uid'], $condition);
|
|
||||||
if (!DBA::isResult($contact)) {
|
if (!DBA::isResult($contact)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,13 @@
|
||||||
*/
|
*/
|
||||||
namespace Friendica\Worker;
|
namespace Friendica\Worker;
|
||||||
|
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Config;
|
use Friendica\Core\Config;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Core\Protocol;
|
use Friendica\Core\Protocol;
|
||||||
use Friendica\Core\Search;
|
use Friendica\Core\Search;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
|
use Friendica\DI;
|
||||||
use Friendica\Model\GContact;
|
use Friendica\Model\GContact;
|
||||||
use Friendica\Model\GServer;
|
use Friendica\Model\GServer;
|
||||||
use Friendica\Network\Probe;
|
use Friendica\Network\Probe;
|
||||||
|
@ -26,7 +27,7 @@ class SearchDirectory
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = Cache::get('SearchDirectory:' . $search);
|
$data = DI::cache()->get('SearchDirectory:' . $search);
|
||||||
if (!is_null($data)) {
|
if (!is_null($data)) {
|
||||||
// Only search for the same item every 24 hours
|
// Only search for the same item every 24 hours
|
||||||
if (time() < $data + (60 * 60 * 24)) {
|
if (time() < $data + (60 * 60 * 24)) {
|
||||||
|
@ -80,6 +81,6 @@ class SearchDirectory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cache::set('SearchDirectory:' . $search, time(), Cache::DAY);
|
DI::cache()->set('SearchDirectory:' . $search, time(), Cache::DAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
|
|
||||||
if (!defined('DB_UPDATE_VERSION')) {
|
if (!defined('DB_UPDATE_VERSION')) {
|
||||||
define('DB_UPDATE_VERSION', 1329);
|
define('DB_UPDATE_VERSION', 1330);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -8,8 +8,10 @@ use Friendica\Core\L10n\L10n;
|
||||||
use Friendica\Core\Lock\ILock;
|
use Friendica\Core\Lock\ILock;
|
||||||
use Friendica\Core\Process;
|
use Friendica\Core\Process;
|
||||||
use Friendica\Core\Session\ISession;
|
use Friendica\Core\Session\ISession;
|
||||||
|
use Friendica\Core\StorageManager;
|
||||||
use Friendica\Database\Database;
|
use Friendica\Database\Database;
|
||||||
use Friendica\Factory;
|
use Friendica\Factory;
|
||||||
|
use Friendica\Model\Storage\IStorage;
|
||||||
use Friendica\Model\User\Cookie;
|
use Friendica\Model\User\Cookie;
|
||||||
use Friendica\Util;
|
use Friendica\Util;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
@ -193,5 +195,11 @@ return [
|
||||||
'constructParams' => [
|
'constructParams' => [
|
||||||
$_SERVER, $_COOKIE
|
$_SERVER, $_COOKIE
|
||||||
],
|
],
|
||||||
]
|
],
|
||||||
|
IStorage::class => [
|
||||||
|
'instanceOf' => StorageManager::class,
|
||||||
|
'call' => [
|
||||||
|
['getBackend', [], Dice::CHAIN_CALL],
|
||||||
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Friendica\Test\Util;
|
namespace Friendica\Test\Util;
|
||||||
|
|
||||||
use Friendica\Core\Cache;
|
use Friendica\Core\Cache\Cache;
|
||||||
use Friendica\Core\Lock\DatabaseLock;
|
use Friendica\Core\Lock\DatabaseLock;
|
||||||
|
|
||||||
trait DbaLockMockTrait
|
trait DbaLockMockTrait
|
||||||
|
|
106
tests/Util/SampleStorageBackend.php
Normal file
106
tests/Util/SampleStorageBackend.php
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Test\Util;
|
||||||
|
|
||||||
|
use Friendica\App;
|
||||||
|
use Friendica\Core\Hook;
|
||||||
|
use Friendica\Model\Storage\IStorage;
|
||||||
|
|
||||||
|
use Friendica\Core\L10n\L10n;
|
||||||
|
use Mockery\MockInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A backend storage example class
|
||||||
|
*/
|
||||||
|
class SampleStorageBackend implements IStorage
|
||||||
|
{
|
||||||
|
const NAME = 'Sample Storage';
|
||||||
|
|
||||||
|
/** @var L10n */
|
||||||
|
private $l10n;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $options = [
|
||||||
|
'filename' => [
|
||||||
|
'input', // will use a simple text input
|
||||||
|
'The file to return', // the label
|
||||||
|
'sample', // the current value
|
||||||
|
'Enter the path to a file', // the help text
|
||||||
|
// no extra data for 'input' type..
|
||||||
|
],
|
||||||
|
];
|
||||||
|
/** @var array Just save the data in memory */
|
||||||
|
private $data = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SampleStorageBackend constructor.
|
||||||
|
*
|
||||||
|
* @param L10n $l10n The configuration of Friendica
|
||||||
|
*
|
||||||
|
* You can add here every dynamic class as dependency you like and add them to a private field
|
||||||
|
* Friendica automatically creates these classes and passes them as argument to the constructor
|
||||||
|
*/
|
||||||
|
public function __construct(L10n $l10n)
|
||||||
|
{
|
||||||
|
$this->l10n = $l10n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $reference)
|
||||||
|
{
|
||||||
|
// we return always the same image data. Which file we load is defined by
|
||||||
|
// a config key
|
||||||
|
return $this->data[$reference] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function put(string $data, string $reference = '')
|
||||||
|
{
|
||||||
|
if ($reference === '') {
|
||||||
|
$reference = 'sample';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->data[$reference] = $data;
|
||||||
|
|
||||||
|
return $reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $reference)
|
||||||
|
{
|
||||||
|
if (isset($this->data[$reference])) {
|
||||||
|
unset($this->data[$reference]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOptions()
|
||||||
|
{
|
||||||
|
return $this->options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveOptions(array $data)
|
||||||
|
{
|
||||||
|
$this->options = $data;
|
||||||
|
|
||||||
|
// no errors, return empty array
|
||||||
|
return $this->options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getName()
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This one is a hack to register this class to the hook
|
||||||
|
*/
|
||||||
|
public static function registerHook()
|
||||||
|
{
|
||||||
|
Hook::register('storage_instance', __DIR__ . '/SampleStorageBackendInstance.php', 'create_instance');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
tests/Util/SampleStorageBackendInstance.php
Normal file
18
tests/Util/SampleStorageBackendInstance.php
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// contains a test-hook call for creating a storage instance
|
||||||
|
|
||||||
|
use Friendica\App;
|
||||||
|
use Friendica\Core\L10n\L10n;
|
||||||
|
use Friendica\Test\Util\SampleStorageBackend;
|
||||||
|
use Mockery\MockInterface;
|
||||||
|
|
||||||
|
function create_instance(App $a, &$data)
|
||||||
|
{
|
||||||
|
/** @var L10n|MockInterface $l10n */
|
||||||
|
$l10n = \Mockery::mock(L10n::class);
|
||||||
|
|
||||||
|
if ($data['name'] == SampleStorageBackend::getName()) {
|
||||||
|
$data['storage'] = new SampleStorageBackend($l10n);
|
||||||
|
}
|
||||||
|
}
|
40
tests/datasets/storage/database.fixture.php
Normal file
40
tests/datasets/storage/database.fixture.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'photo' => [
|
||||||
|
// move from data-attribute to storage backend
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'backend-class' => null,
|
||||||
|
'backend-ref' => 'f0c0d0i2',
|
||||||
|
'data' => 'without class',
|
||||||
|
],
|
||||||
|
// move from storage-backend to maybe filesystem backend, skip at database backend
|
||||||
|
[
|
||||||
|
'id' => 2,
|
||||||
|
'backend-class' => 'Database',
|
||||||
|
'backend-ref' => 1,
|
||||||
|
'data' => '',
|
||||||
|
],
|
||||||
|
// move data if invalid storage
|
||||||
|
[
|
||||||
|
'id' => 3,
|
||||||
|
'backend-class' => 'invalid!',
|
||||||
|
'backend-ref' => 'unimported',
|
||||||
|
'data' => 'invalid data moved',
|
||||||
|
],
|
||||||
|
// skip everytime because of invalid storage and no data
|
||||||
|
[
|
||||||
|
'id' => 3,
|
||||||
|
'backend-class' => 'invalid!',
|
||||||
|
'backend-ref' => 'unimported',
|
||||||
|
'data' => '',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'storage' => [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'data' => 'inside database',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
264
tests/src/Core/StorageManagerTest.php
Normal file
264
tests/src/Core/StorageManagerTest.php
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Test\src\Core;
|
||||||
|
|
||||||
|
use Dice\Dice;
|
||||||
|
use Friendica\Core\Config\IConfiguration;
|
||||||
|
use Friendica\Core\Config\PreloadConfiguration;
|
||||||
|
use Friendica\Core\Hook;
|
||||||
|
use Friendica\Core\L10n\L10n;
|
||||||
|
use Friendica\Core\Session\ISession;
|
||||||
|
use Friendica\Core\StorageManager;
|
||||||
|
use Friendica\Database\Database;
|
||||||
|
use Friendica\DI;
|
||||||
|
use Friendica\Factory\ConfigFactory;
|
||||||
|
use Friendica\Model\Config\Config;
|
||||||
|
use Friendica\Model\Storage;
|
||||||
|
use Friendica\Core\Session;
|
||||||
|
use Friendica\Test\DatabaseTest;
|
||||||
|
use Friendica\Test\Util\Database\StaticDatabase;
|
||||||
|
use Friendica\Test\Util\VFSTrait;
|
||||||
|
use Friendica\Util\ConfigFileLoader;
|
||||||
|
use Friendica\Util\Profiler;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Psr\Log\NullLogger;
|
||||||
|
use Friendica\Test\Util\SampleStorageBackend;
|
||||||
|
|
||||||
|
class StorageManagerTest extends DatabaseTest
|
||||||
|
{
|
||||||
|
/** @var Database */
|
||||||
|
private $dba;
|
||||||
|
/** @var IConfiguration */
|
||||||
|
private $config;
|
||||||
|
/** @var LoggerInterface */
|
||||||
|
private $logger;
|
||||||
|
/** @var L10n */
|
||||||
|
private $l10n;
|
||||||
|
|
||||||
|
use VFSTrait;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->setUpVfsDir();
|
||||||
|
|
||||||
|
$this->logger = new NullLogger();
|
||||||
|
|
||||||
|
$profiler = \Mockery::mock(Profiler::class);
|
||||||
|
$profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
|
||||||
|
|
||||||
|
// load real config to avoid mocking every config-entry which is related to the Database class
|
||||||
|
$configFactory = new ConfigFactory();
|
||||||
|
$loader = new ConfigFileLoader($this->root->url());
|
||||||
|
$configCache = $configFactory->createCache($loader);
|
||||||
|
|
||||||
|
$this->dba = new StaticDatabase($configCache, $profiler, $this->logger);
|
||||||
|
|
||||||
|
$configModel = new Config($this->dba);
|
||||||
|
$this->config = new PreloadConfiguration($configCache, $configModel);
|
||||||
|
|
||||||
|
$this->l10n = \Mockery::mock(L10n::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test plain instancing first
|
||||||
|
*/
|
||||||
|
public function testInstance()
|
||||||
|
{
|
||||||
|
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(StorageManager::class, $storageManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataStorages()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'empty' => [
|
||||||
|
'name' => '',
|
||||||
|
'assert' => null,
|
||||||
|
'assertName' => '',
|
||||||
|
'userBackend' => false,
|
||||||
|
],
|
||||||
|
'database' => [
|
||||||
|
'name' => Storage\Database::NAME,
|
||||||
|
'assert' => Storage\Database::class,
|
||||||
|
'assertName' => Storage\Database::NAME,
|
||||||
|
'userBackend' => true,
|
||||||
|
],
|
||||||
|
'filesystem' => [
|
||||||
|
'name' => Storage\Filesystem::NAME,
|
||||||
|
'assert' => Storage\Filesystem::class,
|
||||||
|
'assertName' => Storage\Filesystem::NAME,
|
||||||
|
'userBackend' => true,
|
||||||
|
],
|
||||||
|
'systemresource' => [
|
||||||
|
'name' => Storage\SystemResource::NAME,
|
||||||
|
'assert' => Storage\SystemResource::class,
|
||||||
|
'assertName' => Storage\SystemResource::NAME,
|
||||||
|
// false here, because SystemResource isn't meant to be a user backend,
|
||||||
|
// it's for system resources only
|
||||||
|
'userBackend' => false,
|
||||||
|
],
|
||||||
|
'invalid' => [
|
||||||
|
'name' => 'invalid',
|
||||||
|
'assert' => null,
|
||||||
|
'assertName' => '',
|
||||||
|
'userBackend' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the getByName() method
|
||||||
|
*
|
||||||
|
* @dataProvider dataStorages
|
||||||
|
*/
|
||||||
|
public function testGetByName($name, $assert, $assertName, $userBackend)
|
||||||
|
{
|
||||||
|
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
|
||||||
|
|
||||||
|
$storage = $storageManager->getByName($name, $userBackend);
|
||||||
|
|
||||||
|
if (!empty($assert)) {
|
||||||
|
$this->assertInstanceOf(Storage\IStorage::class, $storage);
|
||||||
|
$this->assertInstanceOf($assert, $storage);
|
||||||
|
$this->assertEquals($name, $storage::getName());
|
||||||
|
} else {
|
||||||
|
$this->assertNull($storage);
|
||||||
|
}
|
||||||
|
$this->assertEquals($assertName, $storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the isValidBackend() method
|
||||||
|
*
|
||||||
|
* @dataProvider dataStorages
|
||||||
|
*/
|
||||||
|
public function testIsValidBackend($name, $assert, $assertName, $userBackend)
|
||||||
|
{
|
||||||
|
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
|
||||||
|
|
||||||
|
$this->assertEquals($userBackend, $storageManager->isValidBackend($name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the method listBackends() with default setting
|
||||||
|
*/
|
||||||
|
public function testListBackends()
|
||||||
|
{
|
||||||
|
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
|
||||||
|
|
||||||
|
$this->assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the method getBackend()
|
||||||
|
*
|
||||||
|
* @dataProvider dataStorages
|
||||||
|
*/
|
||||||
|
public function testGetBackend($name, $assert, $assertName, $userBackend)
|
||||||
|
{
|
||||||
|
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
|
||||||
|
|
||||||
|
$this->assertNull($storageManager->getBackend());
|
||||||
|
|
||||||
|
if ($userBackend) {
|
||||||
|
$storageManager->setBackend($name);
|
||||||
|
|
||||||
|
$this->assertInstanceOf($assert, $storageManager->getBackend());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the method getBackend() with a pre-configured backend
|
||||||
|
*
|
||||||
|
* @dataProvider dataStorages
|
||||||
|
*/
|
||||||
|
public function testPresetBackend($name, $assert, $assertName, $userBackend)
|
||||||
|
{
|
||||||
|
$this->config->set('storage', 'name', $name);
|
||||||
|
|
||||||
|
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
|
||||||
|
|
||||||
|
if ($userBackend) {
|
||||||
|
$this->assertInstanceOf($assert, $storageManager->getBackend());
|
||||||
|
} else {
|
||||||
|
$this->assertNull($storageManager->getBackend());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the register and unregister methods for a new backend storage class
|
||||||
|
*
|
||||||
|
* Uses a sample storage for testing
|
||||||
|
*
|
||||||
|
* @see SampleStorageBackend
|
||||||
|
*/
|
||||||
|
public function testRegisterUnregisterBackends()
|
||||||
|
{
|
||||||
|
/// @todo Remove dice once "Hook" is dynamic and mockable
|
||||||
|
$dice = (new Dice())
|
||||||
|
->addRules(include __DIR__ . '/../../../static/dependencies.config.php')
|
||||||
|
->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true])
|
||||||
|
->addRule(ISession::class, ['instanceOf' => Session\Memory::class, 'shared' => true, 'call' => null]);
|
||||||
|
DI::init($dice);
|
||||||
|
|
||||||
|
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
|
||||||
|
|
||||||
|
$this->assertTrue($storageManager->register(SampleStorageBackend::class));
|
||||||
|
|
||||||
|
$this->assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
|
||||||
|
SampleStorageBackend::getName() => SampleStorageBackend::class,
|
||||||
|
]), $storageManager->listBackends());
|
||||||
|
$this->assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
|
||||||
|
SampleStorageBackend::getName() => SampleStorageBackend::class,
|
||||||
|
]), $this->config->get('storage', 'backends'));
|
||||||
|
|
||||||
|
// inline call to register own class as hook (testing purpose only)
|
||||||
|
SampleStorageBackend::registerHook();
|
||||||
|
Hook::loadHooks();
|
||||||
|
|
||||||
|
$this->assertTrue($storageManager->setBackend(SampleStorageBackend::NAME));
|
||||||
|
$this->assertEquals(SampleStorageBackend::NAME, $this->config->get('storage', 'name'));
|
||||||
|
|
||||||
|
$this->assertInstanceOf(SampleStorageBackend::class, $storageManager->getBackend());
|
||||||
|
|
||||||
|
$this->assertTrue($storageManager->unregister(SampleStorageBackend::class));
|
||||||
|
$this->assertEquals(StorageManager::DEFAULT_BACKENDS, $this->config->get('storage', 'backends'));
|
||||||
|
$this->assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
|
||||||
|
|
||||||
|
$this->assertNull($storageManager->getBackend());
|
||||||
|
$this->assertNull($this->config->get('storage', 'name'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test moving data to a new storage (currently testing db & filesystem)
|
||||||
|
*
|
||||||
|
* @dataProvider dataStorages
|
||||||
|
*/
|
||||||
|
public function testMoveStorage($name, $assert, $assertName, $userBackend)
|
||||||
|
{
|
||||||
|
if (!$userBackend) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->loadFixture(__DIR__ . '/../../datasets/storage/database.fixture.php', $this->dba);
|
||||||
|
|
||||||
|
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
|
||||||
|
$storage = $storageManager->getByName($name);
|
||||||
|
$storageManager->move($storage);
|
||||||
|
|
||||||
|
$photos = $this->dba->select('photo', ['backend-ref', 'backend-class', 'id', 'data']);
|
||||||
|
|
||||||
|
while ($photo = $this->dba->fetch($photos)) {
|
||||||
|
|
||||||
|
$this->assertEmpty($photo['data']);
|
||||||
|
|
||||||
|
$storage = $storageManager->getByName($photo['backend-class']);
|
||||||
|
$data = $storage->get($photo['backend-ref']);
|
||||||
|
|
||||||
|
$this->assertNotEmpty($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
tests/src/Model/Storage/DatabaseStorageTest.php
Normal file
52
tests/src/Model/Storage/DatabaseStorageTest.php
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Test\src\Model\Storage;
|
||||||
|
|
||||||
|
use Friendica\Core\L10n\L10n;
|
||||||
|
use Friendica\Factory\ConfigFactory;
|
||||||
|
use Friendica\Model\Storage\Database;
|
||||||
|
use Friendica\Model\Storage\IStorage;
|
||||||
|
use Friendica\Test\DatabaseTestTrait;
|
||||||
|
use Friendica\Test\Util\Database\StaticDatabase;
|
||||||
|
use Friendica\Test\Util\VFSTrait;
|
||||||
|
use Friendica\Util\ConfigFileLoader;
|
||||||
|
use Friendica\Util\Profiler;
|
||||||
|
use Mockery\MockInterface;
|
||||||
|
use Psr\Log\NullLogger;
|
||||||
|
|
||||||
|
class DatabaseStorageTest extends StorageTest
|
||||||
|
{
|
||||||
|
use DatabaseTestTrait;
|
||||||
|
use VFSTrait;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->setUpVfsDir();
|
||||||
|
|
||||||
|
parent::setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getInstance()
|
||||||
|
{
|
||||||
|
$logger = new NullLogger();
|
||||||
|
$profiler = \Mockery::mock(Profiler::class);
|
||||||
|
$profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
|
||||||
|
|
||||||
|
// load real config to avoid mocking every config-entry which is related to the Database class
|
||||||
|
$configFactory = new ConfigFactory();
|
||||||
|
$loader = new ConfigFileLoader($this->root->url());
|
||||||
|
$configCache = $configFactory->createCache($loader);
|
||||||
|
|
||||||
|
$dba = new StaticDatabase($configCache, $profiler, $logger);
|
||||||
|
|
||||||
|
/** @var MockInterface|L10n $l10n */
|
||||||
|
$l10n = \Mockery::mock(L10n::class)->makePartial();
|
||||||
|
|
||||||
|
return new Database($dba, $logger, $l10n);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assertOption(IStorage $storage)
|
||||||
|
{
|
||||||
|
$this->assertEmpty($storage->getOptions());
|
||||||
|
}
|
||||||
|
}
|
111
tests/src/Model/Storage/FilesystemStorageTest.php
Normal file
111
tests/src/Model/Storage/FilesystemStorageTest.php
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Test\src\Model\Storage;
|
||||||
|
|
||||||
|
use Friendica\Core\Config\IConfiguration;
|
||||||
|
use Friendica\Core\L10n\L10n;
|
||||||
|
use Friendica\Model\Storage\Filesystem;
|
||||||
|
use Friendica\Model\Storage\IStorage;
|
||||||
|
use Friendica\Test\Util\VFSTrait;
|
||||||
|
use Friendica\Util\Profiler;
|
||||||
|
use Mockery\MockInterface;
|
||||||
|
use org\bovigo\vfs\vfsStream;
|
||||||
|
use Psr\Log\NullLogger;
|
||||||
|
use function GuzzleHttp\Psr7\uri_for;
|
||||||
|
|
||||||
|
class FilesystemStorageTest extends StorageTest
|
||||||
|
{
|
||||||
|
use VFSTrait;
|
||||||
|
|
||||||
|
/** @var MockInterface|IConfiguration */
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->setUpVfsDir();
|
||||||
|
|
||||||
|
vfsStream::create(['storage' => []], $this->root);
|
||||||
|
|
||||||
|
parent::setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getInstance()
|
||||||
|
{
|
||||||
|
$logger = new NullLogger();
|
||||||
|
$profiler = \Mockery::mock(Profiler::class);
|
||||||
|
$profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
|
||||||
|
|
||||||
|
/** @var MockInterface|L10n $l10n */
|
||||||
|
$l10n = \Mockery::mock(L10n::class)->makePartial();
|
||||||
|
$this->config = \Mockery::mock(IConfiguration::class);
|
||||||
|
$this->config->shouldReceive('get')
|
||||||
|
->with('storage', 'filesystem_path', Filesystem::DEFAULT_BASE_FOLDER)
|
||||||
|
->andReturn($this->root->getChild('storage')->url());
|
||||||
|
|
||||||
|
return new Filesystem($this->config, $logger, $l10n);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assertOption(IStorage $storage)
|
||||||
|
{
|
||||||
|
$this->assertEquals([
|
||||||
|
'storagepath' => [
|
||||||
|
'input', 'Storage base path',
|
||||||
|
$this->root->getChild('storage')->url(),
|
||||||
|
'Folder where uploaded files are saved. For maximum security, This should be a path outside web server folder tree'
|
||||||
|
]
|
||||||
|
], $storage->getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the exception in case of missing directorsy permissions
|
||||||
|
*
|
||||||
|
* @expectedException \Friendica\Model\Storage\StorageException
|
||||||
|
* @expectedExceptionMessageRegExp /Filesystem storage failed to create \".*\". Check you write permissions./
|
||||||
|
*/
|
||||||
|
public function testMissingDirPermissions()
|
||||||
|
{
|
||||||
|
$this->root->getChild('storage')->chmod(000);
|
||||||
|
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
$instance->put('test');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the exception in case of missing file permissions
|
||||||
|
*
|
||||||
|
* @expectedException \Friendica\Model\Storage\StorageException
|
||||||
|
* @expectedExceptionMessageRegExp /Filesystem storage failed to save data to \".*\". Check your write permissions/
|
||||||
|
*/
|
||||||
|
public function testMissingFilePermissions()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete("Cannot catch file_put_content() error due vfsStream failure");
|
||||||
|
|
||||||
|
vfsStream::create(['storage' => ['f0' => ['c0' => ['k0i0' => '']]]], $this->root);
|
||||||
|
|
||||||
|
$this->root->getChild('storage/f0/c0/k0i0')->chmod(000);
|
||||||
|
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
$instance->put('test', 'f0c0k0i0');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the backend storage of the Filesystem Storage class
|
||||||
|
*/
|
||||||
|
public function testDirectoryTree()
|
||||||
|
{
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
|
||||||
|
$instance->put('test', 'f0c0d0i0');
|
||||||
|
|
||||||
|
$dir = $this->root->getChild('storage/f0/c0')->url();
|
||||||
|
$file = $this->root->getChild('storage/f0/c0/d0i0')->url();
|
||||||
|
|
||||||
|
$this->assertDirectoryExists($dir);
|
||||||
|
$this->assertFileExists($file);
|
||||||
|
|
||||||
|
$this->assertDirectoryIsWritable($dir);
|
||||||
|
$this->assertFileIsWritable($file);
|
||||||
|
|
||||||
|
$this->assertEquals('test', file_get_contents($file));
|
||||||
|
}
|
||||||
|
}
|
96
tests/src/Model/Storage/StorageTest.php
Normal file
96
tests/src/Model/Storage/StorageTest.php
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Test\src\Model\Storage;
|
||||||
|
|
||||||
|
use Friendica\Model\Storage\IStorage;
|
||||||
|
use Friendica\Test\MockedTest;
|
||||||
|
|
||||||
|
abstract class StorageTest extends MockedTest
|
||||||
|
{
|
||||||
|
/** @return IStorage */
|
||||||
|
abstract protected function getInstance();
|
||||||
|
|
||||||
|
abstract protected function assertOption(IStorage $storage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if the instance is "really" implementing the interface
|
||||||
|
*/
|
||||||
|
public function testInstance()
|
||||||
|
{
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
$this->assertInstanceOf(IStorage::class, $instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if the "getOption" is asserted
|
||||||
|
*/
|
||||||
|
public function testGetOptions()
|
||||||
|
{
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
|
||||||
|
$this->assertOption($instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test basic put, get and delete operations
|
||||||
|
*/
|
||||||
|
public function testPutGetDelete()
|
||||||
|
{
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
|
||||||
|
$ref = $instance->put('data12345');
|
||||||
|
$this->assertNotEmpty($ref);
|
||||||
|
|
||||||
|
$this->assertEquals('data12345', $instance->get($ref));
|
||||||
|
|
||||||
|
$this->assertTrue($instance->delete($ref));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test a delete with an invalid reference
|
||||||
|
*/
|
||||||
|
public function testInvalidDelete()
|
||||||
|
{
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
|
||||||
|
// Even deleting not existing references should return "true"
|
||||||
|
$this->assertTrue($instance->delete(-1234456));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test a get with an invalid reference
|
||||||
|
*/
|
||||||
|
public function testInvalidGet()
|
||||||
|
{
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
|
||||||
|
// Invalid references return an empty string
|
||||||
|
$this->assertEmpty($instance->get(-123456));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test an update with a given reference
|
||||||
|
*/
|
||||||
|
public function testUpdateReference()
|
||||||
|
{
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
|
||||||
|
$ref = $instance->put('data12345');
|
||||||
|
$this->assertNotEmpty($ref);
|
||||||
|
|
||||||
|
$this->assertEquals('data12345', $instance->get($ref));
|
||||||
|
|
||||||
|
$this->assertEquals($ref, $instance->put('data5432', $ref));
|
||||||
|
$this->assertEquals('data5432', $instance->get($ref));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an invalid update results in an insert
|
||||||
|
*/
|
||||||
|
public function testInvalidUpdate()
|
||||||
|
{
|
||||||
|
$instance = $this->getInstance();
|
||||||
|
|
||||||
|
$this->assertEquals(-123, $instance->put('data12345', -123));
|
||||||
|
}
|
||||||
|
}
|
24
update.php
24
update.php
|
@ -12,6 +12,7 @@ use Friendica\Model\Contact;
|
||||||
use Friendica\Model\GContact;
|
use Friendica\Model\GContact;
|
||||||
use Friendica\Model\Item;
|
use Friendica\Model\Item;
|
||||||
use Friendica\Model\User;
|
use Friendica\Model\User;
|
||||||
|
use Friendica\Model\Storage;
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
use Friendica\Worker\Delivery;
|
use Friendica\Worker\Delivery;
|
||||||
|
|
||||||
|
@ -408,3 +409,26 @@ function update_1327()
|
||||||
return Update::SUCCESS;
|
return Update::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function update_1330()
|
||||||
|
{
|
||||||
|
$currStorage = Config::get('storage', 'class', '');
|
||||||
|
|
||||||
|
// set the name of the storage instead of the classpath as config
|
||||||
|
if (!empty($currStorage)) {
|
||||||
|
/** @var Storage\IStorage $currStorage */
|
||||||
|
if (!Config::set('storage', 'name', $currStorage::getName())) {
|
||||||
|
return Update::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to delete the class since it isn't needed. This won't work with config files
|
||||||
|
Config::delete('storage', 'class');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update attachments and photos
|
||||||
|
if (!DBA::p("UPDATE `photo` SET `photo`.`backend-class` = SUBSTR(`photo`.`backend-class`, 22) WHERE `photo`.`backend-class` LIKE 'Friendica\\Model\\Storage\\%'") ||
|
||||||
|
!DBA::p("UPDATE `attach` SET `attach`.`backend-class` = SUBSTR(`attach`.`backend-class`, 22) WHERE `attach`.`backend-class` LIKE 'Friendica\\Model\\Storage\\%'")) {
|
||||||
|
return Update::FAILED;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Update::SUCCESS;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue