Merge remote-tracking branch 'upstream/develop' into logging

This commit is contained in:
Michael 2021-10-25 18:56:29 +00:00
commit 87673fd0c5
60 changed files with 4012 additions and 2911 deletions

View File

@ -81,7 +81,7 @@ $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['auth_ejabberd']]);
\Friendica\DI::init($dice);
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
$appMode = $dice->create(Mode::class);
if ($appMode->isNormal()) {

View File

@ -33,4 +33,6 @@ require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['console']]);
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
(new Friendica\Core\Console($dice, $argv))->execute();

View File

@ -60,6 +60,7 @@ $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['daemon']]);
DI::init($dice);
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
$a = DI::app();
if (DI::mode()->isInstall()) {

View File

@ -57,6 +57,7 @@ $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['worker']]);
DI::init($dice);
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
$a = DI::app();
DI::mode()->setExecutor(Mode::WORKER);

View File

@ -34,6 +34,8 @@ $dice = $dice->addRule(Friendica\App\Mode::class, ['call' => [['determineRunMode
\Friendica\DI::init($dice);
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
$a = \Friendica\DI::app();
\Friendica\DI::mode()->setExecutor(\Friendica\App\Mode::INDEX);

View File

@ -121,7 +121,7 @@ function fbrowser_content(App $a)
$tpl = Renderer::getMarkupTemplate($template_file);
$o = Renderer::replaceMacros($tpl, [
'$type' => 'file',
'$path' => [ [ "", DI::l10n()->t("Files")] ],
'$path' => ['' => DI::l10n()->t('Files')],
'$folders' => false,
'$files' => $files,
'$cancel' => DI::l10n()->t('Cancel'),

View File

@ -631,7 +631,9 @@ class App
Model\Profile::openWebAuthInit($token);
}
if (!$this->mode->isBackend()) {
$auth->withSession($this);
}
if (empty($_SESSION['authenticated'])) {
header('X-Account-Management-Status: none');

View File

@ -1,163 +0,0 @@
<?php
namespace Friendica;
use Exception;
use Friendica\Capabilities\ICanCreateFromTableRow;
use Friendica\Database\Database;
use Friendica\Database\DBA;
use Friendica\Network\HTTPException\NotFoundException;
use Psr\Log\LoggerInterface;
/**
* Depositories are meant to store and retrieve Entities from the database.
*
* The reason why there are methods prefixed with an underscore is because PHP doesn't support generic polymorphism
* which means we can't directly overload base methods and make parameters more strict (from a parent class to a child
* class for example)
*
* Similarly, we can't make an overloaded method return type more strict until we only support PHP version 7.4 but this
* is less pressing.
*/
abstract class BaseDepository
{
const LIMIT = 30;
/**
* @var string This should be set to the main database table name the depository is using
*/
protected static $table_name;
/** @var Database */
protected $db;
/** @var LoggerInterface */
protected $logger;
/** @var ICanCreateFromTableRow */
protected $factory;
public function __construct(Database $database, LoggerInterface $logger, ICanCreateFromTableRow $factory)
{
$this->db = $database;
$this->logger = $logger;
$this->factory = $factory;
}
/**
* Populates the collection according to the condition. Retrieves a limited subset of entities depending on the
* boundaries and the limit. The total count of rows matching the condition is stored in the collection.
*
* Depends on the corresponding table featuring a numerical auto incremented column called `id`.
*
* max_id and min_id are susceptible to the query order:
* - min_id alone only reliably works with ASC order
* - max_id alone only reliably works with DESC order
* If the wrong order is detected in either case, we reverse the query order and the entity list order after the query
*
* Chainable.
*
* @param array $condition
* @param array $params
* @param int|null $min_id Retrieve models with an id no fewer than this, as close to it as possible
* @param int|null $max_id Retrieve models with an id no greater than this, as close to it as possible
* @param int $limit
* @return BaseCollection
* @throws \Exception
*/
protected function _selectByBoundaries(
array $condition = [],
array $params = [],
int $min_id = null,
int $max_id = null,
int $limit = self::LIMIT
): BaseCollection {
$totalCount = $this->count($condition);
$boundCondition = $condition;
$reverseOrder = false;
if (isset($min_id)) {
$boundCondition = DBA::mergeConditions($boundCondition, ['`id` > ?', $min_id]);
if (!isset($max_id) && isset($params['order']['id']) && ($params['order']['id'] === true || $params['order']['id'] === 'DESC')) {
$reverseOrder = true;
$params['order']['id'] = 'ASC';
}
}
if (isset($max_id) && $max_id > 0) {
$boundCondition = DBA::mergeConditions($boundCondition, ['`id` < ?', $max_id]);
if (!isset($min_id) && (!isset($params['order']['id']) || $params['order']['id'] === false || $params['order']['id'] === 'ASC')) {
$reverseOrder = true;
$params['order']['id'] = 'DESC';
}
}
$params['limit'] = $limit;
$Entities = $this->_select($boundCondition, $params);
if ($reverseOrder) {
$Entities->reverse();
}
return new BaseCollection($Entities->getArrayCopy(), $totalCount);
}
/**
* @param array $condition
* @param array $params
* @return BaseCollection
* @throws Exception
*/
protected function _select(array $condition, array $params = []): BaseCollection
{
$rows = $this->db->selectToArray(static::$table_name, [], $condition, $params);
$Entities = new BaseCollection();
foreach ($rows as $fields) {
$Entities[] = $this->factory->createFromTableRow($fields);
}
return $Entities;
}
/**
* @param array $condition
* @param array $params
* @return BaseEntity
* @throws NotFoundException
*/
protected function _selectOne(array $condition, array $params = []): BaseEntity
{
$fields = $this->db->selectFirst(static::$table_name, [], $condition, $params);
if (!$this->db->isResult($fields)) {
throw new NotFoundException();
}
return $this->factory->createFromTableRow($fields);
}
/**
* @param array $condition
* @param array $params
* @return int
* @throws Exception
*/
public function count(array $condition, array $params = []): int
{
return $this->db->count(static::$table_name, $condition, $params);
}
/**
* @param array $condition
* @return bool
* @throws Exception
*/
public function exists(array $condition): bool
{
return $this->db->exists(static::$table_name, $condition);
}
}

View File

@ -21,231 +21,162 @@
namespace Friendica;
use Exception;
use Friendica\Capabilities\ICanCreateFromTableRow;
use Friendica\Database\Database;
use Friendica\Database\DBA;
use Friendica\Network\HTTPException;
use Friendica\Network\HTTPException\NotFoundException;
use Psr\Log\LoggerInterface;
/**
* Repositories are Factories linked to one or more database tables.
* Repositories are meant to store and retrieve Entities from the database.
*
* @see BaseModel
* @see BaseCollection
* The reason why there are methods prefixed with an underscore is because PHP doesn't support generic polymorphism
* which means we can't directly overload base methods and make parameters more strict (from a parent class to a child
* class for example)
*
* Similarly, we can't make an overloaded method return type more strict until we only support PHP version 7.4 but this
* is less pressing.
*/
abstract class BaseRepository extends BaseFactory
abstract class BaseRepository
{
const LIMIT = 30;
/** @var Database */
protected $dba;
/** @var string */
/**
* @var string This should be set to the main database table name the depository is using
*/
protected static $table_name;
/** @var BaseModel */
protected static $model_class;
/** @var Database */
protected $db;
/** @var BaseCollection */
protected static $collection_class;
/** @var LoggerInterface */
protected $logger;
public function __construct(Database $dba, LoggerInterface $logger)
/** @var ICanCreateFromTableRow */
protected $factory;
public function __construct(Database $database, LoggerInterface $logger, ICanCreateFromTableRow $factory)
{
parent::__construct($logger);
$this->dba = $dba;
$this->db = $database;
$this->logger = $logger;
$this->factory = $factory;
}
/**
* Fetches a single model record. The condition array is expected to contain a unique index (primary or otherwise).
* Populates the collection according to the condition. Retrieves a limited subset of entities depending on the
* boundaries and the limit. The total count of rows matching the condition is stored in the collection.
*
* Chainable.
*
* @param array $condition
* @return BaseModel
* @throws HTTPException\NotFoundException
*/
public function selectFirst(array $condition)
{
$data = $this->dba->selectFirst(static::$table_name, [], $condition);
if (!$data) {
throw new HTTPException\NotFoundException(static::class . ' record not found.');
}
return $this->create($data);
}
/**
* Populates a Collection according to the condition.
*
* Chainable.
*
* @param array $condition
* @param array $params
* @return BaseCollection
* @throws \Exception
*/
public function select(array $condition = [], array $params = [])
{
$models = $this->selectModels($condition, $params);
return new static::$collection_class($models);
}
/**
* Populates the collection according to the condition. Retrieves a limited subset of models depending on the boundaries
* and the limit. The total count of rows matching the condition is stored in the collection.
* Depends on the corresponding table featuring a numerical auto incremented column called `id`.
*
* max_id and min_id are susceptible to the query order:
* - min_id alone only reliably works with ASC order
* - max_id alone only reliably works with DESC order
* If the wrong order is detected in either case, we inverse the query order and we reverse the model array after the query
* If the wrong order is detected in either case, we reverse the query order and the entity list order after the query
*
* Chainable.
*
* @param array $condition
* @param array $params
* @param int? $min_id Retrieve models with an id no fewer than this, as close to it as possible
* @param int? $max_id Retrieve models with an id no greater than this, as close to it as possible
* @param int|null $min_id Retrieve models with an id no fewer than this, as close to it as possible
* @param int|null $max_id Retrieve models with an id no greater than this, as close to it as possible
* @param int $limit
* @return BaseCollection
* @throws \Exception
*/
public function selectByBoundaries(array $condition = [], array $params = [], int $min_id = null, int $max_id = null, int $limit = self::LIMIT)
{
$totalCount = DBA::count(static::$table_name, $condition);
protected function _selectByBoundaries(
array $condition = [],
array $params = [],
int $min_id = null,
int $max_id = null,
int $limit = self::LIMIT
): BaseCollection {
$totalCount = $this->count($condition);
$boundCondition = $condition;
$reverseModels = false;
$reverseOrder = false;
if (isset($min_id)) {
$boundCondition = DBA::mergeConditions($boundCondition, ['`id` > ?', $min_id]);
if (!isset($max_id) && isset($params['order']['id']) && ($params['order']['id'] === true || $params['order']['id'] === 'DESC')) {
$reverseModels = true;
$reverseOrder = true;
$params['order']['id'] = 'ASC';
}
}
if (isset($max_id)) {
if (isset($max_id) && $max_id > 0) {
$boundCondition = DBA::mergeConditions($boundCondition, ['`id` < ?', $max_id]);
if (!isset($min_id) && (!isset($params['order']['id']) || $params['order']['id'] === false || $params['order']['id'] === 'ASC')) {
$reverseModels = true;
$reverseOrder = true;
$params['order']['id'] = 'DESC';
}
}
$params['limit'] = $limit;
$models = $this->selectModels($boundCondition, $params);
if ($reverseModels) {
$models = array_reverse($models);
$Entities = $this->_select($boundCondition, $params);
if ($reverseOrder) {
$Entities->reverse();
}
return new static::$collection_class($models, $totalCount);
return new BaseCollection($Entities->getArrayCopy(), $totalCount);
}
/**
* This method updates the database row from the model.
*
* @param BaseModel $model
* @param array $condition
* @param array $params
* @return BaseCollection
* @throws Exception
*/
protected function _select(array $condition, array $params = []): BaseCollection
{
$rows = $this->db->selectToArray(static::$table_name, [], $condition, $params);
$Entities = new BaseCollection();
foreach ($rows as $fields) {
$Entities[] = $this->factory->createFromTableRow($fields);
}
return $Entities;
}
/**
* @param array $condition
* @param array $params
* @return BaseEntity
* @throws NotFoundException
*/
protected function _selectOne(array $condition, array $params = []): BaseEntity
{
$fields = $this->db->selectFirst(static::$table_name, [], $condition, $params);
if (!$this->db->isResult($fields)) {
throw new NotFoundException();
}
return $this->factory->createFromTableRow($fields);
}
/**
* @param array $condition
* @param array $params
* @return int
* @throws Exception
*/
public function count(array $condition, array $params = []): int
{
return $this->db->count(static::$table_name, $condition, $params);
}
/**
* @param array $condition
* @return bool
* @throws \Exception
* @throws Exception
*/
public function update(BaseModel $model)
public function exists(array $condition): bool
{
if ($this->dba->update(static::$table_name, $model->toArray(), ['id' => $model->id], $model->getOriginalData())) {
$model->resetOriginalData();
return true;
}
return false;
}
/**
* This method creates a new database row and returns a model if it was successful.
*
* @param array $fields
* @return BaseModel|bool
* @throws \Exception
*/
public function insert(array $fields)
{
$return = $this->dba->insert(static::$table_name, $fields);
if (!$return) {
throw new HTTPException\InternalServerErrorException('Unable to insert new row in table "' . static::$table_name . '"');
}
$fields['id'] = $this->dba->lastInsertId();
$return = $this->create($fields);
return $return;
}
/**
* Deletes the model record from the database.
*
* @param BaseModel $model
* @return bool
* @throws \Exception
*/
public function delete(BaseModel &$model)
{
if ($success = $this->dba->delete(static::$table_name, ['id' => $model->id])) {
$model = null;
}
return $success;
}
/**
* Base instantiation method, can be overriden to add specific dependencies
*
* @param array $data
* @return BaseModel
*/
protected function create(array $data)
{
return new static::$model_class($this->dba, $this->logger, $data);
}
/**
* @param array $condition Query condition
* @param array $params Additional query parameters
* @return BaseModel[]
* @throws \Exception
*/
protected function selectModels(array $condition, array $params = [])
{
$result = $this->dba->select(static::$table_name, [], $condition, $params);
/** @var BaseModel $prototype */
$prototype = null;
$models = [];
while ($record = $this->dba->fetch($result)) {
if ($prototype === null) {
$prototype = $this->create($record);
$models[] = $prototype;
} else {
$models[] = static::$model_class::createFromPrototype($prototype, $record);
}
}
$this->dba->close($result);
return $models;
}
/**
* @param BaseCollection $collection
*/
public function saveCollection(BaseCollection $collection)
{
$collection->map([$this, 'update']);
return $this->db->exists(static::$table_name, $condition);
}
}

View File

@ -19,11 +19,10 @@
*
*/
namespace Friendica\Collection;
namespace Friendica\Contact\FriendSuggest\Collection;
use Friendica\BaseCollection;
class FSuggests extends BaseCollection
class FriendSuggests extends BaseCollection
{
}

View File

@ -0,0 +1,83 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Contact\FriendSuggest\Entity;
use Friendica\BaseEntity;
/**
* Model for interacting with a friend suggestion
*
* @property-read int $uid
* @property-read int $cid
* @property-read string $name
* @property-read string $url
* @property-read string $request
* @property-read string $photo
* @property-read string $note
* @property-read \DateTime created
* @property-read int|null $id
*/
class FriendSuggest extends BaseEntity
{
/** @var int */
protected $uid;
/** @var int */
protected $cid;
/** @var string */
protected $name;
/** @var string */
protected $url;
/** @var string */
protected $request;
/** @var string */
protected $photo;
/** @var string */
protected $note;
/** @var \DateTime */
protected $created;
/** @var int|null */
protected $id;
/**
* @param int $uid
* @param int $cid
* @param string $name
* @param string $url
* @param string $request
* @param string $photo
* @param string $note
* @param \DateTime $created
* @param int|null $id
*/
public function __construct(int $uid, int $cid, string $name, string $url, string $request, string $photo, string $note, \DateTime $created, ?int $id = null)
{
$this->uid = $uid;
$this->cid = $cid;
$this->name = $name;
$this->url = $url;
$this->request = $request;
$this->photo = $photo;
$this->note = $note;
$this->created = $created;
$this->id = $id;
}
}

View File

@ -19,23 +19,12 @@
*
*/
namespace Friendica\Model;
namespace Friendica\Contact\FriendSuggest\Exception;
use Friendica\BaseModel;
/**
* Model for interacting with a friend suggestion
*
* @property int uid
* @property int cid
* @property string name
* @property string url
* @property string request
* @property string photo
* @property string note
* @property string created
*/
class FSuggest extends BaseModel
class FriendSuggestNotFoundException extends \OutOfBoundsException
{
public function __construct($message = '', \Throwable $previous = null)
{
parent::__construct($message, 404, $previous);
}
}

View File

@ -19,18 +19,12 @@
*
*/
namespace Friendica\Collection;
namespace Friendica\Contact\FriendSuggest\Exception;
use Friendica\BaseCollection;
use Friendica\Model;
class Notifications extends BaseCollection
class FriendSuggestPersistenceException extends \RuntimeException
{
/**
* @return Model\Notification
*/
public function current()
public function __construct($message = '', \Throwable $previous = null)
{
return parent::current();
parent::__construct($message, 500, $previous);
}
}

View File

@ -0,0 +1,72 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Contact\FriendSuggest\Factory;
use Friendica\BaseFactory;
use Friendica\Capabilities\ICanCreateFromTableRow;
use Friendica\Contact\FriendSuggest\Entity;
class FriendSuggest extends BaseFactory implements ICanCreateFromTableRow
{
/**
* @inheritDoc
*/
public function createFromTableRow(array $row): Entity\FriendSuggest
{
return new Entity\FriendSuggest(
$row['uid'] ?? 0,
$row['cid'] ?? 0,
$row['name'] ?? '',
$row['url'] ?? '',
$row['request'] ?? '',
$row['photo'] ?? '',
$row['note'] ?? '',
new \DateTime($row['created'] ?? 'now', new \DateTimeZone('UTC')),
$row['id'] ?? null
);
}
public function createNew(
int $uid,
int $cid,
string $name = '',
string $url = '',
string $request = '',
string $photo = '',
string $note = ''
): Entity\FriendSuggest {
return $this->createFromTableRow([
'uid' => $uid,
'cid' => $cid,
'name' => $name,
'url' => $url,
'request' => $request,
'photo' => $photo,
'note' => $note,
]);
}
public function createEmpty(int $id): Entity\FriendSuggest
{
return $this->createFromTableRow(['id' => $id]);
}
}

View File

@ -0,0 +1,159 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Contact\FriendSuggest\Repository;
use Friendica\BaseRepository;
use Friendica\Contact\FriendSuggest\Collection;
use Friendica\Contact\FriendSuggest\Entity;
use Friendica\Contact\FriendSuggest\Exception\FriendSuggestNotFoundException;
use Friendica\Contact\FriendSuggest\Exception\FriendSuggestPersistenceException;
use Friendica\Contact\FriendSuggest\Factory;
use Friendica\Database\Database;
use Friendica\Network\HTTPException\NotFoundException;
use Friendica\Util\DateTimeFormat;
use Psr\Log\LoggerInterface;
class FriendSuggest extends BaseRepository
{
/** @var Factory\FriendSuggest */
protected $factory;
protected static $table_name = 'fsuggest';
public function __construct(Database $database, LoggerInterface $logger, Factory\FriendSuggest $factory)
{
parent::__construct($database, $logger, $factory);
}
private function convertToTableRow(Entity\FriendSuggest $fsuggest): array
{
return [
'uid' => $fsuggest->uid,
'cid' => $fsuggest->cid,
'name' => $fsuggest->name,
'url' => $fsuggest->url,
'request' => $fsuggest->request,
'photo' => $fsuggest->photo,
'note' => $fsuggest->note,
'created' => $fsuggest->created->format(DateTimeFormat::MYSQL),
];
}
/**
* @param array $condition
* @param array $params
*
* @return Entity\FriendSuggest
*
* @throws NotFoundException The underlying exception if there's no FriendSuggest with the given conditions
*/
private function selectOne(array $condition, array $params = []): Entity\FriendSuggest
{
return parent::_selectOne($condition, $params);
}
/**
* @param array $condition
* @param array $params
*
* @return Collection\FriendSuggests
*
* @throws \Exception
*/
private function select(array $condition, array $params = []): Collection\FriendSuggests
{
return new Collection\FriendSuggests(parent::_select($condition, $params)->getArrayCopy());
}
/**
* @param int $id
*
* @return Entity\FriendSuggest
*
* @throws FriendSuggestNotFoundException in case there's no suggestion for this id
*/
public function selectOneById(int $id): Entity\FriendSuggest
{
try {
return $this->selectOne(['id' => $id]);
} catch (NotFoundException $e) {
throw new FriendSuggestNotFoundException(sprintf('No FriendSuggest found for id %d', $id));
}
}
/**
* @param int $cid
*
* @return Collection\FriendSuggests
*
* @throws FriendSuggestPersistenceException In case the underlying storage cannot select the suggestion
*/
public function selectForContact(int $cid): Collection\FriendSuggests
{
try {
return $this->select(['cid' => $cid]);
} catch (\Exception $e) {
throw new FriendSuggestPersistenceException(sprintf('Cannot select FriendSuggestion for contact %d', $cid));
}
}
/**
* @param Entity\FriendSuggest $fsuggest
*
* @return Entity\FriendSuggest
*
* @throws FriendSuggestNotFoundException in case the underlying storage cannot save the suggestion
*/
public function save(Entity\FriendSuggest $fsuggest): Entity\FriendSuggest
{
try {
$fields = $this->convertToTableRow($fsuggest);
if ($fsuggest->id) {
$this->db->update(self::$table_name, $fields, ['id' => $fsuggest->id]);
return $this->selectOneById($fsuggest->id);
} else {
$this->db->insert(self::$table_name, $fields);
return $this->selectOneById($this->db->lastInsertId());
}
} catch (\Exception $exception) {
throw new FriendSuggestNotFoundException(sprintf('Cannot insert/update the FriendSuggestion %d for user %d', $fsuggest->id, $fsuggest->uid), $exception);
}
}
/**
* @param Collection\FriendSuggests $fsuggests
*
* @return bool
*
* @throws FriendSuggestNotFoundException in case the underlying storage cannot delete the suggestion
*/
public function delete(Collection\FriendSuggests $fsuggests): bool
{
try {
$ids = $fsuggests->column('id');
return $this->db->delete(self::$table_name, ['id' => $ids]);
} catch (\Exception $exception) {
throw new FriendSuggestNotFoundException('Cannot delete the FriendSuggestions', $exception);
}
}
}

View File

@ -1,4 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Contact\Introduction\Collection;

View File

@ -1,4 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Contact\Introduction\Exception;

View File

@ -1,4 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Contact\Introduction\Exception;

View File

@ -19,9 +19,9 @@
*
*/
namespace Friendica\Contact\Introduction\Depository;
namespace Friendica\Contact\Introduction\Repository;
use Friendica\BaseDepository;
use Friendica\BaseRepository;
use Friendica\Contact\Introduction\Exception\IntroductionNotFoundException;
use Friendica\Contact\Introduction\Exception\IntroductionPersistenceException;
use Friendica\Contact\Introduction\Collection;
@ -32,7 +32,7 @@ use Friendica\Network\HTTPException\NotFoundException;
use Friendica\Util\DateTimeFormat;
use Psr\Log\LoggerInterface;
class Introduction extends BaseDepository
class Introduction extends BaseRepository
{
/** @var Factory\Introduction */
protected $factory;

View File

@ -0,0 +1,347 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
declare(strict_types=1);
namespace Friendica\Core\Logger\Handler;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Throwable;
/**
* A facility to enable logging of runtime errors, exceptions and fatal errors.
*
* Quick setup: <code>ErrorHandler::register($logger);</code>
*/
class ErrorHandler
{
/** @var LoggerInterface */
private $logger;
/** @var ?callable */
private $previousExceptionHandler = null;
/** @var array<class-string, LogLevel::*> an array of class name to LogLevel::* constant mapping */
private $uncaughtExceptionLevelMap = [];
/** @var callable|true|null */
private $previousErrorHandler = null;
/** @var array<int, LogLevel::*> an array of E_* constant to LogLevel::* constant mapping */
private $errorLevelMap = [];
/** @var bool */
private $handleOnlyReportedErrors = true;
/** @var bool */
private $hasFatalErrorHandler = false;
/** @var LogLevel::* */
private $fatalLevel = LogLevel::ALERT;
/** @var ?string */
private $reservedMemory = null;
/** @var ?mixed */
private $lastFatalTrace;
/** @var int[] */
private static $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR];
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* Registers a new ErrorHandler for a given Logger
*
* By default it will handle errors, exceptions and fatal errors
*
* @param LoggerInterface $logger
* @param array<int, LogLevel::*>|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling
* @param array<class-string, LogLevel::*>|false $exceptionLevelMap an array of class name to LogLevel::* constant mapping, or false to disable exception handling
* @param LogLevel::*|null|false $fatalLevel a LogLevel::* constant, null to use the default LogLevel::ALERT or false to disable fatal error handling
*
* @return ErrorHandler
*/
public static function register(LoggerInterface $logger, $errorLevelMap = [], $exceptionLevelMap = [], $fatalLevel = null): self
{
/** @phpstan-ignore-next-line */
$handler = new static($logger);
if ($errorLevelMap !== false) {
$handler->registerErrorHandler($errorLevelMap);
}
if ($exceptionLevelMap !== false) {
$handler->registerExceptionHandler($exceptionLevelMap);
}
if ($fatalLevel !== false) {
$handler->registerFatalHandler($fatalLevel);
}
return $handler;
}
/**
* Stringify the class of the given object for logging purpose
*
* @param object $object An object to retrieve the class
*
* @return string the classname of the object
*/
public static function getClass(object $object): string
{
$class = \get_class($object);
if (false === ($pos = \strpos($class, "@anonymous\0"))) {
return $class;
}
if (false === ($parent = \get_parent_class($class))) {
return \substr($class, 0, $pos + 10);
}
return $parent . '@anonymous';
}
/**
* @param array<class-string, LogLevel::*> $levelMap an array of class name to LogLevel::* constant mapping
* @param bool $callPrevious Set to true, if a previously defined exception handler should be called after handling this exception
*
* @return $this
*/
public function registerExceptionHandler(array $levelMap = [], bool $callPrevious = true): self
{
$prev = set_exception_handler(function (Throwable $e): void {
$this->handleException($e);
});
$this->uncaughtExceptionLevelMap = $levelMap;
foreach ($this->defaultExceptionLevelMap() as $class => $level) {
if (!isset($this->uncaughtExceptionLevelMap[$class])) {
$this->uncaughtExceptionLevelMap[$class] = $level;
}
}
if ($callPrevious && $prev) {
$this->previousExceptionHandler = $prev;
}
return $this;
}
/**
* @param array<int, LogLevel::*> $levelMap an array of E_* constant to LogLevel::* constant mapping
* @param bool $callPrevious Set to true, if a previously defined exception handler should be called after handling this exception
* @param int $errorTypes a Mask for masking the errortypes, which should be handled by this error handler
* @param bool $handleOnlyReportedErrors Set to true, only errors set per error_reporting() will be logged
*
* @return $this
*/
public function registerErrorHandler(array $levelMap = [], bool $callPrevious = true, int $errorTypes = -1, bool $handleOnlyReportedErrors = true): self
{
$prev = set_error_handler([$this, 'handleError'], $errorTypes);
$this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
if ($callPrevious) {
$this->previousErrorHandler = $prev ?: true;
} else {
$this->previousErrorHandler = null;
}
$this->handleOnlyReportedErrors = $handleOnlyReportedErrors;
return $this;
}
/**
* @param LogLevel::*|null $level a LogLevel::* constant, null to use the default LogLevel::ALERT
* @param int $reservedMemorySize Amount of KBs to reserve in memory so that it can be freed when handling fatal errors giving Monolog some room in memory to get its job done
*
* @return $this
*/
public function registerFatalHandler($level = null, int $reservedMemorySize = 20): self
{
register_shutdown_function([$this, 'handleFatalError']);
$this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
$this->fatalLevel = null === $level ? LogLevel::ALERT : $level;
$this->hasFatalErrorHandler = true;
return $this;
}
/**
* @return array<class-string, LogLevel::*>
*/
protected function defaultExceptionLevelMap(): array
{
return [
'ParseError' => LogLevel::CRITICAL,
'Throwable' => LogLevel::ERROR,
];
}
/**
* @return array<int, LogLevel::*>
*/
protected function defaultErrorLevelMap(): array
{
return [
E_ERROR => LogLevel::CRITICAL,
E_WARNING => LogLevel::WARNING,
E_PARSE => LogLevel::ALERT,
E_NOTICE => LogLevel::NOTICE,
E_CORE_ERROR => LogLevel::CRITICAL,
E_CORE_WARNING => LogLevel::WARNING,
E_COMPILE_ERROR => LogLevel::ALERT,
E_COMPILE_WARNING => LogLevel::WARNING,
E_USER_ERROR => LogLevel::ERROR,
E_USER_WARNING => LogLevel::WARNING,
E_USER_NOTICE => LogLevel::NOTICE,
E_STRICT => LogLevel::NOTICE,
E_RECOVERABLE_ERROR => LogLevel::ERROR,
E_DEPRECATED => LogLevel::NOTICE,
E_USER_DEPRECATED => LogLevel::NOTICE,
];
}
/**
* The Exception handler
*
* @param Throwable $e The Exception to handle
*/
private function handleException(Throwable $e): void
{
$level = LogLevel::ERROR;
foreach ($this->uncaughtExceptionLevelMap as $class => $candidate) {
if ($e instanceof $class) {
$level = $candidate;
break;
}
}
$this->logger->log(
$level,
sprintf('Uncaught Exception %s: "%s" at %s line %s', self::getClass($e), $e->getMessage(), $e->getFile(), $e->getLine()),
['exception' => $e]
);
if ($this->previousExceptionHandler) {
($this->previousExceptionHandler)($e);
}
if (!headers_sent() && !ini_get('display_errors')) {
http_response_code(500);
}
exit(255);
}
/**
* The Error handler
*
* @private
*
* @param int $code The PHP error code
* @param string $message The error message
* @param string $file If possible, set the file at which the failure occurred
* @param int $line
* @param array|null $context If possible, add a context to the error for better analysis
*
* @return bool
*/
public function handleError(int $code, string $message, string $file = '', int $line = 0, ?array $context = []): bool
{
if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) {
return false;
}
// fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries
if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) {
$level = $this->errorLevelMap[$code] ?? LogLevel::CRITICAL;
$this->logger->log($level, self::codeToString($code).': '.$message, ['code' => $code, 'message' => $message, 'file' => $file, 'line' => $line]);
} else {
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
array_shift($trace); // Exclude handleError from trace
$this->lastFatalTrace = $trace;
}
if ($this->previousErrorHandler === true) {
return false;
} elseif ($this->previousErrorHandler) {
return (bool) ($this->previousErrorHandler)($code, $message, $file, $line, $context);
}
return true;
}
/**
* @private
*/
public function handleFatalError(): void
{
$this->reservedMemory = '';
$lastError = error_get_last();
if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) {
$this->logger->log(
$this->fatalLevel,
'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
['code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace]
);
}
}
/**
* @param mixed $code
*
* @return string
*/
private static function codeToString($code): string
{
switch ($code) {
case E_ERROR:
return 'E_ERROR';
case E_WARNING:
return 'E_WARNING';
case E_PARSE:
return 'E_PARSE';
case E_NOTICE:
return 'E_NOTICE';
case E_CORE_ERROR:
return 'E_CORE_ERROR';
case E_CORE_WARNING:
return 'E_CORE_WARNING';
case E_COMPILE_ERROR:
return 'E_COMPILE_ERROR';
case E_COMPILE_WARNING:
return 'E_COMPILE_WARNING';
case E_USER_ERROR:
return 'E_USER_ERROR';
case E_USER_WARNING:
return 'E_USER_WARNING';
case E_USER_NOTICE:
return 'E_USER_NOTICE';
case E_STRICT:
return 'E_STRICT';
case E_RECOVERABLE_ERROR:
return 'E_RECOVERABLE_ERROR';
case E_DEPRECATED:
return 'E_DEPRECATED';
case E_USER_DEPRECATED:
return 'E_USER_DEPRECATED';
}
return 'Unknown PHP error';
}
}

View File

@ -27,7 +27,7 @@ use Friendica\DI;
use Friendica\Model\Photo;
use Friendica\Model\Profile;
use Friendica\Object\Image;
use Friendica\Security\PermissionSet\Depository\PermissionSet;
use Friendica\Security\PermissionSet\Repository\PermissionSet;
use Friendica\Util\Strings;
use Friendica\Worker\Delivery;

View File

@ -427,19 +427,27 @@ abstract class DI
//
/**
* @return Repository\FSuggest;
* @return Contact\FriendSuggest\Repository\FriendSuggest;
*/
public static function fsuggest()
{
return self::$dice->create(Repository\FSuggest::class);
return self::$dice->create(Contact\FriendSuggest\Repository\FriendSuggest::class);
}
/**
* @return Contact\Introduction\Depository\Introduction
* @return Contact\FriendSuggest\Factory\FriendSuggest;
*/
public static function fsuggestFactory()
{
return self::$dice->create(Contact\FriendSuggest\Factory\FriendSuggest::class);
}
/**
* @return Contact\Introduction\Repository\Introduction
*/
public static function intro()
{
return self::$dice->create(Contact\Introduction\Depository\Introduction::class);
return self::$dice->create(Contact\Introduction\Repository\Introduction::class);
}
/**
@ -450,9 +458,9 @@ abstract class DI
return self::$dice->create(Contact\Introduction\Factory\Introduction::class);
}
public static function permissionSet(): Security\PermissionSet\Depository\PermissionSet
public static function permissionSet(): Security\PermissionSet\Repository\PermissionSet
{
return self::$dice->create(Security\PermissionSet\Depository\PermissionSet::class);
return self::$dice->create(Security\PermissionSet\Repository\PermissionSet::class);
}
public static function permissionSetFactory(): Security\PermissionSet\Factory\PermissionSet
@ -460,9 +468,9 @@ abstract class DI
return self::$dice->create(Security\PermissionSet\Factory\PermissionSet::class);
}
public static function profileField(): Profile\ProfileField\Depository\ProfileField
public static function profileField(): Profile\ProfileField\Repository\ProfileField
{
return self::$dice->create(Profile\ProfileField\Depository\ProfileField::class);
return self::$dice->create(Profile\ProfileField\Repository\ProfileField::class);
}
public static function profileFieldFactory(): Profile\ProfileField\Factory\ProfileField
@ -470,9 +478,9 @@ abstract class DI
return self::$dice->create(Profile\ProfileField\Factory\ProfileField::class);
}
public static function notification(): Navigation\Notifications\Depository\Notification
public static function notification(): Navigation\Notifications\Repository\Notification
{
return self::$dice->create(Navigation\Notifications\Depository\Notification::class);
return self::$dice->create(Navigation\Notifications\Repository\Notification::class);
}
public static function notificationFactory(): Navigation\Notifications\Factory\Notification
@ -480,9 +488,9 @@ abstract class DI
return self::$dice->create(Navigation\Notifications\Factory\Notification::class);
}
public static function notify(): Navigation\Notifications\Depository\Notify
public static function notify(): Navigation\Notifications\Repository\Notify
{
return self::$dice->create(Navigation\Notifications\Depository\Notify::class);
return self::$dice->create(Navigation\Notifications\Repository\Notify::class);
}
public static function notifyFactory(): Navigation\Notifications\Factory\Notify

View File

@ -27,7 +27,7 @@ use Friendica\Collection\Api\Mastodon\Fields;
use Friendica\Model\APContact;
use Friendica\Model\Contact;
use Friendica\Network\HTTPException;
use Friendica\Profile\ProfileField\Depository\ProfileField as ProfileFieldDepository;
use Friendica\Profile\ProfileField\Repository\ProfileField as ProfileFieldRepository;
use ImagickException;
use Psr\Log\LoggerInterface;
@ -35,17 +35,17 @@ class Account extends BaseFactory
{
/** @var BaseURL */
private $baseUrl;
/** @var ProfileFieldDepository */
private $profileFieldDepo;
/** @var ProfileFieldRepository */
private $profileFieldRepo;
/** @var Field */
private $mstdnFieldFactory;
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileFieldDepository $profileFieldDepo, Field $mstdnFieldFactory)
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileFieldRepository $profileFieldRepo, Field $mstdnFieldFactory)
{
parent::__construct($logger);
$this->baseUrl = $baseURL;
$this->profileFieldDepo = $profileFieldDepo;
$this->profileFieldRepo = $profileFieldRepo;
$this->mstdnFieldFactory = $mstdnFieldFactory;
}
@ -76,7 +76,7 @@ class Account extends BaseFactory
$self_contact = Contact::selectFirst(['uid'], ['nurl' => $publicContact['nurl'], 'self' => true]);
if (!empty($self_contact['uid'])) {
$profileFields = $this->profileFieldDepo->selectPublicFieldsByUserId($self_contact['uid']);
$profileFields = $this->profileFieldRepo->selectPublicFieldsByUserId($self_contact['uid']);
$fields = $this->mstdnFieldFactory->createFromProfileFields($profileFields);
} else {
$fields = new Fields();
@ -94,7 +94,7 @@ class Account extends BaseFactory
{
$publicContact = Contact::selectFirst([], ['uid' => $userId, 'self' => true]);
$profileFields = $this->profileFieldDepo->selectPublicFieldsByUserId($userId);
$profileFields = $this->profileFieldRepo->selectPublicFieldsByUserId($userId);
$fields = $this->mstdnFieldFactory->createFromProfileFields($profileFields);
$apContact = APContact::getByURL($publicContact['url'], false);

View File

@ -1553,18 +1553,22 @@ class Contact
*/
public static function checkAvatarCache(int $cid)
{
$contact = DBA::selectFirst('contact', ['url', 'avatar', 'photo', 'thumb', 'micro'], ['id' => $cid, 'uid' => 0, 'self' => false]);
$contact = DBA::selectFirst('contact', ['url', 'network', 'avatar', 'photo', 'thumb', 'micro'], ['id' => $cid, 'uid' => 0, 'self' => false]);
if (!DBA::isResult($contact)) {
return;
}
if (empty($contact['avatar']) || (!empty($contact['photo']) && !empty($contact['thumb']) && !empty($contact['micro']))) {
if (in_array($contact['network'], [Protocol::FEED, Protocol::MAIL]) || DI::config()->get('system', 'cache_contact_avatar')) {
if (!empty($contact['avatar']) && (empty($contact['photo']) || empty($contact['thumb']) || empty($contact['micro']))) {
Logger::info('Adding avatar cache', ['id' => $cid, 'contact' => $contact]);
self::updateAvatar($cid, $contact['avatar'], true);
return;
}
Logger::info('Adding avatar cache', ['id' => $cid, 'contact' => $contact]);
} elseif (!empty($contact['photo']) || !empty($contact['thumb']) || !empty($contact['micro'])) {
Logger::info('Removing avatar cache', ['id' => $cid, 'contact' => $contact]);
self::updateAvatar($cid, $contact['avatar'], true);
return;
}
}
/**
@ -1868,6 +1872,7 @@ class Contact
$avatar = self::getDefaultAvatar($contact, Proxy::SIZE_SMALL);
}
if (in_array($contact['network'], [Protocol::FEED, Protocol::MAIL]) || DI::config()->get('system', 'cache_contact_avatar')) {
if ($default_avatar && Proxy::isLocalImage($avatar)) {
$fields = ['avatar' => $avatar, 'avatar-date' => DateTimeFormat::utcNow(),
'photo' => $avatar,
@ -1917,6 +1922,12 @@ class Contact
} else {
$update = ($fields['photo'] . $fields['thumb'] . $fields['micro'] != $contact['photo'] . $contact['thumb'] . $contact['micro']) || $force;
}
} else {
Photo::delete(['uid' => $uid, 'contact-id' => $cid, 'photo-type' => Photo::CONTACT_AVATAR]);
$fields = ['avatar' => $avatar, 'avatar-date' => DateTimeFormat::utcNow(),
'photo' => '', 'thumb' => '', 'micro' => ''];
$update = ($avatar != $contact['avatar'] . $contact['photo'] . $contact['thumb'] . $contact['micro']) || $force;
}
if (!$update) {
return;

View File

@ -49,7 +49,7 @@ class Event
$uriid = $event['uri-id'] ?? $uriid;
$bd_format = DI::l10n()->t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8 AM.
$bd_format = DI::l10n()->t('l F d, Y \@ g:i A \G\M\TP (e)'); // Friday October 29, 2021 @ 9:15 AM GMT-04:00 (America/New_York)
$event_start = DI::l10n()->getDay(DateTimeFormat::local($event['start'], $bd_format));

View File

@ -31,6 +31,7 @@ use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Network\HTTPException;
use Friendica\Protocol\ActivityPub;
use Friendica\Security\PermissionSet\Repository\PermissionSet;
use Friendica\Util\HTTPSignature;
use Friendica\Util\Network;
use Friendica\Util\Strings;
@ -84,11 +85,8 @@ class Objects extends BaseModule
$requester_id = Contact::getIdForURL($requester, $item['uid']);
if (!empty($requester_id)) {
$permissionSets = DI::permissionSet()->selectByContactId($requester_id, $item['uid']);
if (!empty($permissionSets)) {
$psid = array_merge($permissionSets->column('id'),
[DI::permissionSet()->selectPublicForUser($item['uid'])]);
$validated = in_array($item['psid'], $psid);
}
$psids = array_merge($permissionSets->column('id'), [PermissionSet::PUBLIC]);
$validated = in_array($item['psid'], $psids);
}
}
}

View File

@ -163,6 +163,7 @@ class Site extends BaseAdmin
$allow_users_remote_self = !empty($_POST['allow_users_remote_self']);
$explicit_content = !empty($_POST['explicit_content']);
$proxify_content = !empty($_POST['proxify_content']);
$cache_contact_avatar = !empty($_POST['cache_contact_avatar']);
$enable_multi_reg = !empty($_POST['enable_multi_reg']);
$enable_openid = !empty($_POST['enable_openid']);
@ -330,6 +331,7 @@ class Site extends BaseAdmin
DI::config()->set('system', 'allow_users_remote_self', $allow_users_remote_self);
DI::config()->set('system', 'explicit_content' , $explicit_content);
DI::config()->set('system', 'proxify_content' , $proxify_content);
DI::config()->set('system', 'cache_contact_avatar' , $cache_contact_avatar);
DI::config()->set('system', 'check_new_version_url' , $check_new_version_url);
DI::config()->set('system', 'block_extended_register', !$enable_multi_reg);
@ -554,6 +556,7 @@ class Site extends BaseAdmin
'$disable_embedded' => ['disable_embedded', DI::l10n()->t('Don\'t embed private images in posts'), DI::config()->get('system', 'disable_embedded'), DI::l10n()->t('Don\'t replace locally-hosted private photos in posts with an embedded copy of the image. This means that contacts who receive posts containing private photos will have to authenticate and load each image, which may take a while.')],
'$explicit_content' => ['explicit_content', DI::l10n()->t('Explicit Content'), DI::config()->get('system', 'explicit_content'), DI::l10n()->t('Set this to announce that your node is used mostly for explicit content that might not be suited for minors. This information will be published in the node information and might be used, e.g. by the global directory, to filter your node from listings of nodes to join. Additionally a note about this will be shown at the user registration page.')],
'$proxify_content' => ['proxify_content', DI::l10n()->t('Proxify external content'), DI::config()->get('system', 'proxify_content'), DI::l10n()->t('Route external content via the proxy functionality. This is used for example for some OEmbed accesses and in some other rare cases.')],
'$cache_contact_avatar' => ['cache_contact_avatar', DI::l10n()->t('Cache contact avatars'), DI::config()->get('system', 'cache_contact_avatar'), DI::l10n()->t('Locally store the avatar pictures of the contacts. This uses a lot of storage space but it increases the performance.')],
'$allow_users_remote_self'=> ['allow_users_remote_self', DI::l10n()->t('Allow Users to set remote_self'), DI::config()->get('system', 'allow_users_remote_self'), DI::l10n()->t('With checking this, every user is allowed to mark every contact as a remote_self in the repair contact dialog. Setting this flag on a contact causes mirroring every posting of that contact in the users stream.')],
'$enable_multi_reg' => ['enable_multi_reg', DI::l10n()->t('Enable multiple registrations'), !DI::config()->get('system', 'block_extended_register'), DI::l10n()->t('Enable users to register additional accounts for use as pages.')],
'$enable_openid' => ['enable_openid', DI::l10n()->t('Enable OpenID'), !DI::config()->get('system', 'no_openid'), DI::l10n()->t('Enable OpenID support for registration and logins.')],

View File

@ -28,7 +28,7 @@ use Friendica\Model\Contact;
use Friendica\Model\Profile;
use Friendica\Module\BaseApi;
use Friendica\Network\HTTPException;
use Friendica\Security\PermissionSet\Depository\PermissionSet;
use Friendica\Security\PermissionSet\Repository\PermissionSet;
/**
* API endpoint: /api/friendica/profile/show

View File

@ -68,16 +68,15 @@ class FriendSuggest extends BaseModule
$note = Strings::escapeHtml(trim($_POST['note'] ?? ''));
$suggest = DI::fsuggest()->insert([
'uid' => local_user(),
'cid' => $cid,
'name' => $contact['name'],
'url' => $contact['url'],
'request' => $contact['request'],
'photo' => $contact['avatar'],
'note' => $note,
'created' => DateTimeFormat::utcNow()
]);
$suggest = DI::fsuggest()->save(DI::fsuggestFactory()->createNew(
local_user(),
$cid,
$contact['name'],
$contact['url'],
$contact['request'],
$contact['avatar'],
$note
));
Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::SUGGESTION, $suggest->id);
@ -94,7 +93,7 @@ class FriendSuggest extends BaseModule
DI::baseUrl()->redirect();
}
$contacts = ContactModel::selectToArray(['id', 'name'], [
$suggestableContacts = ContactModel::selectToArray(['id', 'name'], [
'`uid` = ?
AND `id` != ?
AND `network` = ?
@ -111,8 +110,8 @@ class FriendSuggest extends BaseModule
$formattedContacts = [];
foreach ($contacts as $contact) {
$formattedContacts[$contact['id']] = $contact['name'];
foreach ($suggestableContacts as $suggestableContact) {
$formattedContacts[$suggestableContact['id']] = $suggestableContact['name'];
}
$tpl = Renderer::getMarkupTemplate('fsuggest.tpl');

View File

@ -36,6 +36,7 @@ use Friendica\Network\HTTPException;
use Friendica\Object\Image;
use Friendica\Util\Images;
use Friendica\Util\Network;
use Friendica\Util\ParseUrl;
use Friendica\Util\Proxy;
/**
@ -284,14 +285,26 @@ class Photo extends BaseModule
$url = $contact['avatar'];
} elseif (!empty($contact['avatar'])) {
$url = $contact['avatar'];
} elseif ($customsize <= Proxy::PIXEL_MICRO) {
}
$mimetext = '';
if (!empty($url)) {
$mime = ParseUrl::getContentType($url);
if (empty($mime) || ($mime[0] != 'image')) {
$url = '';
} else {
$mimetext = $mime[0] . '/' . $mime[1];
}
}
if (empty($url)) {
if ($customsize <= Proxy::PIXEL_MICRO) {
$url = Contact::getDefaultAvatar($contact, Proxy::SIZE_MICRO);
} elseif ($customsize <= Proxy::PIXEL_THUMB) {
$url = Contact::getDefaultAvatar($contact, Proxy::SIZE_THUMB);
} else {
$url = Contact::getDefaultAvatar($contact, Proxy::SIZE_SMALL);
}
return MPhoto::createPhotoForExternalResource($url);
}
return MPhoto::createPhotoForExternalResource($url, 0, $mimetext);
case "header":
$contact = Contact::getById($id, ['uid', 'url', 'header']);
if (empty($contact)) {

View File

@ -32,7 +32,7 @@ use Friendica\Model\Contact;
use Friendica\Model\Post;
use Friendica\Module\BaseNotifications;
use Friendica\Navigation\Notifications\Collection\FormattedNotifications;
use Friendica\Navigation\Notifications\Depository;
use Friendica\Navigation\Notifications\Repository;
use Friendica\Navigation\Notifications\ValueObject;
use Friendica\Network\HTTPException\InternalServerErrorException;
use Friendica\Protocol\Activity;
@ -54,14 +54,14 @@ class FormattedNotification extends BaseFactory
{
/** @var Database */
private $dba;
/** @var Depository\Notify */
/** @var Repository\Notify */
private $notify;
/** @var BaseURL */
private $baseUrl;
/** @var L10n */
private $l10n;
public function __construct(LoggerInterface $logger, Database $dba, Depository\Notify $notify, BaseURL $baseUrl, L10n $l10n)
public function __construct(LoggerInterface $logger, Database $dba, Repository\Notify $notify, BaseURL $baseUrl, L10n $l10n)
{
parent::__construct($logger);

View File

@ -1,10 +1,10 @@
<?php
namespace Friendica\Navigation\Notifications\Depository;
namespace Friendica\Navigation\Notifications\Repository;
use Exception;
use Friendica\BaseCollection;
use Friendica\BaseDepository;
use Friendica\BaseRepository;
use Friendica\Database\Database;
use Friendica\Database\DBA;
use Friendica\Model\Verb;
@ -15,7 +15,7 @@ use Friendica\Network\HTTPException\NotFoundException;
use Friendica\Util\DateTimeFormat;
use Psr\Log\LoggerInterface;
class Notification extends BaseDepository
class Notification extends BaseRepository
{
/** @var Factory\Notification */
protected $factory;

View File

@ -1,9 +1,9 @@
<?php
namespace Friendica\Navigation\Notifications\Depository;
namespace Friendica\Navigation\Notifications\Repository;
use Friendica\App\BaseURL;
use Friendica\BaseDepository;
use Friendica\BaseRepository;
use Friendica\Content\Text\Plaintext;
use Friendica\Core\Config\IConfig;
use Friendica\Core\Hook;
@ -22,7 +22,7 @@ use Friendica\Util\DateTimeFormat;
use Friendica\Util\Emailer;
use Psr\Log\LoggerInterface;
class Notify extends BaseDepository
class Notify extends BaseRepository
{
/** @var Factory\Notify */
protected $factory;

View File

@ -19,9 +19,9 @@
*
*/
namespace Friendica\Profile\ProfileField\Depository;
namespace Friendica\Profile\ProfileField\Repository;
use Friendica\BaseDepository;
use Friendica\BaseRepository;
use Friendica\Database\Database;
use Friendica\Profile\ProfileField\Exception\ProfileFieldNotFoundException;
use Friendica\Profile\ProfileField\Exception\ProfileFieldPersistenceException;
@ -29,11 +29,11 @@ use Friendica\Profile\ProfileField\Exception\UnexpectedPermissionSetException;
use Friendica\Profile\ProfileField\Factory;
use Friendica\Profile\ProfileField\Entity;
use Friendica\Profile\ProfileField\Collection;
use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
use Friendica\Util\DateTimeFormat;
use Psr\Log\LoggerInterface;
class ProfileField extends BaseDepository
class ProfileField extends BaseRepository
{
/** @var Factory\ProfileField */
protected $factory;
@ -42,14 +42,14 @@ class ProfileField extends BaseDepository
protected static $view_name = 'profile_field-view';
/** @var PermissionSetDepository */
protected $permissionSetDepository;
/** @var PermissionSetRepository */
protected $permissionSetRepository;
public function __construct(Database $database, LoggerInterface $logger, Factory\ProfileField $factory, PermissionSetDepository $permissionSetDepository)
public function __construct(Database $database, LoggerInterface $logger, Factory\ProfileField $factory, PermissionSetRepository $permissionSetRepository)
{
parent::__construct($database, $logger, $factory);
$this->permissionSetDepository = $permissionSetDepository;
$this->permissionSetRepository = $permissionSetRepository;
}
/**
@ -124,7 +124,7 @@ class ProfileField extends BaseDepository
public function selectPublicFieldsByUserId(int $uid): Collection\ProfileFields
{
try {
$publicPermissionSet = $this->permissionSetDepository->selectPublicForUser($uid);
$publicPermissionSet = $this->permissionSetRepository->selectPublicForUser($uid);
return $this->select([
'uid' => $uid,
@ -162,12 +162,12 @@ class ProfileField extends BaseDepository
*/
public function selectByContactId(int $cid, int $uid): Collection\ProfileFields
{
$permissionSets = $this->permissionSetDepository->selectByContactId($cid, $uid);
$permissionSets = $this->permissionSetRepository->selectByContactId($cid, $uid);
$permissionSetIds = $permissionSets->column('id');
// Includes public custom fields
$permissionSetIds[] = $this->permissionSetDepository->selectPublicForUser($uid)->id;
$permissionSetIds[] = $this->permissionSetRepository->selectPublicForUser($uid)->id;
return $this->select(
['uid' => $uid, 'psid' => $permissionSetIds],

View File

@ -1782,7 +1782,7 @@ class Transmitter
{
$owner = User::getOwnerDataById($uid);
$suggestion = DI::fsuggest()->getById($suggestion_id);
$suggestion = DI::fsuggest()->selectOneById($suggestion_id);
$data = ['@context' => ActivityPub::CONTEXT,
'id' => DI::baseUrl() . '/activity/' . System::createGUID(),

View File

@ -1,93 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Repository;
use Friendica\BaseRepository;
use Friendica\Collection;
use Friendica\Model;
class FSuggest extends BaseRepository
{
protected static $table_name = 'fsuggest';
protected static $model_class = Model\FSuggest::class;
protected static $collection_class = Collection\FSuggests::class;
/**
* @param array $data
* @return Model\FSuggest
*/
protected function create(array $data)
{
return new Model\FSuggest($this->dba, $this->logger, $data);
}
/**
* Returns the Friend Suggest based on it's ID
*
* @param int $id The id of the fsuggest
*
* @return Model\FSuggest
*
* @throws \Friendica\Network\HTTPException\NotFoundException
*/
public function getById(int $id)
{
return $this->selectFirst(['id' => $id]);
}
/**
* @param array $condition
* @return Model\FSuggest
* @throws \Friendica\Network\HTTPException\NotFoundException
*/
public function selectFirst(array $condition)
{
return parent::selectFirst($condition);
}
/**
* @param array $condition
* @param array $params
* @return Collection\FSuggests
* @throws \Exception
*/
public function select(array $condition = [], array $params = [])
{
return parent::select($condition, $params);
}
/**
* @param array $condition
* @param array $params
* @param int|null $min_id
* @param int|null $max_id
* @param int $limit
* @return Collection\FSuggests
* @throws \Exception
*/
public function selectByBoundaries(array $condition = [], array $params = [], int $min_id = null, int $max_id = null, int $limit = self::LIMIT)
{
return parent::selectByBoundaries($condition, $params, $min_id, $max_id, $limit);
}
}

View File

@ -1,4 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Security\PermissionSet\Collection;

View File

@ -1,9 +1,28 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Security\PermissionSet\Entity;
use Friendica\BaseEntity;
use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
/**
* @property-read int|null $id
@ -55,7 +74,7 @@ class PermissionSet extends BaseEntity
*/
public function isPublic(): bool
{
return (($this->id === PermissionSetDepository::PUBLIC) ||
return (($this->id === PermissionSetRepository::PUBLIC) ||
(is_null($this->id) &&
empty($this->allow_cid) &&
empty($this->allow_gid) &&

View File

@ -1,4 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Security\PermissionSet\Factory;

View File

@ -19,10 +19,10 @@
*
*/
namespace Friendica\Security\PermissionSet\Depository;
namespace Friendica\Security\PermissionSet\Repository;
use Exception;
use Friendica\BaseDepository;
use Friendica\BaseRepository;
use Friendica\Database\Database;
use Friendica\Model\Contact;
use Friendica\Model\Group;
@ -33,7 +33,7 @@ use Friendica\Security\PermissionSet\Entity;
use Friendica\Util\ACLFormatter;
use Psr\Log\LoggerInterface;
class PermissionSet extends BaseDepository
class PermissionSet extends BaseRepository
{
/** @var int Virtual permission set id for public permission */
const PUBLIC = 0;

View File

@ -1,4 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Security\TwoFactor\Collection;

View File

@ -1,4 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Security\TwoFactor\Factory;

View File

@ -1,4 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Security\TwoFactor\Model;

View File

@ -1,4 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Security\TwoFactor\Repository;

View File

@ -80,7 +80,7 @@ class RemoveContent
DBA::delete('contact-relation', ['relation-cid' => $id]);
DBA::delete('contact-relation', ['cid' => $id]);
DBA::delete('event', ['cid' => $id]);
DBA::delete('fsuggest', ['cid' => $id]);
DI::fsuggest()->delete(DI::fsuggest()->selectForContact($id));
DBA::delete('post-tag', ['cid' => $id]);
DBA::delete('user-contact', ['cid' => $id]);

View File

@ -21,6 +21,8 @@
namespace Friendica\Worker;
use Friendica\Contact\FriendSuggest\Collection\FriendSuggests;
use Friendica\Contact\FriendSuggest\Exception\FriendSuggestNotFoundException;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Database\DBA;
@ -64,8 +66,10 @@ class Delivery
}
$uid = $target_item['uid'];
} elseif ($cmd == self::SUGGESTION) {
$target_item = DBA::selectFirst('fsuggest', [], ['id' => $post_uriid]);
if (!DBA::isResult($target_item)) {
try {
$target_item = DI::fsuggest()->selectOneById($post_uriid)->toArray();
} catch (FriendSuggestNotFoundException $e) {
DI::logger()->info('Cannot find FriendSuggestion', ['id' => $post_uriid]);
return;
}
$uid = $target_item['uid'];
@ -209,7 +213,7 @@ class Delivery
// Also transmit via Diaspora if this is a direct answer to a Diaspora comment.
// This is done since the uri wouldn't match (Diaspora doesn't transmit it)
// Also transmit relayed posts from Diaspora contacts via Diaspora.
if (($contact['network'] != Protocol::DIASPORA) && in_array(Protocol::DIASPORA, [$parent['network'] ?? '', $thr_parent['network'] ?? '', $target_item['network']])) {
if (($contact['network'] != Protocol::DIASPORA) && in_array(Protocol::DIASPORA, [$parent['network'] ?? '', $thr_parent['network'] ?? '', $target_item['network']] ?? '')) {
Logger::info('Enforcing the Diaspora protocol', ['id' => $contact['id'], 'network' => $contact['network'], 'parent' => $parent['network'], 'thread-parent' => $thr_parent['network'], 'post' => $target_item['network']]);
$contact['network'] = Protocol::DIASPORA;
}
@ -269,7 +273,7 @@ class Delivery
private static function deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup, $server_protocol)
{
// Transmit Diaspora reshares via Diaspora if the Friendica contact support Diaspora
if (Diaspora::isReshare($target_item['body']) && !empty(FContact::getByURL($contact['addr'], false))) {
if (Diaspora::isReshare($target_item['body'] ?? '') && !empty(FContact::getByURL($contact['addr'], false))) {
Logger::info('Reshare will be transmitted via Diaspora', ['url' => $contact['url'], 'guid' => ($target_item['guid'] ?? '') ?: $target_item['id']]);
self::deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
return;
@ -284,7 +288,7 @@ class Delivery
} elseif ($cmd == self::SUGGESTION) {
$item = $target_item;
$atom = DFRN::fsuggest($item, $owner);
DBA::delete('fsuggest', ['id' => $item['id']]);
DI::fsuggest()->delete(new FriendSuggests([DI::fsuggest()->selectOneById($item['id'])]));
} elseif ($cmd == self::RELOCATION) {
$atom = DFRN::relocate($owner, $owner['uid']);
} elseif ($followup) {

View File

@ -90,7 +90,7 @@ class Notifier
'APDelivery', $cmd, $target_id, $inbox, $uid, $receivers, $post_uriid);
}
} elseif ($cmd == Delivery::SUGGESTION) {
$suggest = DI::fsuggest()->getById($target_id);
$suggest = DI::fsuggest()->selectOneById($target_id);
$uid = $suggest->uid;
$recipients[] = $suggest->cid;
} elseif ($cmd == Delivery::REMOVAL) {

View File

@ -64,6 +64,10 @@ return [
// Themes users can change to in their settings.
'allowed_themes' => 'frio,quattro,vier,duepuntozero,smoothly',
// cache_contact_avatar (Boolean)
// Cache versions of the contact avatars. Uses a lot of storage space
'cache_contact_avatar' => true,
// curl_timeout (Integer)
// Value is in seconds. Set to 0 for unlimited (not recommended).
'curl_timeout' => 60,

View File

@ -0,0 +1,122 @@
<?php
namespace Friendica\Test\src\Contact\FriendSuggest\Factory;
use Friendica\Contact\FriendSuggest\Factory\FriendSuggest;
use Friendica\Contact\FriendSuggest\Entity;
use Friendica\Test\MockedTest;
use Friendica\Util\Logger\VoidLogger;
class FriendSuggestTest extends MockedTest
{
public function dataCreate()
{
return [
'default' => [
'input' => [
'uid' => 12,
'cid' => 13,
'name' => 'test',
'url' => 'https://friendica.local/profile/test',
'request' => 'https://friendica.local/dfrn_request/test',
'photo' => 'https://friendica.local/photo/profile/test',
'note' => 'a common note',
'created' => '2021-10-12 12:23:00'
],
'assertion' => new Entity\FriendSuggest(
12,
13,
'test',
'https://friendica.local/profile/test',
'https://friendica.local/dfrn_request/test',
'https://friendica.local/photo/profile/test',
'a common note',
new \DateTime('2021-10-12 12:23:00', new \DateTimeZone('UTC'))
),
],
'minimum' => [
'input' => [
'id' => 20,
],
'assertion' => new Entity\FriendSuggest(
0,
0,
'',
'',
'',
'',
'',
new \DateTime('now', new \DateTimeZone('URC')),
28
),
],
'full' => [
'input' => [
'uid' => 12,
'cid' => 13,
'name' => 'test',
'url' => 'https://friendica.local/profile/test',
'request' => 'https://friendica.local/dfrn_request/test',
'photo' => 'https://friendica.local/photo/profile/test',
'note' => 'a common note',
'created' => '2021-10-12 12:23:00',
'id' => 666,
],
'assertion' => new Entity\FriendSuggest(
12,
13,
'test',
'https://friendica.local/profile/test',
'https://friendica.local/dfrn_request/test',
'https://friendica.local/photo/profile/test',
'a common note',
new \DateTime('2021-10-12 12:23:00', new \DateTimeZone('UTC')),
666
),
],
];
}
public function assertFriendSuggest(Entity\FriendSuggest $assertion, Entity\FriendSuggest $friendSuggest)
{
self::assertEquals($assertion->id, $friendSuggest->id);
self::assertEquals($assertion->uid, $friendSuggest->uid);
self::assertEquals($assertion->cid, $friendSuggest->cid);
self::assertEquals($assertion->name, $friendSuggest->name);
self::assertEquals($assertion->url, $friendSuggest->url);
self::assertEquals($assertion->request, $friendSuggest->request);
self::assertEquals($assertion->photo, $friendSuggest->photo);
self::assertEquals($assertion->note, $friendSuggest->note);
}
public function testCreateNew()
{
$factory = new FriendSuggest(new VoidLogger());
$this->assertFriendSuggest(
$factory->createNew(12, 13),
new Entity\FriendSuggest(12, 13, '', '', '', '', '',
new \DateTime('now', new \DateTimeZone('UTC')), null
)
);
}
/**
* @dataProvider dataCreate
*/
public function testCreateFromTableRow(array $input, Entity\FriendSuggest $assertion)
{
$factory = new FriendSuggest(new VoidLogger());
$this->assertFriendSuggest($factory->createFromTableRow($input), $assertion);
}
public function testCreateEmpty()
{
$factory = new FriendSuggest(new VoidLogger());
$this->assertFriendSuggest($factory->createEmpty(66), new Entity\FriendSuggest(0, 0, '', '', '', '', '',
new \DateTime('now', new \DateTimeZone('UTC')), 66
));
}
}

View File

@ -6,7 +6,7 @@ use Friendica\Profile\ProfileField\Entity\ProfileField;
use Friendica\Profile\ProfileField\Exception\ProfileFieldNotFoundException;
use Friendica\Profile\ProfileField\Exception\UnexpectedPermissionSetException;
use Friendica\Profile\ProfileField\Factory\ProfileField as ProfileFieldFactory;
use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory;
use Friendica\Test\MockedTest;
use Friendica\Util\ACLFormatter;
@ -16,8 +16,8 @@ use Mockery\MockInterface;
class ProfileFieldTest extends MockedTest
{
/** @var MockInterface|PermissionSetDepository */
protected $permissionSetDepository;
/** @var MockInterface|PermissionSetRepository */
protected $permissionSetRepository;
/** @var ProfileFieldFactory */
protected $profileFieldFactory;
/** @var MockInterface|PermissionSetFactory */
@ -27,7 +27,7 @@ class ProfileFieldTest extends MockedTest
{
parent::setUp();
$this->permissionSetDepository = \Mockery::mock(PermissionSetDepository::class);
$this->permissionSetRepository = \Mockery::mock(PermissionSetRepository::class);
$this->permissionSetFactory = new PermissionSetFactory(new VoidLogger(), new ACLFormatter());
$this->profileFieldFactory = new ProfileFieldFactory(new VoidLogger(), $this->permissionSetFactory);
}
@ -180,7 +180,7 @@ class ProfileFieldTest extends MockedTest
$permissionSet = $this->permissionSetFactory->createFromTableRow(['uid' => $uid, 'id' => $psid]);
$this->permissionSetDepository->shouldReceive('selectOneById')->with($psid, $uid)->andReturns($permissionSet);
$this->permissionSetRepository->shouldReceive('selectOneById')->with($psid, $uid)->andReturns($permissionSet);
self::assertEquals($psid, $entity->permissionSet->id);
}

View File

@ -1,27 +1,27 @@
<?php
namespace Friendica\Test\src\Profile\ProfileField\Depository;
namespace Friendica\Test\src\Profile\ProfileField\Repository;
use Friendica\Profile\ProfileField\Collection\ProfileFields;
use Friendica\Profile\ProfileField\Depository\ProfileField as ProfileFieldDepository;
use Friendica\Profile\ProfileField\Repository\ProfileField as ProfileFieldRepository;
use Friendica\Profile\ProfileField\Exception\ProfileFieldPersistenceException;
use Friendica\Profile\ProfileField\Factory\ProfileField as ProfileFieldFactory;
use Friendica\Security\PermissionSet\Depository\PermissionSet;
use Friendica\Security\PermissionSet\Repository\PermissionSet;
use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory;
use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
use Friendica\Test\FixtureTest;
use Friendica\DI;
class ProfileFieldTest extends FixtureTest
{
/** @var ProfileFieldDepository */
/** @var ProfileFieldRepository */
private $depository;
/** @var ProfileFieldFactory */
private $factory;
/** @var PermissionSetFactory */
private $permissionSetFactory;
/** @var PermissionSetDepository */
private $permissionSetDepository;
/** @var PermissionSetRepository */
private $permissionSetRepository;
public function setUp(): void
{
@ -30,7 +30,7 @@ class ProfileFieldTest extends FixtureTest
$this->depository = DI::profileField();
$this->factory = DI::profileFieldFactory();
$this->permissionSetFactory = DI::permissionSetFactory();
$this->permissionSetDepository = DI::permissionSet();
$this->permissionSetRepository = DI::permissionSet();
}
/**
@ -53,7 +53,7 @@ class ProfileFieldTest extends FixtureTest
*/
public function testSaveNew()
{
$profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetDepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
$profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetRepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
@ -75,7 +75,7 @@ class ProfileFieldTest extends FixtureTest
*/
public function testUpdateOrder()
{
$profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetDepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
$profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetRepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
@ -108,7 +108,7 @@ class ProfileFieldTest extends FixtureTest
*/
public function testUpdate()
{
$profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetDepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
$profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetRepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
@ -121,12 +121,12 @@ class ProfileFieldTest extends FixtureTest
self::assertEquals($savedProfileField, $selectedProfileField);
$savedProfileField->update('another', 5, $this->permissionSetDepository->selectPublicForUser(42));
$savedProfileField->update('another', 5, $this->permissionSetRepository->selectPublicForUser(42));
self::assertEquals(PermissionSet::PUBLIC, $savedProfileField->permissionSet->id);
$publicProfileField = $this->depository->save($savedProfileField);
self::assertEquals($this->permissionSetDepository->selectPublicForUser(42), $publicProfileField->permissionSet);
self::assertEquals($this->permissionSetRepository->selectPublicForUser(42), $publicProfileField->permissionSet);
self::assertEquals('another', $publicProfileField->value);
self::assertEquals(5, $publicProfileField->order);

View File

@ -1,8 +1,8 @@
<?php
namespace Friendica\Test\src\Security\PermissionSet\Depository;
namespace Friendica\Test\src\Security\PermissionSet\Repository;
use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
use Friendica\Security\PermissionSet\Entity\PermissionSet;
use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory;
use Friendica\Test\FixtureTest;
@ -10,8 +10,8 @@ use Friendica\DI;
class PermissionSetTest extends FixtureTest
{
/** @var PermissionSetDepository */
private $depository;
/** @var PermissionSetRepository */
private $repository;
/** @var PermissionSetFactory */
private $factory;
@ -19,20 +19,20 @@ class PermissionSetTest extends FixtureTest
{
parent::setUp();
$this->depository = DI::permissionSet();
$this->repository = DI::permissionSet();
$this->factory = DI::permissionSetFactory();
}
public function testSelectOneByIdPublic()
{
$permissionSet = $this->depository->selectPublicForUser(1);
$permissionSet = $this->repository->selectPublicForUser(1);
$this->assertInstanceOf(PermissionSet::class, $permissionSet);
self::assertEmpty($permissionSet->allow_cid);
self::assertEmpty($permissionSet->allow_gid);
self::assertEmpty($permissionSet->deny_cid);
self::assertEmpty($permissionSet->deny_gid);
self::assertEmpty(PermissionSetDepository::PUBLIC, $permissionSet->id);
self::assertEmpty(PermissionSetRepository::PUBLIC, $permissionSet->id);
self::assertEquals(1, $permissionSet->uid);
}
@ -43,21 +43,21 @@ class PermissionSetTest extends FixtureTest
{
$permissionSet = $this->factory->createFromString(42, '', '<~>');
$permissionSet = $this->depository->selectOrCreate($permissionSet);
$permissionSet = $this->repository->selectOrCreate($permissionSet);
self::assertNotNull($permissionSet->id);
$permissionSetSelected = $this->depository->selectOneById($permissionSet->id, 42);
$permissionSetSelected = $this->repository->selectOneById($permissionSet->id, 42);
self::assertEquals($permissionSet, $permissionSetSelected);
$newPermissionSet = $permissionSet->withAllowedContacts(['1', '2']);
$savedPermissionSet = $this->depository->save($newPermissionSet);
$savedPermissionSet = $this->repository->save($newPermissionSet);
self::assertNotNull($savedPermissionSet->id);
self::assertNull($newPermissionSet->id);
$permissionSetSavedSelected = $this->depository->selectOneById($savedPermissionSet->id, 42);
$permissionSetSavedSelected = $this->repository->selectOneById($savedPermissionSet->id, 42);
self::assertEquals($savedPermissionSet, $permissionSetSavedSelected);
}

View File

@ -55,7 +55,7 @@ use Friendica\Model\Photo;
use Friendica\Model\Post;
use Friendica\Model\Profile;
use Friendica\Model\Storage;
use Friendica\Security\PermissionSet\Depository\PermissionSet;
use Friendica\Security\PermissionSet\Repository\PermissionSet;
use Friendica\Worker\Delivery;
// Post-update script of PR 5751

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1491,6 +1491,8 @@ $a->strings['Explicit Content'] = 'Sensibler Inhalt';
$a->strings['Set this to announce that your node is used mostly for explicit content that might not be suited for minors. This information will be published in the node information and might be used, e.g. by the global directory, to filter your node from listings of nodes to join. Additionally a note about this will be shown at the user registration page.'] = 'Wähle dies, um anzuzeigen, dass dein Knoten hauptsächlich für explizite Inhalte verwendet wird, die möglicherweise nicht für Minderjährige geeignet sind. Diese Info wird in der Knoteninformation veröffentlicht und kann durch das Globale Verzeichnis genutzt werden, um deinen Knoten von den Auflistungen auszuschließen. Zusätzlich wird auf der Registrierungsseite ein Hinweis darüber angezeigt.';
$a->strings['Proxify external content'] = 'Proxy für externe Inhalte';
$a->strings['Route external content via the proxy functionality. This is used for example for some OEmbed accesses and in some other rare cases.'] = 'Externe Inhalte werden durch einen Proxy geleitet. Die wird z.B. für das aufrufen von OEmbed Inhalten verwendet und einigen anderen seltenen Fällen.';
$a->strings['Cache contact avatars'] = 'Kontaktprofilbilder zwischenspeichern';
$a->strings['Locally store the avatar pictures of the contacts. This uses a lot of storage space but it increases the performance.'] = 'Die Profilbilder der Kontakte zwischenspeichern. Der Zwischenspeicher verbraucht viel Platz im Speicherplatz, verbessert aber die Performance.';
$a->strings['Allow Users to set remote_self'] = 'Nutzern erlauben, das remote_self Flag zu setzen';
$a->strings['With checking this, every user is allowed to mark every contact as a remote_self in the repair contact dialog. Setting this flag on a contact causes mirroring every posting of that contact in the users stream.'] = 'Ist dies ausgewählt, kann jeder Nutzer jeden seiner Kontakte als remote_self (entferntes Konto) im "Erweitert"-Reiter der Kontaktansicht markieren. Nach dem Setzen dieses Flags werden alle Top-Level-Beiträge dieser Kontakte automatisch in den Stream dieses Nutzers gepostet (gespiegelt).';
$a->strings['Enable multiple registrations'] = 'Erlaube Mehrfachregistrierung';
@ -2457,6 +2459,38 @@ $a->strings['Friendica respects your privacy. By default, your posts will only s
$a->strings['Getting Help'] = 'Hilfe bekommen';
$a->strings['Go to the Help Section'] = 'Zum Hilfe Abschnitt gehen';
$a->strings['Our <strong>help</strong> pages may be consulted for detail on other program features and resources.'] = 'Unsere <strong>Hilfe</strong>-Seiten können herangezogen werden, um weitere Einzelheiten zu anderen Programm-Features zu erhalten.';
$a->strings['%s liked %s\'s post'] = '%s mag %ss Beitrag';
$a->strings['%s disliked %s\'s post'] = '%s mag %ss Beitrag nicht';
$a->strings['%s is attending %s\'s event'] = '%s nimmt an %s\'s Event teil';
$a->strings['%s is not attending %s\'s event'] = '%s nimmt nicht an %s\'s Event teil';
$a->strings['%s may attending %s\'s event'] = '%s nimmt eventuell an %s\'s Veranstaltung teil';
$a->strings['%s is now friends with %s'] = '%s ist jetzt mit %s befreundet';
$a->strings['%s commented on %s\'s post'] = '%s hat %ss Beitrag kommentiert';
$a->strings['%s created a new post'] = '%s hat einen neuen Beitrag erstellt';
$a->strings['Friend Suggestion'] = 'Kontaktvorschlag';
$a->strings['Friend/Connect Request'] = 'Kontakt-/Freundschaftsanfrage';
$a->strings['New Follower'] = 'Neuer Bewunderer';
$a->strings['%1$s wants to follow you'] = '%1$s möchte dir folgen';
$a->strings['%1$s had started following you'] = '%1$s hat angefangen dir zu folgen';
$a->strings['%1$s liked your comment %2$s'] = '%1$s mag deinen Kommentar %2$s';
$a->strings['%1$s liked your post %2$s'] = '%1$s mag deinen Beitrag %2$s';
$a->strings['%1$s disliked your comment %2$s'] = '%1$s mag deinen Kommentar %2$s nicht';
$a->strings['%1$s disliked your post %2$s'] = '%1$s mag deinen Beitrag %2$s nicht';
$a->strings['%1$s shared your comment %2$s'] = '%1$s hat deinen Kommentar %2$s geteilt';
$a->strings['%1$s shared your post %2$s'] = '%1$s hat deinen Beitrag %2$s geteilt';
$a->strings['%1$s tagged you on %2$s'] = '%1$s erwähnte dich auf %2$s';
$a->strings['%1$s replied to you on %2$s'] = '%1$s hat dir auf %2$s geantwortet';
$a->strings['%1$s commented in your thread %2$s'] = '%1$s hat deine Unterhaltung %2$s kommentiert';
$a->strings['%1$s commented on your comment %2$s'] = '%1$s hat deinen Kommentar %2$s kommentiert';
$a->strings['%1$s commented in their thread %2$s'] = '%1$s hat in der eigenen Unterhaltung %2$s kommentiert';
$a->strings['%1$s commented in their thread'] = '%1$s kommentierte in der eigenen Unterhaltung';
$a->strings['%1$s commented in the thread %2$s from %3$s'] = '%1$s hat in der Unterhaltung %2$s von %3$s kommentiert';
$a->strings['%1$s commented in the thread from %3$s'] = '%1$s hat in der Unterhaltung von %3$s kommentiert';
$a->strings['%1$s commented on your thread %2$s'] = '%1$s hat in deiner Unterhaltung %2$s kommentiert';
$a->strings['%1$s shared the post %2$s from %3$s'] = '%1$s hat den Beitrag %2$s von %3$s geteilt';
$a->strings['%1$s shared a post from %3$s'] = '%1$s hat einen Beitrag von %3$s geteilt';
$a->strings['%1$s shared the post %2$s'] = '%1$s hat den Beitrag %2$s geteilt';
$a->strings['%1$s shared a post'] = '%1$s hat einen Beitrag geteilt';
$a->strings['[Friendica:Notify]'] = '[Friendica Meldung]';
$a->strings['%s New mail received at %s'] = '%sNeue Nachricht auf %s empfangen';
$a->strings['%1$s sent you a new private message at %2$s.'] = '%1$s hat dir eine neue, private Nachricht auf %2$s geschickt.';
@ -2509,38 +2543,6 @@ Login Name: %s(%s)';
$a->strings['Please visit %s to approve or reject the request.'] = 'Bitte besuche %s, um die Anfrage zu bearbeiten.';
$a->strings['%s %s tagged you'] = '%s %s hat dich erwähnt';
$a->strings['%s %s shared a new post'] = '%s%shat einen Beitrag geteilt';
$a->strings['%s liked %s\'s post'] = '%s mag %ss Beitrag';
$a->strings['%s disliked %s\'s post'] = '%s mag %ss Beitrag nicht';
$a->strings['%s is attending %s\'s event'] = '%s nimmt an %s\'s Event teil';
$a->strings['%s is not attending %s\'s event'] = '%s nimmt nicht an %s\'s Event teil';
$a->strings['%s may attending %s\'s event'] = '%s nimmt eventuell an %s\'s Veranstaltung teil';
$a->strings['%s is now friends with %s'] = '%s ist jetzt mit %s befreundet';
$a->strings['%s commented on %s\'s post'] = '%s hat %ss Beitrag kommentiert';
$a->strings['%s created a new post'] = '%s hat einen neuen Beitrag erstellt';
$a->strings['Friend Suggestion'] = 'Kontaktvorschlag';
$a->strings['Friend/Connect Request'] = 'Kontakt-/Freundschaftsanfrage';
$a->strings['New Follower'] = 'Neuer Bewunderer';
$a->strings['%1$s wants to follow you'] = '%1$s möchte dir folgen';
$a->strings['%1$s had started following you'] = '%1$s hat angefangen dir zu folgen';
$a->strings['%1$s liked your comment %2$s'] = '%1$s mag deinen Kommentar %2$s';
$a->strings['%1$s liked your post %2$s'] = '%1$s mag deinen Beitrag %2$s';
$a->strings['%1$s disliked your comment %2$s'] = '%1$s mag deinen Kommentar %2$s nicht';
$a->strings['%1$s disliked your post %2$s'] = '%1$s mag deinen Beitrag %2$s nicht';
$a->strings['%1$s shared your comment %2$s'] = '%1$s hat deinen Kommentar %2$s geteilt';
$a->strings['%1$s shared your post %2$s'] = '%1$s hat deinen Beitrag %2$s geteilt';
$a->strings['%1$s tagged you on %2$s'] = '%1$s erwähnte dich auf %2$s';
$a->strings['%1$s replied to you on %2$s'] = '%1$s hat dir auf %2$s geantwortet';
$a->strings['%1$s commented in your thread %2$s'] = '%1$s hat deine Unterhaltung %2$s kommentiert';
$a->strings['%1$s commented on your comment %2$s'] = '%1$s hat deinen Kommentar %2$s kommentiert';
$a->strings['%1$s commented in their thread %2$s'] = '%1$s hat in der eigenen Unterhaltung %2$s kommentiert';
$a->strings['%1$s commented in their thread'] = '%1$s kommentierte in der eigenen Unterhaltung';
$a->strings['%1$s commented in the thread %2$s from %3$s'] = '%1$s hat in der Unterhaltung %2$s von %3$s kommentiert';
$a->strings['%1$s commented in the thread from %3$s'] = '%1$s hat in der Unterhaltung von %3$s kommentiert';
$a->strings['%1$s commented on your thread %2$s'] = '%1$s hat in deiner Unterhaltung %2$s kommentiert';
$a->strings['%1$s shared the post %2$s from %3$s'] = '%1$s hat den Beitrag %2$s von %3$s geteilt';
$a->strings['%1$s shared a post from %3$s'] = '%1$s hat einen Beitrag von %3$s geteilt';
$a->strings['%1$s shared the post %2$s'] = '%1$s hat den Beitrag %2$s geteilt';
$a->strings['%1$s shared a post'] = '%1$s hat einen Beitrag geteilt';
$a->strings['This message was sent to you by %s, a member of the Friendica social network.'] = 'Diese Nachricht wurde dir von %s geschickt, einem Mitglied des Sozialen Netzwerks Friendica.';
$a->strings['You may visit them online at %s'] = 'Du kannst sie online unter %s besuchen';
$a->strings['Please contact the sender by replying to this post if you do not wish to receive these messages.'] = 'Falls du diese Beiträge nicht erhalten möchtest, kontaktiere bitte den Autor, indem du auf diese Nachricht antwortest.';

View File

@ -116,6 +116,7 @@
{{include file="field_input.tpl" field=$dbclean_unclaimed}}
{{include file="field_input.tpl" field=$dbclean_expire_conv}}
{{include file="field_checkbox.tpl" field=$optimize_tables}}
{{include file="field_checkbox.tpl" field=$cache_contact_avatar}}
<div class="submit"><input type="submit" name="page_site" value="{{$submit}}"/></div>
<h2>{{$worker_title}}</h2>

View File

@ -251,6 +251,7 @@
{{include file="field_input.tpl" field=$dbclean_unclaimed}}
{{include file="field_input.tpl" field=$dbclean_expire_conv}}
{{include file="field_checkbox.tpl" field=$optimize_tables}}
{{include file="field_checkbox.tpl" field=$cache_contact_avatar}}
</div>
<div class="panel-footer">
<input type="submit" name="page_site" class="btn btn-primary" value="{{$submit}}"/>