Merge branch '2023.03-rc' into stable
This commit is contained in:
+32
-78
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -25,11 +25,11 @@ use Exception;
|
||||
use Friendica\App\Arguments;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\Capabilities\ICanCreateResponses;
|
||||
use Friendica\Content\Nav;
|
||||
use Friendica\Core\Config\Factory\Config;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Database\Definition\DbaDefinition;
|
||||
use Friendica\Database\Definition\ViewDefinition;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Module\Maintenance;
|
||||
use Friendica\Security\Authentication;
|
||||
use Friendica\Core\Config\ValueObject\Cache;
|
||||
@@ -64,7 +64,7 @@ class App
|
||||
{
|
||||
const PLATFORM = 'Friendica';
|
||||
const CODENAME = 'Giant Rhubarb';
|
||||
const VERSION = '2023.01';
|
||||
const VERSION = '2023.03-rc';
|
||||
|
||||
// Allow themes to control internal parameters
|
||||
// by changing App values in theme.php
|
||||
@@ -73,8 +73,6 @@ class App
|
||||
'videoheight' => 350,
|
||||
];
|
||||
|
||||
private $user_id = 0;
|
||||
private $nickname = '';
|
||||
private $timezone = '';
|
||||
private $profile_owner = 0;
|
||||
private $contact_id = 0;
|
||||
@@ -136,64 +134,39 @@ class App
|
||||
private $session;
|
||||
|
||||
/**
|
||||
* Set the user ID
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return void
|
||||
* @deprecated 2022.03
|
||||
* @see IHandleUserSessions::isAuthenticated()
|
||||
*/
|
||||
public function setLoggedInUserId(int $user_id)
|
||||
{
|
||||
$this->user_id = $user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the nickname
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return void
|
||||
*/
|
||||
public function setLoggedInUserNickname(string $nickname)
|
||||
{
|
||||
$this->nickname = $nickname;
|
||||
}
|
||||
|
||||
public function isLoggedIn(): bool
|
||||
{
|
||||
return $this->session->getLocalUserId() && $this->user_id && ($this->user_id == $this->session->getLocalUserId());
|
||||
return $this->session->isAuthenticated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current user has admin role.
|
||||
*
|
||||
* @return bool true if user is an admin
|
||||
* @throws Exception
|
||||
* @deprecated 2022.03
|
||||
* @see IHandleUserSessions::isSiteAdmin()
|
||||
*/
|
||||
public function isSiteAdmin(): bool
|
||||
{
|
||||
return
|
||||
$this->session->getLocalUserId()
|
||||
&& $this->database->exists('user', [
|
||||
'uid' => $this->getLoggedInUserId(),
|
||||
'email' => User::getAdminEmailList()
|
||||
]);
|
||||
return $this->session->isSiteAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the user id
|
||||
* @return int User id
|
||||
* @deprecated 2022.03
|
||||
* @see IHandleUserSessions::getLocalUserId()
|
||||
*/
|
||||
public function getLoggedInUserId(): int
|
||||
{
|
||||
return $this->user_id;
|
||||
return $this->session->getLocalUserId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the user nick name
|
||||
* @return string User's nickname
|
||||
* @deprecated 2022.03
|
||||
* @see IHandleUserSessions::getLocalUserNickname()
|
||||
*/
|
||||
public function getLoggedInUserNickname(): string
|
||||
{
|
||||
return $this->nickname;
|
||||
return $this->session->getLocalUserNickname();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,8 +297,7 @@ class App
|
||||
*/
|
||||
public function getBasePath(): string
|
||||
{
|
||||
// Don't use the basepath of the config table for basepath (it should always be the config-file one)
|
||||
return $this->config->getCache()->get('system', 'basepath');
|
||||
return $this->config->get('system', 'basepath');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,10 +357,8 @@ class App
|
||||
$this->profiler->reset();
|
||||
|
||||
if ($this->mode->has(App\Mode::DBAVAILABLE)) {
|
||||
$this->profiler->update($this->config);
|
||||
|
||||
Core\Hook::loadHooks();
|
||||
$loader = (new Config())->createConfigFileLoader($this->getBasePath(), $_SERVER);
|
||||
$loader = (new Config())->createConfigFileManager($this->getBasePath(), $_SERVER);
|
||||
Core\Hook::callAll('load_config', $loader);
|
||||
|
||||
// Hooks are now working, reload the whole definitions with hook enabled
|
||||
@@ -421,7 +391,7 @@ class App
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current theme name. May be overriden by the mobile theme name.
|
||||
* Returns the current theme name. May be overridden by the mobile theme name.
|
||||
*
|
||||
* @return string Current theme name or empty string in installation phase
|
||||
* @throws Exception
|
||||
@@ -562,7 +532,7 @@ class App
|
||||
/**
|
||||
* Provide a sane default if nothing is chosen or the specified theme does not exist.
|
||||
*
|
||||
* @return string Current theme's stylsheet path
|
||||
* @return string Current theme's stylesheet path
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentThemeStylesheetPath(): string
|
||||
@@ -570,25 +540,6 @@ class App
|
||||
return Core\Theme::getStylesheetPath($this->getCurrentTheme());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base url for use in cmdline programs which don't have
|
||||
* $_SERVER variables
|
||||
*/
|
||||
public function checkURL()
|
||||
{
|
||||
$url = $this->config->get('system', 'url');
|
||||
|
||||
// if the url isn't set or the stored url is radically different
|
||||
// than the currently visited url, store the current value accordingly.
|
||||
// "Radically different" ignores common variations such as http vs https
|
||||
// and www.example.com vs example.com.
|
||||
// We will only change the url to an ip address if there is no existing setting
|
||||
|
||||
if (empty($url) || (!Util\Strings::compareLink($url, $this->baseURL->get())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $this->baseURL->getHostname()))) {
|
||||
$this->config->set('system', 'url', $this->baseURL->get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frontend App script
|
||||
*
|
||||
@@ -601,13 +552,15 @@ class App
|
||||
* @param IManagePersonalConfigValues $pconfig
|
||||
* @param Authentication $auth The Authentication backend of the node
|
||||
* @param App\Page $page The Friendica page printing container
|
||||
* @param ModuleHTTPException $httpException The possible HTTP Exception container
|
||||
* @param HTTPInputData $httpInput A library for processing PHP input streams
|
||||
* @param float $start_time The start time of the overall script execution
|
||||
* @param array $server The $_SERVER array
|
||||
*
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, HTTPInputData $httpInput, float $start_time)
|
||||
public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, Nav $nav, ModuleHTTPException $httpException, HTTPInputData $httpInput, float $start_time, array $server)
|
||||
{
|
||||
$this->profiler->set($start_time, 'start');
|
||||
$this->profiler->set(microtime(true), 'classinit');
|
||||
@@ -623,10 +576,12 @@ class App
|
||||
|
||||
if (!$this->mode->isInstall()) {
|
||||
// Force SSL redirection
|
||||
if ($this->baseURL->checkRedirectHttps()) {
|
||||
System::externalRedirect($this->baseURL->get() . '/' . $this->args->getQueryString());
|
||||
if ($this->config->get('system', 'force_ssl') &&
|
||||
(empty($server['HTTPS']) || $server['HTTPS'] === 'off') &&
|
||||
!empty($server['REQUEST_METHOD']) &&
|
||||
$server['REQUEST_METHOD'] === 'GET') {
|
||||
System::externalRedirect($this->baseURL . '/' . $this->args->getQueryString());
|
||||
}
|
||||
|
||||
Core\Hook::callAll('init_1');
|
||||
}
|
||||
|
||||
@@ -686,8 +641,7 @@ class App
|
||||
if ($this->mode->isInstall() && $moduleName !== 'install') {
|
||||
$this->baseURL->redirect('install');
|
||||
} else {
|
||||
$this->checkURL();
|
||||
Core\Update::check($this->getBasePath(), false, $this->mode);
|
||||
Core\Update::check($this->getBasePath(), false);
|
||||
Core\Addon::loadAddons();
|
||||
Core\Hook::loadHooks();
|
||||
}
|
||||
@@ -741,17 +695,17 @@ class App
|
||||
$httpinput = $httpInput->process();
|
||||
$input = array_merge($httpinput['variables'], $httpinput['files'], $request ?? $_REQUEST);
|
||||
|
||||
// Let the module run it's internal process (init, get, post, ...)
|
||||
// Let the module run its internal process (init, get, post, ...)
|
||||
$timestamp = microtime(true);
|
||||
$response = $module->run($input);
|
||||
$response = $module->run($httpException, $input);
|
||||
$this->profiler->set(microtime(true) - $timestamp, 'content');
|
||||
if ($response->getHeaderLine(ICanCreateResponses::X_HEADER) === ICanCreateResponses::TYPE_HTML) {
|
||||
$page->run($this, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $this->session->getLocalUserId());
|
||||
$page->run($this, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $nav, $this->session->getLocalUserId());
|
||||
} else {
|
||||
$page->exit($response);
|
||||
}
|
||||
} catch (HTTPException $e) {
|
||||
(new ModuleHTTPException())->rawContent($e);
|
||||
$httpException->rawContent($e);
|
||||
}
|
||||
$page->logRuntime($this->config, 'runFrontend');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
+36
-376
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -23,396 +23,64 @@ namespace Friendica\App;
|
||||
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Strings;
|
||||
use Friendica\Network\HTTPException;
|
||||
use GuzzleHttp\Psr7\ServerRequest;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* A class which checks and contains the basic
|
||||
* environment for the BaseURL (url, urlpath, ssl_policy, hostname, scheme)
|
||||
*/
|
||||
class BaseURL
|
||||
class BaseURL extends Uri implements UriInterface
|
||||
{
|
||||
/**
|
||||
* No SSL necessary
|
||||
*/
|
||||
const SSL_POLICY_NONE = 0;
|
||||
|
||||
/**
|
||||
* SSL is necessary
|
||||
*/
|
||||
const SSL_POLICY_FULL = 1;
|
||||
|
||||
/**
|
||||
* SSL is optional, but preferred
|
||||
*/
|
||||
const SSL_POLICY_SELFSIGN = 2;
|
||||
|
||||
/**
|
||||
* Define the Default SSL scheme
|
||||
*/
|
||||
const DEFAULT_SSL_SCHEME = self::SSL_POLICY_SELFSIGN;
|
||||
|
||||
/**
|
||||
* The Friendica Config
|
||||
*
|
||||
* @var IManageConfigValues
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* The server side variables
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* The hostname of the Base URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $hostname;
|
||||
|
||||
/**
|
||||
* The SSL_POLICY of the Base URL
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $sslPolicy;
|
||||
|
||||
/**
|
||||
* The URL sub-path of the Base URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $urlPath;
|
||||
|
||||
/**
|
||||
* The full URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* The current scheme of this call
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $scheme;
|
||||
|
||||
/**
|
||||
* Returns the hostname of this node
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHostname(): string
|
||||
public function __construct(IManageConfigValues $config, LoggerInterface $logger, array $server = [])
|
||||
{
|
||||
return $this->hostname;
|
||||
$url = $config->get('system', 'url');
|
||||
if (empty($url)) {
|
||||
$logger->critical('Invalid config - Missing system.url');
|
||||
$url = ServerRequest::getUriFromGlobals()
|
||||
->withQuery('')
|
||||
->withPath($this->determineURLPath($server));
|
||||
}
|
||||
|
||||
parent::__construct($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current scheme of this call
|
||||
*
|
||||
* @return string
|
||||
* Figure out if we are running at the top of a domain or in a subdirectory
|
||||
*/
|
||||
public function getScheme(): string
|
||||
private function determineURLPath(array $server): string
|
||||
{
|
||||
return $this->scheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SSL policy of this node
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSSLPolicy(): int
|
||||
{
|
||||
return $this->sslPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sub-path of this URL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUrlPath(): string
|
||||
{
|
||||
return $this->urlPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full URL of this call
|
||||
*
|
||||
* Note: $ssl parameter value doesn't directly correlate with the resulting protocol
|
||||
*
|
||||
* @param bool $ssl True, if ssl should get used
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get(bool $ssl = false): string
|
||||
{
|
||||
if ($this->sslPolicy === self::SSL_POLICY_SELFSIGN && $ssl) {
|
||||
return Network::switchScheme($this->url);
|
||||
}
|
||||
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save current parts of the base Url
|
||||
*
|
||||
* @param string? $hostname
|
||||
* @param int? $sslPolicy
|
||||
* @param string? $urlPath
|
||||
*
|
||||
* @return bool true, if successful
|
||||
* @TODO Find proper types
|
||||
*/
|
||||
public function save($hostname = null, $sslPolicy = null, $urlPath = null): bool
|
||||
{
|
||||
$currHostname = $this->hostname;
|
||||
$currSSLPolicy = $this->sslPolicy;
|
||||
$currURLPath = $this->urlPath;
|
||||
|
||||
if (!empty($hostname) && $hostname !== $this->hostname) {
|
||||
if ($this->config->set('config', 'hostname', $hostname)) {
|
||||
$this->hostname = $hostname;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($sslPolicy) && $sslPolicy !== $this->sslPolicy) {
|
||||
if ($this->config->set('system', 'ssl_policy', $sslPolicy)) {
|
||||
$this->sslPolicy = $sslPolicy;
|
||||
} else {
|
||||
$this->hostname = $currHostname;
|
||||
$this->config->set('config', 'hostname', $this->hostname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($urlPath) && $urlPath !== $this->urlPath) {
|
||||
if ($this->config->set('system', 'urlpath', $urlPath)) {
|
||||
$this->urlPath = $urlPath;
|
||||
} else {
|
||||
$this->hostname = $currHostname;
|
||||
$this->sslPolicy = $currSSLPolicy;
|
||||
$this->config->set('config', 'hostname', $this->hostname);
|
||||
$this->config->set('system', 'ssl_policy', $this->sslPolicy);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->determineBaseUrl();
|
||||
if (!$this->config->set('system', 'url', $this->url)) {
|
||||
$this->hostname = $currHostname;
|
||||
$this->sslPolicy = $currSSLPolicy;
|
||||
$this->urlPath = $currURLPath;
|
||||
$this->determineBaseUrl();
|
||||
|
||||
$this->config->set('config', 'hostname', $this->hostname);
|
||||
$this->config->set('system', 'ssl_policy', $this->sslPolicy);
|
||||
$this->config->set('system', 'urlpath', $this->urlPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current url as base URL
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool true, if the save was successful
|
||||
*/
|
||||
public function saveByURL(string $url): bool
|
||||
{
|
||||
$parsed = @parse_url($url);
|
||||
|
||||
if (empty($parsed) || empty($parsed['host'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hostname = $parsed['host'];
|
||||
if (!empty($hostname) && !empty($parsed['port'])) {
|
||||
$hostname .= ':' . $parsed['port'];
|
||||
}
|
||||
|
||||
$urlPath = null;
|
||||
if (!empty($parsed['path'])) {
|
||||
$urlPath = trim($parsed['path'], '\\/');
|
||||
}
|
||||
|
||||
$sslPolicy = null;
|
||||
if (!empty($parsed['scheme'])) {
|
||||
if ($parsed['scheme'] == 'https') {
|
||||
$sslPolicy = BaseURL::SSL_POLICY_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->save($hostname, $sslPolicy, $urlPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, if a redirect to the HTTPS site would be necessary
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function checkRedirectHttps()
|
||||
{
|
||||
return $this->config->get('system', 'force_ssl') &&
|
||||
($this->getScheme() == "http") &&
|
||||
intval($this->getSSLPolicy()) == BaseURL::SSL_POLICY_FULL &&
|
||||
strpos($this->get(), 'https://') === 0 &&
|
||||
!empty($this->server['REQUEST_METHOD']) &&
|
||||
$this->server['REQUEST_METHOD'] === 'GET';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IManageConfigValues $config The Friendica IConfiguration
|
||||
* @param array $server The $_SERVER array
|
||||
*/
|
||||
public function __construct(IManageConfigValues $config, array $server)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->server = $server;
|
||||
|
||||
$this->determineSchema();
|
||||
$this->checkConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the current config during loading
|
||||
*/
|
||||
public function checkConfig()
|
||||
{
|
||||
$this->hostname = $this->config->get('config', 'hostname');
|
||||
$this->urlPath = $this->config->get('system', 'urlpath');
|
||||
$this->sslPolicy = $this->config->get('system', 'ssl_policy');
|
||||
$this->url = $this->config->get('system', 'url');
|
||||
|
||||
if (empty($this->hostname)) {
|
||||
$this->determineHostname();
|
||||
|
||||
if (!empty($this->hostname)) {
|
||||
$this->config->set('config', 'hostname', $this->hostname);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($this->urlPath)) {
|
||||
$this->determineURLPath();
|
||||
$this->config->set('system', 'urlpath', $this->urlPath);
|
||||
}
|
||||
|
||||
if (!isset($this->sslPolicy)) {
|
||||
if ($this->scheme == 'https') {
|
||||
$this->sslPolicy = self::SSL_POLICY_FULL;
|
||||
} else {
|
||||
$this->sslPolicy = self::DEFAULT_SSL_SCHEME;
|
||||
}
|
||||
$this->config->set('system', 'ssl_policy', $this->sslPolicy);
|
||||
}
|
||||
|
||||
if (empty($this->url)) {
|
||||
$this->determineBaseUrl();
|
||||
|
||||
if (!empty($this->url)) {
|
||||
$this->config->set('system', 'url', $this->url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the hostname of this node if not set already
|
||||
*/
|
||||
private function determineHostname()
|
||||
{
|
||||
$this->hostname = '';
|
||||
|
||||
if (!empty($this->server['SERVER_NAME'])) {
|
||||
$this->hostname = $this->server['SERVER_NAME'];
|
||||
|
||||
if (!empty($this->server['SERVER_PORT']) && $this->server['SERVER_PORT'] != 80 && $this->server['SERVER_PORT'] != 443) {
|
||||
$this->hostname .= ':' . $this->server['SERVER_PORT'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Figure out if we are running at the top of a domain or in a sub-directory
|
||||
*/
|
||||
private function determineURLPath()
|
||||
{
|
||||
$this->urlPath = '';
|
||||
|
||||
/*
|
||||
* The automatic path detection in this function is currently deactivated,
|
||||
* see issue https://github.com/friendica/friendica/issues/6679
|
||||
*
|
||||
* The problem is that the function seems to be confused with some url.
|
||||
* These then confuses the detection which changes the url path.
|
||||
*/
|
||||
|
||||
/* Relative script path to the web server root
|
||||
* Not all of those $_SERVER properties can be present, so we do by inverse priority order
|
||||
*/
|
||||
$relative_script_path =
|
||||
($this->server['REDIRECT_URL'] ?? '') ?:
|
||||
($this->server['REDIRECT_URI'] ?? '') ?:
|
||||
($this->server['REDIRECT_SCRIPT_URL'] ?? '') ?:
|
||||
($this->server['SCRIPT_URL'] ?? '') ?:
|
||||
$this->server['REQUEST_URI'] ?? '';
|
||||
$relativeScriptPath =
|
||||
($server['REDIRECT_URL'] ?? '') ?:
|
||||
($server['REDIRECT_URI'] ?? '') ?:
|
||||
($server['REDIRECT_SCRIPT_URL'] ?? '') ?:
|
||||
($server['SCRIPT_URL'] ?? '') ?:
|
||||
$server['REQUEST_URI'] ?? '';
|
||||
|
||||
/* $relative_script_path gives /relative/path/to/friendica/module/parameter
|
||||
/* $relativeScriptPath gives /relative/path/to/friendica/module/parameter
|
||||
* QUERY_STRING gives pagename=module/parameter
|
||||
*
|
||||
* To get /relative/path/to/friendica we perform dirname() for as many levels as there are slashes in the QUERY_STRING
|
||||
*/
|
||||
if (!empty($relative_script_path)) {
|
||||
if (!empty($relativeScriptPath)) {
|
||||
// Module
|
||||
if (!empty($this->server['QUERY_STRING'])) {
|
||||
$this->urlPath = trim(dirname($relative_script_path, substr_count(trim($this->server['QUERY_STRING'], '/'), '/') + 1), '/');
|
||||
if (!empty($server['QUERY_STRING'])) {
|
||||
return trim(dirname($relativeScriptPath, substr_count(trim($server['QUERY_STRING'], '/'), '/') + 1), '/');
|
||||
} else {
|
||||
// Root page
|
||||
$this->urlPath = trim($relative_script_path, '/');
|
||||
$scriptPathParts = explode('?', $relativeScriptPath, 2);
|
||||
return trim($scriptPathParts[0], '/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the full URL based on all parts
|
||||
*/
|
||||
private function determineBaseUrl()
|
||||
{
|
||||
$scheme = 'http';
|
||||
|
||||
if ($this->sslPolicy == self::SSL_POLICY_FULL) {
|
||||
$scheme = 'https';
|
||||
}
|
||||
|
||||
$this->url = $scheme . '://' . $this->hostname . (!empty($this->urlPath) ? '/' . $this->urlPath : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the scheme of the current used link
|
||||
*/
|
||||
private function determineSchema()
|
||||
{
|
||||
$this->scheme = 'http';
|
||||
|
||||
if (!empty($this->server['HTTPS']) ||
|
||||
!empty($this->server['HTTP_FORWARDED']) && preg_match('/proto=https/', $this->server['HTTP_FORWARDED']) ||
|
||||
!empty($this->server['HTTP_X_FORWARDED_PROTO']) && $this->server['HTTP_X_FORWARDED_PROTO'] == 'https' ||
|
||||
!empty($this->server['HTTP_X_FORWARDED_SSL']) && $this->server['HTTP_X_FORWARDED_SSL'] == 'on' ||
|
||||
!empty($this->server['FRONT_END_HTTPS']) && $this->server['FRONT_END_HTTPS'] == 'on' ||
|
||||
!empty($this->server['SERVER_PORT']) && (intval($this->server['SERVER_PORT']) == 443) // XXX: reasonable assumption, but isn't this hardcoding too much?
|
||||
) {
|
||||
$this->scheme = 'https';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -426,11 +94,11 @@ class BaseURL
|
||||
{
|
||||
// Remove the hostname from the url if it is an internal link
|
||||
$nurl = Strings::normaliseLink($origURL);
|
||||
$base = Strings::normaliseLink($this->get());
|
||||
$base = Strings::normaliseLink($this->__toString());
|
||||
$url = str_replace($base . '/', '', $nurl);
|
||||
|
||||
// if it is an external link return the orignal value
|
||||
if ($url == Strings::normaliseLink($origURL)) {
|
||||
// if it is an external link return the original value
|
||||
if ($url === $nurl) {
|
||||
return $origURL;
|
||||
} else {
|
||||
return $url;
|
||||
@@ -453,18 +121,10 @@ class BaseURL
|
||||
public function redirect(string $toUrl = '', bool $ssl = false)
|
||||
{
|
||||
if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) {
|
||||
throw new HTTPException\InternalServerErrorException("'$toUrl is not a relative path, please use System::externalRedirectTo");
|
||||
throw new HTTPException\InternalServerErrorException("$toUrl is not a relative path, please use System::externalRedirectTo");
|
||||
}
|
||||
|
||||
$redirectTo = $this->get($ssl) . '/' . ltrim($toUrl, '/');
|
||||
$redirectTo = $this->__toString() . '/' . ltrim($toUrl, '/');
|
||||
System::externalRedirect($redirectTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base url as string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->get();
|
||||
}
|
||||
}
|
||||
|
||||
+9
-22
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -22,9 +22,8 @@
|
||||
namespace Friendica\App;
|
||||
|
||||
use Detection\MobileDetect;
|
||||
use Friendica\Core\Config\ValueObject\Cache;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Util\BasePath;
|
||||
|
||||
/**
|
||||
* Mode of the current Friendica Node
|
||||
@@ -129,15 +128,13 @@ class Mode
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function determine(BasePath $basepath, Database $database, Cache $configCache): Mode
|
||||
public function determine(string $basePath, Database $database, IManageConfigValues $config): Mode
|
||||
{
|
||||
$mode = 0;
|
||||
|
||||
$basepathName = $basepath->getPath();
|
||||
|
||||
if (!file_exists($basepathName . '/config/local.config.php')
|
||||
&& !file_exists($basepathName . '/config/local.ini.php')
|
||||
&& !file_exists($basepathName . '/.htconfig.php')) {
|
||||
if (!file_exists($basePath . '/config/local.config.php') &&
|
||||
!file_exists($basePath . '/config/local.ini.php') &&
|
||||
!file_exists($basePath . '/.htconfig.php')) {
|
||||
return new Mode($mode);
|
||||
}
|
||||
|
||||
@@ -149,16 +146,7 @@ class Mode
|
||||
|
||||
$mode |= Mode::DBAVAILABLE;
|
||||
|
||||
if ($database->fetchFirst("SHOW TABLES LIKE 'config'") === false) {
|
||||
return new Mode($mode);
|
||||
}
|
||||
|
||||
$mode |= Mode::DBCONFIGAVAILABLE;
|
||||
|
||||
if (!empty($configCache->get('system', 'maintenance')) ||
|
||||
// Don't use Config or Configuration here because we're possibly BEFORE initializing the Configuration,
|
||||
// so this could lead to a dependency circle
|
||||
!empty($database->selectFirst('config', ['v'], ['cat' => 'system', 'k' => 'maintenance'])['v'])) {
|
||||
if (!empty($config->get('system', 'maintenance'))) {
|
||||
return new Mode($mode);
|
||||
}
|
||||
|
||||
@@ -232,14 +220,14 @@ class Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* Install mode is when the local config file is missing or the DB schema hasn't been installed yet.
|
||||
* Install mode is when the local config file is missing or the database isn't available.
|
||||
*
|
||||
* @return bool Whether installation mode is active (local/database configuration files present or not)
|
||||
*/
|
||||
public function isInstall(): bool
|
||||
{
|
||||
return !$this->has(Mode::LOCALCONFIGPRESENT) ||
|
||||
!$this->has(MODE::DBCONFIGAVAILABLE);
|
||||
!$this->has(MODE::DBAVAILABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,7 +239,6 @@ class Mode
|
||||
{
|
||||
return $this->has(Mode::LOCALCONFIGPRESENT) &&
|
||||
$this->has(Mode::DBAVAILABLE) &&
|
||||
$this->has(Mode::DBCONFIGAVAILABLE) &&
|
||||
$this->has(Mode::MAINTENANCEDISABLED);
|
||||
}
|
||||
|
||||
|
||||
+44
-13
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -27,18 +27,18 @@ use DOMXPath;
|
||||
use Friendica\App;
|
||||
use Friendica\Content\Nav;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Theme;
|
||||
use Friendica\Module\Response;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Strings;
|
||||
use Friendica\Util\Profiler;
|
||||
use Friendica\Util\Strings;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
@@ -243,15 +243,43 @@ class Page implements ArrayAccess
|
||||
* being first
|
||||
*/
|
||||
$this->page['htmlhead'] = Renderer::replaceMacros($tpl, [
|
||||
'$l10n' => [
|
||||
'delitem' => $l10n->t('Delete this item?'),
|
||||
'blockAuthor' => $l10n->t('Block this author? They won\'t be able to follow you nor see your public posts, and you won\'t be able to see their posts and their notifications.'),
|
||||
'ignoreAuthor' => $l10n->t('Ignore this author? You won\'t be able to see their posts and their notifications.'),
|
||||
|
||||
'likeError' => $l10n->t('Like not successful'),
|
||||
'dislikeError' => $l10n->t('Dislike not successful'),
|
||||
'announceError' => $l10n->t('Sharing not successful'),
|
||||
'attendError' => $l10n->t('Attendance unsuccessful'),
|
||||
'srvError' => $l10n->t('Backend error'),
|
||||
'netError' => $l10n->t('Network error'),
|
||||
|
||||
// Dropzone
|
||||
'dictDefaultMessage' => $l10n->t('Drop files here to upload'),
|
||||
'dictFallbackMessage' => $l10n->t("Your browser does not support drag and drop file uploads."),
|
||||
'dictFallbackText' => $l10n->t('Please use the fallback form below to upload your files like in the olden days.'),
|
||||
'dictFileTooBig' => $l10n->t('File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.'),
|
||||
'dictInvalidFileType' => $l10n->t("You can't upload files of this type."),
|
||||
'dictResponseError' => $l10n->t('Server responded with {{statusCode}} code.'),
|
||||
'dictCancelUpload' => $l10n->t('Cancel upload'),
|
||||
'dictUploadCanceled' => $l10n->t('Upload canceled.'),
|
||||
'dictCancelUploadConfirmation' => $l10n->t('Are you sure you want to cancel this upload?'),
|
||||
'dictRemoveFile' => $l10n->t('Remove file'),
|
||||
'dictMaxFilesExceeded' => $l10n->t("You can't upload any more files."),
|
||||
],
|
||||
|
||||
'$local_user' => $localUID,
|
||||
'$generator' => 'Friendica' . ' ' . App::VERSION,
|
||||
'$delitem' => $l10n->t('Delete this item?'),
|
||||
'$blockAuthor' => $l10n->t('Block this author? They won\'t be able to follow you nor see your public posts, and you won\'t be able to see their posts and their notifications.'),
|
||||
'$update_interval' => $interval,
|
||||
'$shortcut_icon' => $shortcut_icon,
|
||||
'$touch_icon' => $touch_icon,
|
||||
'$block_public' => intval($config->get('system', 'block_public')),
|
||||
'$stylesheets' => $this->stylesheets,
|
||||
|
||||
// Dropzone
|
||||
'$max_imagesize' => round(\Friendica\Util\Strings::getBytesFromShorthand($config->get('system', 'maximagesize')) / 1000000, 1),
|
||||
|
||||
]) . $this->page['htmlhead'];
|
||||
}
|
||||
|
||||
@@ -281,7 +309,7 @@ class Page implements ArrayAccess
|
||||
* Initializes Page->page['footer'].
|
||||
*
|
||||
* Includes:
|
||||
* - Javascript homebase
|
||||
* - JavaScript homebase
|
||||
* - Mobile toggle link
|
||||
* - Registered footer scripts (through App->registerFooterScript())
|
||||
* - footer.tpl template
|
||||
@@ -408,13 +436,16 @@ class Page implements ArrayAccess
|
||||
* @param Mode $mode The current node mode
|
||||
* @param ResponseInterface $response The Response of the module class, including type, content & headers
|
||||
* @param L10n $l10n The l10n language class
|
||||
* @param Profiler $profiler
|
||||
* @param IManageConfigValues $config The Configuration of this node
|
||||
* @param IManagePersonalConfigValues $pconfig The personal/user configuration
|
||||
* @param int $localUID The UID of the local user
|
||||
*
|
||||
* @throws HTTPException\InternalServerErrorException|HTTPException\ServiceUnavailableException
|
||||
* @param Nav $nav
|
||||
* @param int $localUID
|
||||
* @throws HTTPException\MethodNotAllowedException
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\ServiceUnavailableException
|
||||
*/
|
||||
public function run(App $app, BaseURL $baseURL, Arguments $args, Mode $mode, ResponseInterface $response, L10n $l10n, Profiler $profiler, IManageConfigValues $config, IManagePersonalConfigValues $pconfig, int $localUID)
|
||||
public function run(App $app, BaseURL $baseURL, Arguments $args, Mode $mode, ResponseInterface $response, L10n $l10n, Profiler $profiler, IManageConfigValues $config, IManagePersonalConfigValues $pconfig, Nav $nav, int $localUID)
|
||||
{
|
||||
$moduleName = $args->getModuleName();
|
||||
|
||||
@@ -464,7 +495,7 @@ class Page implements ArrayAccess
|
||||
// Add the navigation (menu) template
|
||||
if ($moduleName != 'install' && $moduleName != 'maintenance') {
|
||||
$this->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('nav_head.tpl'), []);
|
||||
$this->page['nav'] = Nav::build($app);
|
||||
$this->page['nav'] = $nav->getHtml();
|
||||
}
|
||||
|
||||
foreach ($response->getHeaders() as $key => $header) {
|
||||
@@ -490,7 +521,7 @@ class Page implements ArrayAccess
|
||||
|
||||
$content = mb_convert_encoding($this->page["content"], 'HTML-ENTITIES', "UTF-8");
|
||||
|
||||
/// @TODO one day, kill those error-surpressing @ stuff, or PHP should ban it
|
||||
/// @TODO one day, kill those error-suppressing @ stuff, or PHP should ban it
|
||||
@$doc->loadHTML($content);
|
||||
|
||||
$xpath = new DOMXPath($doc);
|
||||
@@ -519,7 +550,7 @@ class Page implements ArrayAccess
|
||||
header("X-Friendica-Version: " . App::VERSION);
|
||||
header("Content-type: text/html; charset=utf-8");
|
||||
|
||||
if ($config->get('system', 'hsts') && ($baseURL->getSSLPolicy() == BaseURL::SSL_POLICY_FULL)) {
|
||||
if ($config->get('system', 'hsts') && ($baseURL->getScheme() === 'https')) {
|
||||
header("Strict-Transport-Security: max-age=31536000");
|
||||
}
|
||||
|
||||
|
||||
+21
-1
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -22,6 +22,7 @@
|
||||
namespace Friendica\App;
|
||||
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\System;
|
||||
|
||||
/**
|
||||
* Container for the whole request
|
||||
@@ -38,9 +39,17 @@ class Request
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_FORWARD_FOR_HEADER = 'HTTP_X_FORWARDED_FOR';
|
||||
/**
|
||||
* The default Request-ID header to retrieve the current transaction ID from the HTTP header (if set)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_REQUEST_ID_HEADER = 'HTTP_X_REQUEST_ID';
|
||||
|
||||
/** @var string The remote IP address of the current request */
|
||||
protected $remoteAddress;
|
||||
/** @var string The request-id of the current request */
|
||||
protected $requestId;
|
||||
|
||||
/**
|
||||
* @return string The remote IP address of the current request
|
||||
@@ -52,9 +61,20 @@ class Request
|
||||
return $this->remoteAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The request ID of the current request
|
||||
*
|
||||
* Do always use this instead of $_SERVER['X_REQUEST_ID']
|
||||
*/
|
||||
public function getRequestId(): string
|
||||
{
|
||||
return $this->requestId;
|
||||
}
|
||||
|
||||
public function __construct(IManageConfigValues $config, array $server = [])
|
||||
{
|
||||
$this->remoteAddress = $this->determineRemoteAddress($config, $server);
|
||||
$this->requestId = $server[static::DEFAULT_REQUEST_ID_HEADER] ?? System::createGUID(8, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -412,7 +412,7 @@ class Router
|
||||
}
|
||||
|
||||
if (!$this->lock->acquire('getCachedDispatchData', 0)) {
|
||||
// Immediately return uncached data when we can't aquire a lock
|
||||
// Immediately return uncached data when we can't acquire a lock
|
||||
return $this->getDispatchData();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -24,7 +24,7 @@ namespace Friendica;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Factories act as an intermediary to avoid direct Entitiy instanciation.
|
||||
* Factories act as an intermediary to avoid direct Entity instantiation.
|
||||
*
|
||||
* @see BaseModel
|
||||
* @see BaseCollection
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -94,7 +94,7 @@ abstract class BaseModel extends BaseDataTransferObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic isset method. Returns true if the field exists, either in the data prperty array or in any of the local properties.
|
||||
* Magic isset method. Returns true if the field exists, either in the data property array or in any of the local properties.
|
||||
* Used by array_column() on an array of objects.
|
||||
*
|
||||
* @param $name
|
||||
|
||||
+13
-5
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -90,9 +90,9 @@ abstract class BaseModule implements ICanHandleRequests
|
||||
*
|
||||
* @see L10n::tt()
|
||||
*/
|
||||
protected function tt(string $singular, string $plurarl, int $count): string
|
||||
protected function tt(string $singular, string $plural, int $count): string
|
||||
{
|
||||
return $this->l10n->tt($singular, $plurarl, $count);
|
||||
return $this->l10n->tt($singular, $plural, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +181,7 @@ abstract class BaseModule implements ICanHandleRequests
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function run(array $request = []): ResponseInterface
|
||||
public function run(ModuleHTTPException $httpException, array $request = []): ResponseInterface
|
||||
{
|
||||
// @see https://github.com/tootsuite/mastodon/blob/c3aef491d66aec743a3a53e934a494f653745b61/config/initializers/cors.rb
|
||||
if (substr($this->args->getQueryString(), 0, 12) == '.well-known/') {
|
||||
@@ -243,7 +243,15 @@ abstract class BaseModule implements ICanHandleRequests
|
||||
$this->response->addContent($arr['content']);
|
||||
$this->response->addContent($this->content($request));
|
||||
} catch (HTTPException $e) {
|
||||
$this->response->addContent((new ModuleHTTPException())->content($e));
|
||||
// In case of System::externalRedirects(), we don't want to prettyprint the exception
|
||||
// just redirect to the new location
|
||||
if (($e instanceof HTTPException\FoundException) ||
|
||||
($e instanceof HTTPException\MovedPermanentlyException) ||
|
||||
($e instanceof HTTPException\TemporaryRedirectException)) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->response->addContent($httpException->content($e));
|
||||
} finally {
|
||||
$this->profiler->set(microtime(true) - $timestamp, 'content');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
namespace Friendica\Capabilities;
|
||||
|
||||
use Friendica\Module\Special\HTTPException as ModuleHTTPException;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
@@ -30,11 +31,12 @@ use Psr\Http\Message\ResponseInterface;
|
||||
interface ICanHandleRequests
|
||||
{
|
||||
/**
|
||||
* @param array $request The $_REQUEST content (including content from the PHP input stream)
|
||||
* @param ModuleHTTPException $httpException The special HTTPException Module in case of underlying errors
|
||||
* @param array $request The $_REQUEST content (including content from the PHP input stream)
|
||||
*
|
||||
* @return ResponseInterface responding to the request handling
|
||||
*
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function run(array $request = []): ResponseInterface;
|
||||
public function run(ModuleHTTPException $httpException, array $request = []): ResponseInterface;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -95,7 +95,7 @@ Examples
|
||||
bin/console autoinstall --savedb
|
||||
Installs Friendica with environment variables and saves them to the 'config/local.config.php' file
|
||||
|
||||
bin/console autoinstall -H localhost -p 3365 -u user -P passwort1234 -d friendica -U https://friendica.fqdn
|
||||
bin/console autoinstall -H localhost -p 3365 -u user -P password1234 -d friendica -U https://friendica.fqdn
|
||||
Installs Friendica with a local mysql database with credentials
|
||||
HELP;
|
||||
}
|
||||
@@ -199,8 +199,7 @@ HELP;
|
||||
$this->out('The Friendica URL has to be set during CLI installation.');
|
||||
return 1;
|
||||
} else {
|
||||
$baseUrl = new BaseURL($this->config, []);
|
||||
$baseUrl->saveByURL($url);
|
||||
$configCache->set('system', 'url', $url);
|
||||
}
|
||||
|
||||
$installer->createConfig($configCache);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -99,7 +99,7 @@ HELP;
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (!$this->appMode->has(App\Mode::DBCONFIGAVAILABLE)) {
|
||||
if (!$this->appMode->has(App\Mode::DBAVAILABLE)) {
|
||||
$this->out('Database isn\'t ready or populated yet, database cache won\'t be available');
|
||||
}
|
||||
|
||||
|
||||
+3
-11
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -115,10 +115,6 @@ HELP;
|
||||
throw new CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
if (!$this->appMode->has(App\Mode::DBCONFIGAVAILABLE)) {
|
||||
$this->out('Database isn\'t ready or populated yet, showing file config only');
|
||||
}
|
||||
|
||||
if (count($this->args) == 3) {
|
||||
$cat = $this->getArgument(0);
|
||||
$key = $this->getArgument(1);
|
||||
@@ -157,7 +153,7 @@ HELP;
|
||||
|
||||
if (count($this->args) == 1) {
|
||||
$cat = $this->getArgument(0);
|
||||
$this->config->load($cat);
|
||||
$this->config->reload();
|
||||
$configCache = $this->config->getCache();
|
||||
|
||||
if ($configCache->get($cat) !== null) {
|
||||
@@ -178,11 +174,7 @@ HELP;
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$this->config->load();
|
||||
|
||||
if ($this->config->get('system', 'config_adapter') == 'jit' && $this->appMode->has(App\Mode::DBCONFIGAVAILABLE)) {
|
||||
$this->out('Warning: The JIT (Just In Time) Config adapter doesn\'t support loading the entire configuration, showing file config only');
|
||||
}
|
||||
$this->config->reload();
|
||||
|
||||
$config = $this->config->getCache()->getAll();
|
||||
foreach ($config as $cat => $section) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -157,7 +157,7 @@ HELP;
|
||||
|
||||
$url = Probe::cleanURI($url);
|
||||
|
||||
$contact = ContactModel::getByURLForUser($url, $user['uid']);
|
||||
$contact = ContactModel::getByURL($url, null, [], $user['uid']);
|
||||
if (!empty($contact)) {
|
||||
throw new RuntimeException('Contact already exists');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Friendica\Core\Config\ValueObject\Cache;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Update;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DBStructure;
|
||||
@@ -43,8 +43,8 @@ class DatabaseStructure extends \Asika\SimpleConsole\Console
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
|
||||
/** @var Cache */
|
||||
private $configCache;
|
||||
/** @var IManageConfigValues */
|
||||
private $config;
|
||||
|
||||
/** @var DbaDefinition */
|
||||
private $dbaDefinition;
|
||||
@@ -83,14 +83,14 @@ HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(Database $dba, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, BasePath $basePath, Cache $configCache, $argv = null)
|
||||
public function __construct(Database $dba, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, BasePath $basePath, IManageConfigValues $config, $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->dba = $dba;
|
||||
$this->dbaDefinition = $dbaDefinition;
|
||||
$this->viewDefinition = $viewDefinition;
|
||||
$this->configCache = $configCache;
|
||||
$this->config = $config;
|
||||
$this->basePath = $basePath->getPath();
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ HELP;
|
||||
throw new RuntimeException('Unable to connect to database');
|
||||
}
|
||||
|
||||
$basePath = $this->configCache->get('system', 'basepath');
|
||||
$basePath = $this->config->get('system', 'basepath');
|
||||
|
||||
switch ($this->getArgument(0)) {
|
||||
case "dryrun":
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -30,7 +30,7 @@ use Friendica\App;
|
||||
*
|
||||
* Basically, docblox takes a list of files to build documentation from. This script assumes there is a file or set of files
|
||||
* breaking the build when it is included in that list. It tries to calculate the smallest list containing these files.
|
||||
* Unfortunatly, the original problem is NP-complete, so what the script does is a best guess only.
|
||||
* Unfortunately, the original problem is NP-complete, so what the script does is a best guess only.
|
||||
*
|
||||
* So it starts with a list of all files in the project.
|
||||
* If that list can't be build, it cuts it in two parts and tries both parts independently. If only one of them breaks,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -129,7 +129,7 @@ HELP;
|
||||
if (!$parameters) {
|
||||
$this->errored++;
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Unabled to parse parameter JSON of the row with id ' . $workerqueueItem['id']);
|
||||
$this->out('Unable to parse parameter JSON of the row with id ' . $workerqueueItem['id']);
|
||||
$this->out('JSON: ' . var_export($workerqueueItem['parameter'], true));
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ HELP;
|
||||
} else {
|
||||
$this->errored++;
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Unabled to update the row with id ' . $workerqueueItem['id']);
|
||||
$this->out('Unable to update the row with id ' . $workerqueueItem['id']);
|
||||
$this->out('Fields: ' . var_export($fields, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -93,7 +93,7 @@ HELP;
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (!$this->appMode->has(App\Mode::DBCONFIGAVAILABLE)) {
|
||||
if (!$this->appMode->has(App\Mode::DBAVAILABLE)) {
|
||||
$this->out('Database isn\'t ready or populated yet, database cache won\'t be available');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -100,16 +100,20 @@ HELP;
|
||||
|
||||
$enabled = intval($this->getArgument(0));
|
||||
|
||||
$this->config->set('system', 'maintenance', $enabled);
|
||||
$transactionConfig = $this->config->beginTransaction();
|
||||
|
||||
$transactionConfig->set('system', 'maintenance', $enabled);
|
||||
|
||||
$reason = $this->getArgument(1);
|
||||
|
||||
if ($enabled && $this->getArgument(1)) {
|
||||
$this->config->set('system', 'maintenance_reason', $this->getArgument(1));
|
||||
$transactionConfig->set('system', 'maintenance_reason', $this->getArgument(1));
|
||||
} else {
|
||||
$this->config->set('system', 'maintenance_reason', '');
|
||||
$transactionConfig->delete('system', 'maintenance_reason');
|
||||
}
|
||||
|
||||
$transactionConfig->commit();
|
||||
|
||||
if ($enabled) {
|
||||
$mode_str = "maintenance mode";
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -94,7 +94,7 @@ HELP;
|
||||
|
||||
$fields = ['id', 'avatar', 'photo', 'thumb', 'micro', 'uri-id', 'url', 'avatar', 'network'];
|
||||
$condition = ["NOT `self` AND `avatar` != ? AND `photo` LIKE ? AND `uid` = ? AND `uri-id` != ? AND NOT `uri-id` IS NULL AND NOT `network` IN (?, ?)",
|
||||
'', $this->baseUrl->get() . '/photo/%', 0, 0, Protocol::MAIL, Protocol::FEED];
|
||||
'', $this->baseUrl . '/photo/%', 0, 0, Protocol::MAIL, Protocol::FEED];
|
||||
|
||||
$count = 0;
|
||||
$total = $this->dba->count('contact', $condition);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -99,7 +99,7 @@ HELP;
|
||||
|
||||
$out = '';
|
||||
$out .= "# FRIENDICA Distributed Social Network\n";
|
||||
$out .= "# Copyright (C) 2010-2022, the Friendica project\n";
|
||||
$out .= "# Copyright (C) 2010-2023, the Friendica project\n";
|
||||
$out .= "# This file is distributed under the same license as the Friendica package.\n";
|
||||
$out .= "# \n";
|
||||
$out .= 'msgid ""' . "\n";
|
||||
@@ -231,7 +231,7 @@ HELP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string and retun a message.po ready text
|
||||
* Get a string and return a message.po ready text
|
||||
* - replace " with \"
|
||||
* - replace tab char with \t
|
||||
* - manage multiline strings
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -22,7 +22,7 @@
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Update;
|
||||
|
||||
@@ -38,9 +38,9 @@ class PostUpdate extends \Asika\SimpleConsole\Console
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
* @var IManageConfigValues
|
||||
* @var IManageKeyValuePairs
|
||||
*/
|
||||
private $config;
|
||||
private $keyValue;
|
||||
/**
|
||||
* @var L10n
|
||||
*/
|
||||
@@ -60,13 +60,13 @@ HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, IManageConfigValues $config, L10n $l10n, array $argv = null)
|
||||
public function __construct(App\Mode $appMode, IManageKeyValuePairs $keyValue, L10n $l10n, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->appMode = $appMode;
|
||||
$this->config = $config;
|
||||
$this->l10n = $l10n;
|
||||
$this->appMode = $appMode;
|
||||
$this->keyValue = $keyValue;
|
||||
$this->l10n = $l10n;
|
||||
}
|
||||
|
||||
protected function doExecute(): int
|
||||
@@ -83,7 +83,7 @@ HELP;
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
} elseif ($reset_version) {
|
||||
$this->config->set('system', 'post_update_version', $reset_version);
|
||||
$this->keyValue->set('post_update_version', $reset_version);
|
||||
echo $this->l10n->t('Post update version number has been set to %s.', $reset_version) . "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
+12
-10
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -24,8 +24,8 @@ namespace Friendica\Console;
|
||||
use Asika\SimpleConsole\Console;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Protocol\Delivery;
|
||||
use Friendica\Util\Strings;
|
||||
use Friendica\Worker\Delivery;
|
||||
|
||||
class Relocate extends Console
|
||||
{
|
||||
@@ -92,18 +92,19 @@ HELP;
|
||||
throw new \InvalidArgumentException('Can not parse new base URL. Must have at least <scheme>://<domain>');
|
||||
}
|
||||
|
||||
$this->out(sprintf('Relocation started from %s to %s. Could take a while to complete.', $this->baseUrl->get(true), $this->getArgument(0)));
|
||||
$this->out(sprintf('Relocation started from %s to %s. Could take a while to complete.', $this->baseUrl, $this->getArgument(0)));
|
||||
|
||||
$old_url = $this->baseUrl->get(true);
|
||||
$old_url = (string)$this->baseUrl;
|
||||
|
||||
// Generate host names for relocation the addresses in the format user@address.tld
|
||||
$new_host = str_replace('http://', '@', Strings::normaliseLink($new_url));
|
||||
$old_host = str_replace('http://', '@', Strings::normaliseLink($old_url));
|
||||
|
||||
$this->out('Entering maintenance mode');
|
||||
$this->config->set('system', 'maintenance', true);
|
||||
$this->config->set('system', 'maintenance_reason', 'Relocating node to ' . $new_url);
|
||||
|
||||
$this->config->beginTransaction()
|
||||
->set('system', 'maintenance', true)
|
||||
->set('system', 'maintenance_reason', 'Relocating node to ' . $new_url)
|
||||
->commit();
|
||||
try {
|
||||
if (!$this->database->transaction()) {
|
||||
throw new \Exception('Unable to start a transaction, please retry later.');
|
||||
@@ -178,7 +179,6 @@ HELP;
|
||||
// update config
|
||||
$this->out('Updating config values');
|
||||
$this->config->set('system', 'url', $new_url);
|
||||
$this->baseUrl->saveByURL($new_url);
|
||||
|
||||
$this->database->commit();
|
||||
} catch (\Throwable $e) {
|
||||
@@ -189,8 +189,10 @@ HELP;
|
||||
return 1;
|
||||
} finally {
|
||||
$this->out('Leaving maintenance mode');
|
||||
$this->config->set('system', 'maintenance', false);
|
||||
$this->config->set('system', 'maintenance_reason', '');
|
||||
$this->config->beginTransaction()
|
||||
->set('system', 'maintenance', false)
|
||||
->delete('system', 'maintenance_reason')
|
||||
->commit();
|
||||
}
|
||||
|
||||
// send relocate
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -24,6 +24,7 @@ namespace Friendica\Console;
|
||||
use Asika\SimpleConsole\CommandArgsException;
|
||||
use Asika\SimpleConsole\Console;
|
||||
use Console_Table;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Moderation\DomainPatternBlocklist;
|
||||
|
||||
/**
|
||||
@@ -106,6 +107,11 @@ HELP;
|
||||
{
|
||||
$filename = $this->getArgument(1);
|
||||
|
||||
if (empty($filename)) {
|
||||
$this->out('A file name is required, e.g. ./bin/console serverblock export backup.csv');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->blocklist->exportToFile($filename);
|
||||
|
||||
// Success
|
||||
@@ -127,6 +133,7 @@ HELP;
|
||||
|
||||
if ($this->blocklist->append($newBlockList)) {
|
||||
$this->out(sprintf("Entries from %s that were not blocked before are now blocked", $filename));
|
||||
Worker::add(Worker::PRIORITY_LOW, 'UpdateBlockedServers');
|
||||
return 0;
|
||||
} else {
|
||||
$this->out("Couldn't save the block list");
|
||||
@@ -169,6 +176,7 @@ HELP;
|
||||
} else {
|
||||
$this->out(sprintf("The domain pattern '%s' is now blocked. (Reason: '%s')", $pattern, $reason));
|
||||
}
|
||||
Worker::add(Worker::PRIORITY_LOW, 'UpdateBlockedServers');
|
||||
return 0;
|
||||
} else {
|
||||
$this->out(sprintf("Couldn't save '%s' as blocked domain pattern", $pattern));
|
||||
@@ -193,6 +201,7 @@ HELP;
|
||||
if ($result) {
|
||||
if ($result == 2) {
|
||||
$this->out(sprintf("The domain pattern '%s' isn't blocked anymore", $pattern));
|
||||
Worker::add(Worker::PRIORITY_LOW, 'UpdateBlockedServers');
|
||||
return 0;
|
||||
} else {
|
||||
$this->out(sprintf("The domain pattern '%s' wasn't blocked.", $pattern));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -270,7 +270,7 @@ HELP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows or denys a user based on it's nickname
|
||||
* Allows or denies a user based on it's nickname
|
||||
*
|
||||
* @param bool $allow True, if the pending user is allowed, false if denies
|
||||
*
|
||||
|
||||
+12
-4
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -73,7 +73,12 @@ class Avatar
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
||||
try {
|
||||
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
||||
} catch (\Exception $exception) {
|
||||
Logger::notice('Avatar is invalid', ['avatar' => $avatar, 'exception' => $exception]);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$img_str = $fetchResult->getBody();
|
||||
if (empty($img_str)) {
|
||||
@@ -246,13 +251,16 @@ class Avatar
|
||||
* Delete locally cached avatar pictures of a contact
|
||||
*
|
||||
* @param string $avatar
|
||||
* @return void
|
||||
* @return bool
|
||||
*/
|
||||
public static function deleteCache(array $contact)
|
||||
public static function deleteCache(array $contact): bool
|
||||
{
|
||||
$existed = (self::isCacheFile($contact['photo']) || self::isCacheFile($contact['thumb']) || self::isCacheFile($contact['micro']));
|
||||
self::deleteCacheFile($contact['photo']);
|
||||
self::deleteCacheFile($contact['thumb']);
|
||||
self::deleteCacheFile($contact['micro']);
|
||||
|
||||
return $existed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -94,7 +94,7 @@ class BoundariesPager extends Pager
|
||||
* $params = ['order' => ['sort_field' => true], 'limit' => $itemsPerPage];
|
||||
* $items = DBA::toArray(DBA::select($table, $fields, $condition, $params));
|
||||
*
|
||||
* $pager = new BoundariesPager($a->query_string, $items[0]['sort_field'], $items[coutn($items) - 1]['sort_field'], $itemsPerPage);
|
||||
* $pager = new BoundariesPager($a->query_string, $items[0]['sort_field'], $items[count($items) - 1]['sort_field'], $itemsPerPage);
|
||||
*
|
||||
* $html = $pager->renderMinimal(count($items));
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -140,6 +140,7 @@ class ContactSelector
|
||||
Protocol::STATUSNET => DI::l10n()->t('GNU Social Connector'),
|
||||
Protocol::ACTIVITYPUB => DI::l10n()->t('ActivityPub'),
|
||||
Protocol::PNUT => DI::l10n()->t('pnut'),
|
||||
Protocol::TUMBLR => DI::l10n()->t('Tumblr'),
|
||||
];
|
||||
|
||||
Hook::callAll('network_to_name', $nets);
|
||||
@@ -210,6 +211,7 @@ class ContactSelector
|
||||
Protocol::STATUSNET => 'gnu-social',
|
||||
Protocol::ACTIVITYPUB => 'activitypub',
|
||||
Protocol::PNUT => 'file-text-o', /// @todo
|
||||
Protocol::TUMBLR => 'tumblr',
|
||||
];
|
||||
|
||||
$platform_icons = ['diaspora' => 'diaspora', 'friendica' => 'friendica', 'friendika' => 'friendica',
|
||||
|
||||
+224
-76
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -41,6 +41,7 @@ use Friendica\Model\Post;
|
||||
use Friendica\Model\Tag;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Model\Verb;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Object\Post as PostObject;
|
||||
use Friendica\Object\Thread;
|
||||
use Friendica\Protocol\Activity;
|
||||
@@ -53,6 +54,16 @@ use Psr\Log\LoggerInterface;
|
||||
|
||||
class Conversation
|
||||
{
|
||||
const MODE_COMMUNITY = 'community';
|
||||
const MODE_CONTACTS = 'contacts';
|
||||
const MODE_CONTACT_POSTS = 'contact-posts';
|
||||
const MODE_DISPLAY = 'display';
|
||||
const MODE_FILED = 'filed';
|
||||
const MODE_NETWORK = 'network';
|
||||
const MODE_NOTES = 'notes';
|
||||
const MODE_SEARCH = 'search';
|
||||
const MODE_PROFILE = 'profile';
|
||||
|
||||
/** @var Activity */
|
||||
private $activity;
|
||||
/** @var L10n */
|
||||
@@ -183,6 +194,52 @@ class Conversation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the liker phrase based on a list of likers
|
||||
*
|
||||
* @param string $verb the activity verb
|
||||
* @param array $likers a list of likers
|
||||
*
|
||||
* @return string the liker phrase
|
||||
*
|
||||
* @throws InternalServerErrorException in case either the verb is invalid or the list of likers is empty
|
||||
*/
|
||||
private function getLikerPhrase(string $verb, array $likers): string
|
||||
{
|
||||
$total = count($likers);
|
||||
|
||||
if ($total === 0) {
|
||||
throw new InternalServerErrorException(sprintf('There has to be at least one Liker for verb "%s"', $verb));
|
||||
} else if ($total === 1) {
|
||||
$likerString = $likers[0];
|
||||
} else {
|
||||
if ($total < $this->config->get('system', 'max_likers')) {
|
||||
$likerString = implode(', ', array_slice($likers, 0, -1));
|
||||
$likerString .= ' ' . $this->l10n->t('and') . ' ' . $likers[count($likers) - 1];
|
||||
} else {
|
||||
$likerString = implode(', ', array_slice($likers, 0, $this->config->get('system', 'max_likers') - 1));
|
||||
$likerString .= ' ' . $this->l10n->t('and %d other people', $total - $this->config->get('system', 'max_likers'));
|
||||
}
|
||||
}
|
||||
|
||||
switch ($verb) {
|
||||
case 'like':
|
||||
return $this->l10n->tt('%2$s likes this.', '%2$s like this.', $total, $likerString);
|
||||
case 'dislike':
|
||||
return $this->l10n->tt('%2$s doesn\'t like this.', '%2$s don\'t like this.', $total, $likerString);
|
||||
case 'attendyes':
|
||||
return $this->l10n->tt('%2$s attends.', '%2$s attend.', $total, $likerString);
|
||||
case 'attendno':
|
||||
return $this->l10n->tt('%2$s doesn\'t attend.', '%2$s don\'t attend.', $total, $likerString);
|
||||
case 'attendmaybe':
|
||||
return $this->l10n->tt('%2$s attends maybe.', '%2$s attend maybe.', $total, $likerString);
|
||||
case 'announce':
|
||||
return $this->l10n->tt('%2$s reshared this.', '%2$s reshared this.', $total, $likerString);
|
||||
default:
|
||||
throw new InternalServerErrorException(sprintf('Unknown verb "%s"', $verb));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the activity text for an item/photo/video
|
||||
*
|
||||
@@ -195,87 +252,48 @@ class Conversation
|
||||
public function formatActivity(array $links, string $verb, int $id): string
|
||||
{
|
||||
$this->profiler->startRecording('rendering');
|
||||
$o = '';
|
||||
$expanded = '';
|
||||
$phrase = '';
|
||||
|
||||
$total = count($links);
|
||||
if ($total == 1) {
|
||||
$likers = $links[0];
|
||||
$phrase = $this->getLikerPhrase($verb, $links);
|
||||
$total = count($links);
|
||||
|
||||
if ($total > 1) {
|
||||
$spanatts = "class=\"btn btn-link fakelink\" onclick=\"openClose('{$verb}list-$id');\"";
|
||||
$explikers = $phrase;
|
||||
|
||||
// Phrase if there is only one liker. In other cases it will be uses for the expanded
|
||||
// list which show all likers
|
||||
switch ($verb) {
|
||||
case 'like':
|
||||
$phrase = $this->l10n->t('%s likes this.', $likers);
|
||||
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> likes this', '<button type="button" %2$s>%1$d people</button> like this', $total, $spanatts);
|
||||
break;
|
||||
case 'dislike':
|
||||
$phrase = $this->l10n->t('%s doesn\'t like this.', $likers);
|
||||
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> doesn\'t like this', '<button type="button" %2$s>%1$d peiple</button> don\'t like this', $total, $spanatts);
|
||||
break;
|
||||
case 'attendyes':
|
||||
$phrase = $this->l10n->t('%s attends.', $likers);
|
||||
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> attends', '<button type="button" %2$s>%1$d people</button> attend', $total, $spanatts);
|
||||
break;
|
||||
case 'attendno':
|
||||
$phrase = $this->l10n->t('%s doesn\'t attend.', $likers);
|
||||
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> doesn\'t attend','<button type="button" %2$s>%1$d people</button> don\'t attend', $total, $spanatts);
|
||||
break;
|
||||
case 'attendmaybe':
|
||||
$phrase = $this->l10n->t('%s attends maybe.', $likers);
|
||||
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> attends maybe', '<button type="button" %2$s>%1$d people</button> attend maybe', $total, $spanatts);
|
||||
break;
|
||||
case 'announce':
|
||||
$phrase = $this->l10n->t('%s reshared this.', $likers);
|
||||
break;
|
||||
}
|
||||
} elseif ($total > 1) {
|
||||
if ($total < $this->config->get('system', 'max_likers')) {
|
||||
$likers = implode(', ', array_slice($links, 0, -1));
|
||||
$likers .= ' ' . $this->l10n->t('and') . ' ' . $links[count($links) - 1];
|
||||
} else {
|
||||
$likers = implode(', ', array_slice($links, 0, $this->config->get('system', 'max_likers') - 1));
|
||||
$likers .= ' ' . $this->l10n->t('and %d other people', $total - $this->config->get('system', 'max_likers'));
|
||||
}
|
||||
|
||||
$spanatts = "class=\"fakelink\" onclick=\"openClose('{$verb}list-$id');\"";
|
||||
|
||||
$explikers = '';
|
||||
switch ($verb) {
|
||||
case 'like':
|
||||
$phrase = $this->l10n->t('<span %1$s>%2$d people</span> like this', $spanatts, $total);
|
||||
$explikers = $this->l10n->t('%s like this.', $likers);
|
||||
break;
|
||||
case 'dislike':
|
||||
$phrase = $this->l10n->t('<span %1$s>%2$d people</span> don\'t like this', $spanatts, $total);
|
||||
$explikers = $this->l10n->t('%s don\'t like this.', $likers);
|
||||
break;
|
||||
case 'attendyes':
|
||||
$phrase = $this->l10n->t('<span %1$s>%2$d people</span> attend', $spanatts, $total);
|
||||
$explikers = $this->l10n->t('%s attend.', $likers);
|
||||
break;
|
||||
case 'attendno':
|
||||
$phrase = $this->l10n->t('<span %1$s>%2$d people</span> don\'t attend', $spanatts, $total);
|
||||
$explikers = $this->l10n->t('%s don\'t attend.', $likers);
|
||||
break;
|
||||
case 'attendmaybe':
|
||||
$phrase = $this->l10n->t('<span %1$s>%2$d people</span> attend maybe', $spanatts, $total);
|
||||
$explikers = $this->l10n->t('%s attend maybe.', $likers);
|
||||
break;
|
||||
case 'announce':
|
||||
$phrase = $this->l10n->t('<span %1$s>%2$d people</span> reshared this', $spanatts, $total);
|
||||
$explikers = $this->l10n->t('%s reshared this.', $likers);
|
||||
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> reshared this', '<button type="button" %2$s>%1$d people</button> reshared this', $total, $spanatts);
|
||||
break;
|
||||
}
|
||||
|
||||
$expanded .= "\t" . '<p class="wall-item-' . $verb . '-expanded" id="' . $verb . 'list-' . $id . '" style="display: none;" >' . $explikers . '</p>';
|
||||
}
|
||||
|
||||
$o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('voting_fakelink.tpl'), [
|
||||
$output = Renderer::replaceMacros(Renderer::getMarkupTemplate('voting_fakelink.tpl'), [
|
||||
'$phrase' => $phrase,
|
||||
'$type' => $verb,
|
||||
'$id' => $id
|
||||
]);
|
||||
$o .= $expanded;
|
||||
$output .= $expanded;
|
||||
|
||||
$this->profiler->stopRecording();
|
||||
return $o;
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function statusEditor(array $x = [], int $notes_cid = 0, bool $popup = false): string
|
||||
@@ -304,7 +322,7 @@ class Conversation
|
||||
$tpl = Renderer::getMarkupTemplate('jot-header.tpl');
|
||||
$this->page['htmlhead'] .= Renderer::replaceMacros($tpl, [
|
||||
'$newpost' => 'true',
|
||||
'$baseurl' => $this->baseURL->get(true),
|
||||
'$baseurl' => $this->baseURL,
|
||||
'$geotag' => $geotag,
|
||||
'$nickname' => $x['nickname'],
|
||||
'$ispublic' => $this->l10n->t('Visible to <strong>everybody</strong>'),
|
||||
@@ -375,7 +393,7 @@ class Conversation
|
||||
'$posttype' => $notes_cid ? ItemModel::PT_PERSONAL_NOTE : ItemModel::PT_ARTICLE,
|
||||
'$content' => $x['content'] ?? '',
|
||||
'$post_id' => $x['post_id'] ?? '',
|
||||
'$baseurl' => $this->baseURL->get(true),
|
||||
'$baseurl' => $this->baseURL,
|
||||
'$defloc' => $x['default_location'],
|
||||
'$visitor' => $x['visitor'],
|
||||
'$pvisit' => $notes_cid ? 'none' : $x['visitor'],
|
||||
@@ -436,15 +454,13 @@ class Conversation
|
||||
$this->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
|
||||
$this->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
|
||||
|
||||
$ssl_state = (bool)$this->session->getLocalUserId();
|
||||
|
||||
$live_update_div = '';
|
||||
|
||||
$blocklist = $this->getBlocklist();
|
||||
|
||||
$previewing = (($preview) ? ' preview ' : '');
|
||||
|
||||
if ($mode === 'network') {
|
||||
if ($mode === self::MODE_NETWORK) {
|
||||
$items = $this->addChildren($items, false, $order, $uid, $mode);
|
||||
if (!$update) {
|
||||
/*
|
||||
@@ -470,7 +486,7 @@ class Conversation
|
||||
|
||||
. "'; </script>\r\n";
|
||||
}
|
||||
} elseif ($mode === 'profile') {
|
||||
} elseif ($mode === self::MODE_PROFILE) {
|
||||
$items = $this->addChildren($items, false, $order, $uid, $mode);
|
||||
|
||||
if (!$update) {
|
||||
@@ -487,7 +503,7 @@ class Conversation
|
||||
. "; var netargs = '?f='; </script>\r\n";
|
||||
}
|
||||
}
|
||||
} elseif ($mode === 'notes') {
|
||||
} elseif ($mode === self::MODE_NOTES) {
|
||||
$items = $this->addChildren($items, false, $order, $this->session->getLocalUserId(), $mode);
|
||||
|
||||
if (!$update) {
|
||||
@@ -495,7 +511,7 @@ class Conversation
|
||||
. "<script> var profile_uid = " . $this->session->getLocalUserId()
|
||||
. "; var netargs = '?f='; </script>\r\n";
|
||||
}
|
||||
} elseif ($mode === 'display') {
|
||||
} elseif ($mode === self::MODE_DISPLAY) {
|
||||
$items = $this->addChildren($items, false, $order, $uid, $mode);
|
||||
|
||||
if (!$update) {
|
||||
@@ -503,7 +519,7 @@ class Conversation
|
||||
. "<script> var profile_uid = " . ($this->session->getLocalUserId() ?: 0) . ";"
|
||||
. "</script>";
|
||||
}
|
||||
} elseif ($mode === 'community') {
|
||||
} elseif ($mode === self::MODE_COMMUNITY) {
|
||||
$items = $this->addChildren($items, true, $order, $uid, $mode);
|
||||
|
||||
if (!$update) {
|
||||
@@ -514,7 +530,7 @@ class Conversation
|
||||
. (!empty($_GET['accounttype']) ? '&accounttype=' . rawurlencode($_GET['accounttype']) : '')
|
||||
. "'; </script>\r\n";
|
||||
}
|
||||
} elseif ($mode === 'contacts') {
|
||||
} elseif ($mode === self::MODE_CONTACTS) {
|
||||
$items = $this->addChildren($items, false, $order, $uid, $mode);
|
||||
|
||||
if (!$update) {
|
||||
@@ -522,11 +538,11 @@ class Conversation
|
||||
. "<script> var profile_uid = -1; var netargs = '" . substr($this->args->getCommand(), 8)
|
||||
."?f='; </script>\r\n";
|
||||
}
|
||||
} elseif ($mode === 'search') {
|
||||
} elseif ($mode === self::MODE_SEARCH) {
|
||||
$live_update_div = '<div id="live-search"></div>' . "\r\n";
|
||||
}
|
||||
|
||||
$page_dropping = $this->session->getLocalUserId() && $this->session->getLocalUserId() == $uid && $mode != 'search';
|
||||
$page_dropping = $this->session->getLocalUserId() && $this->session->getLocalUserId() == $uid && $mode != self::MODE_SEARCH;
|
||||
|
||||
if (!$update) {
|
||||
$_SESSION['return_path'] = $this->args->getQueryString();
|
||||
@@ -558,7 +574,7 @@ class Conversation
|
||||
$formSecurityToken = BaseModule::getFormSecurityToken('contact_action');
|
||||
|
||||
if (!empty($items)) {
|
||||
if (in_array($mode, ['community', 'contacts', 'profile'])) {
|
||||
if (in_array($mode, [self::MODE_COMMUNITY, self::MODE_CONTACTS, self::MODE_PROFILE])) {
|
||||
$writable = true;
|
||||
} else {
|
||||
$writable = $items[0]['writable'] || ($items[0]['uid'] == 0) && in_array($items[0]['network'], Protocol::FEDERATED);
|
||||
@@ -568,7 +584,7 @@ class Conversation
|
||||
$writable = false;
|
||||
}
|
||||
|
||||
if (in_array($mode, ['filed', 'search', 'contact-posts'])) {
|
||||
if (in_array($mode, [self::MODE_FILED, self::MODE_SEARCH, self::MODE_CONTACT_POSTS])) {
|
||||
|
||||
/*
|
||||
* "New Item View" on network page or search page results
|
||||
@@ -621,7 +637,7 @@ class Conversation
|
||||
$location_html = $locate['html'] ?: Strings::escapeHtml($locate['location'] ?: $locate['coord'] ?: '');
|
||||
|
||||
$this->item->localize($item);
|
||||
if ($mode === 'filed') {
|
||||
if ($mode === self::MODE_FILED) {
|
||||
$dropping = true;
|
||||
} else {
|
||||
$dropping = false;
|
||||
@@ -774,7 +790,7 @@ class Conversation
|
||||
}
|
||||
|
||||
$o = Renderer::replaceMacros($page_template, [
|
||||
'$baseurl' => $this->baseURL->get($ssl_state),
|
||||
'$baseurl' => $this->baseURL,
|
||||
'$return_path' => $this->args->getQueryString(),
|
||||
'$live_update' => $live_update_div,
|
||||
'$remove' => $this->l10n->t('remove'),
|
||||
@@ -969,8 +985,20 @@ class Conversation
|
||||
$condition['author-hidden'] = false;
|
||||
}
|
||||
|
||||
if ($this->config->get('system', 'emoji_activities')) {
|
||||
$emojis = $this->getEmojis($uriids);
|
||||
$condition = DBA::mergeConditions($condition, ["(`gravity` != ? OR `origin`)", ItemModel::GRAVITY_ACTIVITY]);
|
||||
}
|
||||
|
||||
$condition = DBA::mergeConditions($condition,
|
||||
["`uid` IN (0, ?) AND (NOT `vid` IN (?, ?) OR `vid` IS NULL)", $uid, Verb::getID(Activity::FOLLOW), Verb::getID(Activity::VIEW)]);
|
||||
["`uid` IN (0, ?) AND (NOT `vid` IN (?, ?, ?) OR `vid` IS NULL)", $uid, Verb::getID(Activity::FOLLOW), Verb::getID(Activity::VIEW), Verb::getID(Activity::READ)]);
|
||||
|
||||
$condition = DBA::mergeConditions($condition, ["(`uid` != ? OR `private` != ?)", 0, ItemModel::PRIVATE]);
|
||||
|
||||
$condition = DBA::mergeConditions($condition,
|
||||
["`visible` AND NOT `deleted` AND NOT `author-blocked` AND NOT `owner-blocked`
|
||||
AND ((NOT `contact-pending` AND (`contact-rel` IN (?, ?))) OR `self` OR `contact-uid` = ?)",
|
||||
Contact::SHARING, Contact::FRIEND, 0]);
|
||||
|
||||
$thread_parents = Post::select(['uri-id', 'causer-id'], $condition, ['order' => ['uri-id' => false, 'uid']]);
|
||||
|
||||
@@ -983,16 +1011,18 @@ class Conversation
|
||||
|
||||
$params = ['order' => ['uri-id' => true, 'uid' => true]];
|
||||
|
||||
$thread_items = Post::selectForUser($uid, array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), $condition, $params);
|
||||
$thread_items = Post::select(array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), $condition, $params);
|
||||
|
||||
$items = [];
|
||||
$items = [];
|
||||
$quote_uri_ids = [];
|
||||
$authors = [];
|
||||
|
||||
while ($row = Post::fetch($thread_items)) {
|
||||
if (!empty($items[$row['uri-id']]) && ($row['uid'] == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (($mode != 'contacts') && !$row['origin']) {
|
||||
if (($mode != self::MODE_CONTACTS) && !$row['origin']) {
|
||||
$row['featured'] = false;
|
||||
}
|
||||
|
||||
@@ -1005,17 +1035,135 @@ class Conversation
|
||||
}
|
||||
}
|
||||
|
||||
$authors[] = $row['author-id'];
|
||||
$authors[] = $row['owner-id'];
|
||||
|
||||
if (in_array($row['gravity'], [ItemModel::GRAVITY_PARENT, ItemModel::GRAVITY_COMMENT])) {
|
||||
$quote_uri_ids[$row['uri-id']] = [
|
||||
'uri-id' => $row['uri-id'],
|
||||
'uri' => $row['uri'],
|
||||
'parent-uri-id' => $row['parent-uri-id'],
|
||||
'parent-uri' => $row['parent-uri'],
|
||||
];
|
||||
}
|
||||
|
||||
$items[$row['uri-id']] = $this->addRowInformation($row, $activities[$row['uri-id']] ?? [], $thr_parent[$row['thr-parent-id']] ?? []);
|
||||
}
|
||||
|
||||
DBA::close($thread_items);
|
||||
|
||||
$quotes = Post::select(array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), ['quote-uri-id' => array_column($quote_uri_ids, 'uri-id'), 'body' => '', 'uid' => 0]);
|
||||
while ($quote = Post::fetch($quotes)) {
|
||||
$row = $quote;
|
||||
|
||||
$row['uid'] = $uid;
|
||||
$row['verb'] = $row['body'] = $row['raw-body'] = Activity::ANNOUNCE;
|
||||
$row['gravity'] = ItemModel::GRAVITY_ACTIVITY;
|
||||
$row['object-type'] = Activity\ObjectType::NOTE;
|
||||
$row['parent-uri'] = $quote_uri_ids[$quote['quote-uri-id']]['parent-uri'];
|
||||
$row['parent-uri-id'] = $quote_uri_ids[$quote['quote-uri-id']]['parent-uri-id'];
|
||||
$row['thr-parent'] = $quote_uri_ids[$quote['quote-uri-id']]['uri'];
|
||||
$row['thr-parent-id'] = $quote_uri_ids[$quote['quote-uri-id']]['uri-id'];
|
||||
|
||||
$authors[] = $row['author-id'];
|
||||
$authors[] = $row['owner-id'];
|
||||
|
||||
$items[$row['uri-id']] = $this->addRowInformation($row, [], []);
|
||||
}
|
||||
DBA::close($quotes);
|
||||
|
||||
$authors = array_unique($authors);
|
||||
|
||||
$blocks = [];
|
||||
$ignores = [];
|
||||
$collapses = [];
|
||||
if (!empty($authors)) {
|
||||
$usercontacts = DBA::select('user-contact', ['cid', 'blocked', 'ignored', 'collapsed'], ['uid' => $uid, 'cid' => $authors]);
|
||||
while ($usercontact = DBA::fetch($usercontacts)) {
|
||||
if ($usercontact['blocked']) {
|
||||
$blocks[] = $usercontact['cid'];
|
||||
}
|
||||
if ($usercontact['ignored']) {
|
||||
$ignores[] = $usercontact['cid'];
|
||||
}
|
||||
if ($usercontact['collapsed']) {
|
||||
$collapses[] = $usercontact['cid'];
|
||||
}
|
||||
}
|
||||
DBA::close($usercontacts);
|
||||
}
|
||||
|
||||
foreach ($items as $key => $row) {
|
||||
$items[$key]['emojis'] = $emojis[$key] ?? [];
|
||||
|
||||
$always_display = in_array($mode, [self::MODE_CONTACTS, self::MODE_CONTACT_POSTS]);
|
||||
|
||||
$items[$key]['user-blocked-author'] = !$always_display && in_array($row['author-id'], $blocks);
|
||||
$items[$key]['user-ignored-author'] = !$always_display && in_array($row['author-id'], $ignores);
|
||||
$items[$key]['user-blocked-owner'] = !$always_display && in_array($row['owner-id'], $blocks);
|
||||
$items[$key]['user-ignored-owner'] = !$always_display && in_array($row['owner-id'], $ignores);
|
||||
$items[$key]['user-collapsed-author'] = !$always_display && in_array($row['author-id'], $collapses);
|
||||
$items[$key]['user-collapsed-owner'] = !$always_display && in_array($row['owner-id'], $collapses);
|
||||
|
||||
if (in_array($mode, [self::MODE_COMMUNITY, self::MODE_NETWORK]) &&
|
||||
(in_array($row['author-id'], $blocks) || in_array($row['owner-id'], $blocks) || in_array($row['author-id'], $ignores) || in_array($row['owner-id'], $ignores))) {
|
||||
unset($items[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$items = $this->convSort($items, $order);
|
||||
|
||||
$this->profiler->stopRecording();
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch emoji reaction from the conversation
|
||||
*
|
||||
* @param array $uriids
|
||||
* @return array
|
||||
*/
|
||||
private function getEmojis(array $uriids): array
|
||||
{
|
||||
$activity_emoji = [
|
||||
Activity::LIKE => '👍',
|
||||
Activity::DISLIKE => '👎',
|
||||
Activity::ATTEND => '✔️',
|
||||
Activity::ATTENDMAYBE => '❓',
|
||||
Activity::ATTENDNO => '❌',
|
||||
Activity::ANNOUNCE => '♻',
|
||||
Activity::VIEW => '📺',
|
||||
];
|
||||
|
||||
$index_list = array_values($activity_emoji);
|
||||
$verbs = array_merge(array_keys($activity_emoji), [Activity::EMOJIREACT]);
|
||||
|
||||
$condition = DBA::mergeConditions(['parent-uri-id' => $uriids, 'gravity' => ItemModel::GRAVITY_ACTIVITY, 'verb' => $verbs], ["NOT `deleted`"]);
|
||||
$separator = chr(255) . chr(255) . chr(255);
|
||||
|
||||
$sql = "SELECT `thr-parent-id`, `body`, `verb`, COUNT(*) AS `total`, GROUP_CONCAT(REPLACE(`author-name`, '" . $separator . "', ' ') SEPARATOR '". $separator ."' LIMIT 50) AS `title` FROM `post-view` WHERE " . array_shift($condition) . " GROUP BY `thr-parent-id`, `verb`, `body`";
|
||||
|
||||
$emojis = [];
|
||||
|
||||
$rows = DBA::p($sql, $condition);
|
||||
while ($row = DBA::fetch($rows)) {
|
||||
$row['verb'] = $row['body'] ? Activity::EMOJIREACT : $row['verb'];
|
||||
$emoji = $row['body'] ?: $activity_emoji[$row['verb']];
|
||||
if (!isset($index_list[$emoji])) {
|
||||
$index_list[] = $emoji;
|
||||
}
|
||||
$index = array_search($emoji, $index_list);
|
||||
|
||||
$emojis[$row['thr-parent-id']][$index]['emoji'] = $emoji;
|
||||
$emojis[$row['thr-parent-id']][$index]['verb'] = $row['verb'];
|
||||
$emojis[$row['thr-parent-id']][$index]['total'] = ($emojis[$row['thr-parent-id']][$index]['total'] ?? 0) + $row['total'];
|
||||
$emojis[$row['thr-parent-id']][$index]['title'] = array_unique(array_merge($emojis[$row['thr-parent-id']][$index]['title'] ?? [], explode($separator, $row['title'])));
|
||||
}
|
||||
DBA::close($rows);
|
||||
|
||||
return $emojis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plucks the children of the given parent from a given item list.
|
||||
*
|
||||
@@ -1222,7 +1370,7 @@ class Conversation
|
||||
}
|
||||
}
|
||||
|
||||
/// @TODO: Stop recusrsively adding all children back to the top level (!!!)
|
||||
/// @TODO: Stop recursively adding all children back to the top level (!!!)
|
||||
/// However, this apparently ensures responses (likes, attendance) display (?!)
|
||||
foreach ($parents as $parent) {
|
||||
if (count($parent['children'])) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -79,7 +79,7 @@ class Feature
|
||||
* Get a list of all available features
|
||||
*
|
||||
* The array includes the setting group, the setting name,
|
||||
* explainations for the setting and if it's enabled or disabled
|
||||
* explanations for the setting and if it's enabled or disabled
|
||||
* by default
|
||||
*
|
||||
* @param bool $filtered True removes any locked features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -38,7 +38,7 @@ class ForumManager
|
||||
*
|
||||
* @param int $uid of the profile owner
|
||||
* @param boolean $lastitem Sort by lastitem
|
||||
* @param boolean $showhidden Show frorums which are not hidden
|
||||
* @param boolean $showhidden Show forums which are not hidden
|
||||
* @param boolean $showprivate Show private groups
|
||||
*
|
||||
* @return array
|
||||
@@ -60,10 +60,10 @@ class ForumManager
|
||||
$condition = [
|
||||
'contact-type' => Contact::TYPE_COMMUNITY,
|
||||
'network' => [Protocol::DFRN, Protocol::ACTIVITYPUB],
|
||||
'uid' => $uid,
|
||||
'uid' => $uid,
|
||||
'blocked' => false,
|
||||
'pending' => false,
|
||||
'archive' => false,
|
||||
'archive' => false,
|
||||
];
|
||||
|
||||
$condition = DBA::mergeConditions($condition, ["`platform` != ?", 'peertube']);
|
||||
@@ -102,7 +102,7 @@ class ForumManager
|
||||
/**
|
||||
* Forumlist widget
|
||||
*
|
||||
* Sidebar widget to show subcribed friendica forums. If activated
|
||||
* Sidebar widget to show subscribed friendica forums. If activated
|
||||
* in the settings, it appears at the notwork page sidebar
|
||||
*
|
||||
* @param string $baseurl Base module path
|
||||
|
||||
+319
-28
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -21,22 +21,36 @@
|
||||
|
||||
namespace Friendica\Content;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Content\Text\BBCode\Video;
|
||||
use Friendica\Content\Text\HTML;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Model\Attach;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Conversation;
|
||||
use Friendica\Model\FileTag;
|
||||
use Friendica\Model\Group;
|
||||
use Friendica\Model\Item as ItemModel;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Model\Tag;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Object\EMail\ItemCCEMail;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Friendica\Util\ACLFormatter;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Emailer;
|
||||
use Friendica\Util\ParseUrl;
|
||||
use Friendica\Util\Profiler;
|
||||
use Friendica\Util\Proxy;
|
||||
use Friendica\Util\XML;
|
||||
@@ -54,13 +68,31 @@ class Item
|
||||
private $profiler;
|
||||
/** @var IHandleUserSessions */
|
||||
private $userSession;
|
||||
/** @var Video */
|
||||
private $bbCodeVideo;
|
||||
/** @var ACLFormatter */
|
||||
private $aclFormatter;
|
||||
/** @var IManagePersonalConfigValues */
|
||||
private $pConfig;
|
||||
/** @var BaseURL */
|
||||
private $baseURL;
|
||||
/** @var Emailer */
|
||||
private $emailer;
|
||||
/** @var App */
|
||||
private $app;
|
||||
|
||||
public function __construct(Profiler $profiler, Activity $activity, L10n $l10n, IHandleUserSessions $userSession)
|
||||
public function __construct(Profiler $profiler, Activity $activity, L10n $l10n, IHandleUserSessions $userSession, Video $bbCodeVideo, ACLFormatter $aclFormatter, IManagePersonalConfigValues $pConfig, BaseURL $baseURL, Emailer $emailer, App $app)
|
||||
{
|
||||
$this->profiler = $profiler;
|
||||
$this->activity = $activity;
|
||||
$this->l10n = $l10n;
|
||||
$this->userSession = $userSession;
|
||||
$this->profiler = $profiler;
|
||||
$this->activity = $activity;
|
||||
$this->l10n = $l10n;
|
||||
$this->userSession = $userSession;
|
||||
$this->bbCodeVideo = $bbCodeVideo;
|
||||
$this->aclFormatter = $aclFormatter;
|
||||
$this->baseURL = $baseURL;
|
||||
$this->pConfig = $pConfig;
|
||||
$this->emailer = $emailer;
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,15 +223,13 @@ class Item
|
||||
|
||||
// select someone by nick in the current network
|
||||
if (!DBA::isResult($contact) && ($network != '')) {
|
||||
$condition = ["`nick` = ? AND `network` = ? AND `uid` = ?",
|
||||
$name, $network, $profile_uid];
|
||||
$condition = ['nick' => $name, 'network' => $network, 'uid' => $profile_uid];
|
||||
$contact = DBA::selectFirst('contact', $fields, $condition);
|
||||
}
|
||||
|
||||
// select someone by attag in the current network
|
||||
if (!DBA::isResult($contact) && ($network != '')) {
|
||||
$condition = ["`attag` = ? AND `network` = ? AND `uid` = ?",
|
||||
$name, $network, $profile_uid];
|
||||
$condition = ['attag' => $name, 'network' => $network, 'uid' => $profile_uid];
|
||||
$contact = DBA::selectFirst('contact', $fields, $condition);
|
||||
}
|
||||
|
||||
@@ -211,13 +241,13 @@ class Item
|
||||
|
||||
// select someone by nick in any network
|
||||
if (!DBA::isResult($contact)) {
|
||||
$condition = ["`nick` = ? AND `uid` = ?", $name, $profile_uid];
|
||||
$condition = ['nick' => $name, 'uid' => $profile_uid];
|
||||
$contact = DBA::selectFirst('contact', $fields, $condition);
|
||||
}
|
||||
|
||||
// select someone by attag in any network
|
||||
if (!DBA::isResult($contact)) {
|
||||
$condition = ["`attag` = ? AND `uid` = ?", $name, $profile_uid];
|
||||
$condition = ['attag' => $name, 'uid' => $profile_uid];
|
||||
$contact = DBA::selectFirst('contact', $fields, $condition);
|
||||
}
|
||||
|
||||
@@ -239,7 +269,7 @@ class Item
|
||||
$replaced = true;
|
||||
// create profile link
|
||||
$profile = str_replace(',', '%2c', $profile);
|
||||
$newtag = $tag_type.'[url=' . $profile . ']' . $newname . '[/url]';
|
||||
$newtag = $tag_type . '[url=' . $profile . ']' . $newname . '[/url]';
|
||||
$body = str_replace($tag_type . $name, $newtag, $body);
|
||||
}
|
||||
}
|
||||
@@ -263,8 +293,10 @@ class Item
|
||||
$xmlhead = '<?xml version="1.0" encoding="UTF-8" ?>';
|
||||
|
||||
if ($this->activity->match($item['verb'], Activity::TAG)) {
|
||||
$fields = ['author-id', 'author-link', 'author-name', 'author-network',
|
||||
'verb', 'object-type', 'resource-id', 'body', 'plink'];
|
||||
$fields = [
|
||||
'author-id', 'author-link', 'author-name', 'author-network',
|
||||
'verb', 'object-type', 'resource-id', 'body', 'plink'
|
||||
];
|
||||
$obj = Post::selectFirst($fields, ['uri' => $item['parent-uri']]);
|
||||
if (!DBA::isResult($obj)) {
|
||||
$this->profiler->stopRecording();
|
||||
@@ -301,12 +333,12 @@ class Item
|
||||
default:
|
||||
if ($obj['resource-id']) {
|
||||
$post_type = $this->l10n->t('photo');
|
||||
$m=[]; preg_match("/\[url=([^]]*)\]/", $obj['body'], $m);
|
||||
$rr['plink'] = $m[1];
|
||||
preg_match("/\[url=([^]]*)\]/", $obj['body'], $matches);
|
||||
$rr['plink'] = $matches[1];
|
||||
} else {
|
||||
$post_type = $this->l10n->t('status');
|
||||
}
|
||||
// Let's break everthing ... ;-)
|
||||
// Let's break everything ... ;-)
|
||||
break;
|
||||
}
|
||||
$plink = '[url=' . $obj['plink'] . ']' . $post_type . '[/url]';
|
||||
@@ -366,10 +398,11 @@ class Item
|
||||
}
|
||||
|
||||
if (!empty($pcid)) {
|
||||
$contact_url = 'contact/' . $pcid;
|
||||
$posts_link = $contact_url . '/posts';
|
||||
$block_link = $item['self'] ? '' : $contact_url . '/block?t=' . $formSecurityToken;
|
||||
$ignore_link = $item['self'] ? '' : $contact_url . '/ignore?t=' . $formSecurityToken;
|
||||
$contact_url = 'contact/' . $pcid;
|
||||
$posts_link = $contact_url . '/posts';
|
||||
$block_link = $item['self'] ? '' : $contact_url . '/block?t=' . $formSecurityToken;
|
||||
$ignore_link = $item['self'] ? '' : $contact_url . '/ignore?t=' . $formSecurityToken;
|
||||
$collapse_link = $item['self'] ? '' : $contact_url . '/collapse?t=' . $formSecurityToken;
|
||||
}
|
||||
|
||||
if ($cid && !$item['self']) {
|
||||
@@ -391,7 +424,8 @@ class Item
|
||||
$this->l10n->t('View Contact') => $contact_url,
|
||||
$this->l10n->t('Send PM') => $pm_url,
|
||||
$this->l10n->t('Block') => $block_link,
|
||||
$this->l10n->t('Ignore') => $ignore_link
|
||||
$this->l10n->t('Ignore') => $ignore_link,
|
||||
$this->l10n->t('Collapse') => $collapse_link
|
||||
];
|
||||
|
||||
if (!empty($item['language'])) {
|
||||
@@ -399,7 +433,8 @@ class Item
|
||||
}
|
||||
|
||||
if ((($cid == 0) || ($rel == Contact::FOLLOWER)) &&
|
||||
in_array($item['network'], Protocol::FEDERATED)) {
|
||||
in_array($item['network'], Protocol::FEDERATED)
|
||||
) {
|
||||
$menu[$this->l10n->t('Connect/Follow')] = 'contact/follow?url=' . urlencode($item['author-link']) . '&auto=1';
|
||||
}
|
||||
} else {
|
||||
@@ -513,7 +548,7 @@ class Item
|
||||
$item['allow_cid'] = '';
|
||||
$item['allow_gid'] = '';
|
||||
}
|
||||
} elseif ($setPermissions && ($item['gravity'] == ItemModel::GRAVITY_PARENT)) {
|
||||
} elseif ($setPermissions) {
|
||||
if (empty($receivers)) {
|
||||
// For security reasons direct posts without any receiver will be posts to yourself
|
||||
$self = Contact::selectFirst(['id'], ['uid' => $item['uid'], 'self' => true]);
|
||||
@@ -650,11 +685,11 @@ class Item
|
||||
|
||||
// If it is a reshared post then reformat it to avoid display problems with two share elements
|
||||
if (!empty($shared)) {
|
||||
if (!empty($shared['guid']) && ($encaspulated_share = $this->createSharedPostByGuid($shared['guid'], true))) {
|
||||
if (!empty($shared['guid']) && ($encapsulated_share = $this->createSharedPostByGuid($shared['guid'], true))) {
|
||||
if (!empty(BBCode::fetchShareAttributes($item['body']))) {
|
||||
$item['body'] = preg_replace("/\[share.*?\](.*)\[\/share\]/ism", $encaspulated_share, $item['body']);
|
||||
$item['body'] = preg_replace("/\[share.*?\](.*)\[\/share\]/ism", $encapsulated_share, $item['body']);
|
||||
} else {
|
||||
$item['body'] .= $encaspulated_share;
|
||||
$item['body'] .= $encapsulated_share;
|
||||
}
|
||||
}
|
||||
$item['body'] = HTML::toBBCode(BBCode::convertForUriId($item['uri-id'], $item['body'], BBCode::ACTIVITYPUB));
|
||||
@@ -756,4 +791,260 @@ class Item
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
public function storeAttachmentFromRequest(array $request): string
|
||||
{
|
||||
$attachment_type = $request['attachment_type'] ?? '';
|
||||
$attachment_title = $request['attachment_title'] ?? '';
|
||||
$attachment_text = $request['attachment_text'] ?? '';
|
||||
|
||||
$attachment_url = hex2bin($request['attachment_url'] ?? '');
|
||||
$attachment_img_src = hex2bin($request['attachment_img_src'] ?? '');
|
||||
|
||||
$attachment_img_width = $request['attachment_img_width'] ?? 0;
|
||||
$attachment_img_height = $request['attachment_img_height'] ?? 0;
|
||||
|
||||
// Fetch the basic attachment data
|
||||
$attachment = ParseUrl::getSiteinfoCached($attachment_url);
|
||||
unset($attachment['keywords']);
|
||||
|
||||
// Overwrite the basic data with possible changes from the frontend
|
||||
$attachment['type'] = $attachment_type;
|
||||
$attachment['title'] = $attachment_title;
|
||||
$attachment['text'] = $attachment_text;
|
||||
$attachment['url'] = $attachment_url;
|
||||
|
||||
if (!empty($attachment_img_src)) {
|
||||
$attachment['images'] = [
|
||||
0 => [
|
||||
'src' => $attachment_img_src,
|
||||
'width' => $attachment_img_width,
|
||||
'height' => $attachment_img_height
|
||||
]
|
||||
];
|
||||
} else {
|
||||
unset($attachment['images']);
|
||||
}
|
||||
|
||||
return "\n" . PageInfo::getFooterFromData($attachment);
|
||||
}
|
||||
|
||||
public function addCategories(array $post, string $category): array
|
||||
{
|
||||
if (!empty($post['file'])) {
|
||||
// get the "fileas" tags for this post
|
||||
$filedas = FileTag::fileToArray($post['file']);
|
||||
}
|
||||
|
||||
$list_array = explode(',', trim($category));
|
||||
$post['file'] = FileTag::arrayToFile($list_array, 'category');
|
||||
|
||||
if (!empty($filedas) && is_array($filedas)) {
|
||||
// append the fileas stuff to the new categories list
|
||||
$post['file'] .= FileTag::arrayToFile($filedas);
|
||||
}
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function getACL(array $post, array $toplevel_item, array $request): array
|
||||
{
|
||||
// If this is a comment, set the permissions from the parent.
|
||||
if ($toplevel_item) {
|
||||
$post['allow_cid'] = $toplevel_item['allow_cid'] ?? '';
|
||||
$post['allow_gid'] = $toplevel_item['allow_gid'] ?? '';
|
||||
$post['deny_cid'] = $toplevel_item['deny_cid'] ?? '';
|
||||
$post['deny_gid'] = $toplevel_item['deny_gid'] ?? '';
|
||||
$post['private'] = $toplevel_item['private'];
|
||||
return $post;
|
||||
}
|
||||
|
||||
$user = User::getById($post['uid'], ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']);
|
||||
if (!$user) {
|
||||
throw new HTTPException\NotFoundException($this->l10n->t('Unable to fetch user.'));
|
||||
}
|
||||
|
||||
$post['allow_cid'] = isset($request['contact_allow']) ? $this->aclFormatter->toString($request['contact_allow']) : $user['allow_cid'] ?? '';
|
||||
$post['allow_gid'] = isset($request['group_allow']) ? $this->aclFormatter->toString($request['group_allow']) : $user['allow_gid'] ?? '';
|
||||
$post['deny_cid'] = isset($request['contact_deny']) ? $this->aclFormatter->toString($request['contact_deny']) : $user['deny_cid'] ?? '';
|
||||
$post['deny_gid'] = isset($request['group_deny']) ? $this->aclFormatter->toString($request['group_deny']) : $user['deny_gid'] ?? '';
|
||||
|
||||
$visibility = $request['visibility'] ?? '';
|
||||
if ($visibility === 'public') {
|
||||
// The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected
|
||||
$post['allow_cid'] = $post['allow_gid'] = $post['deny_cid'] = $post['deny_gid'] = '';
|
||||
} else if ($visibility === 'custom') {
|
||||
// Since we know from the visibility parameter the item should be private, we have to prevent the empty ACL
|
||||
// case that would make it public. So we always append the author's contact id to the allowed contacts.
|
||||
// See https://github.com/friendica/friendica/issues/9672
|
||||
$post['allow_cid'] .= $this->aclFormatter->toString(Contact::getPublicIdByUserId($post['uid']));
|
||||
}
|
||||
|
||||
if ($post['allow_gid'] || $post['allow_cid'] || $post['deny_gid'] || $post['deny_cid']) {
|
||||
$post['private'] = ItemModel::PRIVATE;
|
||||
} elseif ($this->pConfig->get($post['uid'], 'system', 'unlisted')) {
|
||||
$post['private'] = ItemModel::UNLISTED;
|
||||
} else {
|
||||
$post['private'] = ItemModel::PUBLIC;
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function moveAttachmentsFromBodyToAttach(array $post): array
|
||||
{
|
||||
if (!preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/', $post['body'], $match)) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
foreach ($match[2] as $attachment_id) {
|
||||
$attachment = Attach::selectFirst(['id', 'uid', 'filename', 'filesize', 'filetype'], ['id' => $attachment_id, 'uid' => $post['uid']]);
|
||||
if (empty($attachment)) {
|
||||
continue;
|
||||
}
|
||||
if ($post['attach']) {
|
||||
$post['attach'] .= ',';
|
||||
}
|
||||
$post['attach'] .= Post\Media::getAttachElement(
|
||||
$this->baseURL . '/attach/' . $attachment['id'],
|
||||
$attachment['filesize'],
|
||||
$attachment['filetype'],
|
||||
$attachment['filename'] ?? ''
|
||||
);
|
||||
|
||||
$fields = [
|
||||
'allow_cid' => $post['allow_cid'], 'allow_gid' => $post['allow_gid'],
|
||||
'deny_cid' => $post['deny_cid'], 'deny_gid' => $post['deny_gid']
|
||||
];
|
||||
$condition = ['id' => $attachment_id];
|
||||
Attach::update($fields, $condition);
|
||||
}
|
||||
|
||||
$post['body'] = str_replace($match[1], '', $post['body']);
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
private function setObjectType(array $post): array
|
||||
{
|
||||
if (empty($post['post-type'])) {
|
||||
$post['post-type'] = empty($post['title']) ? ItemModel::PT_NOTE : ItemModel::PT_ARTICLE;
|
||||
}
|
||||
|
||||
// embedded bookmark or attachment in post? set bookmark flag
|
||||
$data = BBCode::getAttachmentData($post['body']);
|
||||
if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $post['body'], $match, PREG_SET_ORDER) || !empty($data['type']))
|
||||
&& ($post['post-type'] != ItemModel::PT_PERSONAL_NOTE)
|
||||
) {
|
||||
$post['post-type'] = ItemModel::PT_PAGE;
|
||||
$post['object-type'] = Activity\ObjectType::BOOKMARK;
|
||||
}
|
||||
|
||||
// Setting the object type if not defined before
|
||||
if (empty($post['object-type'])) {
|
||||
$post['object-type'] = ($post['gravity'] == ItemModel::GRAVITY_PARENT) ? Activity\ObjectType::NOTE : Activity\ObjectType::COMMENT;
|
||||
}
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function initializePost(array $post): array
|
||||
{
|
||||
$post['network'] = Protocol::DFRN;
|
||||
$post['protocol'] = Conversation::PARCEL_DIRECT;
|
||||
$post['direction'] = Conversation::PUSH;
|
||||
$post['received'] = DateTimeFormat::utcNow();
|
||||
$post['origin'] = true;
|
||||
$post['wall'] = $post['wall'] ?? true;
|
||||
$post['guid'] = $post['guid'] ?? System::createUUID();
|
||||
$post['verb'] = $post['verb'] ?? Activity::POST;
|
||||
$post['uri'] = $post['uri'] ?? ItemModel::newURI($post['guid']);
|
||||
$post['thr-parent'] = $post['thr-parent'] ?? $post['uri'];
|
||||
|
||||
if (empty($post['gravity'])) {
|
||||
$post['gravity'] = ($post['uri'] == $post['thr-parent']) ? ItemModel::GRAVITY_PARENT : ItemModel::GRAVITY_COMMENT;
|
||||
}
|
||||
|
||||
$owner = User::getOwnerDataById($post['uid']);
|
||||
|
||||
if (!isset($post['allow_cid']) || !isset($post['allow_gid']) || !isset($post['deny_cid']) || !isset($post['deny_gid'])) {
|
||||
$post['allow_cid'] = $owner['allow_cid'];
|
||||
$post['allow_gid'] = $owner['allow_gid'];
|
||||
$post['deny_cid'] = $owner['deny_cid'];
|
||||
$post['deny_gid'] = $owner['deny_gid'];
|
||||
}
|
||||
|
||||
if ($post['allow_gid'] || $post['allow_cid'] || $post['deny_gid'] || $post['deny_cid']) {
|
||||
$post['private'] = ItemModel::PRIVATE;
|
||||
} elseif ($this->pConfig->get($post['uid'], 'system', 'unlisted')) {
|
||||
$post['private'] = ItemModel::UNLISTED;
|
||||
} else {
|
||||
$post['private'] = ItemModel::PUBLIC;
|
||||
}
|
||||
|
||||
if (empty($post['contact-id'])) {
|
||||
$post['contact-id'] = $owner['id'];
|
||||
}
|
||||
|
||||
if (empty($post['author-link']) && empty($post['author-id'])) {
|
||||
$post['author-link'] = $owner['url'];
|
||||
$post['author-id'] = Contact::getIdForURL($post['author-link']);
|
||||
$post['author-name'] = $owner['name'];
|
||||
$post['author-avatar'] = $owner['thumb'];
|
||||
}
|
||||
|
||||
if (empty($post['owner-link']) && empty($post['owner-id'])) {
|
||||
$post['owner-link'] = $post['author-link'];
|
||||
$post['owner-id'] = Contact::getIdForURL($post['owner-link']);
|
||||
$post['owner-name'] = $post['author-name'];
|
||||
$post['owner-avatar'] = $post['author-avatar'];
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function finalizePost(array $post): array
|
||||
{
|
||||
if (preg_match("/\[attachment\](.*?)\[\/attachment\]/ism", $post['body'], $matches)) {
|
||||
$post['body'] = preg_replace("/\[attachment].*?\[\/attachment\]/ism", PageInfo::getFooterFromUrl($matches[1]), $post['body']);
|
||||
}
|
||||
|
||||
// Convert links with empty descriptions to links without an explicit description
|
||||
$post['body'] = trim(preg_replace('#\[url=([^\]]*?)\]\[/url\]#ism', '[url]$1[/url]', $post['body']));
|
||||
$post['body'] = $this->bbCodeVideo->transform($post['body']);
|
||||
$post = $this->setObjectType($post);
|
||||
|
||||
// Personal notes must never be altered to a forum post.
|
||||
if ($post['post-type'] != ItemModel::PT_PERSONAL_NOTE) {
|
||||
// Look for any tags and linkify them
|
||||
$post = $this->expandTags($post);
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function postProcessPost(array $post, array $recipients = [])
|
||||
{
|
||||
if (!\Friendica\Content\Feature::isEnabled($post['uid'], 'explicit_mentions') && ($post['gravity'] == ItemModel::GRAVITY_COMMENT)) {
|
||||
Tag::createImplicitMentions($post['uri-id'], $post['thr-parent-id']);
|
||||
}
|
||||
|
||||
Hook::callAll('post_local_end', $post);
|
||||
|
||||
$author = DBA::selectFirst('contact', ['thumb'], ['uid' => $post['uid'], 'self' => true]);
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
$address = trim($recipient);
|
||||
if (!$address) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->emailer->send(new ItemCCEMail(
|
||||
$this->app,
|
||||
$this->l10n,
|
||||
$this->baseURL,
|
||||
$post,
|
||||
$address,
|
||||
$author['thumb'] ?? ''
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+131
-97
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -21,15 +21,21 @@
|
||||
|
||||
namespace Friendica\Content;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\App\Router;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Profile;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Module\Conversation\Community;
|
||||
use Friendica\Module\Home;
|
||||
use Friendica\Module\Security\Login;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
||||
class Nav
|
||||
{
|
||||
@@ -53,9 +59,32 @@ class Nav
|
||||
/**
|
||||
* An array of HTML links provided by addons providing a module via the app_menu hook
|
||||
*
|
||||
* @var array
|
||||
* @var array|null
|
||||
*/
|
||||
private static $app_menu = null;
|
||||
private $appMenu = null;
|
||||
|
||||
/** @var BaseURL */
|
||||
private $baseUrl;
|
||||
/** @var L10n */
|
||||
private $l10n;
|
||||
/** @var IHandleUserSessions */
|
||||
private $session;
|
||||
/** @var Database */
|
||||
private $database;
|
||||
/** @var IManageConfigValues */
|
||||
private $config;
|
||||
/** @var Router */
|
||||
private $router;
|
||||
|
||||
public function __construct(BaseURL $baseUrl, L10n $l10n, IHandleUserSessions $session, Database $database, IManageConfigValues $config, Router $router)
|
||||
{
|
||||
$this->baseUrl = $baseUrl;
|
||||
$this->l10n = $l10n;
|
||||
$this->session = $session;
|
||||
$this->database = $database;
|
||||
$this->config = $config;
|
||||
$this->router = $router;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a menu item in navbar as selected
|
||||
@@ -70,16 +99,17 @@ class Nav
|
||||
/**
|
||||
* Build page header and site navigation bars
|
||||
*
|
||||
* @param App $a
|
||||
* @return string
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\MethodNotAllowedException
|
||||
* @throws HTTPException\ServiceUnavailableException
|
||||
*/
|
||||
public static function build(App $a): string
|
||||
public function getHtml(): string
|
||||
{
|
||||
// Placeholder div for popup panel
|
||||
$nav = '<div id="panel" style="display: none;"></div>';
|
||||
|
||||
$nav_info = self::getInfo($a);
|
||||
$nav_info = $this->getInfo();
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('nav.tpl');
|
||||
|
||||
@@ -87,13 +117,13 @@ class Nav
|
||||
'$sitelocation' => $nav_info['sitelocation'],
|
||||
'$nav' => $nav_info['nav'],
|
||||
'$banner' => $nav_info['banner'],
|
||||
'$emptynotifications' => DI::l10n()->t('Nothing new here'),
|
||||
'$emptynotifications' => $this->l10n->t('Nothing new here'),
|
||||
'$userinfo' => $nav_info['userinfo'],
|
||||
'$sel' => self::$selected,
|
||||
'$apps' => self::getAppMenu(),
|
||||
'$home' => DI::l10n()->t('Go back'),
|
||||
'$clear_notifs' => DI::l10n()->t('Clear notifications'),
|
||||
'$search_hint' => DI::l10n()->t('@name, !forum, #tags, content')
|
||||
'$apps' => $this->getAppMenu(),
|
||||
'$home' => $this->l10n->t('Go back'),
|
||||
'$clear_notifs' => $this->l10n->t('Clear notifications'),
|
||||
'$search_hint' => $this->l10n->t('@name, !forum, #tags, content')
|
||||
]);
|
||||
|
||||
Hook::callAll('page_header', $nav);
|
||||
@@ -105,60 +135,64 @@ class Nav
|
||||
* Returns the addon app menu
|
||||
*
|
||||
* @return array
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function getAppMenu(): array
|
||||
public function getAppMenu(): array
|
||||
{
|
||||
if (is_null(self::$app_menu)) {
|
||||
self::populateAppMenu();
|
||||
if (is_null($this->appMenu)) {
|
||||
$this->appMenu = $this->populateAppMenu();
|
||||
}
|
||||
|
||||
return self::$app_menu;
|
||||
return $this->appMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the apps static variable with apps that require a menu
|
||||
* Returns menus for apps that require one
|
||||
*
|
||||
* @return void
|
||||
* @return array
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function populateAppMenu()
|
||||
private function populateAppMenu(): array
|
||||
{
|
||||
self::$app_menu = [];
|
||||
$appMenu = [];
|
||||
|
||||
//Don't populate apps_menu if apps are private
|
||||
$privateapps = DI::config()->get('config', 'private_addons', false);
|
||||
if (DI::userSession()->getLocalUserId() || !$privateapps) {
|
||||
$arr = ['app_menu' => self::$app_menu];
|
||||
if (
|
||||
$this->session->getLocalUserId()
|
||||
|| !$this->config->get('config', 'private_addons', false)
|
||||
) {
|
||||
$arr = ['app_menu' => $appMenu];
|
||||
|
||||
Hook::callAll('app_menu', $arr);
|
||||
|
||||
self::$app_menu = $arr['app_menu'];
|
||||
$appMenu = $arr['app_menu'];
|
||||
}
|
||||
|
||||
return $appMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a list of navigation links
|
||||
*
|
||||
* @param App $a
|
||||
* @return array Navigation links
|
||||
* string 'sitelocation' => The webbie (username@site.com)
|
||||
* array 'nav' => Array of links used in the nav menu
|
||||
* string 'banner' => Formatted html link with banner image
|
||||
* array 'userinfo' => Array of user information (name, icon)
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\MethodNotAllowedException
|
||||
*/
|
||||
private static function getInfo(App $a): array
|
||||
private function getInfo(): array
|
||||
{
|
||||
$ssl_state = (bool) DI::userSession()->getLocalUserId();
|
||||
|
||||
/*
|
||||
* Our network is distributed, and as you visit friends some of the
|
||||
* Our network is distributed, and as you visit friends some
|
||||
* sites look exactly the same - it isn't always easy to know where you are.
|
||||
* Display the current site location as a navigation aid.
|
||||
*/
|
||||
|
||||
$myident = !empty($a->getLoggedInUserNickname()) ? $a->getLoggedInUserNickname() . '@' : '';
|
||||
$myident = !empty($this->session->getLocalUserNickname()) ? $this->session->getLocalUserNickname() . '@' : '';
|
||||
|
||||
$sitelocation = $myident . substr(DI::baseUrl()->get($ssl_state), strpos(DI::baseUrl()->get($ssl_state), '//') + 2);
|
||||
$sitelocation = $myident . substr($this->baseUrl, strpos($this->baseUrl, '//') + 2);
|
||||
|
||||
$nav = [
|
||||
'admin' => null,
|
||||
@@ -182,23 +216,23 @@ class Nav
|
||||
$userinfo = null;
|
||||
|
||||
// nav links: array of array('href', 'text', 'extra css classes', 'title')
|
||||
if (DI::userSession()->isAuthenticated()) {
|
||||
$nav['logout'] = ['logout', DI::l10n()->t('Logout'), '', DI::l10n()->t('End this session')];
|
||||
if ($this->session->isAuthenticated()) {
|
||||
$nav['logout'] = ['logout', $this->l10n->t('Logout'), '', $this->l10n->t('End this session')];
|
||||
} else {
|
||||
$nav['login'] = ['login', DI::l10n()->t('Login'), (DI::args()->getModuleName() == 'login' ? 'selected' : ''), DI::l10n()->t('Sign in')];
|
||||
$nav['login'] = ['login', $this->l10n->t('Login'), ($this->router->getModuleClass() == Login::class ? 'selected' : ''), $this->l10n->t('Sign in')];
|
||||
}
|
||||
|
||||
if ($a->isLoggedIn()) {
|
||||
if ($this->session->isAuthenticated()) {
|
||||
// user menu
|
||||
$nav['usermenu'][] = ['profile/' . $a->getLoggedInUserNickname(), DI::l10n()->t('Status'), '', DI::l10n()->t('Your posts and conversations')];
|
||||
$nav['usermenu'][] = ['profile/' . $a->getLoggedInUserNickname() . '/profile', DI::l10n()->t('Profile'), '', DI::l10n()->t('Your profile page')];
|
||||
$nav['usermenu'][] = ['profile/' . $a->getLoggedInUserNickname() . '/photos', DI::l10n()->t('Photos'), '', DI::l10n()->t('Your photos')];
|
||||
$nav['usermenu'][] = ['profile/' . $a->getLoggedInUserNickname() . '/media', DI::l10n()->t('Media'), '', DI::l10n()->t('Your postings with media')];
|
||||
$nav['usermenu'][] = ['calendar/', DI::l10n()->t('Calendar'), '', DI::l10n()->t('Your calendar')];
|
||||
$nav['usermenu'][] = ['notes/', DI::l10n()->t('Personal notes'), '', DI::l10n()->t('Your personal notes')];
|
||||
$nav['usermenu'][] = ['profile/' . $this->session->getLocalUserNickname(), $this->l10n->t('Conversations'), '', $this->l10n->t('Conversations you started')];
|
||||
$nav['usermenu'][] = ['profile/' . $this->session->getLocalUserNickname() . '/profile', $this->l10n->t('Profile'), '', $this->l10n->t('Your profile page')];
|
||||
$nav['usermenu'][] = ['profile/' . $this->session->getLocalUserNickname() . '/photos', $this->l10n->t('Photos'), '', $this->l10n->t('Your photos')];
|
||||
$nav['usermenu'][] = ['profile/' . $this->session->getLocalUserNickname() . '/media', $this->l10n->t('Media'), '', $this->l10n->t('Your postings with media')];
|
||||
$nav['usermenu'][] = ['calendar/', $this->l10n->t('Calendar'), '', $this->l10n->t('Your calendar')];
|
||||
$nav['usermenu'][] = ['notes/', $this->l10n->t('Personal notes'), '', $this->l10n->t('Your personal notes')];
|
||||
|
||||
// user info
|
||||
$contact = DBA::selectFirst('contact', ['id', 'url', 'avatar', 'micro', 'name', 'nick', 'baseurl', 'updated'], ['uid' => $a->getLoggedInUserId(), 'self' => true]);
|
||||
$contact = $this->database->selectFirst('contact', ['id', 'url', 'avatar', 'micro', 'name', 'nick', 'baseurl', 'updated'], ['uid' => $this->session->getLocalUserId(), 'self' => true]);
|
||||
$userinfo = [
|
||||
'icon' => Contact::getMicro($contact),
|
||||
'name' => $contact['name'],
|
||||
@@ -206,103 +240,103 @@ class Nav
|
||||
}
|
||||
|
||||
// "Home" should also take you home from an authenticated remote profile connection
|
||||
$homelink = Profile::getMyURL();
|
||||
if (! $homelink) {
|
||||
$homelink = DI::session()->get('visitor_home', '');
|
||||
$homelink = $this->session->getMyUrl();
|
||||
if (!$homelink) {
|
||||
$homelink = $this->session->get('visitor_home', '');
|
||||
}
|
||||
|
||||
if (DI::args()->getModuleName() != 'home' && ! DI::userSession()->getLocalUserId()) {
|
||||
$nav['home'] = [$homelink, DI::l10n()->t('Home'), '', DI::l10n()->t('Home Page')];
|
||||
if ($this->router->getModuleClass() != Home::class && !$this->session->getLocalUserId()) {
|
||||
$nav['home'] = [$homelink, $this->l10n->t('Home'), '', $this->l10n->t('Home Page')];
|
||||
}
|
||||
|
||||
if (intval(DI::config()->get('config', 'register_policy')) === \Friendica\Module\Register::OPEN && !DI::userSession()->isAuthenticated()) {
|
||||
$nav['register'] = ['register', DI::l10n()->t('Register'), '', DI::l10n()->t('Create an account')];
|
||||
if (intval($this->config->get('config', 'register_policy')) === \Friendica\Module\Register::OPEN && !$this->session->isAuthenticated()) {
|
||||
$nav['register'] = ['register', $this->l10n->t('Register'), '', $this->l10n->t('Create an account')];
|
||||
}
|
||||
|
||||
$help_url = 'help';
|
||||
|
||||
if (!DI::config()->get('system', 'hide_help')) {
|
||||
$nav['help'] = [$help_url, DI::l10n()->t('Help'), '', DI::l10n()->t('Help and documentation')];
|
||||
if (!$this->config->get('system', 'hide_help')) {
|
||||
$nav['help'] = [$help_url, $this->l10n->t('Help'), '', $this->l10n->t('Help and documentation')];
|
||||
}
|
||||
|
||||
if (count(self::getAppMenu()) > 0) {
|
||||
$nav['apps'] = ['apps', DI::l10n()->t('Apps'), '', DI::l10n()->t('Addon applications, utilities, games')];
|
||||
if (count($this->getAppMenu()) > 0) {
|
||||
$nav['apps'] = ['apps', $this->l10n->t('Apps'), '', $this->l10n->t('Addon applications, utilities, games')];
|
||||
}
|
||||
|
||||
if (DI::userSession()->getLocalUserId() || !DI::config()->get('system', 'local_search')) {
|
||||
$nav['search'] = ['search', DI::l10n()->t('Search'), '', DI::l10n()->t('Search site content')];
|
||||
if ($this->session->getLocalUserId() || !$this->config->get('system', 'local_search')) {
|
||||
$nav['search'] = ['search', $this->l10n->t('Search'), '', $this->l10n->t('Search site content')];
|
||||
|
||||
$nav['searchoption'] = [
|
||||
DI::l10n()->t('Full Text'),
|
||||
DI::l10n()->t('Tags'),
|
||||
DI::l10n()->t('Contacts')
|
||||
$this->l10n->t('Full Text'),
|
||||
$this->l10n->t('Tags'),
|
||||
$this->l10n->t('Contacts')
|
||||
];
|
||||
|
||||
if (DI::config()->get('system', 'poco_local_search')) {
|
||||
$nav['searchoption'][] = DI::l10n()->t('Forums');
|
||||
if ($this->config->get('system', 'poco_local_search')) {
|
||||
$nav['searchoption'][] = $this->l10n->t('Forums');
|
||||
}
|
||||
}
|
||||
|
||||
$gdirpath = 'directory';
|
||||
if (DI::config()->get('system', 'singleuser') && DI::config()->get('system', 'directory')) {
|
||||
$gdirpath = Profile::zrl(DI::config()->get('system', 'directory'), true);
|
||||
if ($this->config->get('system', 'singleuser') && $this->config->get('system', 'directory')) {
|
||||
$gdirpath = Profile::zrl($this->config->get('system', 'directory'), true);
|
||||
}
|
||||
|
||||
if ((DI::userSession()->getLocalUserId() || DI::config()->get('system', 'community_page_style') != Community::DISABLED_VISITOR) &&
|
||||
!(DI::config()->get('system', 'community_page_style') == Community::DISABLED)) {
|
||||
$nav['community'] = ['community', DI::l10n()->t('Community'), '', DI::l10n()->t('Conversations on this and other servers')];
|
||||
if (($this->session->getLocalUserId() || $this->config->get('system', 'community_page_style') != Community::DISABLED_VISITOR) &&
|
||||
!($this->config->get('system', 'community_page_style') == Community::DISABLED)) {
|
||||
$nav['community'] = ['community', $this->l10n->t('Community'), '', $this->l10n->t('Conversations on this and other servers')];
|
||||
}
|
||||
|
||||
if (DI::userSession()->getLocalUserId()) {
|
||||
$nav['calendar'] = ['calendar', DI::l10n()->t('Calendar'), '', DI::l10n()->t('Calendar')];
|
||||
if ($this->session->getLocalUserId()) {
|
||||
$nav['calendar'] = ['calendar', $this->l10n->t('Calendar'), '', $this->l10n->t('Calendar')];
|
||||
}
|
||||
|
||||
$nav['directory'] = [$gdirpath, DI::l10n()->t('Directory'), '', DI::l10n()->t('People directory')];
|
||||
$nav['directory'] = [$gdirpath, $this->l10n->t('Directory'), '', $this->l10n->t('People directory')];
|
||||
|
||||
$nav['about'] = ['friendica', DI::l10n()->t('Information'), '', DI::l10n()->t('Information about this friendica instance')];
|
||||
$nav['about'] = ['friendica', $this->l10n->t('Information'), '', $this->l10n->t('Information about this friendica instance')];
|
||||
|
||||
if (DI::config()->get('system', 'tosdisplay')) {
|
||||
$nav['tos'] = ['tos', DI::l10n()->t('Terms of Service'), '', DI::l10n()->t('Terms of Service of this Friendica instance')];
|
||||
if ($this->config->get('system', 'tosdisplay')) {
|
||||
$nav['tos'] = ['tos', $this->l10n->t('Terms of Service'), '', $this->l10n->t('Terms of Service of this Friendica instance')];
|
||||
}
|
||||
|
||||
// The following nav links are only show to logged in users
|
||||
if (DI::userSession()->getLocalUserId() && !empty($a->getLoggedInUserNickname())) {
|
||||
$nav['network'] = ['network', DI::l10n()->t('Network'), '', DI::l10n()->t('Conversations from your friends')];
|
||||
// The following nav links are only show to logged-in users
|
||||
if ($this->session->getLocalUserNickname()) {
|
||||
$nav['network'] = ['network', $this->l10n->t('Network'), '', $this->l10n->t('Conversations from your friends')];
|
||||
|
||||
$nav['home'] = ['profile/' . $a->getLoggedInUserNickname(), DI::l10n()->t('Home'), '', DI::l10n()->t('Your posts and conversations')];
|
||||
$nav['home'] = ['profile/' . $this->session->getLocalUserNickname(), $this->l10n->t('Home'), '', $this->l10n->t('Your posts and conversations')];
|
||||
|
||||
// Don't show notifications for public communities
|
||||
if (DI::session()->get('page_flags', '') != User::PAGE_FLAGS_COMMUNITY) {
|
||||
$nav['introductions'] = ['notifications/intros', DI::l10n()->t('Introductions'), '', DI::l10n()->t('Friend Requests')];
|
||||
$nav['notifications'] = ['notifications', DI::l10n()->t('Notifications'), '', DI::l10n()->t('Notifications')];
|
||||
$nav['notifications']['all'] = ['notifications/system', DI::l10n()->t('See all notifications'), '', ''];
|
||||
$nav['notifications']['mark'] = ['', DI::l10n()->t('Mark as seen'), '', DI::l10n()->t('Mark all system notifications as seen')];
|
||||
if ($this->session->get('page_flags', '') != User::PAGE_FLAGS_COMMUNITY) {
|
||||
$nav['introductions'] = ['notifications/intros', $this->l10n->t('Introductions'), '', $this->l10n->t('Friend Requests')];
|
||||
$nav['notifications'] = ['notifications', $this->l10n->t('Notifications'), '', $this->l10n->t('Notifications')];
|
||||
$nav['notifications']['all'] = ['notifications/system', $this->l10n->t('See all notifications'), '', ''];
|
||||
$nav['notifications']['mark'] = ['', $this->l10n->t('Mark as seen'), '', $this->l10n->t('Mark all system notifications as seen')];
|
||||
}
|
||||
|
||||
$nav['messages'] = ['message', DI::l10n()->t('Messages'), '', DI::l10n()->t('Private mail')];
|
||||
$nav['messages']['inbox'] = ['message', DI::l10n()->t('Inbox'), '', DI::l10n()->t('Inbox')];
|
||||
$nav['messages']['outbox'] = ['message/sent', DI::l10n()->t('Outbox'), '', DI::l10n()->t('Outbox')];
|
||||
$nav['messages']['new'] = ['message/new', DI::l10n()->t('New Message'), '', DI::l10n()->t('New Message')];
|
||||
$nav['messages'] = ['message', $this->l10n->t('Messages'), '', $this->l10n->t('Private mail')];
|
||||
$nav['messages']['inbox'] = ['message', $this->l10n->t('Inbox'), '', $this->l10n->t('Inbox')];
|
||||
$nav['messages']['outbox'] = ['message/sent', $this->l10n->t('Outbox'), '', $this->l10n->t('Outbox')];
|
||||
$nav['messages']['new'] = ['message/new', $this->l10n->t('New Message'), '', $this->l10n->t('New Message')];
|
||||
|
||||
if (User::hasIdentities(DI::userSession()->getSubManagedUserId() ?: DI::userSession()->getLocalUserId())) {
|
||||
$nav['delegation'] = ['delegation', DI::l10n()->t('Accounts'), '', DI::l10n()->t('Manage other pages')];
|
||||
if (User::hasIdentities($this->session->getSubManagedUserId() ?: $this->session->getLocalUserId())) {
|
||||
$nav['delegation'] = ['delegation', $this->l10n->t('Accounts'), '', $this->l10n->t('Manage other pages')];
|
||||
}
|
||||
|
||||
$nav['settings'] = ['settings', DI::l10n()->t('Settings'), '', DI::l10n()->t('Account settings')];
|
||||
$nav['settings'] = ['settings', $this->l10n->t('Settings'), '', $this->l10n->t('Account settings')];
|
||||
|
||||
$nav['contacts'] = ['contact', DI::l10n()->t('Contacts'), '', DI::l10n()->t('Manage/edit friends and contacts')];
|
||||
$nav['contacts'] = ['contact', $this->l10n->t('Contacts'), '', $this->l10n->t('Manage/edit friends and contacts')];
|
||||
}
|
||||
|
||||
// Show the link to the admin configuration page if user is admin
|
||||
if ($a->isSiteAdmin()) {
|
||||
$nav['admin'] = ['admin/', DI::l10n()->t('Admin'), '', DI::l10n()->t('Site setup and configuration')];
|
||||
$nav['moderation'] = ['moderation/', DI::l10n()->t('Moderation'), '', DI::l10n()->t('Content and user moderation')];
|
||||
if ($this->session->isSiteAdmin()) {
|
||||
$nav['admin'] = ['admin/', $this->l10n->t('Admin'), '', $this->l10n->t('Site setup and configuration')];
|
||||
$nav['moderation'] = ['moderation/', $this->l10n->t('Moderation'), '', $this->l10n->t('Content and user moderation')];
|
||||
}
|
||||
|
||||
$nav['navigation'] = ['navigation/', DI::l10n()->t('Navigation'), '', DI::l10n()->t('Site map')];
|
||||
$nav['navigation'] = ['navigation/', $this->l10n->t('Navigation'), '', $this->l10n->t('Site map')];
|
||||
|
||||
// Provide a banner/logo/whatever
|
||||
$banner = DI::config()->get('system', 'banner');
|
||||
$banner = $this->config->get('system', 'banner');
|
||||
if (is_null($banner)) {
|
||||
$banner = '<a href="https://friendi.ca"><img id="logo-img" width="32" height="32" src="images/friendica.svg" alt="logo" /></a><span id="logo-text"><a href="https://friendi.ca">Friendica</a></span>';
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -316,7 +316,7 @@ class OEmbed
|
||||
if ($stopoembed == true) {
|
||||
return preg_replace("/\[embed\](.+?)\[\/embed\]/is", "<!-- oembed $1 --><i>" . DI::l10n()->t('Embedding disabled') . " : $1</i><!-- /oembed $1 -->", $text);
|
||||
}
|
||||
return preg_replace_callback("/\[embed\](.+?)\[\/embed\]/is", ['self', 'replaceCallback'], $text);
|
||||
return preg_replace_callback("/\[embed\](.+?)\[\/embed\]/is", [self::class, 'replaceCallback'], $text);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -334,8 +334,8 @@ class OEmbed
|
||||
$html_text = mb_convert_encoding($text, 'HTML-ENTITIES', mb_detect_encoding($text));
|
||||
|
||||
// If it doesn't parse at all, just return the text.
|
||||
$dom = @DOMDocument::loadHTML($html_text);
|
||||
if (!$dom) {
|
||||
$dom = new DOMDocument();
|
||||
if (!@$dom->loadHTML($html_text)) {
|
||||
return $text;
|
||||
}
|
||||
$xpath = new DOMXPath($dom);
|
||||
@@ -385,7 +385,7 @@ class OEmbed
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formmated HTML code from given URL and sets optional title
|
||||
* Returns a formatted HTML code from given URL and sets optional title
|
||||
*
|
||||
* @param string $url URL to fetch
|
||||
* @param string $title Optional title (default: what comes from OEmbed object)
|
||||
@@ -447,7 +447,7 @@ class OEmbed
|
||||
* Generates an XPath query to select elements whose provided attribute contains
|
||||
* the provided value in a space-separated list.
|
||||
*
|
||||
* @param string $attr Name of the attribute to seach
|
||||
* @param string $attr Name of the attribute to search
|
||||
* @param string $value Value to search in a space-separated list
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -141,7 +141,7 @@ class PageInfo
|
||||
$data['text'] = '';
|
||||
}
|
||||
|
||||
// Only embedd a picture link when it seems to be a valid picture ("width" is set)
|
||||
// Only embed a picture link when it seems to be a valid picture ("width" is set)
|
||||
if (!empty($data['images']) && !empty($data['images'][0]['width'])) {
|
||||
$preview = str_replace(['[', ']'], ['[', ']'], htmlentities($data['images'][0]['src'], ENT_QUOTES, 'UTF-8', false));
|
||||
// if the preview picture is larger than 500 pixels then show it in a larger mode
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -133,7 +133,7 @@ class Smilies
|
||||
'<img class="smiley" src="' . $baseUrl . '/images/smiley-cry.gif" alt=":\'(" title=":\'("/>',
|
||||
'<img class="smiley" src="' . $baseUrl . '/images/smiley-foot-in-mouth.gif" alt=":-!" title=":-!" />',
|
||||
'<img class="smiley" src="' . $baseUrl . '/images/smiley-undecided.gif" alt=":-/" title=":-/" />',
|
||||
'<img class="smiley" src="' . $baseUrl . '/images/smiley-embarassed.gif" alt=":-[" title=":-[" />',
|
||||
'<img class="smiley" src="' . $baseUrl . '/images/smiley-embarrassed.gif" alt=":-[" title=":-[" />',
|
||||
'<img class="smiley" src="' . $baseUrl . '/images/smiley-cool.gif" alt="8-)" title="8-)" />',
|
||||
'<img class="smiley" src="' . $baseUrl . '/images/beer_mug.gif" alt=":beer" title=":beer" />',
|
||||
'<img class="smiley" src="' . $baseUrl . '/images/beer_mug.gif" alt=":homebrew" title=":homebrew" />',
|
||||
@@ -218,8 +218,8 @@ class Smilies
|
||||
return $text;
|
||||
}
|
||||
|
||||
$text = preg_replace_callback('/<(pre)>(.*?)<\/pre>/ism', 'self::encode', $text);
|
||||
$text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', 'self::encode', $text);
|
||||
$text = preg_replace_callback('/<(pre)>(.*?)<\/pre>/ism', [self::class, 'encode'], $text);
|
||||
$text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', [self::class, 'encode'], $text);
|
||||
|
||||
if ($no_images) {
|
||||
$cleaned = ['texts' => [], 'icons' => []];
|
||||
@@ -233,11 +233,11 @@ class Smilies
|
||||
$smilies = $cleaned;
|
||||
}
|
||||
|
||||
$text = preg_replace_callback('/<(3+)/', 'self::heartReplaceCallback', $text);
|
||||
$text = preg_replace_callback('/<(3+)/', [self::class, 'heartReplaceCallback'], $text);
|
||||
$text = self::strOrigReplace($smilies['texts'], $smilies['icons'], $text);
|
||||
|
||||
$text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', 'self::decode', $text);
|
||||
$text = preg_replace_callback('/<(pre)>(.*?)<\/pre>/ism', 'self::decode', $text);
|
||||
$text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', [self::class, 'decode'], $text);
|
||||
$text = preg_replace_callback('/<(pre)>(.*?)<\/pre>/ism', [self::class, 'decode'], $text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
+227
-454
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
+80
-32
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -23,6 +23,7 @@ namespace Friendica\Content\Text;
|
||||
|
||||
use DOMDocument;
|
||||
use DOMXPath;
|
||||
use Friendica\Protocol\HTTP\MediaType;
|
||||
use Friendica\Content\Widget\ContactBlock;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\Renderer;
|
||||
@@ -33,6 +34,7 @@ use Friendica\Util\Network;
|
||||
use Friendica\Util\Strings;
|
||||
use Friendica\Util\XML;
|
||||
use League\HTMLToMarkdown\HtmlConverter;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
class HTML
|
||||
{
|
||||
@@ -279,9 +281,9 @@ class HTML
|
||||
self::tagToBBCode($doc, 'div', [], "\r", "\r");
|
||||
self::tagToBBCode($doc, 'p', [], "\n", "\n");
|
||||
|
||||
self::tagToBBCode($doc, 'ul', [], "[list]", "[/list]");
|
||||
self::tagToBBCode($doc, 'ol', [], "[list=1]", "[/list]");
|
||||
self::tagToBBCode($doc, 'li', [], "[*]", "");
|
||||
self::tagToBBCode($doc, 'ul', [], "[ul]", "\n[/ul]");
|
||||
self::tagToBBCode($doc, 'ol', [], "[ol]", "\n[/ol]");
|
||||
self::tagToBBCode($doc, 'li', [], "\n[li]", "[/li]");
|
||||
|
||||
self::tagToBBCode($doc, 'hr', [], "[hr]", "");
|
||||
|
||||
@@ -347,33 +349,6 @@ class HTML
|
||||
$message = str_replace("\n\n\n", "\n\n", $message);
|
||||
} while ($oldmessage != $message);
|
||||
|
||||
do {
|
||||
$oldmessage = $message;
|
||||
$message = str_replace(
|
||||
[
|
||||
"[/size]\n\n",
|
||||
"\n[hr]",
|
||||
"[hr]\n",
|
||||
"\n[list",
|
||||
"[/list]\n",
|
||||
"\n[/",
|
||||
"[list]\n",
|
||||
"[list=1]\n",
|
||||
"\n[*]"],
|
||||
[
|
||||
"[/size]\n",
|
||||
"[hr]",
|
||||
"[hr]",
|
||||
"[list",
|
||||
"[/list]",
|
||||
"[/",
|
||||
"[list]",
|
||||
"[list=1]",
|
||||
"[*]"],
|
||||
$message
|
||||
);
|
||||
} while ($message != $oldmessage);
|
||||
|
||||
$message = str_replace(
|
||||
['[b][b]', '[/b][/b]', '[i][i]', '[/i][/i]'],
|
||||
['[b]', '[/b]', '[i]', '[/i]'],
|
||||
@@ -867,7 +842,7 @@ class HTML
|
||||
*
|
||||
* @param string $s Search query.
|
||||
* @param string $id HTML id
|
||||
* @param bool $aside Display the search widgit aside.
|
||||
* @param bool $aside Display the search widget aside.
|
||||
*
|
||||
* @return string Formatted HTML.
|
||||
* @throws \Exception
|
||||
@@ -1007,4 +982,77 @@ class HTML
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* XPath arbitrary string quoting
|
||||
*
|
||||
* @see https://stackoverflow.com/a/45228168
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
public static function xpathQuote(string $value): string
|
||||
{
|
||||
if (false === strpos($value, '"')) {
|
||||
return '"' . $value . '"';
|
||||
}
|
||||
|
||||
if (false === strpos($value, "'")) {
|
||||
return "'" . $value . "'";
|
||||
}
|
||||
|
||||
// if the value contains both single and double quotes, construct an
|
||||
// expression that concatenates all non-double-quote substrings with
|
||||
// the quotes, e.g.:
|
||||
//
|
||||
// concat("'foo'", '"', "bar")
|
||||
return 'concat(' . implode(', \'"\', ', array_map([self::class, 'xpathQuote'], explode('"', $value))) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided URL is present in the DOM document in an element with the rel="me" attribute
|
||||
*
|
||||
* XHTML Friends Network http://gmpg.org/xfn/
|
||||
*
|
||||
* @param DOMDocument $doc
|
||||
* @param UriInterface $meUrl
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkRelMeLink(DOMDocument $doc, UriInterface $meUrl): bool
|
||||
{
|
||||
$xpath = new \DOMXpath($doc);
|
||||
|
||||
// This expression checks that "me" is among the space-delimited values of the "rel" attribute.
|
||||
// And that the href attribute contains exactly the provided URL
|
||||
$expression = "//*[contains(concat(' ', normalize-space(@rel), ' '), ' me ')][@href = " . self::xpathQuote($meUrl) . "]";
|
||||
|
||||
$result = $xpath->query($expression);
|
||||
|
||||
return $result !== false && $result->length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMDocument $doc
|
||||
* @return string|null Lowercase charset
|
||||
*/
|
||||
public static function extractCharset(DOMDocument $doc): ?string
|
||||
{
|
||||
$xpath = new DOMXPath($doc);
|
||||
|
||||
$expression = "string(//meta[@charset]/@charset)";
|
||||
if ($charset = $xpath->evaluate($expression)) {
|
||||
return strtolower($charset);
|
||||
}
|
||||
|
||||
try {
|
||||
// This expression looks for a meta tag with the http-equiv attribute set to "content-type" ignoring case
|
||||
// whose content attribute contains a "charset" string and returns its value
|
||||
$expression = "string(//meta[@http-equiv][translate(@http-equiv, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = 'content-type'][contains(translate(@content, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'charset')]/@content)";
|
||||
$mediaType = MediaType::fromContentType($xpath->evaluate($expression));
|
||||
if (isset($mediaType->parameters['charset'])) {
|
||||
return strtolower($mediaType->parameters['charset']);
|
||||
}
|
||||
} catch(\InvalidArgumentException $e) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -145,9 +145,6 @@ class Markdown
|
||||
// remove duplicate adjacent code tags
|
||||
$s = preg_replace('/(\[code\])+(.*?)(\[\/code\])+/ism', '[code]$2[/code]', $s);
|
||||
|
||||
// Don't show link to full picture (until it is fixed)
|
||||
$s = BBCode::scaleExternalImages($s);
|
||||
|
||||
DI::profiler()->stopRecording();
|
||||
return $s;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -0,0 +1,616 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2023, 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\Content\Text;
|
||||
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Model\Post;
|
||||
|
||||
/**
|
||||
* Tumblr Neue Post Format
|
||||
* @see https://www.tumblr.com/docs/npf
|
||||
*/
|
||||
class NPF
|
||||
{
|
||||
private static $heading_subtype = [];
|
||||
|
||||
/**
|
||||
* Convert BBCode into NPF (Tumblr Neue Post Format)
|
||||
*
|
||||
* @param string $bbcode
|
||||
* @param integer $uri_id
|
||||
* @return array NPF
|
||||
*/
|
||||
public static function fromBBCode(string $bbcode, int $uri_id): array
|
||||
{
|
||||
$bbcode = self::prepareBody($bbcode);
|
||||
|
||||
$html = BBCode::convert($bbcode, false, BBCode::NPF);
|
||||
if (empty($html)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$doc = new DOMDocument();
|
||||
|
||||
$doc->formatOutput = true;
|
||||
if (!@$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
self::setHeadingSubStyles($doc);
|
||||
|
||||
$element = $doc->getElementsByTagName('body')->item(0);
|
||||
|
||||
list($npf, $text, $formatting) = self::routeChildren($element, $uri_id, true, []);
|
||||
|
||||
return self::addLinkBlockForUriId($uri_id, 0, $npf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the heading types
|
||||
*
|
||||
* @param DOMDocument $doc
|
||||
* @return void
|
||||
*/
|
||||
private static function setHeadingSubStyles(DOMDocument $doc)
|
||||
{
|
||||
self::$heading_subtype = [];
|
||||
foreach (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as $element) {
|
||||
if ($doc->getElementsByTagName($element)->count() > 0) {
|
||||
if (empty(self::$heading_subtype)) {
|
||||
self::$heading_subtype[$element] = 'heading1';
|
||||
} else {
|
||||
self::$heading_subtype[$element] = 'heading2';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the BBCode for the NPF conversion
|
||||
*
|
||||
* @param string $bbcode
|
||||
* @return string
|
||||
*/
|
||||
private static function prepareBody(string $bbcode): string
|
||||
{
|
||||
$shared = BBCode::fetchShareAttributes($bbcode);
|
||||
if (!empty($shared)) {
|
||||
$bbcode = $shared['shared'];
|
||||
}
|
||||
|
||||
$bbcode = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $bbcode);
|
||||
|
||||
if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]\s*\[/url\]#ism", $bbcode, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
if (preg_match('#/photo/.*-[01]\.#ism', $picture[2]) && (preg_match('#/photo/.*-0\.#ism', $picture[1]) || preg_match('#/photos/.*/image/#ism', $picture[1]))) {
|
||||
$bbcode = str_replace($picture[0], "\n\n[img=" . str_replace('-1.', '-0.', $picture[2]) . "]" . $picture[3] . "[/img]\n\n", $bbcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$bbcode = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", "\n\n[img=$1]$2[/img]\n\n", $bbcode);
|
||||
|
||||
if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $bbcode, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
if (preg_match('#/photo/.*-[01]\.#ism', $picture[2]) && (preg_match('#/photo/.*-0\.#ism', $picture[1]) || preg_match('#/photos/.*/image/#ism', $picture[1]))) {
|
||||
$bbcode = str_replace($picture[0], "\n\n[img]" . str_replace('-1.', '-0.', $picture[2]) . "[/img]\n\n", $bbcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$bbcode = preg_replace("/\[img\](.*?)\[\/img\]/ism", "\n\n[img]$1[/img]\n\n", $bbcode);
|
||||
|
||||
do {
|
||||
$oldbbcode = $bbcode;
|
||||
$bbcode = str_replace(["\n\n\n"], ["\n\n"], $bbcode);
|
||||
} while ($oldbbcode != $bbcode);
|
||||
|
||||
return trim($bbcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk recursively through the HTML
|
||||
*
|
||||
* @param DOMElement $element
|
||||
* @param integer $uri_id
|
||||
* @param boolean $parse_structure
|
||||
* @param array $callstack
|
||||
* @param array $npf
|
||||
* @param string $text
|
||||
* @param array $formatting
|
||||
* @return array
|
||||
*/
|
||||
private static function routeChildren(DOMElement $element, int $uri_id, bool $parse_structure, array $callstack, array $npf = [], string $text = '', array $formatting = []): array
|
||||
{
|
||||
if ($parse_structure && $text) {
|
||||
list($npf, $text, $formatting) = self::addBlock($text, $formatting, $npf, $callstack);
|
||||
}
|
||||
|
||||
$callstack[] = $element->nodeName;
|
||||
$level = self::getLevelByCallstack($callstack);
|
||||
|
||||
foreach ($element->childNodes as $child) {
|
||||
switch ($child->nodeName) {
|
||||
case 'b':
|
||||
case 'strong':
|
||||
list($npf, $text, $formatting) = self::addFormatting($child, $uri_id, 'bold', $callstack, $npf, $text, $formatting);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
case 'em':
|
||||
list($npf, $text, $formatting) = self::addFormatting($child, $uri_id, 'italic', $callstack, $npf, $text, $formatting);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
list($npf, $text, $formatting) = self::addFormatting($child, $uri_id, 'strikethrough', $callstack, $npf, $text, $formatting);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'span':
|
||||
list($npf, $text, $formatting) = self::addFormatting($child, $uri_id, '', $callstack, $npf, $text, $formatting);
|
||||
break;
|
||||
|
||||
case 'hr':
|
||||
case 'br':
|
||||
if (!empty($text)) {
|
||||
$text .= "\n";
|
||||
}
|
||||
break;
|
||||
|
||||
case '#text':
|
||||
$text .= $child->textContent;
|
||||
break;
|
||||
|
||||
case 'table':
|
||||
case 'summary':
|
||||
// Ignore tables and spoilers
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
list($npf, $text, $formatting) = self::addInlineLink($child, $uri_id, $callstack, $npf, $text, $formatting);
|
||||
break;
|
||||
|
||||
case 'img':
|
||||
$npf = self::addImageBlock($child, $uri_id, $level, $npf);
|
||||
break;
|
||||
|
||||
case 'audio':
|
||||
case 'video':
|
||||
$npf = self::addMediaBlock($child, $uri_id, $level, $npf);
|
||||
break;
|
||||
|
||||
default:
|
||||
list($npf, $text, $formatting) = self::routeChildren($child, $uri_id, true, $callstack, $npf, $text, $formatting);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($parse_structure && $text) {
|
||||
list($npf, $text, $formatting) = self::addBlock($text, $formatting, $npf, $callstack);
|
||||
}
|
||||
return [$npf, $text, $formatting];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the correct indent level
|
||||
*
|
||||
* @param array $callstack
|
||||
* @return integer
|
||||
*/
|
||||
private static function getLevelByCallstack(array $callstack): int
|
||||
{
|
||||
$level = 0;
|
||||
foreach ($callstack as $entry) {
|
||||
if (in_array($entry, ['ol', 'ul', 'blockquote'])) {
|
||||
++$level;
|
||||
}
|
||||
}
|
||||
return max(0, $level - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the subtype via the HTML element callstack
|
||||
*
|
||||
* @param array $callstack
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
private static function getSubTypeByCallstack(array $callstack, string $text): string
|
||||
{
|
||||
$subtype = '';
|
||||
foreach ($callstack as $entry) {
|
||||
switch ($entry) {
|
||||
case 'ol':
|
||||
$subtype = 'ordered-list-item';
|
||||
break;
|
||||
|
||||
case 'ul':
|
||||
$subtype = 'unordered-list-item';
|
||||
break;
|
||||
|
||||
case 'h1':
|
||||
$subtype = self::$heading_subtype[$entry];
|
||||
break;
|
||||
|
||||
case 'h2':
|
||||
$subtype = self::$heading_subtype[$entry];
|
||||
break;
|
||||
|
||||
case 'h3':
|
||||
$subtype = self::$heading_subtype[$entry];
|
||||
break;
|
||||
|
||||
case 'h4':
|
||||
$subtype = self::$heading_subtype[$entry];
|
||||
break;
|
||||
|
||||
case 'h5':
|
||||
$subtype = self::$heading_subtype[$entry];
|
||||
break;
|
||||
|
||||
case 'h6':
|
||||
$subtype = self::$heading_subtype[$entry];
|
||||
break;
|
||||
|
||||
case 'blockquote':
|
||||
$subtype = mb_strlen($text) < 100 ? 'quote' : 'indented';
|
||||
break;
|
||||
|
||||
case 'pre':
|
||||
$subtype = 'indented';
|
||||
break;
|
||||
|
||||
case 'code':
|
||||
$subtype = 'chat';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $subtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add formatting for a text block
|
||||
*
|
||||
* @param DOMElement $element
|
||||
* @param integer $uri_id
|
||||
* @param string $type
|
||||
* @param array $callstack
|
||||
* @param array $npf
|
||||
* @param string $text
|
||||
* @param array $formatting
|
||||
* @return array
|
||||
*/
|
||||
private static function addFormatting(DOMElement $element, int $uri_id, string $type, array $callstack, array $npf, string $text, array $formatting): array
|
||||
{
|
||||
$start = mb_strlen($text);
|
||||
|
||||
list($npf, $text, $formatting) = self::routeChildren($element, $uri_id, false, $callstack, $npf, $text, $formatting);
|
||||
|
||||
if (!empty($type)) {
|
||||
$formatting[] = [
|
||||
'start' => $start,
|
||||
'end' => mb_strlen($text),
|
||||
'type' => $type
|
||||
];
|
||||
}
|
||||
return [$npf, $text, $formatting];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an inline link for a text block
|
||||
*
|
||||
* @param DOMElement $element
|
||||
* @param integer $uri_id
|
||||
* @param array $callstack
|
||||
* @param array $npf
|
||||
* @param string $text
|
||||
* @param array $formatting
|
||||
* @return array
|
||||
*/
|
||||
private static function addInlineLink(DOMElement $element, int $uri_id, array $callstack, array $npf, string $text, array $formatting): array
|
||||
{
|
||||
$start = mb_strlen($text);
|
||||
|
||||
list($npf, $text, $formatting) = self::routeChildren($element, $uri_id, false, $callstack, $npf, $text, $formatting);
|
||||
|
||||
$attributes = [];
|
||||
foreach ($element->attributes as $key => $attribute) {
|
||||
$attributes[$key] = trim($attribute->value);
|
||||
}
|
||||
if (!empty($attributes['href'])) {
|
||||
$formatting[] = [
|
||||
'start' => $start,
|
||||
'end' => mb_strlen($text),
|
||||
'type' => 'link',
|
||||
'url' => $attributes['href']
|
||||
];
|
||||
}
|
||||
return [$npf, $text, $formatting];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a text block
|
||||
*
|
||||
* @param string $text
|
||||
* @param array $formatting
|
||||
* @param array $npf
|
||||
* @param array $callstack
|
||||
* @return array
|
||||
*/
|
||||
private static function addBlock(string $text, array $formatting, array $npf, array $callstack): array
|
||||
{
|
||||
$block = [
|
||||
'type' => 'text',
|
||||
'subtype' => '',
|
||||
'text' => $text,
|
||||
];
|
||||
|
||||
if (!empty($formatting)) {
|
||||
$block['formatting'] = $formatting;
|
||||
}
|
||||
|
||||
$level = self::getLevelByCallstack($callstack);
|
||||
if ($level > 0) {
|
||||
$block['indent_level'] = $level;
|
||||
}
|
||||
|
||||
$subtype = self::getSubTypeByCallstack($callstack, $text);
|
||||
if ($subtype) {
|
||||
$block['subtype'] = $subtype;
|
||||
} else {
|
||||
unset($block['subtype']);
|
||||
}
|
||||
|
||||
$npf[] = $block;
|
||||
return [$npf, '', []];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a block for a preview picture
|
||||
*
|
||||
* @param array $media
|
||||
* @param array $block
|
||||
* @return array
|
||||
*/
|
||||
private static function addPoster(array $media, array $block): array
|
||||
{
|
||||
$poster = [];
|
||||
if (!empty($media['preview'])) {
|
||||
$poster['url'] = $media['preview'];
|
||||
}
|
||||
if (!empty($media['preview-width'])) {
|
||||
$poster['width'] = $media['preview-width'];
|
||||
}
|
||||
if (!empty($media['preview-height'])) {
|
||||
$poster['height'] = $media['preview-height'];
|
||||
}
|
||||
if (!empty($poster)) {
|
||||
$block['poster'] = [$poster];
|
||||
}
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a link block from the HTML attachment of a given post uri-id
|
||||
*
|
||||
* @param integer $uri_id
|
||||
* @param integer $level
|
||||
* @param array $npf
|
||||
* @return array
|
||||
*/
|
||||
private static function addLinkBlockForUriId(int $uri_id, int $level, array $npf): array
|
||||
{
|
||||
foreach (Post\Media::getByURIId($uri_id, [Post\Media::HTML]) as $link) {
|
||||
$host = parse_url($link['url'], PHP_URL_HOST);
|
||||
if (in_array($host, ['www.youtube.com', 'youtu.be'])) {
|
||||
$block = [
|
||||
'type' => 'video',
|
||||
'provider' => 'youtube',
|
||||
'url' => $link['url'],
|
||||
];
|
||||
} elseif (in_array($host, ['vimeo.com'])) {
|
||||
$block = [
|
||||
'type' => 'video',
|
||||
'provider' => 'vimeo',
|
||||
'url' => $link['url'],
|
||||
];
|
||||
} elseif (in_array($host, ['open.spotify.com'])) {
|
||||
$block = [
|
||||
'type' => 'audio',
|
||||
'provider' => 'spotify',
|
||||
'url' => $link['url'],
|
||||
];
|
||||
} else {
|
||||
$block = [
|
||||
'type' => 'link',
|
||||
'url' => $link['url'],
|
||||
];
|
||||
if (!empty($link['name'])) {
|
||||
$block['title'] = $link['name'];
|
||||
}
|
||||
if (!empty($link['description'])) {
|
||||
$block['description'] = $link['description'];
|
||||
}
|
||||
if (!empty($link['author-name'])) {
|
||||
$block['author'] = $link['author-name'];
|
||||
}
|
||||
if (!empty($link['publisher-name'])) {
|
||||
$block['site_name'] = $link['publisher-name'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($level > 0) {
|
||||
$block['indent_level'] = $level;
|
||||
}
|
||||
|
||||
$npf[] = self::addPoster($link, $block);
|
||||
}
|
||||
return $npf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an image block
|
||||
*
|
||||
* @param DOMElement $element
|
||||
* @param integer $uri_id
|
||||
* @param integer $level
|
||||
* @param array $npf
|
||||
* @return array
|
||||
*/
|
||||
private static function addImageBlock(DOMElement $element, int $uri_id, int $level, array $npf): array
|
||||
{
|
||||
$attributes = [];
|
||||
foreach ($element->attributes as $key => $attribute) {
|
||||
$attributes[$key] = trim($attribute->value);
|
||||
}
|
||||
if (empty($attributes['src'])) {
|
||||
return $npf;
|
||||
}
|
||||
|
||||
$block = [
|
||||
'type' => 'image',
|
||||
'media' => [],
|
||||
];
|
||||
|
||||
if (!empty($attributes['alt'])) {
|
||||
$block['alt_text'] = $attributes['alt'];
|
||||
}
|
||||
|
||||
if (!empty($attributes['title']) && (($attributes['alt'] ?? '') != $attributes['title'])) {
|
||||
$block['caption'] = $attributes['title'];
|
||||
}
|
||||
|
||||
$rid = Photo::ridFromURI($attributes['src']);
|
||||
if (!empty($rid)) {
|
||||
$photos = Photo::selectToArray([], ['resource-id' => $rid]);
|
||||
foreach ($photos as $photo) {
|
||||
$block['media'][] = [
|
||||
'type' => $photo['type'],
|
||||
'url' => str_replace('-0.', '-' . $photo['scale'] . '.', $attributes['src']),
|
||||
'width' => $photo['width'],
|
||||
'height' => $photo['height'],
|
||||
];
|
||||
}
|
||||
if (empty($attributes['alt']) && !empty($photos[0]['desc'])) {
|
||||
$block['alt_text'] = $photos[0]['desc'];
|
||||
}
|
||||
} elseif ($media = Post\Media::getByURL($uri_id, $attributes['src'], [Post\Media::IMAGE])) {
|
||||
$block['media'][] = [
|
||||
'type' => $media['mimetype'],
|
||||
'url' => $media['url'],
|
||||
'width' => $media['width'],
|
||||
'height' => $media['height'],
|
||||
];
|
||||
if (empty($attributes['alt']) && !empty($media['description'])) {
|
||||
$block['alt_text'] = $media['description'];
|
||||
}
|
||||
} else {
|
||||
$block['media'][] = ['url' => $attributes['src']];
|
||||
}
|
||||
|
||||
if ($level > 0) {
|
||||
$block['indent_level'] = $level;
|
||||
}
|
||||
|
||||
$npf[] = $block;
|
||||
|
||||
return $npf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an audio or video block
|
||||
*
|
||||
* @param DOMElement $element
|
||||
* @param integer $uri_id
|
||||
* @param integer $level
|
||||
* @param array $npf
|
||||
* @return array
|
||||
*/
|
||||
private static function addMediaBlock(DOMElement $element, int $uri_id, int $level, array $npf): array
|
||||
{
|
||||
$attributes = [];
|
||||
foreach ($element->attributes as $key => $attribute) {
|
||||
$attributes[$key] = trim($attribute->value);
|
||||
}
|
||||
if (empty($attributes['src'])) {
|
||||
return $npf;
|
||||
}
|
||||
|
||||
$media = Post\Media::getByURL($uri_id, $attributes['src'], [Post\Media::AUDIO, Post\Media::VIDEO]);
|
||||
if (!empty($media)) {
|
||||
switch ($media['type']) {
|
||||
case Post\Media::AUDIO:
|
||||
$block = [
|
||||
'type' => 'audio',
|
||||
'media' => [
|
||||
'type' => $media['mimetype'],
|
||||
'url' => $media['url'],
|
||||
]
|
||||
];
|
||||
|
||||
if (!empty($media['name'])) {
|
||||
$block['title'] = $media['name'];
|
||||
} elseif (!empty($media['description'])) {
|
||||
$block['title'] = $media['description'];
|
||||
}
|
||||
|
||||
$block = self::addPoster($media, $block);
|
||||
break;
|
||||
|
||||
case Post\Media::VIDEO:
|
||||
$block = [
|
||||
'type' => 'video',
|
||||
'media' => [
|
||||
'type' => $media['mimetype'],
|
||||
'url' => $media['url'],
|
||||
]
|
||||
];
|
||||
|
||||
$block = self::addPoster($media, $block);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$block = [
|
||||
'type' => 'text',
|
||||
'text' => $element->textContent,
|
||||
'formatting' => [
|
||||
[
|
||||
'start' => 0,
|
||||
'end' => mb_strlen($element->textContent),
|
||||
'type' => 'link',
|
||||
'url' => $attributes['src']
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
if ($level > 0) {
|
||||
$block['indent_level'] = $level;
|
||||
}
|
||||
|
||||
$npf[] = $block;
|
||||
|
||||
return $npf;
|
||||
}
|
||||
}
|
||||
+103
-42
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -23,7 +23,10 @@ namespace Friendica\Content\Text;
|
||||
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
class Plaintext
|
||||
{
|
||||
@@ -109,27 +112,15 @@ class Plaintext
|
||||
* @param int $limit The maximum number of characters when posting to that network
|
||||
* @param bool $includedlinks Has an attached link to be included into the message?
|
||||
* @param int $htmlmode This controls the behavior of the BBCode conversion
|
||||
* @param string $target_network Name of the network where the post should go to.
|
||||
*
|
||||
* @return array Same array structure than \Friendica\Content\Text\BBCode::getAttachedData
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @see \Friendica\Content\Text\BBCode::getAttachedData
|
||||
*/
|
||||
public static function getPost(array $item, int $limit = 0, bool $includedlinks = false, int $htmlmode = BBCode::MASTODON_API, string $target_network = '')
|
||||
public static function getPost(array $item, int $limit = 0, bool $includedlinks = false, int $htmlmode = BBCode::MASTODON_API)
|
||||
{
|
||||
// Remove hashtags
|
||||
$URLSearchString = '^\[\]';
|
||||
$body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $item['body']);
|
||||
|
||||
// Add an URL element if the text contains a raw link
|
||||
$body = preg_replace('/([^\]\=\'"]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism',
|
||||
'$1[url]$2[/url]', $body);
|
||||
|
||||
// Remove the abstract
|
||||
$body = BBCode::stripAbstract($body);
|
||||
|
||||
// At first look at data that is attached via "type-..." stuff
|
||||
$post = BBCode::getAttachedData($body, $item);
|
||||
// Fetch attached media information
|
||||
$post = self::getPostMedia($item);
|
||||
|
||||
if (($item['title'] != '') && ($post['text'] != '')) {
|
||||
$post['text'] = trim($item['title'] . "\n\n" . $post['text']);
|
||||
@@ -137,34 +128,21 @@ class Plaintext
|
||||
$post['text'] = trim($item['title']);
|
||||
}
|
||||
|
||||
$abstract = '';
|
||||
|
||||
// Fetch the abstract from the given target network
|
||||
if ($target_network != '') {
|
||||
$default_abstract = BBCode::getAbstract($item['body']);
|
||||
$abstract = BBCode::getAbstract($item['body'], $target_network);
|
||||
switch ($htmlmode) {
|
||||
case BBCode::TWITTER:
|
||||
$abstract = BBCode::getAbstract($item['body'], Protocol::TWITTER);
|
||||
break;
|
||||
|
||||
// If we post to a network with no limit we only fetch
|
||||
// an abstract exactly for this network
|
||||
if (($limit == 0) && ($abstract == $default_abstract)) {
|
||||
$abstract = '';
|
||||
}
|
||||
} else {// Try to guess the correct target network
|
||||
switch ($htmlmode) {
|
||||
case BBCode::TWITTER:
|
||||
$abstract = BBCode::getAbstract($item['body'], Protocol::TWITTER);
|
||||
break;
|
||||
case BBCode::OSTATUS:
|
||||
$abstract = BBCode::getAbstract($item['body'], Protocol::STATUSNET);
|
||||
break;
|
||||
|
||||
case BBCode::OSTATUS:
|
||||
$abstract = BBCode::getAbstract($item['body'], Protocol::STATUSNET);
|
||||
break;
|
||||
|
||||
default: // We don't know the exact target.
|
||||
// We fetch an abstract since there is a posting limit.
|
||||
if ($limit > 0) {
|
||||
$abstract = BBCode::getAbstract($item['body']);
|
||||
}
|
||||
}
|
||||
default: // We don't know the exact target.
|
||||
// We fetch an abstract since there is a posting limit.
|
||||
if ($limit > 0) {
|
||||
$abstract = BBCode::getAbstract($item['body']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($abstract != '') {
|
||||
@@ -202,7 +180,7 @@ class Plaintext
|
||||
$msg = trim($post['description']);
|
||||
}
|
||||
|
||||
// If the link is already contained in the post, then it neeedn't to be added again
|
||||
// If the link is already contained in the post, then it needn't to be added again
|
||||
// But: if the link is beyond the limit, then it has to be added.
|
||||
if (($link != '') && strstr($msg, $link)) {
|
||||
$pos = strpos($msg, $link);
|
||||
@@ -320,4 +298,87 @@ class Plaintext
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch attached media to the post and simplify the body.
|
||||
*
|
||||
* @param array $item
|
||||
* @return array
|
||||
*/
|
||||
private static function getPostMedia(array $item): array
|
||||
{
|
||||
$post = ['type' => 'text', 'images' => [], 'remote_images' => []];
|
||||
|
||||
// Remove mentions and hashtag links
|
||||
$URLSearchString = '^\[\]';
|
||||
$post['text'] = preg_replace("/([#!@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $item['body']);
|
||||
|
||||
// Remove abstract
|
||||
$post['text'] = BBCode::stripAbstract($post['text']);
|
||||
// Remove attached links
|
||||
$post['text'] = BBCode::removeAttachment($post['text']);
|
||||
// Remove any links
|
||||
$post['text'] = Post\Media::removeFromBody($post['text']);
|
||||
|
||||
$images = Post\Media::getByURIId($item['uri-id'], [Post\Media::IMAGE]);
|
||||
if (!empty($item['quote-uri-id'])) {
|
||||
$images = array_merge($images, Post\Media::getByURIId($item['quote-uri-id'], [Post\Media::IMAGE]));
|
||||
}
|
||||
foreach ($images as $image) {
|
||||
if ($id = Photo::getIdForName($image['url'])) {
|
||||
$post['images'][] = ['url' => $image['url'], 'description' => $image['description'], 'id' => $id];
|
||||
} else {
|
||||
$post['remote_images'][] = ['url' => $image['url'], 'description' => $image['description']];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($post['images'])) {
|
||||
unset($post['images']);
|
||||
}
|
||||
|
||||
if (empty($post['remote_images'])) {
|
||||
unset($post['remote_images']);
|
||||
}
|
||||
|
||||
if (!empty($post['images'])) {
|
||||
$post['type'] = 'photo';
|
||||
$post['image'] = $post['images'][0]['url'];
|
||||
$post['image_description'] = $post['images'][0]['description'];
|
||||
} elseif (!empty($post['remote_images'])) {
|
||||
$post['type'] = 'photo';
|
||||
$post['image'] = $post['remote_images'][0]['url'];
|
||||
$post['image_description'] = $post['remote_images'][0]['description'];
|
||||
}
|
||||
|
||||
// Look for audio or video links
|
||||
$media = Post\Media::getByURIId($item['uri-id'], [Post\Media::AUDIO, Post\Media::VIDEO]);
|
||||
if (!empty($item['quote-uri-id'])) {
|
||||
$media = array_merge($media, Post\Media::getByURIId($item['quote-uri-id'], [Post\Media::AUDIO, Post\Media::VIDEO]));
|
||||
}
|
||||
|
||||
foreach ($media as $medium) {
|
||||
if (in_array($medium['type'], [Post\Media::AUDIO, Post\Media::VIDEO])) {
|
||||
$post['type'] = 'link';
|
||||
$post['url'] = $medium['url'];
|
||||
}
|
||||
}
|
||||
|
||||
// Look for an attached link
|
||||
$page = Post\Media::getByURIId($item['uri-id'], [Post\Media::HTML]);
|
||||
if (!empty($item['quote-uri-id']) && empty($page)) {
|
||||
$page = Post\Media::getByURIId($item['quote-uri-id'], [Post\Media::HTML]);
|
||||
}
|
||||
if (!empty($page)) {
|
||||
$post['type'] = 'link';
|
||||
$post['url'] = $page[0]['url'];
|
||||
$post['description'] = $page[0]['description'];
|
||||
$post['title'] = $page[0]['name'];
|
||||
|
||||
if (empty($post['image']) && !empty($page[0]['preview'])) {
|
||||
$post['image'] = $page[0]['preview'];
|
||||
}
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -59,7 +59,7 @@ class Widget
|
||||
/**
|
||||
* Return Find People widget
|
||||
*
|
||||
* @return string HTML code respresenting "People Widget"
|
||||
* @return string HTML code representing "People Widget"
|
||||
*/
|
||||
public static function findPeople(): string
|
||||
{
|
||||
@@ -120,6 +120,10 @@ class Widget
|
||||
$networks[] = Protocol::TWITTER;
|
||||
}
|
||||
|
||||
if (!Addon::isEnabled("tumblr")) {
|
||||
$networks[] = Protocol::TUMBLR;
|
||||
}
|
||||
|
||||
if (DI::config()->get("system", "ostatus_disabled")) {
|
||||
$networks[] = Protocol::OSTATUS;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -144,7 +144,7 @@ class TagCloud
|
||||
$x ++;
|
||||
}
|
||||
|
||||
usort($tags, 'self::tagsSort');
|
||||
usort($tags, [self::class, 'tagsSort']);
|
||||
$range = max(0.01, $max - $min) * 1.0001;
|
||||
|
||||
for ($x = 0; $x < count($tags); $x ++) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
+6
-6
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -47,7 +47,7 @@ class ACL
|
||||
/**
|
||||
* Returns a select input tag for private message recipient
|
||||
*
|
||||
* @param int $selected Existing recipien contact ID
|
||||
* @param int $selected Existing recipient contact ID
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
@@ -66,7 +66,7 @@ class ACL
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('acl/message_recipient.tpl');
|
||||
$o = Renderer::replaceMacros($tpl, [
|
||||
'$contacts' => $contacts,
|
||||
'$contacts' => json_encode($contacts),
|
||||
'$selected' => $selected,
|
||||
]);
|
||||
|
||||
@@ -327,9 +327,9 @@ class ACL
|
||||
'$emtitle' => DI::l10n()->t('Example: bob@example.com, mary@example.com'),
|
||||
'$jotnets_summary' => DI::l10n()->t('Connectors'),
|
||||
'$visibility' => $visibility,
|
||||
'$acl_contacts' => $acl_contacts,
|
||||
'$acl_groups' => $acl_groups,
|
||||
'$acl_list' => $acl_list,
|
||||
'$acl_contacts' => json_encode($acl_contacts),
|
||||
'$acl_groups' => json_encode($acl_groups),
|
||||
'$acl_list' => json_encode($acl_list),
|
||||
'$contact_allow' => implode(',', $default_permissions['allow_cid']),
|
||||
'$group_allow' => implode(',', $default_permissions['allow_gid']),
|
||||
'$contact_deny' => implode(',', $default_permissions['deny_cid']),
|
||||
|
||||
+32
-31
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
namespace Friendica\Core;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Util\Strings;
|
||||
@@ -52,7 +51,7 @@ class Addon
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getAvailableList()
|
||||
public static function getAvailableList(): array
|
||||
{
|
||||
$addons = [];
|
||||
$files = glob('addon/*/');
|
||||
@@ -82,18 +81,23 @@ class Addon
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getAdminList()
|
||||
public static function getAdminList(): array
|
||||
{
|
||||
$addons_admin = [];
|
||||
$addonsAdminStmt = DBA::select('addon', ['name'], ['plugin_admin' => 1], ['order' => ['name']]);
|
||||
while ($addon = DBA::fetch($addonsAdminStmt)) {
|
||||
$addons_admin[$addon['name']] = [
|
||||
'url' => 'admin/addons/' . $addon['name'],
|
||||
'name' => $addon['name'],
|
||||
$addons = array_filter(DI::config()->get('addons') ?? []);
|
||||
|
||||
ksort($addons);
|
||||
foreach ($addons as $name => $data) {
|
||||
if (empty($data['admin'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$addons_admin[$name] = [
|
||||
'url' => 'admin/addons/' . $name,
|
||||
'name' => $name,
|
||||
'class' => 'addon'
|
||||
];
|
||||
}
|
||||
DBA::close($addonsAdminStmt);
|
||||
|
||||
return $addons_admin;
|
||||
}
|
||||
@@ -113,8 +117,7 @@ class Addon
|
||||
*/
|
||||
public static function loadAddons()
|
||||
{
|
||||
$installed_addons = DBA::selectToArray('addon', ['name'], ['installed' => true]);
|
||||
self::$addons = array_column($installed_addons, 'name');
|
||||
self::$addons = array_keys(array_filter(DI::config()->get('addons') ?? []));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,7 +132,7 @@ class Addon
|
||||
$addon = Strings::sanitizeFilePathItem($addon);
|
||||
|
||||
Logger::debug("Addon {addon}: {action}", ['action' => 'uninstall', 'addon' => $addon]);
|
||||
DBA::delete('addon', ['name' => $addon]);
|
||||
DI::config()->delete('addons', $addon);
|
||||
|
||||
@include_once('addon/' . $addon . '/' . $addon . '.php');
|
||||
if (function_exists($addon . '_uninstall')) {
|
||||
@@ -168,12 +171,9 @@ class Addon
|
||||
$func(DI::app());
|
||||
}
|
||||
|
||||
DBA::insert('addon', [
|
||||
'name' => $addon,
|
||||
'installed' => true,
|
||||
'timestamp' => $t,
|
||||
'plugin_admin' => function_exists($addon . '_addon_admin'),
|
||||
'hidden' => file_exists('addon/' . $addon . '/.hidden')
|
||||
DI::config()->set('addons', $addon, [
|
||||
'last_update' => $t,
|
||||
'admin' => function_exists($addon . '_addon_admin'),
|
||||
]);
|
||||
|
||||
if (!self::isEnabled($addon)) {
|
||||
@@ -187,23 +187,25 @@ class Addon
|
||||
* reload all updated addons
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*
|
||||
*/
|
||||
public static function reload()
|
||||
{
|
||||
$addons = DBA::selectToArray('addon', [], ['installed' => true]);
|
||||
$addons = array_filter(DI::config()->get('addons') ?? []);
|
||||
|
||||
foreach ($addons as $addon) {
|
||||
$addonname = Strings::sanitizeFilePathItem(trim($addon['name']));
|
||||
foreach ($addons as $name => $data) {
|
||||
$addonname = Strings::sanitizeFilePathItem(trim($name));
|
||||
$addon_file_path = 'addon/' . $addonname . '/' . $addonname . '.php';
|
||||
if (file_exists($addon_file_path) && $addon['timestamp'] == filemtime($addon_file_path)) {
|
||||
if (file_exists($addon_file_path) && $data['last_update'] == filemtime($addon_file_path)) {
|
||||
// Addon unmodified, skipping
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger::debug("Addon {addon}: {action}", ['action' => 'reload', 'addon' => $addon['name']]);
|
||||
Logger::debug("Addon {addon}: {action}", ['action' => 'reload', 'addon' => $name]);
|
||||
|
||||
self::uninstall($addon['name']);
|
||||
self::install($addon['name']);
|
||||
self::uninstall($name);
|
||||
self::install($name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,11 +315,10 @@ class Addon
|
||||
public static function getVisibleList(): array
|
||||
{
|
||||
$visible_addons = [];
|
||||
$stmt = DBA::select('addon', ['name'], ['hidden' => false, 'installed' => true]);
|
||||
if (DBA::isResult($stmt)) {
|
||||
foreach (DBA::toArray($stmt) as $addon) {
|
||||
$visible_addons[] = $addon['name'];
|
||||
}
|
||||
$addons = array_filter(DI::config()->get('addons') ?? []);
|
||||
|
||||
foreach ($addons as $name => $data) {
|
||||
$visible_addons[] = $name;
|
||||
}
|
||||
|
||||
return $visible_addons;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
* @copyright Copyright (C) 2010-2023, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
@@ -73,7 +73,7 @@ class Cache
|
||||
|
||||
public function __construct(BaseURL $baseURL, IManageConfigValues $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
|
||||
{
|
||||
$this->hostname = $baseURL->getHostname();
|
||||
$this->hostname = $baseURL->getHost();
|
||||
$this->config = $config;
|
||||
$this->dba = $dba;
|
||||
$this->profiler = $profiler;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user