mirror of
https://github.com/friendica/friendica
synced 2025-04-26 01:10:15 +00:00
Merge branch 'stable' into develop
This commit is contained in:
commit
2b95a7e7cd
323 changed files with 21146 additions and 16271 deletions
|
@ -34,6 +34,7 @@ use Friendica\Core\L10n;
|
|||
use Friendica\Core\System;
|
||||
use Friendica\Core\Theme;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Profile;
|
||||
use Friendica\Module\Special\HTTPException as ModuleHTTPException;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
@ -464,6 +465,11 @@ class App
|
|||
if (Core\Session::get('visitor_home') != $_GET["zrl"]) {
|
||||
Core\Session::set('my_url', $_GET['zrl']);
|
||||
Core\Session::set('authenticated', 0);
|
||||
|
||||
$remote_contact = Contact::getByURL($_GET['zrl'], false, ['subscribe']);
|
||||
if (!empty($remote_contact['subscribe'])) {
|
||||
$_SESSION['remote_comment'] = $remote_contact['subscribe'];
|
||||
}
|
||||
}
|
||||
|
||||
Model\Profile::zrlInit($this);
|
||||
|
|
|
@ -232,7 +232,7 @@ class BaseURL
|
|||
{
|
||||
$parsed = @parse_url($url);
|
||||
|
||||
if (empty($parsed)) {
|
||||
if (empty($parsed) || empty($parsed['host'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ class Module
|
|||
'outbox',
|
||||
'poco',
|
||||
'post',
|
||||
'proxy',
|
||||
'pubsub',
|
||||
'pubsubhubbub',
|
||||
'receive',
|
||||
|
@ -265,6 +264,38 @@ class Module
|
|||
$logger->debug('index.php: page not found.', ['request_uri' => $server['REQUEST_URI'], 'address' => $server['REMOTE_ADDR'], 'query' => $server['QUERY_STRING']]);
|
||||
}
|
||||
|
||||
// @see https://github.com/tootsuite/mastodon/blob/c3aef491d66aec743a3a53e934a494f653745b61/config/initializers/cors.rb
|
||||
if (substr($_REQUEST['pagename'] ?? '', 0, 12) == '.well-known/') {
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Headers: *');
|
||||
header('Access-Control-Allow-Methods: ' . Router::GET);
|
||||
header('Access-Control-Allow-Credentials: false');
|
||||
} elseif (substr($_REQUEST['pagename'] ?? '', 0, 8) == 'profile/') {
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Headers: *');
|
||||
header('Access-Control-Allow-Methods: ' . Router::GET);
|
||||
header('Access-Control-Allow-Credentials: false');
|
||||
} elseif (substr($_REQUEST['pagename'] ?? '', 0, 4) == 'api/') {
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Headers: *');
|
||||
header('Access-Control-Allow-Methods: ' . implode(',', Router::ALLOWED_METHODS));
|
||||
header('Access-Control-Allow-Credentials: false');
|
||||
header('Access-Control-Expose-Headers: Link');
|
||||
} elseif (substr($_REQUEST['pagename'] ?? '', 0, 11) == 'oauth/token') {
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Headers: *');
|
||||
header('Access-Control-Allow-Methods: ' . Router::POST);
|
||||
header('Access-Control-Allow-Credentials: false');
|
||||
}
|
||||
|
||||
// @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
|
||||
// @todo Check allowed methods per requested path
|
||||
if ($server['REQUEST_METHOD'] === Router::OPTIONS) {
|
||||
header('HTTP/1.1 204 No Content');
|
||||
header('Allow: ' . implode(',', Router::ALLOWED_METHODS));
|
||||
exit();
|
||||
}
|
||||
|
||||
$placeholder = '';
|
||||
|
||||
$profiler->set(microtime(true), 'ready');
|
||||
|
|
|
@ -44,11 +44,12 @@ use Friendica\Network\HTTPException;
|
|||
*/
|
||||
class Router
|
||||
{
|
||||
const DELETE = 'DELETE';
|
||||
const GET = 'GET';
|
||||
const PATCH = 'PATCH';
|
||||
const POST = 'POST';
|
||||
const PUT = 'PUT';
|
||||
const DELETE = 'DELETE';
|
||||
const GET = 'GET';
|
||||
const PATCH = 'PATCH';
|
||||
const POST = 'POST';
|
||||
const PUT = 'PUT';
|
||||
const OPTIONS = 'OPTIONS';
|
||||
|
||||
const ALLOWED_METHODS = [
|
||||
self::DELETE,
|
||||
|
@ -56,6 +57,7 @@ class Router
|
|||
self::PATCH,
|
||||
self::POST,
|
||||
self::PUT,
|
||||
self::OPTIONS
|
||||
];
|
||||
|
||||
/** @var RouteCollector */
|
||||
|
|
17
src/Collection/Api/Mastodon/Mentions.php
Normal file
17
src/Collection/Api/Mastodon/Mentions.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Collection\Api\Mastodon;
|
||||
|
||||
use Friendica\BaseCollection;
|
||||
use Friendica\Object\Api\Mastodon\Mention;
|
||||
|
||||
class Mentions extends BaseCollection
|
||||
{
|
||||
/**
|
||||
* @return Mention
|
||||
*/
|
||||
public function current(): Mention
|
||||
{
|
||||
return parent::current();
|
||||
}
|
||||
}
|
|
@ -30,7 +30,6 @@ use Friendica\Core\Installer;
|
|||
use Friendica\Core\Theme;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Util\BasePath;
|
||||
use Friendica\Util\ConfigFileLoader;
|
||||
use RuntimeException;
|
||||
|
||||
class AutomaticInstallation extends Console
|
||||
|
@ -66,7 +65,7 @@ Options
|
|||
-H|--dbhost <host> The host of the mysql/mariadb database (env MYSQL_HOST)
|
||||
-p|--dbport <port> The port of the mysql/mariadb database (env MYSQL_PORT)
|
||||
-d|--dbdata <database> The name of the mysql/mariadb database (env MYSQL_DATABASE)
|
||||
-U|--dbuser <username> The username of the mysql/mariadb database login (env MYSQL_USER or MYSQL_USERNAME)
|
||||
-u|--dbuser <username> The username of the mysql/mariadb database login (env MYSQL_USER or MYSQL_USERNAME)
|
||||
-P|--dbpass <password> The password of the mysql/mariadb database login (env MYSQL_PASSWORD)
|
||||
-U|--url <url> The full base URL of Friendica - f.e. 'https://friendica.local/sub' (env FRIENDICA_URL)
|
||||
-B|--phppath <php_path> The path of the PHP binary (env FRIENDICA_PHP_PATH)
|
||||
|
@ -112,7 +111,7 @@ HELP;
|
|||
protected function doExecute()
|
||||
{
|
||||
// Initialise the app
|
||||
$this->out("Initializing setup...\n");
|
||||
$this->out("Initializing setup...");
|
||||
|
||||
$installer = new Installer();
|
||||
|
||||
|
@ -121,10 +120,10 @@ HELP;
|
|||
$basepath = new BasePath($basePathConf);
|
||||
$installer->setUpCache($configCache, $basepath->getPath());
|
||||
|
||||
$this->out(" Complete!\n\n");
|
||||
$this->out(" Complete!\n");
|
||||
|
||||
// Check Environment
|
||||
$this->out("Checking environment...\n");
|
||||
$this->out("Checking environment...");
|
||||
|
||||
$installer->resetChecks();
|
||||
|
||||
|
@ -133,24 +132,26 @@ HELP;
|
|||
throw new RuntimeException($errorMessage);
|
||||
}
|
||||
|
||||
$this->out(" Complete!\n\n");
|
||||
$this->out(" Complete!\n");
|
||||
|
||||
// if a config file is set,
|
||||
$config_file = $this->getOption(['f', 'file']);
|
||||
|
||||
if (!empty($config_file)) {
|
||||
|
||||
$this->out("Loading config file '$config_file'...");
|
||||
if (!file_exists($config_file)) {
|
||||
throw new RuntimeException("ERROR: Config file does not exist.\n");
|
||||
throw new RuntimeException("ERROR: Config file does not exist.");
|
||||
}
|
||||
|
||||
//reload the config cache
|
||||
$loader = new ConfigFileLoader($config_file);
|
||||
$loader->setupCache($configCache);
|
||||
|
||||
//append config file to the config cache
|
||||
$config = include($config_file);
|
||||
if (!is_array($config)) {
|
||||
throw new Exception('Error loading config file ' . $config_file);
|
||||
}
|
||||
$configCache->load($config, Cache::SOURCE_FILE);
|
||||
} else {
|
||||
// Creating config file
|
||||
$this->out("Creating config file...\n");
|
||||
$this->out("Creating config file...");
|
||||
|
||||
$save_db = $this->getOption(['s', 'savedb'], false);
|
||||
|
||||
|
@ -161,7 +162,7 @@ HELP;
|
|||
$this->getOption(['d', 'dbdata'],
|
||||
($save_db) ? getenv('MYSQL_DATABASE') : ''));
|
||||
$configCache->set('database', 'username',
|
||||
$this->getOption(['U', 'dbuser'],
|
||||
$this->getOption(['u', 'dbuser'],
|
||||
($save_db) ? getenv('MYSQL_USER') . getenv('MYSQL_USERNAME') : ''));
|
||||
$configCache->set('database', 'password',
|
||||
$this->getOption(['P', 'dbpass'],
|
||||
|
@ -202,10 +203,10 @@ HELP;
|
|||
$installer->createConfig($configCache);
|
||||
}
|
||||
|
||||
$this->out("Complete!\n\n");
|
||||
$this->out(" Complete!\n");
|
||||
|
||||
// Check database connection
|
||||
$this->out("Checking database...\n");
|
||||
$this->out("Checking database...");
|
||||
|
||||
$installer->resetChecks();
|
||||
|
||||
|
@ -214,7 +215,7 @@ HELP;
|
|||
throw new RuntimeException($errorMessage);
|
||||
}
|
||||
|
||||
$this->out(" Complete!\n\n");
|
||||
$this->out(" Complete!\n");
|
||||
|
||||
// Install database
|
||||
$this->out("Inserting data into database...\n");
|
||||
|
@ -228,24 +229,24 @@ HELP;
|
|||
|
||||
if (!empty($config_file) && $config_file != 'config' . DIRECTORY_SEPARATOR . 'local.config.php') {
|
||||
// Copy config file
|
||||
$this->out("Copying config file...\n");
|
||||
if (!copy($basePathConf . DIRECTORY_SEPARATOR . $config_file, $basePathConf . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.config.php')) {
|
||||
$this->out("Copying config file...");
|
||||
if (!copy($config_file, $basePathConf . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.config.php')) {
|
||||
throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to '" . $basePathConf . "'" . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "local.config.php' manually.\n");
|
||||
}
|
||||
}
|
||||
|
||||
$this->out(" Complete!\n\n");
|
||||
$this->out(" Complete!\n");
|
||||
|
||||
// Install theme
|
||||
$this->out("Installing theme\n");
|
||||
$this->out("Installing theme");
|
||||
if (!empty($this->config->get('system', 'theme'))) {
|
||||
Theme::install($this->config->get('system', 'theme'));
|
||||
$this->out(" Complete\n\n");
|
||||
$this->out(" Complete\n");
|
||||
} else {
|
||||
$this->out(" Theme setting is empty. Please check the file 'config/local.config.php'\n\n");
|
||||
$this->out(" Theme setting is empty. Please check the file 'config/local.config.php'\n");
|
||||
}
|
||||
|
||||
$this->out("\nInstallation is finished\n");
|
||||
$this->out("\nInstallation is finished");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -120,6 +120,7 @@ HELP;
|
|||
$output = ob_get_clean();
|
||||
break;
|
||||
case "dumpsql":
|
||||
DBStructure::writeStructure();
|
||||
ob_start();
|
||||
DBStructure::printStructure($basePath);
|
||||
$output = ob_get_clean();
|
||||
|
|
|
@ -127,16 +127,6 @@ class Item
|
|||
$tag_type = substr($tag, 0, 1);
|
||||
//is it already replaced?
|
||||
if (strpos($tag, '[url=')) {
|
||||
// Checking for the alias that is used for OStatus
|
||||
$pattern = '/[@!]\[url\=(.*?)\](.*?)\[\/url\]/ism';
|
||||
if (preg_match($pattern, $tag, $matches)) {
|
||||
$data = Contact::getByURL($matches[1], false, ['alias', 'nick']);
|
||||
|
||||
if ($data['alias'] != '') {
|
||||
$newtag = '@[url=' . $data['alias'] . ']' . $data['nick'] . '[/url]';
|
||||
}
|
||||
}
|
||||
|
||||
return $replaced;
|
||||
}
|
||||
|
||||
|
|
|
@ -953,6 +953,10 @@ class BBCode
|
|||
*/
|
||||
public static function fetchShareAttributes($text)
|
||||
{
|
||||
// See Issue https://github.com/friendica/friendica/issues/10454
|
||||
// Hashtags in usernames are expanded to links. This here is a quick fix.
|
||||
$text = preg_replace('/([@!#])\[url\=.*?\](.*?)\[\/url\]/ism', '$1$2', $text);
|
||||
|
||||
$attributes = [];
|
||||
if (!preg_match("/(.*?)\[share(.*?)\](.*)\[\/share\]/ism", $text, $matches)) {
|
||||
return $attributes;
|
||||
|
@ -997,7 +1001,7 @@ class BBCode
|
|||
$attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
$author_contact = Contact::getByURL($attributes['profile'], false, ['url', 'addr', 'name', 'micro']);
|
||||
$author_contact = Contact::getByURL($attributes['profile'], false, ['id', 'url', 'addr', 'name', 'micro']);
|
||||
$author_contact['url'] = ($author_contact['url'] ?? $attributes['profile']);
|
||||
$author_contact['addr'] = ($author_contact['addr'] ?? '') ?: Protocol::getAddrFromProfileUrl($attributes['profile']);
|
||||
|
||||
|
@ -1005,7 +1009,9 @@ class BBCode
|
|||
$attributes['avatar'] = ($author_contact['micro'] ?? '') ?: $attributes['avatar'];
|
||||
$attributes['profile'] = ($author_contact['url'] ?? '') ?: $attributes['profile'];
|
||||
|
||||
if ($attributes['avatar']) {
|
||||
if (!empty($author_contact['id'])) {
|
||||
$attributes['avatar'] = Contact::getAvatarUrlForId($author_contact['id'], ProxyUtils::SIZE_THUMB);
|
||||
} elseif ($attributes['avatar']) {
|
||||
$attributes['avatar'] = ProxyUtils::proxifyUrl($attributes['avatar'], false, ProxyUtils::SIZE_THUMB);
|
||||
}
|
||||
|
||||
|
@ -1039,7 +1045,9 @@ class BBCode
|
|||
|
||||
switch ($simplehtml) {
|
||||
case self::API:
|
||||
$text = ($is_quote_share? '<br>' : '') . '<p>' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ': </p>' . "\n" . $content;
|
||||
$text = ($is_quote_share? '<br>' : '') .
|
||||
'<p><b><a href="' . $attributes['link'] . '">' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . "</a>:</b> </p>\n" .
|
||||
'<blockquote class="shared_content">' . $content . '</blockquote>';
|
||||
break;
|
||||
case self::DIASPORA:
|
||||
if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0) {
|
||||
|
@ -2194,9 +2202,7 @@ class BBCode
|
|||
}
|
||||
}
|
||||
|
||||
$success = Item::replaceTag($body, $inform, $profile_uid, $tag, $network);
|
||||
|
||||
if ($success['replaced']) {
|
||||
if (($success = Item::replaceTag($body, $inform, $profile_uid, $tag, $network)) && $success['replaced']) {
|
||||
$tagged[] = $tag;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
|
||||
namespace Friendica\Content\Widget;
|
||||
|
||||
use Friendica\Content\Feature;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\User;
|
||||
|
||||
/**
|
||||
* TagCloud widget
|
||||
|
@ -34,36 +34,27 @@ class CalendarExport
|
|||
{
|
||||
/**
|
||||
* Get the events widget.
|
||||
* @param int $uid
|
||||
*
|
||||
* @return string Formated HTML of the calendar widget.
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function getHTML() {
|
||||
$a = DI::app();
|
||||
|
||||
if (empty($a->data['user'])) {
|
||||
return;
|
||||
public static function getHTML(int $uid = 0) {
|
||||
if (empty($uid)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$owner_uid = intval($a->data['user']['uid']);
|
||||
|
||||
// The permission testing is a little bit tricky because we have to respect many cases.
|
||||
|
||||
// It's not the private events page (we don't get the $owner_uid for /events).
|
||||
if (!local_user() && !$owner_uid) {
|
||||
return;
|
||||
$user = User::getById($uid, ['nickname']);
|
||||
if (empty($user['nickname'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// $a->data is only available if the profile page is visited. If the visited page is not part
|
||||
// of the profile page it should be the personal /events page. So we can use $a->user.
|
||||
$user = ($a->data['user']['nickname'] ?? '') ?: $a->user['nickname'];
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate("widget/events.tpl");
|
||||
$return = Renderer::replaceMacros($tpl, [
|
||||
'$etitle' => DI::l10n()->t("Export"),
|
||||
'$export_ical' => DI::l10n()->t("Export calendar as ical"),
|
||||
'$export_csv' => DI::l10n()->t("Export calendar as csv"),
|
||||
'$user' => $user
|
||||
'$user' => $user['nickname']
|
||||
]);
|
||||
|
||||
return $return;
|
||||
|
|
|
@ -127,8 +127,8 @@ class TagCloud
|
|||
private static function tagCalc(array $arr)
|
||||
{
|
||||
$tags = [];
|
||||
$min = 1e9;
|
||||
$max = -1e9;
|
||||
$min = 1000000000.0;
|
||||
$max = -1000000000.0;
|
||||
$x = 0;
|
||||
|
||||
if (!$arr) {
|
||||
|
@ -145,7 +145,7 @@ class TagCloud
|
|||
}
|
||||
|
||||
usort($tags, 'self::tagsSort');
|
||||
$range = max(.01, $max - $min) * 1.0001;
|
||||
$range = max(0.01, $max - $min) * 1.0001;
|
||||
|
||||
for ($x = 0; $x < count($tags); $x ++) {
|
||||
$tags[$x][2] = 1 + floor(9 * ($tags[$x][1] - $min) / $range);
|
||||
|
|
|
@ -172,6 +172,8 @@ HELP;
|
|||
|
||||
Friendica\DI::init($this->dice);
|
||||
|
||||
Renderer::registerTemplateEngine('Friendica\Render\FriendicaSmartyEngine');
|
||||
|
||||
/** @var Console $subconsole */
|
||||
$subconsole = $this->dice->create($className, [$subargs]);
|
||||
|
||||
|
|
|
@ -465,7 +465,7 @@ class Installer
|
|||
|
||||
$status = $this->checkFunction('proc_open',
|
||||
DI::l10n()->t('Program execution functions'),
|
||||
DI::l10n()->t('Error: Program execution functions required but not enabled.'),
|
||||
DI::l10n()->t('Error: Program execution functions (proc_open) required but not enabled.'),
|
||||
true
|
||||
);
|
||||
$returnVal = $returnVal ? $status : false;
|
||||
|
|
|
@ -116,16 +116,17 @@ class Session
|
|||
$session = DI::session();
|
||||
|
||||
$session->set('remote', []);
|
||||
$remote = [];
|
||||
|
||||
$remote_contacts = DBA::select('contact', ['id', 'uid'], ['nurl' => Strings::normaliseLink($session->get('my_url')), 'rel' => [Contact::FOLLOWER, Contact::FRIEND], 'self' => false]);
|
||||
while ($contact = DBA::fetch($remote_contacts)) {
|
||||
if (($contact['uid'] == 0) || Contact\User::isBlocked($contact['id'], $contact['uid'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$session->set('remote', [$contact['uid'] => $contact['id']]);
|
||||
$remote[$contact['uid']] = $contact['id'];
|
||||
}
|
||||
DBA::close($remote_contacts);
|
||||
$session->set('remote', $remote);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,7 @@ use Exception;
|
|||
use Friendica\Core\Config\IConfig;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Storage;
|
||||
use Friendica\Network\IHTTPRequest;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
||||
|
@ -60,6 +61,8 @@ class StorageManager
|
|||
private $logger;
|
||||
/** @var L10n */
|
||||
private $l10n;
|
||||
/** @var IHTTPRequest */
|
||||
private $httpRequest;
|
||||
|
||||
/** @var Storage\IStorage */
|
||||
private $currentBackend;
|
||||
|
@ -70,12 +73,13 @@ class StorageManager
|
|||
* @param LoggerInterface $logger
|
||||
* @param L10n $l10n
|
||||
*/
|
||||
public function __construct(Database $dba, IConfig $config, LoggerInterface $logger, L10n $l10n)
|
||||
public function __construct(Database $dba, IConfig $config, LoggerInterface $logger, L10n $l10n, IHTTPRequest $httpRequest)
|
||||
{
|
||||
$this->dba = $dba;
|
||||
$this->config = $config;
|
||||
$this->logger = $logger;
|
||||
$this->l10n = $l10n;
|
||||
$this->dba = $dba;
|
||||
$this->config = $config;
|
||||
$this->logger = $logger;
|
||||
$this->l10n = $l10n;
|
||||
$this->httpRequest = $httpRequest;
|
||||
$this->backends = $config->get('storage', 'backends', self::DEFAULT_BACKENDS);
|
||||
|
||||
$currentName = $this->config->get('storage', 'name', '');
|
||||
|
@ -126,6 +130,9 @@ class StorageManager
|
|||
case Storage\SystemResource::getName():
|
||||
$this->backendInstances[$name] = new Storage\SystemResource();
|
||||
break;
|
||||
case Storage\ExternalResource::getName():
|
||||
$this->backendInstances[$name] = new Storage\ExternalResource($this->httpRequest);
|
||||
break;
|
||||
default:
|
||||
$data = [
|
||||
'name' => $name,
|
||||
|
@ -158,7 +165,7 @@ class StorageManager
|
|||
public function isValidBackend(string $name = null, bool $onlyUserBackend = false)
|
||||
{
|
||||
return array_key_exists($name, $this->backends) ||
|
||||
(!$onlyUserBackend && $name === Storage\SystemResource::getName());
|
||||
(!$onlyUserBackend && in_array($name, [Storage\SystemResource::getName(), Storage\ExternalResource::getName()]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -213,6 +213,8 @@ class Update
|
|||
if ($sendMail) {
|
||||
self::updateSuccessful($stored, $current);
|
||||
}
|
||||
} else {
|
||||
Logger::warning('Update lock could not be acquired');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
24
src/DI.php
24
src/DI.php
|
@ -287,14 +287,6 @@ abstract class DI
|
|||
return self::$dice->create(Factory\Api\Mastodon\Error::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Factory\Api\Mastodon\Field
|
||||
*/
|
||||
public static function mstdnField()
|
||||
{
|
||||
return self::$dice->create(Factory\Api\Mastodon\Field::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Factory\Api\Mastodon\FollowRequest
|
||||
*/
|
||||
|
@ -327,14 +319,6 @@ abstract class DI
|
|||
return self::$dice->create(Factory\Api\Mastodon\ListEntity::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Factory\Api\Mastodon\Mention
|
||||
*/
|
||||
public static function mstdnMention()
|
||||
{
|
||||
return self::$dice->create(Factory\Api\Mastodon\Mention::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Factory\Api\Mastodon\Notification
|
||||
*/
|
||||
|
@ -343,14 +327,6 @@ abstract class DI
|
|||
return self::$dice->create(Factory\Api\Mastodon\Notification::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Factory\Api\Mastodon\Tag
|
||||
*/
|
||||
public static function mstdnTag()
|
||||
{
|
||||
return self::$dice->create(Factory\Api\Mastodon\Tag::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Factory\Api\Twitter\User
|
||||
*/
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace Friendica\Database;
|
|||
use Exception;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\User;
|
||||
|
@ -159,6 +160,108 @@ class DBStructure
|
|||
return DI::l10n()->t('Errors encountered performing database changes: ') . $message . EOL;
|
||||
}
|
||||
|
||||
public static function writeStructure()
|
||||
{
|
||||
$tables = [];
|
||||
foreach (self::definition(null) as $name => $definition) {
|
||||
$indexes = [[
|
||||
'name' => 'Name',
|
||||
'fields' => 'Fields',
|
||||
],
|
||||
[
|
||||
'name' => '-',
|
||||
'fields' => '-',
|
||||
]];
|
||||
|
||||
$lengths = ['name' => 4, 'fields' => 6];
|
||||
foreach ($definition['indexes'] as $key => $value) {
|
||||
$fieldlist = implode(', ', $value);
|
||||
$indexes[] = ['name' => $key, 'fields' => $fieldlist];
|
||||
$lengths['name'] = max($lengths['name'], strlen($key));
|
||||
$lengths['fields'] = max($lengths['fields'], strlen($fieldlist));
|
||||
}
|
||||
|
||||
array_walk_recursive($indexes, function(&$value, $key) use ($lengths)
|
||||
{
|
||||
$value = str_pad($value, $lengths[$key], $value === '-' ? '-' : ' ');
|
||||
});
|
||||
|
||||
$foreign = [];
|
||||
$fields = [[
|
||||
'name' => 'Field',
|
||||
'comment' => 'Description',
|
||||
'type' => 'Type',
|
||||
'null' => 'Null',
|
||||
'primary' => 'Key',
|
||||
'default' => 'Default',
|
||||
'extra' => 'Extra',
|
||||
],
|
||||
[
|
||||
'name' => '-',
|
||||
'comment' => '-',
|
||||
'type' => '-',
|
||||
'null' => '-',
|
||||
'primary' => '-',
|
||||
'default' => '-',
|
||||
'extra' => '-',
|
||||
]];
|
||||
$lengths = [
|
||||
'name' => 5,
|
||||
'comment' => 11,
|
||||
'type' => 4,
|
||||
'null' => 4,
|
||||
'primary' => 3,
|
||||
'default' => 7,
|
||||
'extra' => 5,
|
||||
];
|
||||
foreach ($definition['fields'] as $key => $value) {
|
||||
$field = [];
|
||||
$field['name'] = $key;
|
||||
$field['comment'] = $value['comment'] ?? '';
|
||||
$field['type'] = $value['type'];
|
||||
$field['null'] = ($value['not null'] ?? false) ? 'NO' : 'YES';
|
||||
$field['primary'] = ($value['primary'] ?? false) ? 'PRI' : '';
|
||||
$field['default'] = $value['default'] ?? 'NULL';
|
||||
$field['extra'] = $value['extra'] ?? '';
|
||||
|
||||
foreach ($field as $fieldname => $fieldvalue) {
|
||||
$lengths[$fieldname] = max($lengths[$fieldname] ?? 0, strlen($fieldvalue));
|
||||
}
|
||||
$fields[] = $field;
|
||||
|
||||
if (!empty($value['foreign'])) {
|
||||
$foreign[] = [
|
||||
'field' => $key,
|
||||
'targettable' => array_keys($value['foreign'])[0],
|
||||
'targetfield' => array_values($value['foreign'])[0]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
array_walk_recursive($fields, function(&$value, $key) use ($lengths)
|
||||
{
|
||||
$value = str_pad($value, $lengths[$key], $value === '-' ? '-' : ' ');
|
||||
});
|
||||
|
||||
$tables[] = ['name' => $name, 'comment' => $definition['comment']];
|
||||
$content = Renderer::replaceMacros(Renderer::getMarkupTemplate('structure.tpl'), [
|
||||
'$name' => $name,
|
||||
'$comment' => $definition['comment'],
|
||||
'$fields' => $fields,
|
||||
'$indexes' => $indexes,
|
||||
'$foreign' => $foreign,
|
||||
]);
|
||||
$filename = DI::basePath() . '/doc/database/db_' . $name . '.md';
|
||||
file_put_contents($filename, $content);
|
||||
}
|
||||
asort($tables);
|
||||
$content = Renderer::replaceMacros(Renderer::getMarkupTemplate('tables.tpl'), [
|
||||
'$tables' => $tables,
|
||||
]);
|
||||
$filename = DI::basePath() . '/doc/database.md';
|
||||
file_put_contents($filename, $content);
|
||||
}
|
||||
|
||||
public static function printStructure($basePath)
|
||||
{
|
||||
$database = self::definition($basePath, false);
|
||||
|
@ -241,6 +344,12 @@ class DBStructure
|
|||
// Assign all field that are present in the table
|
||||
foreach ($fieldnames as $field) {
|
||||
if (isset($data[$field])) {
|
||||
// Limit the length of varchar, varbinary, char and binrary fields
|
||||
if (is_string($data[$field]) && preg_match("/char\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) {
|
||||
$data[$field] = mb_substr($data[$field], 0, $result[1]);
|
||||
} elseif (is_string($data[$field]) && preg_match("/binary\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) {
|
||||
$data[$field] = substr($data[$field], 0, $result[1]);
|
||||
}
|
||||
$fields[$field] = $data[$field];
|
||||
}
|
||||
}
|
||||
|
@ -1200,7 +1309,7 @@ class DBStructure
|
|||
if ($verbose) {
|
||||
echo "Zero contact added\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif (self::existsTable('contact') && $verbose) {
|
||||
echo "Zero contact already added\n";
|
||||
} elseif ($verbose) {
|
||||
|
@ -1224,7 +1333,7 @@ class DBStructure
|
|||
|
||||
if (self::existsTable('permissionset')) {
|
||||
if (!DBA::exists('permissionset', ['id' => 0])) {
|
||||
DBA::insert('permissionset', ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']);
|
||||
DBA::insert('permissionset', ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']);
|
||||
$lastid = DBA::lastInsertId();
|
||||
if ($lastid != 0) {
|
||||
DBA::update('permissionset', ['id' => 0], ['id' => $lastid]);
|
||||
|
@ -1259,7 +1368,7 @@ class DBStructure
|
|||
} elseif ($verbose) {
|
||||
echo "permissionset: Table not found\n";
|
||||
}
|
||||
|
||||
|
||||
if (!self::existsForeignKeyForField('tokens', 'client_id')) {
|
||||
$tokens = DBA::p("SELECT `tokens`.`id` FROM `tokens`
|
||||
LEFT JOIN `clients` ON `clients`.`client_id` = `tokens`.`client_id`
|
||||
|
|
|
@ -29,34 +29,36 @@ use Friendica\Model\Contact;
|
|||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Repository\PermissionSet;
|
||||
use Friendica\Repository\ProfileField;
|
||||
use ImagickException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Account extends BaseFactory
|
||||
{
|
||||
/** @var BaseURL */
|
||||
protected $baseUrl;
|
||||
private $baseUrl;
|
||||
/** @var ProfileField */
|
||||
protected $profileField;
|
||||
private $profileFieldRepo;
|
||||
/** @var Field */
|
||||
protected $mstdnField;
|
||||
private $mstdnFieldFactory;
|
||||
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileField $profileField, Field $mstdnField)
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileField $profileFieldRepo, Field $mstdnFieldFactory)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
|
||||
$this->baseUrl = $baseURL;
|
||||
$this->profileField = $profileField;
|
||||
$this->mstdnField = $mstdnField;
|
||||
$this->baseUrl = $baseURL;
|
||||
$this->profileFieldRepo = $profileFieldRepo;
|
||||
$this->mstdnFieldFactory = $mstdnFieldFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contactId
|
||||
* @param int $uid Public contact (=0) or owner user id
|
||||
*
|
||||
* @return \Friendica\Object\Api\Mastodon\Account
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
* @throws ImagickException|HTTPException\NotFoundException
|
||||
*/
|
||||
public function createFromContactId(int $contactId, $uid = 0)
|
||||
public function createFromContactId(int $contactId, $uid = 0): \Friendica\Object\Api\Mastodon\Account
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContacID($contactId, $uid);
|
||||
if (!empty($cdata)) {
|
||||
|
@ -64,7 +66,7 @@ class Account extends BaseFactory
|
|||
$userContact = Contact::getById($cdata['user']);
|
||||
} else {
|
||||
$publicContact = Contact::getById($contactId);
|
||||
$userContact = [];
|
||||
$userContact = [];
|
||||
}
|
||||
|
||||
if (empty($publicContact)) {
|
||||
|
@ -75,8 +77,8 @@ class Account extends BaseFactory
|
|||
|
||||
$self_contact = Contact::selectFirst(['uid'], ['nurl' => $publicContact['nurl'], 'self' => true]);
|
||||
if (!empty($self_contact['uid'])) {
|
||||
$profileFields = $this->profileField->select(['uid' => $self_contact['uid'], 'psid' => PermissionSet::PUBLIC]);
|
||||
$fields = $this->mstdnField->createFromProfileFields($profileFields);
|
||||
$profileFields = $this->profileFieldRepo->select(['uid' => $self_contact['uid'], 'psid' => PermissionSet::PUBLIC]);
|
||||
$fields = $this->mstdnFieldFactory->createFromProfileFields($profileFields);
|
||||
} else {
|
||||
$fields = new Fields();
|
||||
}
|
||||
|
@ -87,18 +89,17 @@ class Account extends BaseFactory
|
|||
/**
|
||||
* @param int $userId
|
||||
* @return \Friendica\Object\Api\Mastodon\Account
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
* @throws ImagickException|HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function createFromUserId(int $userId)
|
||||
public function createFromUserId(int $userId): \Friendica\Object\Api\Mastodon\Account
|
||||
{
|
||||
$publicContact = Contact::selectFirst([], ['uid' => $userId, 'self' => true]);
|
||||
|
||||
$profileFields = $this->profileField->select(['uid' => $userId, 'psid' => PermissionSet::PUBLIC]);
|
||||
$fields = $this->mstdnField->createFromProfileFields($profileFields);
|
||||
$profileFields = $this->profileFieldRepo->select(['uid' => $userId, 'psid' => PermissionSet::PUBLIC]);
|
||||
$fields = $this->mstdnFieldFactory->createFromProfileFields($profileFields);
|
||||
|
||||
$apcontact = APContact::getByURL($publicContact['url'], false);
|
||||
$apContact = APContact::getByURL($publicContact['url'], false);
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Account($this->baseUrl, $publicContact, $fields, $apcontact);
|
||||
return new \Friendica\Object\Api\Mastodon\Account($this->baseUrl, $publicContact, $fields, $apContact);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,28 +22,41 @@
|
|||
namespace Friendica\Factory\Api\Mastodon;
|
||||
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Application extends BaseFactory
|
||||
{
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
|
||||
public function __construct(LoggerInterface $logger, Database $dba)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
$this->dba = $dba;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id Application ID
|
||||
*
|
||||
* @return \Friendica\Object\Api\Mastodon\Application
|
||||
*
|
||||
* @throws InternalServerErrorException
|
||||
*/
|
||||
public function createFromApplicationId(int $id)
|
||||
public function createFromApplicationId(int $id): \Friendica\Object\Api\Mastodon\Application
|
||||
{
|
||||
$application = DBA::selectFirst('application', ['client_id', 'client_secret', 'id', 'name', 'redirect_uri', 'website'], ['id' => $id]);
|
||||
if (!DBA::isResult($application)) {
|
||||
return [];
|
||||
$application = $this->dba->selectFirst('application', ['client_id', 'client_secret', 'id', 'name', 'redirect_uri', 'website'], ['id' => $id]);
|
||||
if (!$this->dba->isResult($application)) {
|
||||
throw new InternalServerErrorException(sprintf("ID '%s' not found", $id));
|
||||
}
|
||||
|
||||
$object = new \Friendica\Object\Api\Mastodon\Application(
|
||||
return new \Friendica\Object\Api\Mastodon\Application(
|
||||
$application['name'],
|
||||
$application['client_id'],
|
||||
$application['client_secret'],
|
||||
$application['id'],
|
||||
$application['redirect_uri'],
|
||||
$application['website']);
|
||||
|
||||
return $object->toArray();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,9 @@ namespace Friendica\Factory\Api\Mastodon;
|
|||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Repository\ProfileField;
|
||||
use Friendica\Util\Images;
|
||||
use Friendica\Util\Proxy;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
@ -35,32 +33,24 @@ use Psr\Log\LoggerInterface;
|
|||
class Attachment extends BaseFactory
|
||||
{
|
||||
/** @var BaseURL */
|
||||
protected $baseUrl;
|
||||
/** @var ProfileField */
|
||||
protected $profileField;
|
||||
/** @var Field */
|
||||
protected $mstdnField;
|
||||
private $baseUrl;
|
||||
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileField $profileField, Field $mstdnField)
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
|
||||
$this->baseUrl = $baseURL;
|
||||
$this->profileField = $profileField;
|
||||
$this->mstdnField = $mstdnField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uriId Uri-ID of the attachments
|
||||
* @return array
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public function createFromUriId(int $uriId)
|
||||
public function createFromUriId(int $uriId): array
|
||||
{
|
||||
$attachments = [];
|
||||
foreach (Post\Media::getByURIId($uriId, [Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE]) as $attachment) {
|
||||
|
||||
$filetype = !empty($attachment['mimetype']) ? strtolower(substr($attachment['mimetype'], 0, strpos($attachment['mimetype'], '/'))) : '';
|
||||
|
||||
if (($filetype == 'audio') || ($attachment['type'] == Post\Media::AUDIO)) {
|
||||
|
@ -77,20 +67,19 @@ class Attachment extends BaseFactory
|
|||
|
||||
$remote = $attachment['url'];
|
||||
if ($type == 'image') {
|
||||
if (Proxy::isLocalImage($attachment['url'])) {
|
||||
$url = $attachment['url'];
|
||||
$preview = $attachment['preview'] ?? $url;
|
||||
$remote = '';
|
||||
} else {
|
||||
$url = Proxy::proxifyUrl($attachment['url']);
|
||||
$preview = Proxy::proxifyUrl($attachment['url'], false, Proxy::SIZE_SMALL);
|
||||
}
|
||||
$url = Post\Media::getPreviewUrlForId($attachment['id']);
|
||||
$preview = Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_SMALL);
|
||||
} else {
|
||||
$url = '';
|
||||
$preview = '';
|
||||
$url = $attachment['url'];
|
||||
|
||||
if (!empty($attachment['preview'])) {
|
||||
$preview = Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_SMALL);
|
||||
} else {
|
||||
$preview = '';
|
||||
}
|
||||
}
|
||||
|
||||
$object = new \Friendica\Object\Api\Mastodon\Attachment($attachment, $type, $url, $preview, $remote);
|
||||
$object = new \Friendica\Object\Api\Mastodon\Attachment($attachment, $type, $url, $preview, $remote);
|
||||
$attachments[] = $object->toArray();
|
||||
}
|
||||
|
||||
|
@ -99,27 +88,27 @@ class Attachment extends BaseFactory
|
|||
|
||||
/**
|
||||
* @param int $id id of the photo
|
||||
*
|
||||
* @return array
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public function createFromPhoto(int $id)
|
||||
public function createFromPhoto(int $id): array
|
||||
{
|
||||
$photo = Photo::selectFirst(['resource-id', 'uid', 'id', 'title', 'type'], ['id' => $id]);
|
||||
if (empty($photo)) {
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
|
||||
$attachment = ['id' => $photo['id'], 'description' => $photo['title']];
|
||||
|
||||
$phototypes = Images::supportedTypes();
|
||||
$ext = $phototypes[$photo['type']];
|
||||
$photoTypes = Images::supportedTypes();
|
||||
$ext = $photoTypes[$photo['type']];
|
||||
|
||||
$url = DI::baseUrl() . '/photo/' . $photo['resource-id'] . '-0.' . $ext;
|
||||
$url = $this->baseUrl . '/photo/' . $photo['resource-id'] . '-0.' . $ext;
|
||||
|
||||
$preview = Photo::selectFirst(['scale'], ["`resource-id` = ? AND `uid` = ? AND `scale` > ?", $photo['resource-id'], $photo['uid'], 0], ['order' => ['scale']]);
|
||||
if (empty($scale)) {
|
||||
$preview_url = DI::baseUrl() . '/photo/' . $photo['resource-id'] . '-' . $preview['scale'] . '.' . $ext;
|
||||
$preview_url = $this->baseUrl . '/photo/' . $photo['resource-id'] . '-' . $preview['scale'] . '.' . $ext;
|
||||
} else {
|
||||
$preview_url = '';
|
||||
}
|
||||
|
|
|
@ -31,11 +31,12 @@ class Card extends BaseFactory
|
|||
{
|
||||
/**
|
||||
* @param int $uriId Uri-ID of the item
|
||||
*
|
||||
* @return \Friendica\Object\Api\Mastodon\Card
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
* @throws \ImagickException*@throws \Exception
|
||||
*/
|
||||
public function createFromUriId(int $uriId)
|
||||
public function createFromUriId(int $uriId): \Friendica\Object\Api\Mastodon\Card
|
||||
{
|
||||
$item = Post::selectFirst(['body'], ['uri-id' => $uriId]);
|
||||
if (!empty($item['body'])) {
|
||||
|
|
|
@ -22,13 +22,33 @@
|
|||
namespace Friendica\Factory\Api\Mastodon;
|
||||
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Network\HTTPException;
|
||||
use ImagickException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Conversation extends BaseFactory
|
||||
{
|
||||
public function CreateFromConvId(int $id)
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
/** @var Status */
|
||||
private $mstdnStatusFactory;
|
||||
/** @var Account */
|
||||
private $mstdnAccountFactory;
|
||||
|
||||
public function __construct(LoggerInterface $logger, Database $dba, Status $mstdnStatusFactory, Account $mstdnAccountFactoryFactory)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
$this->dba = $dba;
|
||||
$this->mstdnStatusFactory = $mstdnStatusFactory;
|
||||
$this->mstdnAccountFactory = $mstdnAccountFactoryFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ImagickException|HTTPException\InternalServerErrorException|HTTPException\NotFoundException
|
||||
*/
|
||||
public function CreateFromConvId(int $id): \Friendica\Object\Api\Mastodon\Conversation
|
||||
{
|
||||
$accounts = [];
|
||||
$unread = false;
|
||||
|
@ -36,8 +56,8 @@ class Conversation extends BaseFactory
|
|||
|
||||
$ids = [];
|
||||
|
||||
$mails = DBA::select('mail', ['id', 'from-url', 'uid', 'seen'], ['convid' => $id], ['order' => ['id' => true]]);
|
||||
while ($mail = DBA::fetch($mails)) {
|
||||
$mails = $this->dba->select('mail', ['id', 'from-url', 'uid', 'seen'], ['convid' => $id], ['order' => ['id' => true]]);
|
||||
while ($mail = $this->dba->fetch($mails)) {
|
||||
if (!$mail['seen']) {
|
||||
$unread = true;
|
||||
}
|
||||
|
@ -50,10 +70,10 @@ class Conversation extends BaseFactory
|
|||
$ids[] = $id;
|
||||
|
||||
if (empty($last_status)) {
|
||||
$last_status = DI::mstdnStatus()->createFromMailId($mail['id']);
|
||||
$last_status = $this->mstdnStatusFactory->createFromMailId($mail['id']);
|
||||
}
|
||||
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($id, 0);
|
||||
$accounts[] = $this->mstdnAccountFactory->createFromContactId($id, 0);
|
||||
}
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Conversation($id, $accounts, $unread, $last_status);
|
||||
|
|
|
@ -26,7 +26,7 @@ use Friendica\Collection\Api\Mastodon\Emojis;
|
|||
|
||||
class Emoji extends BaseFactory
|
||||
{
|
||||
public function create(string $shortcode, string $url)
|
||||
public function create(string $shortcode, string $url): \Friendica\Object\Api\Mastodon\Emoji
|
||||
{
|
||||
return new \Friendica\Object\Api\Mastodon\Emoji($shortcode, $url);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class Emoji extends BaseFactory
|
|||
* @param array $smilies
|
||||
* @return Emojis
|
||||
*/
|
||||
public function createCollectionFromSmilies(array $smilies)
|
||||
public function createCollectionFromSmilies(array $smilies): Emojis
|
||||
{
|
||||
$prototype = null;
|
||||
|
||||
|
@ -47,7 +47,7 @@ class Emoji extends BaseFactory
|
|||
|
||||
if ($prototype === null) {
|
||||
$prototype = $this->create($shortcode, $url);
|
||||
$emojis[] = $prototype;
|
||||
$emojis[] = $prototype;
|
||||
} else {
|
||||
$emojis[] = \Friendica\Object\Api\Mastodon\Emoji::createFromPrototype($prototype, $shortcode, $url);
|
||||
}
|
||||
|
|
|
@ -21,65 +21,82 @@
|
|||
|
||||
namespace Friendica\Factory\Api\Mastodon;
|
||||
|
||||
use Friendica\App\Arguments;
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\DI;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/** @todo A Factory shouldn't return something to the frontpage, it's for creating content, not showing it */
|
||||
class Error extends BaseFactory
|
||||
{
|
||||
/** @var Arguments */
|
||||
private $args;
|
||||
/** @var string[] The $_SERVER array */
|
||||
private $server;
|
||||
/** @var L10n */
|
||||
private $l10n;
|
||||
|
||||
public function __construct(LoggerInterface $logger, Arguments $args, L10n $l10n, array $server)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
$this->args = $args;
|
||||
$this->server = $server;
|
||||
$this->l10n = $l10n;
|
||||
}
|
||||
|
||||
private function logError(int $errorno, string $error)
|
||||
{
|
||||
Logger::info('API Error', ['no' => $errorno, 'error' => $error, 'method' => $_SERVER['REQUEST_METHOD'] ?? '', 'command' => DI::args()->getQueryString(), 'user-agent' => $_SERVER['HTTP_USER_AGENT'] ?? '']);
|
||||
$this->logger->info('API Error', ['no' => $errorno, 'error' => $error, 'method' => $this->server['REQUEST_METHOD'] ?? '', 'command' => $this->args->getQueryString(), 'user-agent' => $this->server['HTTP_USER_AGENT'] ?? '']);
|
||||
}
|
||||
|
||||
public function RecordNotFound()
|
||||
{
|
||||
$error = DI::l10n()->t('Record not found');
|
||||
$error = $this->l10n->t('Record not found');
|
||||
$error_description = '';
|
||||
$errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
$errorObj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
|
||||
$this->logError(404, $error);
|
||||
System::jsonError(404, $errorobj->toArray());
|
||||
System::jsonError(404, $errorObj->toArray());
|
||||
}
|
||||
|
||||
public function UnprocessableEntity(string $error = '')
|
||||
{
|
||||
$error = $error ?: DI::l10n()->t('Unprocessable Entity');
|
||||
$error = $error ?: $this->l10n->t('Unprocessable Entity');
|
||||
$error_description = '';
|
||||
$errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
$errorObj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
|
||||
$this->logError(422, $error);
|
||||
System::jsonError(422, $errorobj->toArray());
|
||||
System::jsonError(422, $errorObj->toArray());
|
||||
}
|
||||
|
||||
public function Unauthorized(string $error = '')
|
||||
{
|
||||
$error = $error ?: DI::l10n()->t('Unauthorized');
|
||||
$error = $error ?: $this->l10n->t('Unauthorized');
|
||||
$error_description = '';
|
||||
$errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
$errorObj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
|
||||
$this->logError(401, $error);
|
||||
System::jsonError(401, $errorobj->toArray());
|
||||
System::jsonError(401, $errorObj->toArray());
|
||||
}
|
||||
|
||||
public function Forbidden(string $error = '')
|
||||
{
|
||||
$error = $error ?: DI::l10n()->t('Token is not authorized with a valid user or is missing a required scope');
|
||||
$error = $error ?: $this->l10n->t('Token is not authorized with a valid user or is missing a required scope');
|
||||
$error_description = '';
|
||||
$errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
$errorObj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
|
||||
$this->logError(403, $error);
|
||||
System::jsonError(403, $errorobj->toArray());
|
||||
System::jsonError(403, $errorObj->toArray());
|
||||
}
|
||||
|
||||
public function InternalError(string $error = '')
|
||||
{
|
||||
$error = $error ?: DI::l10n()->t('Internal Server Error');
|
||||
$error = $error ?: $this->l10n->t('Internal Server Error');
|
||||
$error_description = '';
|
||||
$errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
$errorObj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
|
||||
|
||||
$this->logError(500, $error);
|
||||
System::jsonError(500, $errorobj->toArray());
|
||||
System::jsonError(500, $errorObj->toArray());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,10 +32,10 @@ class Field extends BaseFactory
|
|||
{
|
||||
/**
|
||||
* @param ProfileField $profileField
|
||||
* @return \Friendica\Api\Entity\Mastodon\Field
|
||||
* @return \Friendica\Object\Api\Mastodon\Field
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function createFromProfileField(ProfileField $profileField)
|
||||
public function createFromProfileField(ProfileField $profileField): \Friendica\Object\Api\Mastodon\Field
|
||||
{
|
||||
return new \Friendica\Object\Api\Mastodon\Field($profileField->label, BBCode::convert($profileField->value, false, BBCode::ACTIVITYPUB));
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class Field extends BaseFactory
|
|||
* @return Fields
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function createFromProfileFields(ProfileFields $profileFields)
|
||||
public function createFromProfileFields(ProfileFields $profileFields): Fields
|
||||
{
|
||||
$fields = [];
|
||||
|
||||
|
|
|
@ -27,12 +27,13 @@ use Friendica\Model\APContact;
|
|||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Introduction;
|
||||
use Friendica\Network\HTTPException;
|
||||
use ImagickException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class FollowRequest extends BaseFactory
|
||||
{
|
||||
/** @var BaseURL */
|
||||
protected $baseUrl;
|
||||
private $baseUrl;
|
||||
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL)
|
||||
{
|
||||
|
@ -44,10 +45,9 @@ class FollowRequest extends BaseFactory
|
|||
/**
|
||||
* @param Introduction $introduction
|
||||
* @return \Friendica\Object\Api\Mastodon\FollowRequest
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
* @throws ImagickException|HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function createFromIntroduction(Introduction $introduction)
|
||||
public function createFromIntroduction(Introduction $introduction): \Friendica\Object\Api\Mastodon\FollowRequest
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContacID($introduction->{'contact-id'}, $introduction->uid);
|
||||
|
||||
|
@ -57,10 +57,10 @@ class FollowRequest extends BaseFactory
|
|||
}
|
||||
|
||||
$publicContact = Contact::getById($cdata['public']);
|
||||
$userContact = Contact::getById($cdata['user']);
|
||||
$userContact = Contact::getById($cdata['user']);
|
||||
|
||||
$apcontact = APContact::getByURL($publicContact['url'], false);
|
||||
$apContact = APContact::getByURL($publicContact['url'], false);
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\FollowRequest($this->baseUrl, $introduction->id, $publicContact, $apcontact, $userContact);
|
||||
return new \Friendica\Object\Api\Mastodon\FollowRequest($this->baseUrl, $introduction->id, $publicContact, $apContact, $userContact);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,13 +22,27 @@
|
|||
namespace Friendica\Factory\Api\Mastodon;
|
||||
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class ListEntity extends BaseFactory
|
||||
{
|
||||
public function createFromGroupId(int $id)
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
|
||||
public function __construct(LoggerInterface $logger, Database $dba)
|
||||
{
|
||||
$group = DBA::selectFirst('group', ['name'], ['id' => $id, 'deleted' => false]);
|
||||
parent::__construct($logger);
|
||||
$this->dba = $dba;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InternalServerErrorException
|
||||
*/
|
||||
public function createFromGroupId(int $id): \Friendica\Object\Api\Mastodon\ListEntity
|
||||
{
|
||||
$group = $this->dba->selectFirst('group', ['name'], ['id' => $id, 'deleted' => false]);
|
||||
return new \Friendica\Object\Api\Mastodon\ListEntity($id, $group['name'] ?? '', 'list');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,44 +23,36 @@ namespace Friendica\Factory\Api\Mastodon;
|
|||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Collection\Api\Mastodon\Mentions;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Tag;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Repository\ProfileField;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Mention extends BaseFactory
|
||||
{
|
||||
/** @var BaseURL */
|
||||
protected $baseUrl;
|
||||
/** @var ProfileField */
|
||||
protected $profileField;
|
||||
/** @var Field */
|
||||
protected $mstdnField;
|
||||
private $baseUrl;
|
||||
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileField $profileField, Field $mstdnField)
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
|
||||
$this->baseUrl = $baseURL;
|
||||
$this->profileField = $profileField;
|
||||
$this->mstdnField = $mstdnField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uriId Uri-ID of the item
|
||||
* @return array
|
||||
* @return Mentions
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public function createFromUriId(int $uriId)
|
||||
public function createFromUriId(int $uriId): Mentions
|
||||
{
|
||||
$mentions = [];
|
||||
$tags = Tag::getByURIId($uriId, [Tag::MENTION, Tag::EXCLUSIVE_MENTION, Tag::IMPLICIT_MENTION]);
|
||||
$mentions = new Mentions();
|
||||
$tags = Tag::getByURIId($uriId, [Tag::MENTION, Tag::EXCLUSIVE_MENTION, Tag::IMPLICIT_MENTION]);
|
||||
foreach ($tags as $tag) {
|
||||
$contact = Contact::getByURL($tag['url'], false);
|
||||
$mention = new \Friendica\Object\Api\Mastodon\Mention($this->baseUrl, $tag, $contact);
|
||||
$mentions[] = $mention->toArray();
|
||||
$contact = Contact::getByURL($tag['url'], false);
|
||||
$mentions[] = new \Friendica\Object\Api\Mastodon\Mention($this->baseUrl, $tag, $contact);
|
||||
}
|
||||
return $mentions;
|
||||
}
|
||||
|
|
|
@ -22,25 +22,36 @@
|
|||
namespace Friendica\Factory\Api\Mastodon;
|
||||
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Notification as ModelNotification;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\Verb;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Notification extends BaseFactory
|
||||
{
|
||||
public function createFromNotifyId(int $id)
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
/** @var Account */
|
||||
private $mstdnAccountFactory;
|
||||
/** @var Status */
|
||||
private $mstdnStatusFactory;
|
||||
|
||||
public function __construct(LoggerInterface $logger, Database $dba, Account $mstdnAccountFactory, Status $mstdnStatusFactoryFactory)
|
||||
{
|
||||
$notification = DBA::selectFirst('notify', [], ['id' => $id]);
|
||||
if (!DBA::isResult($notification)) {
|
||||
parent::__construct($logger);
|
||||
$this->dba = $dba;
|
||||
$this->mstdnAccountFactory = $mstdnAccountFactory;
|
||||
$this->mstdnStatusFactory = $mstdnStatusFactoryFactory;
|
||||
}
|
||||
|
||||
public function createFromNotificationId(int $id)
|
||||
{
|
||||
$notification = $this->dba->selectFirst('notification', [], ['id' => $id]);
|
||||
if (!$this->dba->isResult($notification)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cid = Contact::getIdForURL($notification['url'], 0, false);
|
||||
if (empty($cid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
follow = Someone followed you
|
||||
follow_request = Someone requested to follow you
|
||||
|
@ -51,32 +62,30 @@ class Notification extends BaseFactory
|
|||
status = Someone you enabled notifications for has posted a status
|
||||
*/
|
||||
|
||||
switch ($notification['type']) {
|
||||
case ModelNotification\Type::INTRO:
|
||||
$type = 'follow_request';
|
||||
break;
|
||||
|
||||
case ModelNotification\Type::WALL:
|
||||
case ModelNotification\Type::COMMENT:
|
||||
case ModelNotification\Type::MAIL:
|
||||
case ModelNotification\Type::TAG_SELF:
|
||||
case ModelNotification\Type::POKE:
|
||||
$type = 'mention';
|
||||
break;
|
||||
|
||||
case ModelNotification\Type::SHARE:
|
||||
$type = 'status';
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
if (($notification['vid'] == Verb::getID(Activity::FOLLOW)) && ($notification['type'] == Post\UserNotification::NOTIF_NONE)) {
|
||||
$contact = Contact::getById($notification['actor-id'], ['pending']);
|
||||
$type = $contact['pending'] ? $type = 'follow_request' : 'follow';
|
||||
} elseif (($notification['vid'] == Verb::getID(Activity::ANNOUNCE)) &&
|
||||
in_array($notification['type'], [Post\UserNotification::NOTIF_DIRECT_COMMENT, Post\UserNotification::NOTIF_DIRECT_THREAD_COMMENT])) {
|
||||
$type = 'reblog';
|
||||
} elseif (in_array($notification['vid'], [Verb::getID(Activity::LIKE), Verb::getID(Activity::DISLIKE)]) &&
|
||||
in_array($notification['type'], [Post\UserNotification::NOTIF_DIRECT_COMMENT, Post\UserNotification::NOTIF_DIRECT_THREAD_COMMENT])) {
|
||||
$type = 'favourite';
|
||||
} elseif ($notification['type'] == Post\UserNotification::NOTIF_SHARED) {
|
||||
$type = 'status';
|
||||
} elseif (in_array($notification['type'], [Post\UserNotification::NOTIF_EXPLICIT_TAGGED,
|
||||
Post\UserNotification::NOTIF_IMPLICIT_TAGGED, Post\UserNotification::NOTIF_DIRECT_COMMENT,
|
||||
Post\UserNotification::NOTIF_DIRECT_THREAD_COMMENT, Post\UserNotification::NOTIF_THREAD_COMMENT])) {
|
||||
$type = 'mention';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
$account = DI::mstdnAccount()->createFromContactId($cid);
|
||||
$account = $this->mstdnAccountFactory->createFromContactId($notification['actor-id'], $notification['uid']);
|
||||
|
||||
if (!empty($notification['uri-id'])) {
|
||||
if (!empty($notification['target-uri-id'])) {
|
||||
try {
|
||||
$status = DI::mstdnStatus()->createFromUriId($notification['uri-id'], $notification['uid']);
|
||||
$status = $this->mstdnStatusFactory->createFromUriId($notification['target-uri-id'], $notification['uid']);
|
||||
} catch (\Throwable $th) {
|
||||
$status = null;
|
||||
}
|
||||
|
@ -84,6 +93,6 @@ class Notification extends BaseFactory
|
|||
$status = null;
|
||||
}
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Notification($id, $type, $notification['date'], $account, $status);
|
||||
return new \Friendica\Object\Api\Mastodon\Notification($id, $type, $notification['created'], $account, $status);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
namespace Friendica\Factory\Api\Mastodon;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Object\Api\Mastodon\Relationship as RelationshipEntity;
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Model\Contact;
|
||||
|
@ -31,9 +32,9 @@ class Relationship extends BaseFactory
|
|||
* @param int $contactId Contact ID (public or user contact)
|
||||
* @param int $uid User ID
|
||||
* @return RelationshipEntity
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createFromContactId(int $contactId, int $uid)
|
||||
public function createFromContactId(int $contactId, int $uid): RelationshipEntity
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContacID($contactId, $uid);
|
||||
if (!empty($cdata)) {
|
||||
|
|
|
@ -21,46 +21,59 @@
|
|||
|
||||
namespace Friendica\Factory\Api\Mastodon;
|
||||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Content\ContactSelector;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\Verb;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Repository\ProfileField;
|
||||
use ImagickException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Status extends BaseFactory
|
||||
{
|
||||
/** @var BaseURL */
|
||||
protected $baseUrl;
|
||||
/** @var ProfileField */
|
||||
protected $profileField;
|
||||
/** @var Field */
|
||||
protected $mstdnField;
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
/** @var Account */
|
||||
private $mstdnAccountFactory;
|
||||
/** @var Mention */
|
||||
private $mstdnMentionFactory;
|
||||
/** @var Tag */
|
||||
private $mstdnTagFactory;
|
||||
/** @var Card */
|
||||
private $mstdnCardFactory;
|
||||
/** @var Attachment */
|
||||
private $mstdnAttachementFactory;
|
||||
/** @var Error */
|
||||
private $mstdnErrorFactory;
|
||||
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileField $profileField, Field $mstdnField)
|
||||
public function __construct(LoggerInterface $logger, Database $dba,
|
||||
Account $mstdnAccountFactory, Mention $mstdnMentionFactory,
|
||||
Tag $mstdnTagFactory, Card $mstdnCardFactory,
|
||||
Attachment $mstdnAttachementFactory, Error $mstdnErrorFactory)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
|
||||
$this->baseUrl = $baseURL;
|
||||
$this->profileField = $profileField;
|
||||
$this->mstdnField = $mstdnField;
|
||||
$this->dba = $dba;
|
||||
$this->mstdnAccountFactory = $mstdnAccountFactory;
|
||||
$this->mstdnMentionFactory = $mstdnMentionFactory;
|
||||
$this->mstdnTagFactory = $mstdnTagFactory;
|
||||
$this->mstdnCardFactory = $mstdnCardFactory;
|
||||
$this->mstdnAttachementFactory = $mstdnAttachementFactory;
|
||||
$this->mstdnErrorFactory = $mstdnErrorFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uriId Uri-ID of the item
|
||||
* @param int $uid Item user
|
||||
*
|
||||
* @return \Friendica\Object\Api\Mastodon\Status
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
* @throws ImagickException|HTTPException\NotFoundException
|
||||
*/
|
||||
public function createFromUriId(int $uriId, $uid = 0)
|
||||
public function createFromUriId(int $uriId, $uid = 0): \Friendica\Object\Api\Mastodon\Status
|
||||
{
|
||||
$fields = ['uri-id', 'uid', 'author-id', 'author-link', 'starred', 'app', 'title', 'body', 'raw-body', 'created', 'network',
|
||||
'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity'];
|
||||
|
@ -69,29 +82,53 @@ class Status extends BaseFactory
|
|||
throw new HTTPException\NotFoundException('Item with URI ID ' . $uriId . 'not found' . ($uid ? ' for user ' . $uid : '.'));
|
||||
}
|
||||
|
||||
$account = DI::mstdnAccount()->createFromContactId($item['author-id']);
|
||||
$account = $this->mstdnAccountFactory->createFromContactId($item['author-id']);
|
||||
|
||||
$counts = new \Friendica\Object\Api\Mastodon\Status\Counts(
|
||||
Post::count(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_COMMENT, 'deleted' => false], [], false),
|
||||
Post::count(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::ANNOUNCE), 'deleted' => false], [], false),
|
||||
Post::count(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::LIKE), 'deleted' => false], [], false)
|
||||
Post::countPosts(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_COMMENT, 'deleted' => false], []),
|
||||
Post::countPosts([
|
||||
'thr-parent-id' => $uriId,
|
||||
'gravity' => GRAVITY_ACTIVITY,
|
||||
'vid' => Verb::getID(Activity::ANNOUNCE),
|
||||
'deleted' => false
|
||||
], []),
|
||||
Post::countPosts([
|
||||
'thr-parent-id' => $uriId,
|
||||
'gravity' => GRAVITY_ACTIVITY,
|
||||
'vid' => Verb::getID(Activity::LIKE),
|
||||
'deleted' => false
|
||||
], [])
|
||||
);
|
||||
|
||||
$userAttributes = new \Friendica\Object\Api\Mastodon\Status\UserAttributes(
|
||||
Post::exists(['thr-parent-id' => $uriId, 'uid' => $uid, 'origin' => true, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::LIKE), 'deleted' => false]),
|
||||
Post::exists(['thr-parent-id' => $uriId, 'uid' => $uid, 'origin' => true, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::ANNOUNCE), 'deleted' => false]),
|
||||
Post::exists([
|
||||
'thr-parent-id' => $uriId,
|
||||
'uid' => $uid,
|
||||
'origin' => true,
|
||||
'gravity' => GRAVITY_ACTIVITY,
|
||||
'vid' => Verb::getID(Activity::LIKE)
|
||||
, 'deleted' => false
|
||||
]),
|
||||
Post::exists([
|
||||
'thr-parent-id' => $uriId,
|
||||
'uid' => $uid,
|
||||
'origin' => true,
|
||||
'gravity' => GRAVITY_ACTIVITY,
|
||||
'vid' => Verb::getID(Activity::ANNOUNCE),
|
||||
'deleted' => false
|
||||
]),
|
||||
Post\ThreadUser::getIgnored($uriId, $uid),
|
||||
(bool)$item['starred'],
|
||||
(bool)($item['starred'] && ($item['gravity'] == GRAVITY_PARENT)),
|
||||
Post\ThreadUser::getPinned($uriId, $uid)
|
||||
);
|
||||
|
||||
$sensitive = DBA::exists('tag-view', ['uri-id' => $uriId, 'name' => 'nsfw']);
|
||||
$sensitive = $this->dba->exists('tag-view', ['uri-id' => $uriId, 'name' => 'nsfw']);
|
||||
$application = new \Friendica\Object\Api\Mastodon\Application($item['app'] ?: ContactSelector::networkToName($item['network'], $item['author-link']));
|
||||
|
||||
$mentions = DI::mstdnMention()->createFromUriId($uriId);
|
||||
$tags = DI::mstdnTag()->createFromUriId($uriId);
|
||||
$card = DI::mstdnCard()->createFromUriId($uriId);
|
||||
$attachments = DI::mstdnAttachment()->createFromUriId($uriId);
|
||||
$mentions = $this->mstdnMentionFactory->createFromUriId($uriId)->getArrayCopy();
|
||||
$tags = $this->mstdnTagFactory->createFromUriId($uriId);
|
||||
$card = $this->mstdnCardFactory->createFromUriId($uriId);
|
||||
$attachments = $this->mstdnAttachementFactory->createFromUriId($uriId);
|
||||
|
||||
$shared = BBCode::fetchShareAttributes($item['body']);
|
||||
if (!empty($shared['guid'])) {
|
||||
|
@ -99,21 +136,21 @@ class Status extends BaseFactory
|
|||
|
||||
$shared_uri_id = $shared_item['uri-id'] ?? 0;
|
||||
|
||||
$mentions = array_merge($mentions, DI::mstdnMention()->createFromUriId($shared_uri_id));
|
||||
$tags = array_merge($tags, DI::mstdnTag()->createFromUriId($shared_uri_id));
|
||||
$attachments = array_merge($attachments, DI::mstdnAttachment()->createFromUriId($shared_uri_id));
|
||||
$mentions = array_merge($mentions, $this->mstdnMentionFactory->createFromUriId($shared_uri_id)->getArrayCopy());
|
||||
$tags = array_merge($tags, $this->mstdnTagFactory->createFromUriId($shared_uri_id));
|
||||
$attachments = array_merge($attachments, $this->mstdnAttachementFactory->createFromUriId($shared_uri_id));
|
||||
|
||||
if (empty($card->toArray())) {
|
||||
$card = DI::mstdnCard()->createFromUriId($shared_uri_id);
|
||||
$card = $this->mstdnCardFactory->createFromUriId($shared_uri_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($item['vid'] == Verb::getID(Activity::ANNOUNCE)) {
|
||||
$reshare = $this->createFromUriId($item['thr-parent-id'], $uid)->toArray();
|
||||
$reshared_item = Post::selectFirst(['title', 'body'], ['uri-id' => $item['thr-parent-id'], 'uid' => [0, $uid]]);
|
||||
$reshare = $this->createFromUriId($item['thr-parent-id'], $uid)->toArray();
|
||||
$reshared_item = Post::selectFirst(['title', 'body'], ['uri-id' => $item['thr-parent-id'],'uid' => [0, $uid]]);
|
||||
$item['title'] = $reshared_item['title'] ?? $item['title'];
|
||||
$item['body'] = $reshared_item['body'] ?? $item['body'];
|
||||
$item['body'] = $reshared_item['body'] ?? $item['body'];
|
||||
} else {
|
||||
$reshare = [];
|
||||
}
|
||||
|
@ -123,20 +160,23 @@ class Status extends BaseFactory
|
|||
|
||||
/**
|
||||
* @param int $uriId id of the mail
|
||||
*
|
||||
* @return \Friendica\Object\Api\Mastodon\Status
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
* @throws ImagickException|HTTPException\NotFoundException
|
||||
*/
|
||||
public function createFromMailId(int $id)
|
||||
public function createFromMailId(int $id): \Friendica\Object\Api\Mastodon\Status
|
||||
{
|
||||
$item = ActivityPub\Transmitter::ItemArrayFromMail($id, true);
|
||||
if (empty($item)) {
|
||||
DI::mstdnError()->RecordNotFound();
|
||||
$this->mstdnErrorFactory->RecordNotFound();
|
||||
}
|
||||
|
||||
$account = DI::mstdnAccount()->createFromContactId($item['author-id']);
|
||||
$account = $this->mstdnAccountFactory->createFromContactId($item['author-id']);
|
||||
|
||||
$counts = new \Friendica\Object\Api\Mastodon\Status\Counts(0, 0, 0);
|
||||
$replies = $this->dba->count('mail', ['thr-parent-id' => $item['uri-id'], 'reply' => true]);
|
||||
|
||||
$counts = new \Friendica\Object\Api\Mastodon\Status\Counts($replies, 0, 0);
|
||||
|
||||
$userAttributes = new \Friendica\Object\Api\Mastodon\Status\UserAttributes(false, false, false, false, false);
|
||||
|
||||
|
|
|
@ -25,39 +25,31 @@ use Friendica\App\BaseURL;
|
|||
use Friendica\BaseFactory;
|
||||
use Friendica\Model\Tag as TagModel;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Repository\ProfileField;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Tag extends BaseFactory
|
||||
{
|
||||
/** @var BaseURL */
|
||||
protected $baseUrl;
|
||||
/** @var ProfileField */
|
||||
protected $profileField;
|
||||
/** @var Field */
|
||||
protected $mstdnField;
|
||||
private $baseUrl;
|
||||
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileField $profileField, Field $mstdnField)
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
|
||||
$this->baseUrl = $baseURL;
|
||||
$this->profileField = $profileField;
|
||||
$this->mstdnField = $mstdnField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uriId Uri-ID of the item
|
||||
* @return array
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public function createFromUriId(int $uriId)
|
||||
public function createFromUriId(int $uriId): array
|
||||
{
|
||||
$hashtags = [];
|
||||
$tags = TagModel::getByURIId($uriId, [TagModel::HASHTAG]);
|
||||
$tags = TagModel::getByURIId($uriId, [TagModel::HASHTAG]);
|
||||
foreach ($tags as $tag) {
|
||||
$hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag);
|
||||
$hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag);
|
||||
$hashtags[] = $hashtag->toArray();
|
||||
}
|
||||
return $hashtags;
|
||||
|
|
|
@ -139,7 +139,7 @@ class Introduction extends BaseFactory
|
|||
'madeby_zrl' => Contact::magicLink($notification['url']),
|
||||
'madeby_addr' => $notification['addr'],
|
||||
'contact_id' => $notification['contact-id'],
|
||||
'photo' => (!empty($notification['fphoto']) ? Proxy::proxifyUrl($notification['fphoto'], false, Proxy::SIZE_SMALL) : Contact::DEFAULT_AVATAR_PHOTO),
|
||||
'photo' => Contact::getAvatarUrlForUrl($notification['furl'], 0, Proxy::SIZE_SMALL),
|
||||
'name' => $notification['fname'],
|
||||
'url' => $notification['furl'],
|
||||
'zrl' => Contact::magicLink($notification['furl']),
|
||||
|
|
|
@ -32,6 +32,7 @@ use Friendica\Core\PConfig\IPConfig;
|
|||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\Session\ISession;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Module\BaseNotifications;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
|
@ -239,7 +240,7 @@ class Notification extends BaseFactory
|
|||
$formattedNotifications[] = new \Friendica\Object\Notification\Notification([
|
||||
'label' => 'notification',
|
||||
'link' => $this->baseUrl->get(true) . '/notification/' . $notification->id,
|
||||
'image' => Proxy::proxifyUrl($notification->photo, false, Proxy::SIZE_MICRO),
|
||||
'image' => Contact::getAvatarUrlForUrl($notification->url, $notification->uid, Proxy::SIZE_MICRO),
|
||||
'url' => $notification->url,
|
||||
'text' => strip_tags(BBCode::convert($notification->msg)),
|
||||
'when' => DateTimeFormat::local($notification->date, 'r'),
|
||||
|
|
|
@ -26,6 +26,7 @@ use Friendica\Core\Cache\Duration;
|
|||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\DBStructure;
|
||||
use Friendica\DI;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Protocol\ActivityNamespace;
|
||||
|
@ -210,6 +211,11 @@ class APContact
|
|||
$apcontact['photo'] = JsonLD::fetchElement($compacted['as:icon'], 'as:url', '@id');
|
||||
}
|
||||
|
||||
$apcontact['header'] = JsonLD::fetchElement($compacted, 'as:image', '@id');
|
||||
if (is_array($apcontact['header']) || !empty($compacted['as:image']['as:url']['@id'])) {
|
||||
$apcontact['header'] = JsonLD::fetchElement($compacted['as:image'], 'as:url', '@id');
|
||||
}
|
||||
|
||||
if (empty($apcontact['alias'])) {
|
||||
$apcontact['alias'] = JsonLD::fetchElement($compacted, 'as:url', '@id');
|
||||
if (is_array($apcontact['alias'])) {
|
||||
|
@ -278,6 +284,8 @@ class APContact
|
|||
}
|
||||
}
|
||||
|
||||
$apcontact['discoverable'] = JsonLD::fetchElement($compacted, 'toot:discoverable', '@value');
|
||||
|
||||
// To-Do
|
||||
|
||||
// Unhandled
|
||||
|
@ -349,6 +357,9 @@ class APContact
|
|||
DBA::delete('apcontact', ['url' => $url]);
|
||||
}
|
||||
|
||||
// Limit the length on incoming fields
|
||||
$apcontact = DBStructure::getFieldsForTable('apcontact', $apcontact);
|
||||
|
||||
if (DBA::exists('apcontact', ['url' => $apcontact['url']])) {
|
||||
DBA::update('apcontact', $apcontact, ['url' => $apcontact['url']]);
|
||||
} else {
|
||||
|
@ -357,7 +368,7 @@ class APContact
|
|||
|
||||
Logger::info('Updated profile', ['url' => $url]);
|
||||
|
||||
return $apcontact;
|
||||
return DBA::selectFirst('apcontact', [], ['url' => $apcontact['url']]) ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -271,7 +271,7 @@ class Contact
|
|||
|
||||
// Update the contact in the background if needed
|
||||
$updated = max($contact['success_update'], $contact['created'], $contact['updated'], $contact['last-update'], $contact['failure_update']);
|
||||
if (($updated < DateTimeFormat::utc('now -7 days')) && in_array($contact['network'], Protocol::FEDERATED)) {
|
||||
if (($updated < DateTimeFormat::utc('now -7 days')) && in_array($contact['network'], Protocol::FEDERATED) && !self::isLocalById($contact['id'])) {
|
||||
Worker::add(PRIORITY_LOW, "UpdateContact", $contact['id']);
|
||||
}
|
||||
|
||||
|
@ -566,18 +566,13 @@ class Contact
|
|||
*/
|
||||
public static function createSelfFromUserId($uid)
|
||||
{
|
||||
// Only create the entry if it doesn't exist yet
|
||||
if (DBA::exists('contact', ['uid' => $uid, 'self' => true])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$user = DBA::selectFirst('user', ['uid', 'username', 'nickname', 'pubkey', 'prvkey'],
|
||||
['uid' => $uid, 'account_expired' => false]);
|
||||
if (!DBA::isResult($user)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$return = DBA::insert('contact', [
|
||||
$contact = [
|
||||
'uid' => $user['uid'],
|
||||
'created' => DateTimeFormat::utcNow(),
|
||||
'self' => 1,
|
||||
|
@ -602,7 +597,23 @@ class Contact
|
|||
'uri-date' => DateTimeFormat::utcNow(),
|
||||
'avatar-date' => DateTimeFormat::utcNow(),
|
||||
'closeness' => 0
|
||||
]);
|
||||
];
|
||||
|
||||
$return = true;
|
||||
|
||||
// Only create the entry if it doesn't exist yet
|
||||
if (!DBA::exists('contact', ['uid' => $uid, 'self' => true])) {
|
||||
$return = DBA::insert('contact', $contact);
|
||||
}
|
||||
|
||||
// Create the public contact
|
||||
if (!DBA::exists('contact', ['nurl' => $contact['nurl'], 'uid' => 0])) {
|
||||
$contact['self'] = false;
|
||||
$contact['uid'] = 0;
|
||||
$contact['prvkey'] = null;
|
||||
|
||||
DBA::insert('contact', $contact, Database::INSERT_IGNORE);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
@ -612,29 +623,30 @@ class Contact
|
|||
*
|
||||
* @param int $uid
|
||||
* @param boolean $update_avatar Force the avatar update
|
||||
* @return bool "true" if updated
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function updateSelfFromUserID($uid, $update_avatar = false)
|
||||
{
|
||||
$fields = ['id', 'name', 'nick', 'location', 'about', 'keywords', 'avatar', 'prvkey', 'pubkey',
|
||||
'xmpp', 'contact-type', 'forum', 'prv', 'avatar-date', 'url', 'nurl', 'unsearchable',
|
||||
'photo', 'thumb', 'micro', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco'];
|
||||
'photo', 'thumb', 'micro', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco', 'network'];
|
||||
$self = DBA::selectFirst('contact', $fields, ['uid' => $uid, 'self' => true]);
|
||||
if (!DBA::isResult($self)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
$fields = ['nickname', 'page-flags', 'account-type', 'prvkey', 'pubkey'];
|
||||
$user = DBA::selectFirst('user', $fields, ['uid' => $uid, 'account_expired' => false]);
|
||||
if (!DBA::isResult($user)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
$fields = ['name', 'photo', 'thumb', 'about', 'address', 'locality', 'region',
|
||||
'country-name', 'pub_keywords', 'xmpp', 'net-publish'];
|
||||
$profile = DBA::selectFirst('profile', $fields, ['uid' => $uid]);
|
||||
if (!DBA::isResult($profile)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
$file_suffix = 'jpg';
|
||||
|
@ -643,7 +655,7 @@ class Contact
|
|||
'avatar-date' => $self['avatar-date'], 'location' => Profile::formatLocation($profile),
|
||||
'about' => $profile['about'], 'keywords' => $profile['pub_keywords'],
|
||||
'contact-type' => $user['account-type'], 'prvkey' => $user['prvkey'],
|
||||
'pubkey' => $user['pubkey'], 'xmpp' => $profile['xmpp']];
|
||||
'pubkey' => $user['pubkey'], 'xmpp' => $profile['xmpp'], 'network' => Protocol::DFRN];
|
||||
|
||||
// it seems as if ported accounts can have wrong values, so we make sure that now everything is fine.
|
||||
$fields['url'] = DI::baseUrl() . '/profile/' . $user['nickname'];
|
||||
|
@ -704,6 +716,8 @@ class Contact
|
|||
DBA::update('contact', $fields, ['id' => $self['id']]);
|
||||
|
||||
// Update the public contact as well
|
||||
$fields['prvkey'] = null;
|
||||
$fields['self'] = false;
|
||||
DBA::update('contact', $fields, ['uid' => 0, 'nurl' => $self['nurl']]);
|
||||
|
||||
// Update the profile
|
||||
|
@ -711,6 +725,8 @@ class Contact
|
|||
'thumb' => DI::baseUrl() . '/photo/avatar/' . $uid .'.' . $file_suffix];
|
||||
DBA::update('profile', $fields, ['uid' => $uid]);
|
||||
}
|
||||
|
||||
return $update;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1087,7 +1103,7 @@ class Contact
|
|||
if (($uid == 0) && (empty($data['network']) || ($data['network'] == Protocol::PHANTOM))) {
|
||||
// Fetch data for the public contact via the first found personal contact
|
||||
/// @todo Check if this case can happen at all (possibly with mail accounts?)
|
||||
$fields = ['name', 'nick', 'url', 'addr', 'alias', 'avatar', 'contact-type',
|
||||
$fields = ['name', 'nick', 'url', 'addr', 'alias', 'avatar', 'header', 'contact-type',
|
||||
'keywords', 'location', 'about', 'unsearchable', 'batch', 'notify', 'poll',
|
||||
'request', 'confirm', 'poco', 'subscribe', 'network', 'baseurl', 'gsid'];
|
||||
|
||||
|
@ -1485,15 +1501,15 @@ class Contact
|
|||
{
|
||||
if (!empty($contact)) {
|
||||
$contact = self::checkAvatarCacheByArray($contact, $no_update);
|
||||
if (!empty($contact[$field])) {
|
||||
$avatar = $contact[$field];
|
||||
if (!empty($contact['id'])) {
|
||||
return self::getAvatarUrlForId($contact['id'], $size, $contact['updated'] ?? '');
|
||||
} elseif (!empty($contact[$field])) {
|
||||
return $contact[$field];
|
||||
} elseif (!empty($contact['avatar'])) {
|
||||
$avatar = $contact['avatar'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($no_update && empty($avatar) && !empty($contact['avatar'])) {
|
||||
$avatar = $contact['avatar'];
|
||||
}
|
||||
|
||||
if (empty($avatar)) {
|
||||
$avatar = self::getDefaultAvatar([], $size);
|
||||
}
|
||||
|
@ -1598,7 +1614,7 @@ class Contact
|
|||
*
|
||||
* @param array $contact contact array
|
||||
* @param string $size Size of the avatar picture
|
||||
* @return void
|
||||
* @return string avatar URL
|
||||
*/
|
||||
public static function getDefaultAvatar(array $contact, string $size)
|
||||
{
|
||||
|
@ -1646,6 +1662,99 @@ class Contact
|
|||
return DI::baseUrl() . $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get avatar link for given contact id
|
||||
*
|
||||
* @param integer $cid contact id
|
||||
* @param string $size One of the ProxyUtils::SIZE_* constants
|
||||
* @param string $updated Contact update date
|
||||
* @return string avatar link
|
||||
*/
|
||||
public static function getAvatarUrlForId(int $cid, string $size = '', string $updated = ''):string
|
||||
{
|
||||
// We have to fetch the "updated" variable when it wasn't provided
|
||||
// The parameter can be provided to improve performance
|
||||
if (empty($updated)) {
|
||||
$contact = self::getById($cid, ['updated']);
|
||||
$updated = $contact['updated'] ?? '';
|
||||
}
|
||||
|
||||
$url = DI::baseUrl() . '/photo/contact/';
|
||||
switch ($size) {
|
||||
case Proxy::SIZE_MICRO:
|
||||
$url .= Proxy::PIXEL_MICRO . '/';
|
||||
break;
|
||||
case Proxy::SIZE_THUMB:
|
||||
$url .= Proxy::PIXEL_THUMB . '/';
|
||||
break;
|
||||
case Proxy::SIZE_SMALL:
|
||||
$url .= Proxy::PIXEL_SMALL . '/';
|
||||
break;
|
||||
case Proxy::SIZE_MEDIUM:
|
||||
$url .= Proxy::PIXEL_MEDIUM . '/';
|
||||
break;
|
||||
case Proxy::SIZE_LARGE:
|
||||
$url .= Proxy::PIXEL_LARGE . '/';
|
||||
break;
|
||||
}
|
||||
return $url . $cid . ($updated ? '?ts=' . strtotime($updated) : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get avatar link for given contact URL
|
||||
*
|
||||
* @param string $url contact url
|
||||
* @param integer $uid user id
|
||||
* @param string $size One of the ProxyUtils::SIZE_* constants
|
||||
* @return string avatar link
|
||||
*/
|
||||
public static function getAvatarUrlForUrl(string $url, int $uid, string $size = ''):string
|
||||
{
|
||||
$condition = ["`nurl` = ? AND ((`uid` = ? AND `network` IN (?, ?)) OR `uid` = ?)",
|
||||
Strings::normaliseLink($url), $uid, Protocol::FEED, Protocol::MAIL, 0];
|
||||
$contact = self::selectFirst(['id', 'updated'], $condition);
|
||||
return self::getAvatarUrlForId($contact['id'] ?? 0, $size, $contact['updated'] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get header link for given contact id
|
||||
*
|
||||
* @param integer $cid contact id
|
||||
* @param string $size One of the ProxyUtils::SIZE_* constants
|
||||
* @param string $updated Contact update date
|
||||
* @return string header link
|
||||
*/
|
||||
public static function getHeaderUrlForId(int $cid, string $size = '', string $updated = ''):string
|
||||
{
|
||||
// We have to fetch the "updated" variable when it wasn't provided
|
||||
// The parameter can be provided to improve performance
|
||||
if (empty($updated)) {
|
||||
$contact = self::getById($cid, ['updated']);
|
||||
$updated = $contact['updated'] ?? '';
|
||||
}
|
||||
|
||||
$url = DI::baseUrl() . '/photo/header/';
|
||||
switch ($size) {
|
||||
case Proxy::SIZE_MICRO:
|
||||
$url .= Proxy::PIXEL_MICRO . '/';
|
||||
break;
|
||||
case Proxy::SIZE_THUMB:
|
||||
$url .= Proxy::PIXEL_THUMB . '/';
|
||||
break;
|
||||
case Proxy::SIZE_SMALL:
|
||||
$url .= Proxy::PIXEL_SMALL . '/';
|
||||
break;
|
||||
case Proxy::SIZE_MEDIUM:
|
||||
$url .= Proxy::PIXEL_MEDIUM . '/';
|
||||
break;
|
||||
case Proxy::SIZE_LARGE:
|
||||
$url .= Proxy::PIXEL_LARGE . '/';
|
||||
break;
|
||||
}
|
||||
|
||||
return $url . $cid . ($updated ? '?ts=' . strtotime($updated) : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the avatar links in a contact only if needed
|
||||
*
|
||||
|
@ -1933,14 +2042,23 @@ class Contact
|
|||
// These fields aren't updated by this routine:
|
||||
// 'xmpp', 'sensitive'
|
||||
|
||||
$fields = ['uid', 'avatar', 'name', 'nick', 'location', 'keywords', 'about', 'subscribe', 'manually-approve',
|
||||
'unsearchable', 'url', 'addr', 'batch', 'notify', 'poll', 'request', 'confirm', 'poco',
|
||||
$fields = ['uid', 'avatar', 'header', 'name', 'nick', 'location', 'keywords', 'about', 'subscribe',
|
||||
'manually-approve', 'unsearchable', 'url', 'addr', 'batch', 'notify', 'poll', 'request', 'confirm', 'poco',
|
||||
'network', 'alias', 'baseurl', 'gsid', 'forum', 'prv', 'contact-type', 'pubkey', 'last-item'];
|
||||
$contact = DBA::selectFirst('contact', $fields, ['id' => $id]);
|
||||
if (!DBA::isResult($contact)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::isLocal($ret['url'])) {
|
||||
if ($contact['uid'] == 0) {
|
||||
Logger::info('Local contacts are not updated here.');
|
||||
} else {
|
||||
self::updateFromPublicContact($id, $contact);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!empty($ret['account-type']) && $ret['account-type'] == User::ACCOUNT_TYPE_DELETED) {
|
||||
Logger::info('Deleted account', ['id' => $id, 'url' => $ret['url'], 'ret' => $ret]);
|
||||
self::remove($id);
|
||||
|
@ -2072,6 +2190,26 @@ class Contact
|
|||
return true;
|
||||
}
|
||||
|
||||
private static function updateFromPublicContact(int $id, array $contact)
|
||||
{
|
||||
$public = self::getByURL($contact['url'], false);
|
||||
|
||||
$fields = [];
|
||||
|
||||
foreach ($contact as $field => $value) {
|
||||
if ($field == 'uid') {
|
||||
continue;
|
||||
}
|
||||
if ($public[$field] != $value) {
|
||||
$fields[$field] = $public[$field];
|
||||
}
|
||||
}
|
||||
if (!empty($fields)) {
|
||||
DBA::update('contact', $fields, ['id' => $id, 'self' => false]);
|
||||
Logger::info('Updating local contact', ['id' => $id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $url contact url
|
||||
* @return integer Contact id
|
||||
|
@ -2180,8 +2318,10 @@ class Contact
|
|||
}
|
||||
|
||||
if (!empty($arr['contact']['name'])) {
|
||||
$probed = false;
|
||||
$ret = $arr['contact'];
|
||||
} else {
|
||||
$probed = true;
|
||||
$ret = Probe::uri($url, $network, $user['uid']);
|
||||
}
|
||||
|
||||
|
@ -2325,6 +2465,10 @@ class Contact
|
|||
// pull feed and consume it, which should subscribe to the hub.
|
||||
if ($contact['network'] == Protocol::OSTATUS) {
|
||||
Worker::add(PRIORITY_HIGH, 'OnePoll', $contact_id, 'force');
|
||||
}
|
||||
|
||||
if ($probed) {
|
||||
self::updateFromProbeArray($contact_id, $ret);
|
||||
} else {
|
||||
Worker::add(PRIORITY_HIGH, 'UpdateContact', $contact_id);
|
||||
}
|
||||
|
@ -2518,6 +2662,8 @@ class Contact
|
|||
// Ensure to always have the correct network type, independent from the connection request method
|
||||
self::updateFromProbe($contact['id']);
|
||||
|
||||
Post\UserNotification::insertNotication($contact['id'], Verb::getID(Activity::FOLLOW), $importer['uid']);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// send email notification to owner?
|
||||
|
@ -2549,6 +2695,8 @@ class Contact
|
|||
|
||||
self::updateAvatar($contact_id, $photo, true);
|
||||
|
||||
Post\UserNotification::insertNotication($contact_id, Verb::getID(Activity::FOLLOW), $importer['uid']);
|
||||
|
||||
$contact_record = DBA::selectFirst('contact', ['id', 'network', 'name', 'url', 'photo'], ['id' => $contact_id]);
|
||||
|
||||
/// @TODO Encapsulate this into a function/method
|
||||
|
|
|
@ -78,19 +78,22 @@ class Relation
|
|||
{
|
||||
$contact = Contact::getByURL($url);
|
||||
if (empty($contact)) {
|
||||
Logger::info('Contact not found', ['url' => $url]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self::isDiscoverable($url, $contact)) {
|
||||
Logger::info('Contact is not discoverable', ['url' => $url]);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = User::getIdForURL($url);
|
||||
if (!empty($uid)) {
|
||||
// Fetch the followers/followings locally
|
||||
Logger::info('Fetch the followers/followings locally', ['url' => $url]);
|
||||
$followers = self::getContacts($uid, [Contact::FOLLOWER, Contact::FRIEND]);
|
||||
$followings = self::getContacts($uid, [Contact::SHARING, Contact::FRIEND]);
|
||||
} else {
|
||||
} elseif (!Contact::isLocal($url)) {
|
||||
Logger::info('Fetch the followers/followings by polling the endpoints', ['url' => $url]);
|
||||
$apcontact = APContact::getByURL($url, false);
|
||||
|
||||
if (!empty($apcontact['followers']) && is_string($apcontact['followers'])) {
|
||||
|
@ -104,6 +107,10 @@ class Relation
|
|||
} else {
|
||||
$followings = [];
|
||||
}
|
||||
} else {
|
||||
Logger::notice('Contact seems to be local but could not be found here', ['url' => $url]);
|
||||
$followers = [];
|
||||
$followings = [];
|
||||
}
|
||||
|
||||
if (empty($followers) && empty($followings)) {
|
||||
|
|
|
@ -586,10 +586,10 @@ class Event
|
|||
$last_date = '';
|
||||
$fmt = DI::l10n()->t('l, F j');
|
||||
foreach ($event_result as $event) {
|
||||
$item = Post::selectFirst(['plink', 'author-name', 'author-avatar', 'author-link'], ['id' => $event['itemid']]);
|
||||
$item = Post::selectFirst(['plink', 'author-name', 'author-avatar', 'author-link', 'private'], ['id' => $event['itemid']]);
|
||||
if (!DBA::isResult($item)) {
|
||||
// Using default values when no item had been found
|
||||
$item = ['plink' => '', 'author-name' => '', 'author-avatar' => '', 'author-link' => ''];
|
||||
$item = ['plink' => '', 'author-name' => '', 'author-avatar' => '', 'author-link' => '', 'private' => Item::PUBLIC];
|
||||
}
|
||||
|
||||
$event = array_merge($event, $item);
|
||||
|
|
|
@ -802,6 +802,7 @@ class GServer
|
|||
/**
|
||||
* Parses Nodeinfo 2
|
||||
*
|
||||
* @see https://git.feneas.org/jaywink/nodeinfo2
|
||||
* @param string $nodeinfo_url address of the nodeinfo path
|
||||
* @return array Server data
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
|
@ -850,7 +851,9 @@ class GServer
|
|||
if (!empty($nodeinfo['protocols'])) {
|
||||
$protocols = [];
|
||||
foreach ($nodeinfo['protocols'] as $protocol) {
|
||||
$protocols[$protocol] = true;
|
||||
if (is_string($protocol)) {
|
||||
$protocols[$protocol] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($protocols['dfrn'])) {
|
||||
|
|
|
@ -159,6 +159,10 @@ class Item
|
|||
$fields['vid'] = Verb::getID($fields['verb']);
|
||||
}
|
||||
|
||||
if (!empty($fields['edited'])) {
|
||||
$previous = Post::selectFirst(['edited'], $condition);
|
||||
}
|
||||
|
||||
$rows = Post::update($fields, $condition);
|
||||
if (is_bool($rows)) {
|
||||
return $rows;
|
||||
|
@ -180,16 +184,18 @@ class Item
|
|||
if (!empty($fields['body'])) {
|
||||
Post\Media::insertFromAttachmentData($item['uri-id'], $fields['body']);
|
||||
|
||||
if ($item['author-network'] != Protocol::DFRN) {
|
||||
Post\Media::insertFromRelevantUrl($item['uri-id'], $fields['body']);
|
||||
}
|
||||
|
||||
$content_fields = ['raw-body' => trim($fields['raw-body'] ?? $fields['body'])];
|
||||
|
||||
// Remove all media attachments from the body and store them in the post-media table
|
||||
// @todo On shared postings (Diaspora style and commented reshare) don't fetch content from the shared part
|
||||
$content_fields['raw-body'] = Post\Media::insertFromBody($item['uri-id'], $content_fields['raw-body']);
|
||||
$content_fields['raw-body'] = self::setHashtags($content_fields['raw-body']);
|
||||
|
||||
if ($item['author-network'] != Protocol::DFRN) {
|
||||
Post\Media::insertFromRelevantUrl($item['uri-id'], $content_fields['raw-body']);
|
||||
}
|
||||
|
||||
Post\Content::update($item['uri-id'], $content_fields);
|
||||
}
|
||||
|
||||
if (!empty($fields['file'])) {
|
||||
|
@ -201,8 +207,8 @@ class Item
|
|||
}
|
||||
|
||||
// We only need to notfiy others when it is an original entry from us.
|
||||
// Only call the notifier when the item has some content relevant change.
|
||||
if ($item['origin'] && in_array('edited', array_keys($fields))) {
|
||||
// Only call the notifier when the item had been edited and records had been changed.
|
||||
if ($item['origin'] && !empty($fields['edited']) && ($previous['edited'] != $fields['edited'])) {
|
||||
$notify_items[] = $item['id'];
|
||||
}
|
||||
}
|
||||
|
@ -516,7 +522,7 @@ class Item
|
|||
public static function isValid(array $item)
|
||||
{
|
||||
// When there is no content then we don't post it
|
||||
if (($item['body'] . $item['title'] == '') && !Post\Media::existsByURIId($item['uri-id'])) {
|
||||
if (($item['body'] . $item['title'] == '') && (empty($item['uri-id']) || !Post\Media::existsByURIId($item['uri-id']))) {
|
||||
Logger::notice('No body, no title.');
|
||||
return false;
|
||||
}
|
||||
|
@ -991,14 +997,14 @@ class Item
|
|||
|
||||
Post\Media::insertFromAttachmentData($item['uri-id'], $item['body']);
|
||||
|
||||
if (!DBA::exists('contact', ['id' => $item['author-id'], 'network' => Protocol::DFRN])) {
|
||||
Post\Media::insertFromRelevantUrl($item['uri-id'], $item['body']);
|
||||
}
|
||||
|
||||
// Remove all media attachments from the body and store them in the post-media table
|
||||
$item['raw-body'] = Post\Media::insertFromBody($item['uri-id'], $item['raw-body']);
|
||||
$item['raw-body'] = self::setHashtags($item['raw-body']);
|
||||
|
||||
if (!DBA::exists('contact', ['id' => $item['author-id'], 'network' => Protocol::DFRN])) {
|
||||
Post\Media::insertFromRelevantUrl($item['uri-id'], $item['raw-body']);
|
||||
}
|
||||
|
||||
// Check for hashtags in the body and repair or add hashtag links
|
||||
$item['body'] = self::setHashtags($item['body']);
|
||||
|
||||
|
@ -1018,6 +1024,30 @@ class Item
|
|||
|
||||
if (empty($item['event-id'])) {
|
||||
unset($item['event-id']);
|
||||
|
||||
$ev = Event::fromBBCode($item['body']);
|
||||
if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) {
|
||||
Logger::info('Event found.');
|
||||
$ev['cid'] = $item['contact-id'];
|
||||
$ev['uid'] = $item['uid'];
|
||||
$ev['uri'] = $item['uri'];
|
||||
$ev['edited'] = $item['edited'];
|
||||
$ev['private'] = $item['private'];
|
||||
$ev['guid'] = $item['guid'];
|
||||
$ev['plink'] = $item['plink'];
|
||||
$ev['network'] = $item['network'];
|
||||
$ev['protocol'] = $item['protocol'];
|
||||
$ev['direction'] = $item['direction'];
|
||||
$ev['source'] = $item['source'];
|
||||
|
||||
$event = DBA::selectFirst('event', ['id'], ['uri' => $item['uri'], 'uid' => $item['uid']]);
|
||||
if (DBA::isResult($event)) {
|
||||
$ev['id'] = $event['id'];
|
||||
}
|
||||
|
||||
$item['event-id'] = Event::store($ev);
|
||||
Logger::info('Event was stored', ['id' => $item['event-id']]);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($item['causer-id'])) {
|
||||
|
@ -1034,7 +1064,14 @@ class Item
|
|||
Post\Content::insert($item['uri-id'], $item);
|
||||
}
|
||||
|
||||
// Diaspora signature
|
||||
// Create Diaspora signature
|
||||
if ($item['origin'] && empty($item['diaspora_signed_text']) && ($item['gravity'] != GRAVITY_PARENT)) {
|
||||
$signed = Diaspora::createCommentSignature($uid, $item);
|
||||
if (!empty($signed)) {
|
||||
$item['diaspora_signed_text'] = json_encode($signed);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($item['diaspora_signed_text'])) {
|
||||
DBA::replace('diaspora-interaction', ['uri-id' => $item['uri-id'], 'interaction' => $item['diaspora_signed_text']]);
|
||||
}
|
||||
|
@ -1194,13 +1231,10 @@ class Item
|
|||
Logger::info('The resharer is no forum: quit', ['resharer' => $item['author-id'], 'owner' => $parent['owner-id'], 'author' => $parent['author-id'], 'uid' => $item['uid']]);
|
||||
return;
|
||||
}
|
||||
self::update(['post-reason' => self::PR_ANNOUNCEMENT, 'causer-id' => $item['author-id']], ['id' => $parent['id']]);
|
||||
Logger::info('Set announcement post-reason', ['uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
|
||||
return;
|
||||
}
|
||||
|
||||
self::update(['owner-id' => $item['author-id'], 'contact-id' => $cid], ['id' => $parent['id']]);
|
||||
Logger::info('Change owner of the parent', ['uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid'], 'owner-id' => $item['author-id'], 'contact-id' => $cid]);
|
||||
self::update(['post-reason' => self::PR_ANNOUNCEMENT, 'causer-id' => $item['author-id']], ['id' => $parent['id']]);
|
||||
Logger::info('Set announcement post-reason', ['uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1322,19 +1356,26 @@ class Item
|
|||
/**
|
||||
* Store a public item defined by their URI-ID for the given users
|
||||
*
|
||||
* @param integer $uri_id URI-ID of the given item
|
||||
* @param integer $uid The user that will receive the item entry
|
||||
* @param array $fields Additional fields to be stored
|
||||
* @param integer $uri_id URI-ID of the given item
|
||||
* @param integer $uid The user that will receive the item entry
|
||||
* @param array $fields Additional fields to be stored
|
||||
* @param integer $source_uid User id of the source post
|
||||
* @return integer stored item id
|
||||
*/
|
||||
public static function storeForUserByUriId(int $uri_id, int $uid, array $fields = [])
|
||||
public static function storeForUserByUriId(int $uri_id, int $uid, array $fields = [], int $source_uid = 0)
|
||||
{
|
||||
$item = Post::selectFirst(self::ITEM_FIELDLIST, ['uri-id' => $uri_id, 'uid' => 0]);
|
||||
if (!DBA::isResult($item)) {
|
||||
if ($uid == $source_uid) {
|
||||
Logger::warning('target UID must not be be equal to the source UID', ['uri-id' => $uri_id, 'uid' => $uid]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (($item['private'] == self::PRIVATE) || !in_array($item['network'], Protocol::FEDERATED)) {
|
||||
$item = Post::selectFirst(self::ITEM_FIELDLIST, ['uri-id' => $uri_id, 'uid' => $source_uid]);
|
||||
if (!DBA::isResult($item)) {
|
||||
Logger::warning('Item could not be fetched', ['uri-id' => $uri_id, 'uid' => $source_uid]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (($source_uid == 0) && (($item['private'] == self::PRIVATE) || !in_array($item['network'], Protocol::FEDERATED))) {
|
||||
Logger::notice('Item is private or not from a federated network. It will not be stored for the user.', ['uri-id' => $uri_id, 'uid' => $uid, 'private' => $item['private'], 'network' => $item['network']]);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1343,8 +1384,25 @@ class Item
|
|||
|
||||
$item = array_merge($item, $fields);
|
||||
|
||||
$is_reshare = ($item['gravity'] == GRAVITY_ACTIVITY) && ($item['verb'] == Activity::ANNOUNCE);
|
||||
|
||||
if ((($item['gravity'] == GRAVITY_PARENT) || $is_reshare) &&
|
||||
DI::pConfig()->get($uid, 'system', 'accept_only_sharer') &&
|
||||
!Contact::isSharingByURL($item['author-link'], $uid) &&
|
||||
!Contact::isSharingByURL($item['owner-link'], $uid)) {
|
||||
Logger::info('Contact is not a follower, thread will not be stored', ['author' => $item['author-link'], 'uid' => $uid]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((($item['gravity'] == GRAVITY_COMMENT) || $is_reshare) && !Post::exists(['uri-id' => $item['thr-parent-id'], 'uid' => $uid])) {
|
||||
// Only do an auto complete with the source uid "0" to prevent privavy problems
|
||||
$causer = $item['causer-id'] ?: $item['author-id'];
|
||||
$result = self::storeForUserByUriId($item['thr-parent-id'], $uid, ['causer-id' => $causer, 'post-reason' => self::PR_FETCHED]);
|
||||
Logger::info('Fetched thread parent', ['uri-id' => $item['thr-parent-id'], 'uid' => $uid, 'causer' => $causer, 'result' => $result]);
|
||||
}
|
||||
|
||||
$stored = self::storeForUser($item, $uid);
|
||||
Logger::info('Public item stored for user', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'stored' => $stored]);
|
||||
Logger::info('Item stored for user', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'source-uid' => $source_uid, 'stored' => $stored]);
|
||||
return $stored;
|
||||
}
|
||||
|
||||
|
@ -1364,11 +1422,18 @@ class Item
|
|||
}
|
||||
|
||||
unset($item['id']);
|
||||
unset($item['parent']);
|
||||
unset($item['mention']);
|
||||
unset($item['starred']);
|
||||
unset($item['unseen']);
|
||||
unset($item['psid']);
|
||||
unset($item['pinned']);
|
||||
unset($item['ignored']);
|
||||
unset($item['pubmail']);
|
||||
unset($item['forum_mode']);
|
||||
|
||||
unset($item['event-id']);
|
||||
unset($item['hidden']);
|
||||
unset($item['notification-type']);
|
||||
|
||||
$item['uid'] = $uid;
|
||||
$item['origin'] = 0;
|
||||
|
@ -1394,8 +1459,6 @@ class Item
|
|||
$item['contact-id'] = $self['id'];
|
||||
}
|
||||
|
||||
/// @todo Handling of "event-id"
|
||||
|
||||
$notify = false;
|
||||
if ($item['gravity'] == GRAVITY_PARENT) {
|
||||
$contact = DBA::selectFirst('contact', [], ['id' => $item['contact-id'], 'self' => false]);
|
||||
|
@ -1407,9 +1470,9 @@ class Item
|
|||
$distributed = self::insert($item, $notify, true);
|
||||
|
||||
if (!$distributed) {
|
||||
Logger::info("Distributed public item wasn't stored", ['uri-id' => $item['uri-id'], 'user' => $uid]);
|
||||
Logger::info("Distributed item wasn't stored", ['uri-id' => $item['uri-id'], 'user' => $uid]);
|
||||
} else {
|
||||
Logger::info('Distributed public item was stored', ['uri-id' => $item['uri-id'], 'user' => $uid, 'stored' => $distributed]);
|
||||
Logger::info('Distributed item was stored', ['uri-id' => $item['uri-id'], 'user' => $uid, 'stored' => $distributed]);
|
||||
}
|
||||
return $distributed;
|
||||
}
|
||||
|
@ -1850,6 +1913,15 @@ class Item
|
|||
return false;
|
||||
}
|
||||
|
||||
self::performActivity($item['id'], 'announce', $uid);
|
||||
|
||||
/**
|
||||
* All the following lines are only needed for private forums and compatibility to older systems without AP support.
|
||||
* A possible way would be that the followers list of a forum would always be readable by all followers.
|
||||
* So this would mean that the comment distribution could be done exactly for the intended audience.
|
||||
* Or possibly we could store the receivers that had been in the "announce" message above and use this.
|
||||
*/
|
||||
|
||||
// now change this copy of the post to a forum head message and deliver to all the tgroup members
|
||||
$self = DBA::selectFirst('contact', ['id', 'name', 'url', 'thumb'], ['uid' => $uid, 'self' => true]);
|
||||
if (!DBA::isResult($self)) {
|
||||
|
@ -1859,8 +1931,13 @@ class Item
|
|||
$owner_id = Contact::getIdForURL($self['url']);
|
||||
|
||||
// also reset all the privacy bits to the forum default permissions
|
||||
|
||||
$private = ($user['allow_cid'] || $user['allow_gid'] || $user['deny_cid'] || $user['deny_gid']) ? self::PRIVATE : self::PUBLIC;
|
||||
if ($user['allow_cid'] || $user['allow_gid'] || $user['deny_cid'] || $user['deny_gid']) {
|
||||
$private = self::PRIVATE;
|
||||
} elseif (DI::pConfig()->get($user['uid'], 'system', 'unlisted')) {
|
||||
$private = self::UNLISTED;
|
||||
} else {
|
||||
$private = self::PUBLIC;
|
||||
}
|
||||
|
||||
$psid = PermissionSet::getIdFromACL(
|
||||
$user['uid'],
|
||||
|
@ -1878,8 +1955,6 @@ class Item
|
|||
|
||||
Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', Delivery::POST, (int)$item['uri-id'], (int)$item['uid']);
|
||||
|
||||
self::performActivity($item['id'], 'announce', $uid);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2667,6 +2742,23 @@ class Item
|
|||
}
|
||||
|
||||
$body = $item['body'] ?? '';
|
||||
$shared = BBCode::fetchShareAttributes($body);
|
||||
if (!empty($shared['guid'])) {
|
||||
$shared_item = Post::selectFirst(['uri-id', 'plink'], ['guid' => $shared['guid']]);
|
||||
$shared_uri_id = $shared_item['uri-id'] ?? 0;
|
||||
$shared_links = [strtolower($shared_item['plink'] ?? '')];
|
||||
$shared_attachments = Post\Media::splitAttachments($shared_uri_id, $shared['guid']);
|
||||
$shared_links = array_merge($shared_links, array_column($shared_attachments['visual'], 'url'));
|
||||
$shared_links = array_merge($shared_links, array_column($shared_attachments['link'], 'url'));
|
||||
$shared_links = array_merge($shared_links, array_column($shared_attachments['additional'], 'url'));
|
||||
$item['body'] = self::replaceVisualAttachments($shared_attachments, $item['body']);
|
||||
} else {
|
||||
$shared_uri_id = 0;
|
||||
$shared_links = [];
|
||||
}
|
||||
$attachments = Post\Media::splitAttachments($item['uri-id'], $item['guid'] ?? '', $shared_links);
|
||||
$item['body'] = self::replaceVisualAttachments($attachments, $item['body'] ?? '');
|
||||
|
||||
$item['body'] = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", "\n", $item['body']);
|
||||
self::putInCache($item);
|
||||
$item['body'] = $body;
|
||||
|
@ -2689,25 +2781,13 @@ class Item
|
|||
return $s;
|
||||
}
|
||||
|
||||
$shared = BBCode::fetchShareAttributes($item['body']);
|
||||
if (!empty($shared['guid'])) {
|
||||
$shared_item = Post::selectFirst(['uri-id', 'plink'], ['guid' => $shared['guid']]);
|
||||
$shared_uri_id = $shared_item['uri-id'] ?? 0;
|
||||
$shared_links = [strtolower($shared_item['plink'] ?? '')];
|
||||
$attachments = Post\Media::splitAttachments($shared_uri_id, $shared['guid']);
|
||||
$s = self::addVisualAttachments($attachments, $item, $s, true);
|
||||
$s = self::addLinkAttachment($attachments, $body, $s, true, []);
|
||||
$s = self::addNonVisualAttachments($attachments, $item, $s, true);
|
||||
$shared_links = array_merge($shared_links, array_column($attachments['visual'], 'url'));
|
||||
$shared_links = array_merge($shared_links, array_column($attachments['link'], 'url'));
|
||||
$shared_links = array_merge($shared_links, array_column($attachments['additional'], 'url'));
|
||||
if (!empty($shared_attachments)) {
|
||||
$s = self::addVisualAttachments($shared_attachments, $item, $s, true);
|
||||
$s = self::addLinkAttachment($shared_attachments, $body, $s, true, []);
|
||||
$s = self::addNonVisualAttachments($shared_attachments, $item, $s, true);
|
||||
$body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body);
|
||||
} else {
|
||||
$shared_uri_id = 0;
|
||||
$shared_links = [];
|
||||
}
|
||||
|
||||
$attachments = Post\Media::splitAttachments($item['uri-id'], $item['guid'] ?? '', $shared_links);
|
||||
$s = self::addVisualAttachments($attachments, $item, $s, false);
|
||||
$s = self::addLinkAttachment($attachments, $body, $s, false, $shared_links);
|
||||
$s = self::addNonVisualAttachments($attachments, $item, $s, false);
|
||||
|
@ -2739,9 +2819,10 @@ class Item
|
|||
*
|
||||
* @param string $body
|
||||
* @param string $url
|
||||
* @param int $type
|
||||
* @return bool
|
||||
*/
|
||||
public static function containsLink(string $body, string $url)
|
||||
public static function containsLink(string $body, string $url, int $type = 0)
|
||||
{
|
||||
// Make sure that for example site parameters aren't used when testing if the link is contained in the body
|
||||
$urlparts = parse_url($url);
|
||||
|
@ -2749,6 +2830,12 @@ class Item
|
|||
unset($urlparts['fragment']);
|
||||
$url = Network::unparseURL($urlparts);
|
||||
|
||||
// Remove media links to only search in embedded content
|
||||
// @todo Check images for image link, audio for audio links, ...
|
||||
if (in_array($type, [Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE])) {
|
||||
$body = preg_replace("/\[url=[^\[\]]*\](.*)\[\/url\]/Usi", ' $1 ', $body);
|
||||
}
|
||||
|
||||
if (strpos($body, $url)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -2761,6 +2848,28 @@ class Item
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace visual attachments in the body
|
||||
*
|
||||
* @param array $attachments
|
||||
* @param string $body
|
||||
* @return string modified body
|
||||
*/
|
||||
private static function replaceVisualAttachments(array $attachments, string $body)
|
||||
{
|
||||
$stamp1 = microtime(true);
|
||||
|
||||
foreach ($attachments['visual'] as $attachment) {
|
||||
if (!empty($attachment['preview'])) {
|
||||
$body = str_replace($attachment['preview'], Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_LARGE), $body);
|
||||
} elseif ($attachment['filetype'] == 'image') {
|
||||
$body = str_replace($attachment['url'], Post\Media::getUrlForId($attachment['id']), $body);
|
||||
}
|
||||
}
|
||||
DI::profiler()->saveTimestamp($stamp1, 'rendering');
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add visual attachments to the content
|
||||
*
|
||||
|
@ -2777,16 +2886,12 @@ class Item
|
|||
|
||||
// @todo In the future we should make a single for the template engine with all media in it. This allows more flexibilty.
|
||||
foreach ($attachments['visual'] as $attachment) {
|
||||
if (self::containsLink($item['body'], $attachment['url'])) {
|
||||
if (self::containsLink($item['body'], $attachment['url'], $attachment['type'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$author = ['uid' => 0, 'id' => $item['author-id'],
|
||||
'network' => $item['author-network'], 'url' => $item['author-link']];
|
||||
$the_url = Contact::magicLinkByContact($author, $attachment['url']);
|
||||
|
||||
if (!empty($attachment['preview'])) {
|
||||
$preview_url = Proxy::proxifyUrl(Contact::magicLinkByContact($author, $attachment['preview']));
|
||||
$preview_url = Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_LARGE);
|
||||
} else {
|
||||
$preview_url = '';
|
||||
}
|
||||
|
@ -2796,13 +2901,13 @@ class Item
|
|||
$media = Renderer::replaceMacros(Renderer::getMarkupTemplate('video_top.tpl'), [
|
||||
'$video' => [
|
||||
'id' => $attachment['id'],
|
||||
'src' => $the_url,
|
||||
'src' => $attachment['url'],
|
||||
'name' => $attachment['name'] ?: $attachment['url'],
|
||||
'preview' => $preview_url,
|
||||
'mime' => $attachment['mimetype'],
|
||||
],
|
||||
]);
|
||||
if ($item['post-type'] == Item::PT_VIDEO) {
|
||||
if (($item['post-type'] ?? null) == Item::PT_VIDEO) {
|
||||
$leading .= $media;
|
||||
} else {
|
||||
$trailing .= $media;
|
||||
|
@ -2811,25 +2916,22 @@ class Item
|
|||
$media = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/audio.tpl'), [
|
||||
'$audio' => [
|
||||
'id' => $attachment['id'],
|
||||
'src' => $the_url,
|
||||
'name' => $attachment['name'] ?: $attachment['url'],
|
||||
'src' => $attachment['url'],
|
||||
'name' => $attachment['name'] ?: $attachment['url'],
|
||||
'mime' => $attachment['mimetype'],
|
||||
],
|
||||
]);
|
||||
if ($item['post-type'] == Item::PT_AUDIO) {
|
||||
if (($item['post-type'] ?? null) == Item::PT_AUDIO) {
|
||||
$leading .= $media;
|
||||
} else {
|
||||
$trailing .= $media;
|
||||
}
|
||||
} elseif ($attachment['filetype'] == 'image') {
|
||||
if (empty($preview_url) && (max($attachment['width'], $attachment['height']) > 600)) {
|
||||
$preview_url = Proxy::proxifyUrl($the_url, false, ($attachment['width'] > $attachment['height']) ? Proxy::SIZE_MEDIUM : Proxy::SIZE_LARGE);
|
||||
}
|
||||
$media = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image.tpl'), [
|
||||
'$image' => [
|
||||
'src' => Proxy::proxifyUrl($the_url),
|
||||
'preview' => $preview_url,
|
||||
'attachment' => $attachment,
|
||||
'src' => Post\Media::getUrlForId($attachment['id']),
|
||||
'preview' => Post\Media::getPreviewUrlForId($attachment['id'], ($attachment['width'] > $attachment['height']) ? Proxy::SIZE_MEDIUM : Proxy::SIZE_LARGE),
|
||||
'attachment' => $attachment,
|
||||
],
|
||||
]);
|
||||
// On Diaspora posts the attached pictures are leading
|
||||
|
@ -2907,11 +3009,11 @@ class Item
|
|||
'type' => 'link',
|
||||
'url' => $attachment['url']];
|
||||
|
||||
if ($preview) {
|
||||
if ($preview && !empty($attachment['preview'])) {
|
||||
if ($attachment['preview-width'] >= 500) {
|
||||
$data['image'] = $attachment['preview'] ?? '';
|
||||
$data['image'] = Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_MEDIUM);
|
||||
} else {
|
||||
$data['preview'] = $attachment['preview'] ?? '';
|
||||
$data['preview'] = Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_MEDIUM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2955,7 +3057,7 @@ class Item
|
|||
|
||||
// @todo Use a template
|
||||
$rendered = BBCode::convertAttachment('', BBCode::INTERNAL, false, $data);
|
||||
} elseif (!self::containsLink($content, $data['url'])) {
|
||||
} elseif (!self::containsLink($content, $data['url'], Post\Media::HTML)) {
|
||||
$rendered = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/link.tpl'), [
|
||||
'$url' => $data['url'],
|
||||
'$title' => $data['title'],
|
||||
|
@ -3288,18 +3390,18 @@ class Item
|
|||
{
|
||||
$shared = BBCode::fetchShareAttributes($item['body']);
|
||||
if (empty($shared['link'])) {
|
||||
return $item['body'];
|
||||
return $item['body'];
|
||||
}
|
||||
|
||||
|
||||
$id = self::fetchByLink($shared['link']);
|
||||
Logger::info('Fetched shared post', ['uri-id' => $item['uri-id'], 'id' => $id, 'author' => $shared['profile'], 'url' => $shared['link'], 'guid' => $shared['guid'], 'callstack' => System::callstack()]);
|
||||
if (!$id) {
|
||||
return $item['body'];
|
||||
return $item['body'];
|
||||
}
|
||||
|
||||
$shared_item = Post::selectFirst(['author-name', 'author-link', 'author-avatar', 'plink', 'created', 'guid', 'title', 'body'], ['id' => $id]);
|
||||
if (!DBA::isResult($shared_item)) {
|
||||
return $item['body'];
|
||||
return $item['body'];
|
||||
}
|
||||
|
||||
$shared_content = BBCode::getShareOpeningTag($shared_item['author-name'], $shared_item['author-link'], $shared_item['author-avatar'], $shared_item['plink'], $shared_item['created'], $shared_item['guid']);
|
||||
|
|
|
@ -36,15 +36,14 @@ use Friendica\Worker\Delivery;
|
|||
class Mail
|
||||
{
|
||||
/**
|
||||
* Insert received private message
|
||||
* Insert private message
|
||||
*
|
||||
* @param array $msg
|
||||
* @param bool $notifiction
|
||||
* @return int|boolean Message ID or false on error
|
||||
*/
|
||||
public static function insert($msg)
|
||||
public static function insert($msg, $notifiction = true)
|
||||
{
|
||||
$user = User::getById($msg['uid']);
|
||||
|
||||
if (!isset($msg['reply'])) {
|
||||
$msg['reply'] = DBA::exists('mail', ['parent-uri' => $msg['parent-uri']]);
|
||||
}
|
||||
|
@ -63,6 +62,10 @@ class Mail
|
|||
|
||||
$msg['created'] = (!empty($msg['created']) ? DateTimeFormat::utc($msg['created']) : DateTimeFormat::utcNow());
|
||||
|
||||
$msg['author-id'] = Contact::getIdForURL($msg['from-url'], 0, false);
|
||||
$msg['uri-id'] = ItemURI::insert(['uri' => $msg['uri'], 'guid' => $msg['guid']]);
|
||||
$msg['parent-uri-id'] = ItemURI::getIdByURI($msg['parent-uri']);
|
||||
|
||||
DBA::lock('mail');
|
||||
|
||||
if (DBA::exists('mail', ['uri' => $msg['uri'], 'uid' => $msg['uid']])) {
|
||||
|
@ -71,6 +74,16 @@ class Mail
|
|||
return false;
|
||||
}
|
||||
|
||||
if ($msg['reply']) {
|
||||
$reply = DBA::selectFirst('mail', ['uri', 'uri-id'], ['parent-uri' => $msg['parent-uri'], 'reply' => false]);
|
||||
|
||||
$msg['thr-parent'] = $reply['uri'];
|
||||
$msg['thr-parent-id'] = $reply['uri-id'];
|
||||
} else {
|
||||
$msg['thr-parent'] = $msg['uri'];
|
||||
$msg['thr-parent-id'] = $msg['uri-id'];
|
||||
}
|
||||
|
||||
DBA::insert('mail', $msg);
|
||||
|
||||
$msg['id'] = DBA::lastInsertId();
|
||||
|
@ -81,19 +94,22 @@ class Mail
|
|||
DBA::update('conv', ['updated' => DateTimeFormat::utcNow()], ['id' => $msg['convid']]);
|
||||
}
|
||||
|
||||
// send notifications.
|
||||
$notif_params = [
|
||||
'type' => Notification\Type::MAIL,
|
||||
'otype' => Notification\ObjectType::MAIL,
|
||||
'verb' => Activity::POST,
|
||||
'uid' => $user['uid'],
|
||||
'cid' => $msg['contact-id'],
|
||||
'link' => DI::baseUrl() . '/message/' . $msg['id'],
|
||||
];
|
||||
if ($notifiction) {
|
||||
$user = User::getById($msg['uid']);
|
||||
// send notifications.
|
||||
$notif_params = [
|
||||
'type' => Notification\Type::MAIL,
|
||||
'otype' => Notification\ObjectType::MAIL,
|
||||
'verb' => Activity::POST,
|
||||
'uid' => $user['uid'],
|
||||
'cid' => $msg['contact-id'],
|
||||
'link' => DI::baseUrl() . '/message/' . $msg['id'],
|
||||
];
|
||||
|
||||
notification($notif_params);
|
||||
notification($notif_params);
|
||||
|
||||
Logger::info('Mail is processed, notification was sent.', ['id' => $msg['id'], 'uri' => $msg['uri']]);
|
||||
Logger::info('Mail is processed, notification was sent.', ['id' => $msg['id'], 'uri' => $msg['uri']]);
|
||||
}
|
||||
|
||||
return $msg['id'];
|
||||
}
|
||||
|
@ -181,9 +197,7 @@ class Mail
|
|||
$replyto = $convuri;
|
||||
}
|
||||
|
||||
$post_id = null;
|
||||
$success = DBA::insert(
|
||||
'mail',
|
||||
$post_id = self::insert(
|
||||
[
|
||||
'uid' => local_user(),
|
||||
'guid' => $guid,
|
||||
|
@ -200,13 +214,9 @@ class Mail
|
|||
'uri' => $uri,
|
||||
'parent-uri' => $replyto,
|
||||
'created' => DateTimeFormat::utcNow()
|
||||
]
|
||||
], false
|
||||
);
|
||||
|
||||
if ($success) {
|
||||
$post_id = DBA::lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* When a photo was uploaded into the message using the (profile wall) ajax
|
||||
|
@ -287,8 +297,7 @@ class Mail
|
|||
return -4;
|
||||
}
|
||||
|
||||
DBA::insert(
|
||||
'mail',
|
||||
self::insert(
|
||||
[
|
||||
'uid' => $recipient['uid'],
|
||||
'guid' => $guid,
|
||||
|
@ -306,7 +315,7 @@ class Mail
|
|||
'parent-uri' => $me['url'],
|
||||
'created' => DateTimeFormat::utcNow(),
|
||||
'unknown' => 1
|
||||
]
|
||||
], false
|
||||
);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -27,6 +27,7 @@ use Friendica\Core\System;
|
|||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\DBStructure;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Storage\ExternalResource;
|
||||
use Friendica\Model\Storage\SystemResource;
|
||||
use Friendica\Object\Image;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
@ -244,13 +245,17 @@ class Photo
|
|||
* Construct a photo array for a system resource image
|
||||
*
|
||||
* @param string $filename Image file name relative to code root
|
||||
* @param string $mimetype Image mime type. Defaults to "image/jpeg"
|
||||
* @param string $mimetype Image mime type. Is guessed by file name when empty.
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function createPhotoForSystemResource($filename, $mimetype = "image/jpeg")
|
||||
public static function createPhotoForSystemResource($filename, $mimetype = '')
|
||||
{
|
||||
if (empty($mimetype)) {
|
||||
$mimetype = Images::guessTypeByExtension($filename);
|
||||
}
|
||||
|
||||
$fields = self::getFields();
|
||||
$values = array_fill(0, count($fields), "");
|
||||
|
||||
|
@ -263,6 +268,33 @@ class Photo
|
|||
return $photo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a photo array for an external resource image
|
||||
*
|
||||
* @param string $url Image URL
|
||||
* @param int $uid User ID of the requesting person
|
||||
* @param string $mimetype Image mime type. Is guessed by file name when empty.
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function createPhotoForExternalResource($url, $uid = 0, $mimetype = '')
|
||||
{
|
||||
if (empty($mimetype)) {
|
||||
$mimetype = Images::guessTypeByExtension($url);
|
||||
}
|
||||
|
||||
$fields = self::getFields();
|
||||
$values = array_fill(0, count($fields), "");
|
||||
|
||||
$photo = array_combine($fields, $values);
|
||||
$photo['backend-class'] = ExternalResource::NAME;
|
||||
$photo['backend-ref'] = json_encode(['url' => $url, 'uid' => $uid]);
|
||||
$photo['type'] = $mimetype;
|
||||
$photo['cacheable'] = true;
|
||||
|
||||
return $photo;
|
||||
}
|
||||
|
||||
/**
|
||||
* store photo metadata in db and binary in default backend
|
||||
|
|
|
@ -124,24 +124,22 @@ class Post
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if post data exists
|
||||
* Check if post-user-view records exists
|
||||
*
|
||||
* @param array $condition array of fields for condition
|
||||
* @param bool $user_mode true = post-user-view, false = post-view
|
||||
*
|
||||
* @return boolean Are there rows for that condition?
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function exists($condition, bool $user_mode = true) {
|
||||
return DBA::exists($user_mode ? 'post-user-view' : 'post-view', $condition);
|
||||
public static function exists($condition) {
|
||||
return DBA::exists('post-user-view', $condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the posts satisfying the provided condition
|
||||
* Counts the post-user-view records satisfying the provided condition
|
||||
*
|
||||
* @param array $condition array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
* @param bool $user_mode true = post-user-view, false = post-view
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
|
@ -153,17 +151,39 @@ class Post
|
|||
* $count = Post::count($condition);
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function count(array $condition = [], array $params = [], bool $user_mode = true)
|
||||
public static function count(array $condition = [], array $params = [])
|
||||
{
|
||||
return DBA::count($user_mode ? 'post-user-view' : 'post-view', $condition, $params);
|
||||
return DBA::count('post-user-view', $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a single record from the post table and returns it in an associative array
|
||||
* Counts the post-view records satisfying the provided condition
|
||||
*
|
||||
* @param array $condition array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* Example:
|
||||
* $condition = ["network" => 'dspr'];
|
||||
* or:
|
||||
* $condition = ["`network` IN (?, ?)", 1, 'dfrn', 'dspr'];
|
||||
*
|
||||
* $count = Post::count($condition);
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function countPosts(array $condition = [], array $params = [])
|
||||
{
|
||||
return DBA::count('post-view', $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a single record from the post-user-view view and returns it in an associative array
|
||||
*
|
||||
* @param array $fields
|
||||
* @param array $condition
|
||||
* @param array $params
|
||||
* @param bool $user_mode true = post-user-view, false = post-view
|
||||
* @return bool|array
|
||||
* @throws \Exception
|
||||
* @see DBA::select
|
||||
|
@ -184,7 +204,32 @@ class Post
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve a single record from the post-thread table and returns it in an associative array
|
||||
* Retrieve a single record from the post-view view and returns it in an associative array
|
||||
*
|
||||
* @param array $fields
|
||||
* @param array $condition
|
||||
* @param array $params
|
||||
* @return bool|array
|
||||
* @throws \Exception
|
||||
* @see DBA::select
|
||||
*/
|
||||
public static function selectFirstPost(array $fields = [], array $condition = [], $params = [])
|
||||
{
|
||||
$params['limit'] = 1;
|
||||
|
||||
$result = self::selectPosts($fields, $condition, $params);
|
||||
|
||||
if (is_bool($result)) {
|
||||
return $result;
|
||||
} else {
|
||||
$row = self::fetch($result);
|
||||
DBA::close($result);
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a single record from the post-thread-user-view view and returns it in an associative array
|
||||
*
|
||||
* @param array $fields
|
||||
* @param array $condition
|
||||
|
@ -209,7 +254,7 @@ class Post
|
|||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post table and returns them as an array
|
||||
* Select rows from the post-user-view view and returns them as an array
|
||||
*
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
|
@ -262,23 +307,37 @@ class Post
|
|||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post table
|
||||
* Select rows from the post-user-view view
|
||||
*
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
* @param bool $user_mode true = post-user-view, false = post-view
|
||||
*
|
||||
* @return boolean|object
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function select(array $selected = [], array $condition = [], $params = [], bool $user_mode = true)
|
||||
public static function select(array $selected = [], array $condition = [], $params = [])
|
||||
{
|
||||
return self::selectView($user_mode ? 'post-user-view' : 'post-view', $selected, $condition, $params);
|
||||
return self::selectView('post-user-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post table
|
||||
* Select rows from the post-view view
|
||||
*
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
*
|
||||
* @return boolean|object
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function selectPosts(array $selected = [], array $condition = [], $params = [])
|
||||
{
|
||||
return self::selectView('post-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post-thread-user-view view
|
||||
*
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
|
@ -335,7 +394,7 @@ class Post
|
|||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post view for a given user
|
||||
* Select rows from the post-user-view view for a given user
|
||||
*
|
||||
* @param integer $uid User ID
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
|
@ -350,8 +409,24 @@ class Post
|
|||
return self::selectViewForUser('post-user-view', $uid, $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post view for a given user
|
||||
/**
|
||||
* Select rows from the post-view view for a given user
|
||||
*
|
||||
* @param integer $uid User ID
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
*
|
||||
* @return boolean|object
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function selectPostsForUser($uid, array $selected = [], array $condition = [], $params = [])
|
||||
{
|
||||
return self::selectViewForUser('post-view', $uid, $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post-thread-user-view view for a given user
|
||||
*
|
||||
* @param integer $uid User ID
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
|
@ -367,7 +442,7 @@ class Post
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve a single record from the post view for a given user and returns it in an associative array
|
||||
* Retrieve a single record from the post-user-view view for a given user and returns it in an associative array
|
||||
*
|
||||
* @param integer $uid User ID
|
||||
* @param array $selected
|
||||
|
@ -393,7 +468,7 @@ class Post
|
|||
}
|
||||
|
||||
/**
|
||||
* Select pinned rows from the item table for a given user
|
||||
* Select pinned rows from the post-thread-user table for a given user
|
||||
*
|
||||
* @param integer $uid User ID
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
|
|
|
@ -28,9 +28,12 @@ use Friendica\Database\Database;
|
|||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Util\Images;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\ParseUrl;
|
||||
use Friendica\Util\Proxy;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
/**
|
||||
|
@ -157,6 +160,10 @@ class Media
|
|||
*/
|
||||
public static function fetchAdditionalData(array $media)
|
||||
{
|
||||
if (Network::isLocalLink($media['url'])) {
|
||||
$media = self::fetchLocalData($media);
|
||||
}
|
||||
|
||||
// Fetch the mimetype or size if missing.
|
||||
if (empty($media['mimetype']) || empty($media['size'])) {
|
||||
$timeout = DI::config()->get('system', 'xrd_timeout');
|
||||
|
@ -215,6 +222,36 @@ class Media
|
|||
return $media;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch media data from local resources
|
||||
* @param array $media
|
||||
* @return array media with added data
|
||||
*/
|
||||
private static function fetchLocalData(array $media)
|
||||
{
|
||||
if (!preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $media['url'] ?? '', $matches)) {
|
||||
return $media;
|
||||
}
|
||||
$photo = Photo::selectFirst([], ['resource-id' => $matches[1], 'scale' => $matches[2]]);
|
||||
if (!empty($photo)) {
|
||||
$media['mimetype'] = $photo['type'];
|
||||
$media['size'] = $photo['datasize'];
|
||||
$media['width'] = $photo['width'];
|
||||
$media['height'] = $photo['height'];
|
||||
}
|
||||
|
||||
if (!preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $media['preview'] ?? '', $matches)) {
|
||||
return $media;
|
||||
}
|
||||
$photo = Photo::selectFirst([], ['resource-id' => $matches[1], 'scale' => $matches[2]]);
|
||||
if (!empty($photo)) {
|
||||
$media['preview-width'] = $photo['width'];
|
||||
$media['preview-height'] = $photo['height'];
|
||||
}
|
||||
|
||||
return $media;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the detected type to the media array
|
||||
*
|
||||
|
@ -351,7 +388,7 @@ class Media
|
|||
|
||||
foreach ($attachments as $attachment) {
|
||||
// Only store attachments that are part of the unshared body
|
||||
if (strpos($unshared_body, $attachment['url']) !== false) {
|
||||
if (Item::containsLink($unshared_body, $attachment['url'], $attachment['type'])) {
|
||||
self::insert($attachment);
|
||||
}
|
||||
}
|
||||
|
@ -494,10 +531,10 @@ class Media
|
|||
|
||||
/**
|
||||
* Split the attachment media in the three segments "visual", "link" and "additional"
|
||||
*
|
||||
* @param int $uri_id
|
||||
*
|
||||
* @param int $uri_id
|
||||
* @param string $guid
|
||||
* @param array $links ist of links that shouldn't be added
|
||||
* @param array $links ist of links that shouldn't be added
|
||||
* @return array attachments
|
||||
*/
|
||||
public static function splitAttachments(int $uri_id, string $guid = '', array $links = [])
|
||||
|
@ -526,7 +563,7 @@ class Media
|
|||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!empty($medium['preview'])) {
|
||||
$previews[] = $medium['preview'];
|
||||
}
|
||||
|
@ -600,7 +637,7 @@ class Media
|
|||
$body = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body);
|
||||
|
||||
foreach (self::getByURIId($uriid, [self::IMAGE, self::AUDIO, self::VIDEO]) as $media) {
|
||||
if (Item::containsLink($body, $media['url'])) {
|
||||
if (Item::containsLink($body, $media['url'], $media['type'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -631,4 +668,64 @@ class Media
|
|||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get preview link for given media id
|
||||
*
|
||||
* @param integer $id media id
|
||||
* @param string $size One of the ProxyUtils::SIZE_* constants
|
||||
* @return string preview link
|
||||
*/
|
||||
public static function getPreviewUrlForId(int $id, string $size = ''):string
|
||||
{
|
||||
$url = DI::baseUrl() . '/photo/preview/';
|
||||
switch ($size) {
|
||||
case Proxy::SIZE_MICRO:
|
||||
$url .= Proxy::PIXEL_MICRO . '/';
|
||||
break;
|
||||
case Proxy::SIZE_THUMB:
|
||||
$url .= Proxy::PIXEL_THUMB . '/';
|
||||
break;
|
||||
case Proxy::SIZE_SMALL:
|
||||
$url .= Proxy::PIXEL_SMALL . '/';
|
||||
break;
|
||||
case Proxy::SIZE_MEDIUM:
|
||||
$url .= Proxy::PIXEL_MEDIUM . '/';
|
||||
break;
|
||||
case Proxy::SIZE_LARGE:
|
||||
$url .= Proxy::PIXEL_LARGE . '/';
|
||||
break;
|
||||
}
|
||||
return $url . $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get media link for given media id
|
||||
*
|
||||
* @param integer $id media id
|
||||
* @param string $size One of the ProxyUtils::SIZE_* constants
|
||||
* @return string media link
|
||||
*/
|
||||
public static function getUrlForId(int $id, string $size = ''):string
|
||||
{
|
||||
$url = DI::baseUrl() . '/photo/media/';
|
||||
switch ($size) {
|
||||
case Proxy::SIZE_MICRO:
|
||||
$url .= Proxy::PIXEL_MICRO . '/';
|
||||
break;
|
||||
case Proxy::SIZE_THUMB:
|
||||
$url .= Proxy::PIXEL_THUMB . '/';
|
||||
break;
|
||||
case Proxy::SIZE_SMALL:
|
||||
$url .= Proxy::PIXEL_SMALL . '/';
|
||||
break;
|
||||
case Proxy::SIZE_MEDIUM:
|
||||
$url .= Proxy::PIXEL_MEDIUM . '/';
|
||||
break;
|
||||
case Proxy::SIZE_LARGE:
|
||||
$url .= Proxy::PIXEL_LARGE . '/';
|
||||
break;
|
||||
}
|
||||
return $url . $id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ use Friendica\Model\Post;
|
|||
use Friendica\Util\Strings;
|
||||
use Friendica\Model\Tag;
|
||||
use Friendica\Protocol\Activity;
|
||||
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
class UserNotification
|
||||
{
|
||||
|
@ -128,8 +128,8 @@ class UserNotification
|
|||
*/
|
||||
public static function setNotification(int $uri_id, int $uid)
|
||||
{
|
||||
$fields = ['id', 'uri-id', 'parent-uri-id', 'uid', 'body', 'parent', 'gravity',
|
||||
'private', 'contact-id', 'thr-parent', 'parent-uri-id', 'parent-uri', 'author-id', 'verb'];
|
||||
$fields = ['id', 'uri-id', 'parent-uri-id', 'uid', 'body', 'parent', 'gravity', 'vid', 'gravity',
|
||||
'private', 'contact-id', 'thr-parent', 'thr-parent-id', 'parent-uri-id', 'parent-uri', 'author-id', 'verb'];
|
||||
$item = Post::selectFirst($fields, ['uri-id' => $uri_id, 'uid' => $uid, 'origin' => false]);
|
||||
if (!DBA::isResult($item)) {
|
||||
return;
|
||||
|
@ -148,7 +148,7 @@ class UserNotification
|
|||
}
|
||||
|
||||
// Add every user who participated so far in this thread
|
||||
// This can only happen with participations on global items. (means: uid = 0)
|
||||
// This can only happen with participations on global items. (means: uid = 0)
|
||||
$users = DBA::p("SELECT DISTINCT(`contact-uid`) AS `uid` FROM `post-user-view`
|
||||
WHERE `contact-uid` != 0 AND `parent-uri-id` = ? AND `uid` = ?", $item['parent-uri-id'], $uid);
|
||||
while ($user = DBA::fetch($users)) {
|
||||
|
@ -177,6 +177,10 @@ class UserNotification
|
|||
|
||||
if (self::checkShared($item, $uid)) {
|
||||
$notification_type = $notification_type | self::NOTIF_SHARED;
|
||||
self::insertNoticationByItem(self::NOTIF_SHARED, $uid, $item);
|
||||
$notified = true;
|
||||
} else {
|
||||
$notified = false;
|
||||
}
|
||||
|
||||
$profiles = self::getProfileForUser($uid);
|
||||
|
@ -194,38 +198,64 @@ class UserNotification
|
|||
return;
|
||||
}
|
||||
|
||||
// Only create notifications for posts and comments, not for activities
|
||||
if (in_array($item['gravity'], [GRAVITY_PARENT, GRAVITY_COMMENT])) {
|
||||
if (self::checkImplicitMention($item, $profiles)) {
|
||||
$notification_type = $notification_type | self::NOTIF_IMPLICIT_TAGGED;
|
||||
}
|
||||
|
||||
if (self::checkExplicitMention($item, $profiles)) {
|
||||
$notification_type = $notification_type | self::NOTIF_EXPLICIT_TAGGED;
|
||||
}
|
||||
|
||||
if (self::checkCommentedThread($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_THREAD_COMMENT;
|
||||
}
|
||||
|
||||
if (self::checkDirectComment($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_DIRECT_COMMENT;
|
||||
}
|
||||
|
||||
if (self::checkDirectCommentedThread($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_DIRECT_THREAD_COMMENT;
|
||||
}
|
||||
|
||||
if (self::checkCommentedParticipation($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_COMMENT_PARTICIPATION;
|
||||
}
|
||||
|
||||
if (self::checkActivityParticipation($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_ACTIVITY_PARTICIPATION;
|
||||
if (self::checkExplicitMention($item, $profiles)) {
|
||||
$notification_type = $notification_type | self::NOTIF_EXPLICIT_TAGGED;
|
||||
if (!$notified) {
|
||||
self::insertNoticationByItem( self::NOTIF_EXPLICIT_TAGGED, $uid, $item);
|
||||
$notified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($notification_type)) {
|
||||
if (self::checkImplicitMention($item, $profiles)) {
|
||||
$notification_type = $notification_type | self::NOTIF_IMPLICIT_TAGGED;
|
||||
if (!$notified) {
|
||||
self::insertNoticationByItem(self::NOTIF_IMPLICIT_TAGGED, $uid, $item);
|
||||
$notified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (self::checkDirectComment($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_DIRECT_COMMENT;
|
||||
if (!$notified) {
|
||||
self::insertNoticationByItem(self::NOTIF_DIRECT_COMMENT, $uid, $item);
|
||||
$notified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (self::checkDirectCommentedThread($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_DIRECT_THREAD_COMMENT;
|
||||
if (!$notified) {
|
||||
self::insertNoticationByItem(self::NOTIF_DIRECT_THREAD_COMMENT, $uid, $item);
|
||||
$notified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (self::checkCommentedThread($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_THREAD_COMMENT;
|
||||
if (!$notified) {
|
||||
self::insertNoticationByItem(self::NOTIF_THREAD_COMMENT, $uid, $item);
|
||||
$notified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (self::checkCommentedParticipation($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_COMMENT_PARTICIPATION;
|
||||
if (!$notified) {
|
||||
self::insertNoticationByItem(self::NOTIF_COMMENT_PARTICIPATION, $uid, $item);
|
||||
$notified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (self::checkActivityParticipation($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::NOTIF_ACTIVITY_PARTICIPATION;
|
||||
if (!$notified) {
|
||||
self::insertNoticationByItem(self::NOTIF_ACTIVITY_PARTICIPATION, $uid, $item);
|
||||
$notified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Only create notifications for posts and comments, not for activities
|
||||
if (empty($notification_type) || !in_array($item['gravity'], [GRAVITY_PARENT, GRAVITY_COMMENT])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -236,6 +266,61 @@ class UserNotification
|
|||
self::update($item['uri-id'], $uid, $fields, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a notification entry for a given item array
|
||||
*
|
||||
* @param int $type User notification type
|
||||
* @param int $uid User ID
|
||||
* @param array $item Item array
|
||||
* @return boolean
|
||||
*/
|
||||
private static function insertNoticationByItem(int $type, int $uid, array $item)
|
||||
{
|
||||
if (($item['gravity'] == GRAVITY_ACTIVITY) &&
|
||||
!in_array($type, [self::NOTIF_DIRECT_COMMENT, self::NOTIF_DIRECT_THREAD_COMMENT])) {
|
||||
// Activities are only stored when performed on the user's post or comment
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'uid' => $uid,
|
||||
'vid' => $item['vid'],
|
||||
'type' => $type,
|
||||
'actor-id' => $item['author-id'],
|
||||
'parent-uri-id' => $item['parent-uri-id'],
|
||||
'created' => DateTimeFormat::utcNow(),
|
||||
];
|
||||
|
||||
if ($item['gravity'] == GRAVITY_ACTIVITY) {
|
||||
$fields['target-uri-id'] = $item['thr-parent-id'];
|
||||
} else {
|
||||
$fields['target-uri-id'] = $item['uri-id'];
|
||||
}
|
||||
|
||||
return DBA::insert('notification', $fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a notification entry
|
||||
*
|
||||
* @param int $actor Contact ID of the actor
|
||||
* @param int $vid Verb ID
|
||||
* @param int $uid User ID
|
||||
* @return boolean
|
||||
*/
|
||||
public static function insertNotication(int $actor, int $vid, int $uid)
|
||||
{
|
||||
$fields = [
|
||||
'uid' => $uid,
|
||||
'vid' => $vid,
|
||||
'type' => self::NOTIF_NONE,
|
||||
'actor-id' => $actor,
|
||||
'created' => DateTimeFormat::utcNow(),
|
||||
];
|
||||
|
||||
return DBA::insert('notification', $fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all profiles (contact URL) of a given user
|
||||
* @param int $uid User ID
|
||||
|
|
|
@ -29,13 +29,16 @@ use Friendica\Core\Hook;
|
|||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Search;
|
||||
use Friendica\Core\Session;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Friendica\Protocol\Diaspora;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\HTTPSignature;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Proxy as ProxyUtils;
|
||||
use Friendica\Util\Strings;
|
||||
|
@ -84,6 +87,71 @@ class Profile
|
|||
return DBA::selectToArray('profile', $fields, ['uid' => $uid]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a profile entry and distribute the changes if needed
|
||||
*
|
||||
* @param array $fields
|
||||
* @param integer $uid
|
||||
* @return boolean
|
||||
*/
|
||||
public static function update(array $fields, int $uid): bool
|
||||
{
|
||||
$old_owner = User::getOwnerDataById($uid);
|
||||
if (empty($old_owner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DBA::update('profile', $fields, ['uid' => $uid])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$update = Contact::updateSelfFromUserID($uid);
|
||||
|
||||
$owner = User::getOwnerDataById($uid);
|
||||
if (empty($owner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($old_owner['name'] != $owner['name']) {
|
||||
User::update(['username' => $owner['name']], $uid);
|
||||
}
|
||||
|
||||
$profile_fields = ['postal-code', 'dob', 'prv_keywords', 'homepage'];
|
||||
foreach ($profile_fields as $field) {
|
||||
if ($old_owner[$field] != $owner[$field]) {
|
||||
$update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($update) {
|
||||
self::publishUpdate($uid, ($old_owner['net-publish'] != $owner['net-publish']));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a changed profile
|
||||
* @param int $uid
|
||||
* @param bool $force Force publishing to the directory
|
||||
*/
|
||||
public static function publishUpdate(int $uid, bool $force = false)
|
||||
{
|
||||
$owner = User::getOwnerDataById($uid);
|
||||
if (empty($owner)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($owner['net-publish'] || $force) {
|
||||
// Update global directory in background
|
||||
if (Search::getGlobalDirectory()) {
|
||||
Worker::add(PRIORITY_LOW, 'Directory', $owner['url']);
|
||||
}
|
||||
}
|
||||
|
||||
Worker::add(PRIORITY_LOW, 'ProfileUpdate', $uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted location string from the given profile array
|
||||
*
|
||||
|
@ -215,28 +283,6 @@ class Profile
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all profile data of a local user
|
||||
*
|
||||
* If the viewer is an authenticated remote viewer, the profile displayed is the
|
||||
* one that has been configured for his/her viewing in the Contact manager.
|
||||
* Passing a non-zero profile ID can also allow a preview of a selected profile
|
||||
* by the owner
|
||||
*
|
||||
* Includes all available profile data
|
||||
*
|
||||
* @param string $nickname nick
|
||||
* @param int $uid uid
|
||||
* @param int $profile_id ID of the profile
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getByNickname($nickname, $uid = 0)
|
||||
{
|
||||
$profile = DBA::selectFirst('owner-view', [], ['nickname' => $nickname, 'uid' => $uid]);
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a profile for display in the sidebar.
|
||||
*
|
||||
|
@ -263,8 +309,20 @@ class Profile
|
|||
$o = '';
|
||||
$location = false;
|
||||
|
||||
// This function can also use contact information in $profile
|
||||
$is_contact = !empty($profile['cid']);
|
||||
// This function can also use contact information in $profile, but the 'cid'
|
||||
// value is going to be coming from 'owner-view', which means it's the wrong
|
||||
// contact ID for the user viewing this page. Use 'nurl' to look up the
|
||||
// correct contact table entry for the logged-in user.
|
||||
$profile_contact = [];
|
||||
|
||||
if (!empty($profile['nurl'])) {
|
||||
if (local_user() && ($profile['uid'] ?? 0) != local_user()) {
|
||||
$profile_contact = Contact::getByURL($profile['nurl'], null, ['rel'], local_user());
|
||||
}
|
||||
if (!empty($profile['cid']) && self::getMyURL()) {
|
||||
$profile_contact = Contact::selectFirst(['rel'], ['id' => $profile['cid']]);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($profile['nickname'])) {
|
||||
Logger::warning('Received profile with no nickname', ['profile' => $profile, 'callstack' => System::callstack(10)]);
|
||||
|
@ -287,21 +345,23 @@ class Profile
|
|||
$profile_url = DI::baseUrl()->get() . '/profile/' . $profile['nickname'];
|
||||
}
|
||||
|
||||
if (!empty($profile['id'])) {
|
||||
$cid = $profile['id'];
|
||||
} else {
|
||||
$cid = Contact::getIdForURL($profile_url, false);
|
||||
}
|
||||
|
||||
$follow_link = null;
|
||||
$unfollow_link = null;
|
||||
$subscribe_feed_link = null;
|
||||
$wallmessage_link = null;
|
||||
|
||||
// Who is the logged-in user to this profile?
|
||||
$visitor_contact = [];
|
||||
if (!empty($profile['uid']) && self::getMyURL()) {
|
||||
$visitor_contact = Contact::selectFirst(['rel'], ['uid' => $profile['uid'], 'nurl' => Strings::normaliseLink(self::getMyURL())]);
|
||||
}
|
||||
|
||||
$profile_contact = [];
|
||||
if (!empty($profile['cid']) && self::getMyURL()) {
|
||||
$profile_contact = Contact::selectFirst(['rel'], ['id' => $profile['cid']]);
|
||||
}
|
||||
|
||||
$profile_is_dfrn = $profile['network'] == Protocol::DFRN;
|
||||
$profile_is_native = in_array($profile['network'], Protocol::NATIVE_SUPPORT);
|
||||
$local_user_is_self = self::getMyURL() && ($profile['url'] == self::getMyURL());
|
||||
|
@ -332,17 +392,19 @@ class Profile
|
|||
$subscribe_feed_link = 'dfrn_poll/' . $profile['nickname'];
|
||||
}
|
||||
|
||||
if (Contact::canReceivePrivateMessages($profile)) {
|
||||
if (Contact::canReceivePrivateMessages($profile_contact)) {
|
||||
if ($visitor_is_followed || $visitor_is_following) {
|
||||
$wallmessage_link = $visitor_base_path . '/message/new/' . base64_encode($profile['addr'] ?? '');
|
||||
$wallmessage_link = $visitor_base_path . '/message/new/' . $profile_contact['id'];
|
||||
} elseif ($visitor_is_authenticated && !empty($profile['unkmail'])) {
|
||||
$wallmessage_link = 'wallmessage/' . $profile['nickname'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// show edit profile to yourself
|
||||
if (!$is_contact && $local_user_is_self) {
|
||||
// show edit profile to yourself, but only if this is not meant to be
|
||||
// rendered as a "contact". i.e., if 'self' (a "contact" table column) isn't
|
||||
// set in $profile.
|
||||
if (!isset($profile['self']) && $local_user_is_self) {
|
||||
$profile['edit'] = [DI::baseUrl() . '/settings/profile', DI::l10n()->t('Edit profile'), '', DI::l10n()->t('Edit profile')];
|
||||
$profile['menu'] = [
|
||||
'chg_photo' => DI::l10n()->t('Change profile photo'),
|
||||
|
@ -431,11 +493,9 @@ class Profile
|
|||
$p['address'] = BBCode::convert($p['address']);
|
||||
}
|
||||
|
||||
if (isset($p['photo'])) {
|
||||
$p['photo'] = ProxyUtils::proxifyUrl($p['photo'], false, ProxyUtils::SIZE_SMALL);
|
||||
}
|
||||
$p['photo'] = Contact::getAvatarUrlForId($cid, ProxyUtils::SIZE_SMALL);
|
||||
|
||||
$p['url'] = Contact::magicLink(($p['url'] ?? '') ?: $profile_url);
|
||||
$p['url'] = Contact::magicLinkById($cid);
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('profile/vcard.tpl');
|
||||
$o .= Renderer::replaceMacros($tpl, [
|
||||
|
@ -754,11 +814,11 @@ class Profile
|
|||
// Try to find the public contact entry of the visitor.
|
||||
$cid = Contact::getIdForURL($handle);
|
||||
if (!$cid) {
|
||||
Logger::log('unable to finger ' . $handle, Logger::DEBUG);
|
||||
Logger::info('Handle not found', ['handle' => $handle]);
|
||||
return [];
|
||||
}
|
||||
|
||||
$visitor = DBA::selectFirst('contact', [], ['id' => $cid]);
|
||||
$visitor = Contact::getById($cid);
|
||||
|
||||
// Authenticate the visitor.
|
||||
$_SESSION['authenticated'] = 1;
|
||||
|
@ -777,6 +837,19 @@ class Profile
|
|||
return $visitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the visitor cookies (see remote_user()) for signed HTTP requests
|
||||
* @return array Visitor contact array
|
||||
*/
|
||||
public static function addVisitorCookieForHTTPSigner()
|
||||
{
|
||||
$requester = HTTPSignature::getSigner('', $_SERVER);
|
||||
if (empty($requester)) {
|
||||
return [];
|
||||
}
|
||||
return Profile::addVisitorCookieForHandle($requester);
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenWebAuth authentication.
|
||||
*
|
||||
|
|
113
src/Model/Storage/ExternalResource.php
Normal file
113
src/Model/Storage/ExternalResource.php
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2021, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Model\Storage;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Friendica\Util\HTTPSignature;
|
||||
use Friendica\Network\IHTTPRequest;
|
||||
|
||||
/**
|
||||
* External resource storage class
|
||||
*
|
||||
* This class is used to load external resources, like images.
|
||||
* Is not intended to be selectable by admins as default storage class.
|
||||
*/
|
||||
class ExternalResource implements IStorage
|
||||
{
|
||||
const NAME = 'ExternalResource';
|
||||
|
||||
/** @var IHTTPRequest */
|
||||
private $httpRequest;
|
||||
|
||||
public function __construct(IHTTPRequest $httpRequest)
|
||||
{
|
||||
$this->httpRequest = $httpRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get(string $reference)
|
||||
{
|
||||
$data = json_decode($reference);
|
||||
if (empty($data->url)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
$parts = parse_url($data->url);
|
||||
if (empty($parts['scheme']) || empty($parts['host'])) {
|
||||
return "";
|
||||
}
|
||||
|
||||
$fetchResult = HTTPSignature::fetchRaw($data->url, $data->uid);
|
||||
if ($fetchResult->isSuccess()) {
|
||||
return $fetchResult->getBody();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function put(string $data, string $reference = '')
|
||||
{
|
||||
throw new BadMethodCallException();
|
||||
}
|
||||
|
||||
public function delete(string $reference)
|
||||
{
|
||||
throw new BadMethodCallException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function saveOptions(array $data)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
}
|
|
@ -23,6 +23,8 @@ namespace Friendica\Model\Storage;
|
|||
|
||||
/**
|
||||
* Interface for storage backends
|
||||
*
|
||||
* @todo Split this interface into "IStorage" for get() operations (including Resource fetching) and "IUserStorage" for real user backends including put/delete/options
|
||||
*/
|
||||
interface IStorage
|
||||
{
|
||||
|
|
|
@ -312,8 +312,8 @@ class User
|
|||
*/
|
||||
public static function getIdForURL(string $url)
|
||||
{
|
||||
// Avoid any database requests when the hostname isn't even part of the url.
|
||||
if (!strpos($url, DI::baseUrl()->getHostname())) {
|
||||
// Avoid database queries when the local node hostname isn't even part of the url.
|
||||
if (!Contact::isLocal($url)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -391,7 +391,12 @@ class User
|
|||
if (!DBA::exists('user', ['uid' => $uid]) || !$repairMissing) {
|
||||
return false;
|
||||
}
|
||||
Contact::createSelfFromUserId($uid);
|
||||
if (!DBA::exists('profile', ['uid' => $uid])) {
|
||||
DBA::insert('profile', ['uid' => $uid]);
|
||||
}
|
||||
if (!DBA::exists('contact', ['uid' => $uid, 'self' => true])) {
|
||||
Contact::createSelfFromUserId($uid);
|
||||
}
|
||||
$owner = self::getOwnerDataById($uid, false);
|
||||
}
|
||||
|
||||
|
@ -407,7 +412,7 @@ class User
|
|||
|
||||
// Check for correct url and normalised nurl
|
||||
$url = DI::baseUrl() . '/profile/' . $owner['nickname'];
|
||||
$repair = ($owner['url'] != $url) || ($owner['nurl'] != Strings::normaliseLink($owner['url']));
|
||||
$repair = empty($owner['network']) || ($owner['url'] != $url) || ($owner['nurl'] != Strings::normaliseLink($owner['url']));
|
||||
|
||||
if (!$repair) {
|
||||
// Check if "addr" is present and correct
|
||||
|
@ -1123,6 +1128,8 @@ class User
|
|||
Photo::update(['profile' => 1], ['resource-id' => $resource_id]);
|
||||
}
|
||||
}
|
||||
|
||||
Contact::updateSelfFromUserID($uid, true);
|
||||
}
|
||||
|
||||
Hook::callAll('register_account', $uid);
|
||||
|
@ -1131,6 +1138,42 @@ class User
|
|||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user entry and distribute the changes if needed
|
||||
*
|
||||
* @param array $fields
|
||||
* @param integer $uid
|
||||
* @return boolean
|
||||
*/
|
||||
public static function update(array $fields, int $uid): bool
|
||||
{
|
||||
$old_owner = self::getOwnerDataById($uid);
|
||||
if (empty($old_owner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DBA::update('user', $fields, ['uid' => $uid])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$update = Contact::updateSelfFromUserID($uid);
|
||||
|
||||
$owner = self::getOwnerDataById($uid);
|
||||
if (empty($owner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($old_owner['name'] != $owner['name']) {
|
||||
Profile::update(['name' => $owner['name']], $uid);
|
||||
}
|
||||
|
||||
if ($update) {
|
||||
Profile::publishUpdate($uid);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets block state for a given user
|
||||
*
|
||||
|
@ -1462,6 +1505,10 @@ class User
|
|||
*/
|
||||
public static function identities($uid)
|
||||
{
|
||||
if (empty($uid)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$identities = [];
|
||||
|
||||
$user = DBA::selectFirst('user', ['uid', 'nickname', 'username', 'parent-uid'], ['uid' => $uid]);
|
||||
|
|
|
@ -51,6 +51,8 @@ class Federation extends BaseAdmin
|
|||
'socialhome' => ['name' => 'SocialHome', 'color' => '#52056b'], // lilac from the Django Image used at the Socialhome homepage
|
||||
'wordpress' => ['name' => 'WordPress', 'color' => '#016087'], // Background color of the homepage
|
||||
'writefreely' => ['name' => 'WriteFreely', 'color' => '#292929'], // Font color of the homepage
|
||||
'mistpark' => ['name' => 'Nomad projects (Mistpark, Osada, Roadhouse, Zap)', 'color' => '#348a4a'], // Green like the Mistpark green
|
||||
'relay' => ['name' => 'ActivityPub Relay', 'color' => '#888888'], // Grey like the second color of the ActivityPub logo
|
||||
'other' => ['name' => DI::l10n()->t('Other'), 'color' => '#F1007E'], // ActivityPub main color
|
||||
];
|
||||
|
||||
|
@ -80,6 +82,10 @@ class Federation extends BaseAdmin
|
|||
|
||||
if (in_array($gserver['platform'], ['Red Matrix', 'redmatrix', 'red'])) {
|
||||
$version['version'] = 'Red ' . $version['version'];
|
||||
} elseif (in_array($gserver['platform'], ['osada', 'mistpark', 'roadhouse', 'zap'])) {
|
||||
$version['version'] = $gserver['platform'] . ' ' . $version['version'];
|
||||
} elseif (in_array($gserver['platform'], ['activityrelay', 'pub-relay', 'selective-relay', 'aoderelay'])) {
|
||||
$version['version'] = $gserver['platform'] . '-' . $version['version'];
|
||||
}
|
||||
|
||||
$versionCounts[] = $version;
|
||||
|
@ -92,12 +98,16 @@ class Federation extends BaseAdmin
|
|||
$platform = 'friendica';
|
||||
} elseif (in_array($platform, ['red matrix', 'redmatrix', 'red'])) {
|
||||
$platform = 'hubzilla';
|
||||
} elseif (in_array($platform, ['mistpark', 'osada', 'roadhouse', 'zap'])) {
|
||||
$platform = 'mistpark';
|
||||
} elseif(stristr($platform, 'pleroma')) {
|
||||
$platform = 'pleroma';
|
||||
} elseif(stristr($platform, 'statusnet')) {
|
||||
$platform = 'gnusocial';
|
||||
} elseif(stristr($platform, 'wordpress')) {
|
||||
$platform = 'wordpress';
|
||||
} elseif (in_array($platform, ['activityrelay', 'pub-relay', 'selective-relay', 'aoderelay'])) {
|
||||
$platform = 'relay';
|
||||
} elseif (!in_array($platform, $platforms)) {
|
||||
$platform = 'other';
|
||||
}
|
||||
|
@ -122,9 +132,17 @@ class Federation extends BaseAdmin
|
|||
$versionCounts = self::reformaPleromaVersions($versionCounts);
|
||||
} elseif ($platform == 'diaspora') {
|
||||
$versionCounts = self::reformaDiasporaVersions($versionCounts);
|
||||
} elseif ($platform == 'relay') {
|
||||
$versionCounts = self::reformatRelayVersions($versionCounts);
|
||||
} elseif (in_array($platform, ['funkwhale', 'mastodon', 'mobilizon', 'misskey'])) {
|
||||
$versionCounts = self::removeVersionSuffixes($versionCounts);
|
||||
}
|
||||
|
||||
$versionCounts = self::sortVersion($versionCounts);
|
||||
if (!in_array($platform, ['other', 'relay', 'mistpark'])) {
|
||||
$versionCounts = self::sortVersion($versionCounts);
|
||||
} else {
|
||||
ksort($versionCounts);
|
||||
}
|
||||
|
||||
$gserver['platform'] = $systems[$platform]['name'];
|
||||
|
||||
|
@ -250,6 +268,68 @@ class Federation extends BaseAdmin
|
|||
return $versionCounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up version numbers
|
||||
*
|
||||
* @param array $versionCounts list of version numbers
|
||||
* @return array with cleaned version numbers
|
||||
*/
|
||||
private static function removeVersionSuffixes(array $versionCounts)
|
||||
{
|
||||
$compacted = [];
|
||||
foreach ($versionCounts as $key => $value) {
|
||||
$version = $versionCounts[$key]['version'];
|
||||
|
||||
foreach ([' ', '+', '-', '#', '_', '~'] as $delimiter) {
|
||||
$parts = explode($delimiter, trim($version));
|
||||
$version = array_shift($parts);
|
||||
}
|
||||
|
||||
if (empty($compacted[$version])) {
|
||||
$compacted[$version] = $versionCounts[$key]['total'];
|
||||
} else {
|
||||
$compacted[$version] += $versionCounts[$key]['total'];
|
||||
}
|
||||
}
|
||||
|
||||
$versionCounts = [];
|
||||
foreach ($compacted as $version => $pl_total) {
|
||||
$versionCounts[] = ['version' => $version, 'total' => $pl_total];
|
||||
}
|
||||
|
||||
return $versionCounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up relay version numbers
|
||||
*
|
||||
* @param array $versionCounts list of version numbers
|
||||
* @return array with cleaned version numbers
|
||||
*/
|
||||
private static function reformatRelayVersions(array $versionCounts)
|
||||
{
|
||||
$compacted = [];
|
||||
foreach ($versionCounts as $key => $value) {
|
||||
$version = $versionCounts[$key]['version'];
|
||||
|
||||
$parts = explode(' ', trim($version));
|
||||
$version = array_shift($parts);
|
||||
|
||||
if (empty($compacted[$version])) {
|
||||
$compacted[$version] = $versionCounts[$key]['total'];
|
||||
} else {
|
||||
$compacted[$version] += $versionCounts[$key]['total'];
|
||||
}
|
||||
}
|
||||
|
||||
$versionCounts = [];
|
||||
foreach ($compacted as $version => $pl_total) {
|
||||
$versionCounts[] = ['version' => $version, 'total' => $pl_total];
|
||||
}
|
||||
|
||||
return $versionCounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reformat, sort and compact version numbers
|
||||
*
|
||||
|
|
|
@ -32,6 +32,7 @@ use Friendica\Model\Contact;
|
|||
use Friendica\Model\User;
|
||||
use Friendica\Module\BaseAdmin;
|
||||
use Friendica\Module\Register;
|
||||
use Friendica\Protocol\Relay;
|
||||
use Friendica\Util\BasePath;
|
||||
use Friendica\Util\EMailer\MailBuilder;
|
||||
use Friendica\Util\Strings;
|
||||
|
@ -208,8 +209,6 @@ class Site extends BaseAdmin
|
|||
$worker_fastlane = !empty($_POST['worker_fastlane']);
|
||||
|
||||
$relay_directly = !empty($_POST['relay_directly']);
|
||||
$relay_server = (!empty($_POST['relay_server']) ? Strings::escapeTags(trim($_POST['relay_server'])) : '');
|
||||
$relay_subscribe = !empty($_POST['relay_subscribe']);
|
||||
$relay_scope = (!empty($_POST['relay_scope']) ? Strings::escapeTags(trim($_POST['relay_scope'])) : '');
|
||||
$relay_server_tags = (!empty($_POST['relay_server_tags']) ? Strings::escapeTags(trim($_POST['relay_server_tags'])) : '');
|
||||
$relay_deny_tags = (!empty($_POST['relay_deny_tags']) ? Strings::escapeTags(trim($_POST['relay_deny_tags'])) : '');
|
||||
|
@ -418,8 +417,6 @@ class Site extends BaseAdmin
|
|||
DI::config()->set('system', 'worker_fastlane' , $worker_fastlane);
|
||||
|
||||
DI::config()->set('system', 'relay_directly' , $relay_directly);
|
||||
DI::config()->set('system', 'relay_server' , $relay_server);
|
||||
DI::config()->set('system', 'relay_subscribe' , $relay_subscribe);
|
||||
DI::config()->set('system', 'relay_scope' , $relay_scope);
|
||||
DI::config()->set('system', 'relay_server_tags', $relay_server_tags);
|
||||
DI::config()->set('system', 'relay_deny_tags' , $relay_deny_tags);
|
||||
|
@ -589,6 +586,10 @@ class Site extends BaseAdmin
|
|||
'$performance' => DI::l10n()->t('Performance'),
|
||||
'$worker_title' => DI::l10n()->t('Worker'),
|
||||
'$relay_title' => DI::l10n()->t('Message Relay'),
|
||||
'$relay_description' => DI::l10n()->t('Use the command "console relay" in the command line to add or remove relays.'),
|
||||
'$no_relay_list' => DI::l10n()->t('The system is not subscribed to any relays at the moment.'),
|
||||
'$relay_list_title' => DI::l10n()->t('The system is currently subscribed to the following relays:'),
|
||||
'$relay_list' => Relay::getList(['url']),
|
||||
'$relocate' => DI::l10n()->t('Relocate Instance'),
|
||||
'$relocate_warning' => DI::l10n()->t('<strong>Warning!</strong> Advanced function. Could make this server unreachable.'),
|
||||
'$baseurl' => DI::baseUrl()->get(true),
|
||||
|
@ -688,10 +689,8 @@ class Site extends BaseAdmin
|
|||
'$worker_queues' => ['worker_queues', DI::l10n()->t('Maximum number of parallel workers'), DI::config()->get('system', 'worker_queues'), DI::l10n()->t('On shared hosters set this to %d. On larger systems, values of %d are great. Default value is %d.', 5, 20, 10)],
|
||||
'$worker_fastlane' => ['worker_fastlane', DI::l10n()->t('Enable fastlane'), DI::config()->get('system', 'worker_fastlane'), DI::l10n()->t('When enabed, the fastlane mechanism starts an additional worker if processes with higher priority are blocked by processes of lower priority.')],
|
||||
|
||||
'$relay_subscribe' => ['relay_subscribe', DI::l10n()->t('Use relay servers'), DI::config()->get('system', 'relay_subscribe'), DI::l10n()->t('Enables the receiving of public posts from relay servers. They will be included in the search, subscribed tags and on the global community page.')],
|
||||
'$relay_server' => ['relay_server', DI::l10n()->t('"Social Relay" server'), DI::config()->get('system', 'relay_server'), DI::l10n()->t('Address of the "Social Relay" server where public posts should be send to. For example %s. ActivityRelay servers are administrated via the "console relay" command line command.', 'https://social-relay.isurf.ca')],
|
||||
'$relay_directly' => ['relay_directly', DI::l10n()->t('Direct relay transfer'), DI::config()->get('system', 'relay_directly'), DI::l10n()->t('Enables the direct transfer to other servers without using the relay servers')],
|
||||
'$relay_scope' => ['relay_scope', DI::l10n()->t('Relay scope'), DI::config()->get('system', 'relay_scope'), DI::l10n()->t('Can be "all" or "tags". "all" means that every public post should be received. "tags" means that only posts with selected tags should be received.'), ['' => DI::l10n()->t('Disabled'), 'all' => DI::l10n()->t('all'), 'tags' => DI::l10n()->t('tags')]],
|
||||
'$relay_scope' => ['relay_scope', DI::l10n()->t('Relay scope'), DI::config()->get('system', 'relay_scope'), DI::l10n()->t('Can be "all" or "tags". "all" means that every public post should be received. "tags" means that only posts with selected tags should be received.'), [SR_SCOPE_NONE => DI::l10n()->t('Disabled'), SR_SCOPE_ALL => DI::l10n()->t('all'), SR_SCOPE_TAGS => DI::l10n()->t('tags')]],
|
||||
'$relay_server_tags' => ['relay_server_tags', DI::l10n()->t('Server tags'), DI::config()->get('system', 'relay_server_tags'), DI::l10n()->t('Comma separated list of tags for the "tags" subscription.')],
|
||||
'$relay_deny_tags' => ['relay_deny_tags', DI::l10n()->t('Deny Server tags'), DI::config()->get('system', 'relay_deny_tags'), DI::l10n()->t('Comma separated list of tags that are rejected.')],
|
||||
'$relay_user_tags' => ['relay_user_tags', DI::l10n()->t('Allow user tags'), DI::config()->get('system', 'relay_user_tags'), DI::l10n()->t('If enabled, the tags from the saved searches will used for the "tags" subscription in addition to the "relay_server_tags".')],
|
||||
|
|
|
@ -194,7 +194,7 @@ class Summary extends BaseAdmin
|
|||
];
|
||||
|
||||
$users = 0;
|
||||
$pageFlagsCountStmt = DBA::p('SELECT `page-flags`, COUNT(`uid`) AS `count` FROM `user` GROUP BY `page-flags`');
|
||||
$pageFlagsCountStmt = DBA::p('SELECT `page-flags`, COUNT(`uid`) AS `count` FROM `user` WHERE `uid` != ? GROUP BY `page-flags`', 0);
|
||||
while ($pageFlagsCount = DBA::fetch($pageFlagsCountStmt)) {
|
||||
$accounts[$pageFlagsCount['page-flags']][1] = $pageFlagsCount['count'];
|
||||
$users += $pageFlagsCount['count'];
|
||||
|
|
|
@ -35,16 +35,15 @@ class Index extends BaseApi
|
|||
{
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
if (self::login(self::SCOPE_READ) === false) {
|
||||
throw new HTTPException\ForbiddenException();
|
||||
}
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = self::getRequest([
|
||||
'since_id' => 0,
|
||||
'count' => 0,
|
||||
]);
|
||||
|
||||
$condition = ["`id` > ? AND `uid` = ?", $request['since_id'], self::$current_user_id];
|
||||
$condition = ["`id` > ? AND `uid` = ?", $request['since_id'], $uid];
|
||||
$params = ['limit' => $request['count']];
|
||||
$events = DBA::selectToArray('event', [], $condition, $params);
|
||||
|
||||
|
|
|
@ -37,16 +37,15 @@ class Show extends BaseApi
|
|||
{
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
if (self::login(self::SCOPE_READ) === false) {
|
||||
throw new HTTPException\ForbiddenException();
|
||||
}
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
// retrieve general information about profiles for user
|
||||
$directory = DI::config()->get('system', 'directory');
|
||||
|
||||
$profile = Profile::getByUID(self::$current_user_id);
|
||||
$profile = Profile::getByUID($uid);
|
||||
|
||||
$profileFields = DI::profileField()->select(['uid' => self::$current_user_id, 'psid' => PermissionSet::PUBLIC]);
|
||||
$profileFields = DI::profileField()->select(['uid' => $uid, 'psid' => PermissionSet::PUBLIC]);
|
||||
|
||||
$profile = self::formatProfile($profile, $profileFields);
|
||||
|
||||
|
@ -58,7 +57,7 @@ class Show extends BaseApi
|
|||
}
|
||||
|
||||
// return settings, authenticated user and profiles data
|
||||
$self = Contact::selectFirst(['nurl'], ['uid' => self::$current_user_id, 'self' => true]);
|
||||
$self = Contact::selectFirst(['nurl'], ['uid' => $uid, 'self' => true]);
|
||||
|
||||
$result = [
|
||||
'multi_profiles' => false,
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace Friendica\Module\Api\Mastodon;
|
|||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Module\BaseApi;
|
||||
|
||||
/**
|
||||
|
@ -37,16 +38,27 @@ class Accounts extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
if (empty($parameters['id'])) {
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id']) && empty($parameters['name'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
$id = $parameters['id'];
|
||||
if (!DBA::exists('contact', ['id' => $id, 'uid' => 0])) {
|
||||
DI::mstdnError()->RecordNotFound();
|
||||
if (!empty($parameters['id'])) {
|
||||
$id = $parameters['id'];
|
||||
if (!DBA::exists('contact', ['id' => $id, 'uid' => 0])) {
|
||||
DI::mstdnError()->RecordNotFound();
|
||||
}
|
||||
} else {
|
||||
$contact = Contact::selectFirst(['id'], ['nick' => $parameters['name'], 'uid' => 0]);
|
||||
if (!empty($contact['id'])) {
|
||||
$id = $contact['id'];
|
||||
} elseif (!($id = Contact::getIdForURL($parameters['name'], 0, false))) {
|
||||
DI::mstdnError()->RecordNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
$account = DI::mstdnAccount()->createFromContactId($id, self::getCurrentUserID());
|
||||
$account = DI::mstdnAccount()->createFromContactId($id, $uid);
|
||||
System::jsonExit($account);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ class Block extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_FOLLOW);
|
||||
self::checkAllowedScope(self::SCOPE_FOLLOW);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -33,14 +33,14 @@ class Follow extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_FOLLOW);
|
||||
self::checkAllowedScope(self::SCOPE_FOLLOW);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
$cid = Contact::follow($parameters['id'], self::getCurrentUserID());
|
||||
$cid = Contact::follow($parameters['id'], $uid);
|
||||
|
||||
System::jsonExit(DI::mstdnRelationship()->createFromContactId($cid, $uid)->toArray());
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class Followers extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
@ -54,30 +54,31 @@ class Followers extends BaseApi
|
|||
$request = self::getRequest([
|
||||
'max_id' => 0, // Return results older than this id
|
||||
'since_id' => 0, // Return results newer than this id
|
||||
'limit' => 20, // Maximum number of results to return. Defaults to 20.
|
||||
'limit' => 40, // Maximum number of results to return. Defaults to 40.
|
||||
]);
|
||||
|
||||
$params = ['order' => ['cid' => true], 'limit' => $request['limit']];
|
||||
$params = ['order' => ['relation-cid' => true], 'limit' => $request['limit']];
|
||||
|
||||
$condition = ['relation-cid' => $id, 'follows' => true];
|
||||
$condition = ['cid' => $id, 'follows' => true];
|
||||
|
||||
if (!empty($request['max_id'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`cid` < ?", $request['max_id']]);
|
||||
$condition = DBA::mergeConditions($condition, ["`relation-cid` < ?", $request['max_id']]);
|
||||
}
|
||||
|
||||
if (!empty($request['since_id'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $request['since_id']]);
|
||||
$condition = DBA::mergeConditions($condition, ["`relation-cid` > ?", $request['since_id']]);
|
||||
}
|
||||
|
||||
if (!empty($min_id)) {
|
||||
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $min_id]);
|
||||
$condition = DBA::mergeConditions($condition, ["`relation-cid` > ?", $min_id]);
|
||||
|
||||
$params['order'] = ['cid'];
|
||||
}
|
||||
|
||||
$followers = DBA::select('contact-relation', ['cid'], $condition, $parameters);
|
||||
$followers = DBA::select('contact-relation', ['relation-cid'], $condition, $parameters);
|
||||
while ($follower = DBA::fetch($followers)) {
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($follower['cid'], $uid);
|
||||
self::setBoundaries($follower['relation-cid']);
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($follower['relation-cid'], $uid);
|
||||
}
|
||||
DBA::close($followers);
|
||||
|
||||
|
@ -85,6 +86,7 @@ class Followers extends BaseApi
|
|||
array_reverse($accounts);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($accounts);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class Following extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
@ -57,27 +57,28 @@ class Following extends BaseApi
|
|||
'limit' => 40, // Maximum number of results to return. Defaults to 40.
|
||||
]);
|
||||
|
||||
$params = ['order' => ['relation-cid' => true], 'limit' => $request['limit']];
|
||||
$params = ['order' => ['cid' => true], 'limit' => $request['limit']];
|
||||
|
||||
$condition = ['cid' => $id, 'follows' => true];
|
||||
$condition = ['relation-cid' => $id, 'follows' => true];
|
||||
|
||||
if (!empty($request['max_id'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`relation-cid` < ?", $request['max_id']]);
|
||||
$condition = DBA::mergeConditions($condition, ["`cid` < ?", $request['max_id']]);
|
||||
}
|
||||
|
||||
if (!empty($request['since_id'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`relation-cid` > ?", $request['since_id']]);
|
||||
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $request['since_id']]);
|
||||
}
|
||||
|
||||
if (!empty($min_id)) {
|
||||
$condition = DBA::mergeConditions($condition, ["`relation-cid` > ?", $min_id]);
|
||||
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $min_id]);
|
||||
|
||||
$params['order'] = ['cid'];
|
||||
}
|
||||
|
||||
$followers = DBA::select('contact-relation', ['relation-cid'], $condition, $parameters);
|
||||
$followers = DBA::select('contact-relation', ['cid'], $condition, $parameters);
|
||||
while ($follower = DBA::fetch($followers)) {
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($follower['relation-cid'], $uid);
|
||||
self::setBoundaries($follower['cid']);
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($follower['cid'], $uid);
|
||||
}
|
||||
DBA::close($followers);
|
||||
|
||||
|
@ -85,6 +86,7 @@ class Following extends BaseApi
|
|||
array_reverse($accounts);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($accounts);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ class IdentityProofs extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
|
||||
System::jsonExit([]);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ class Lists extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -33,7 +33,7 @@ class Mute extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_FOLLOW);
|
||||
self::checkAllowedScope(self::SCOPE_FOLLOW);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -34,7 +34,7 @@ class Note extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -37,17 +37,21 @@ class Relationships extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = self::getRequest([
|
||||
'id' => [],
|
||||
]);
|
||||
|
||||
if (empty($request['id']) || !is_array($request['id'])) {
|
||||
if (empty($request['id'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
if (!is_array($request['id'])) {
|
||||
$request['id'] = [$request['id']];
|
||||
}
|
||||
|
||||
$relationsships = [];
|
||||
|
||||
foreach ($request['id'] as $id) {
|
||||
|
|
|
@ -40,7 +40,7 @@ class Search extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = self::getRequest([
|
||||
|
|
|
@ -42,6 +42,8 @@ class Statuses extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
@ -66,8 +68,6 @@ class Statuses extends BaseApi
|
|||
|
||||
$params = ['order' => ['uri-id' => true], 'limit' => $request['limit']];
|
||||
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (!$uid) {
|
||||
$condition = ['author-id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED],
|
||||
'uid' => 0, 'network' => Protocol::FEDERATED];
|
||||
|
@ -108,6 +108,7 @@ class Statuses extends BaseApi
|
|||
|
||||
$statuses = [];
|
||||
while ($item = Post::fetch($items)) {
|
||||
self::setBoundaries($item['uri-id']);
|
||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid);
|
||||
}
|
||||
DBA::close($items);
|
||||
|
@ -116,6 +117,7 @@ class Statuses extends BaseApi
|
|||
array_reverse($statuses);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($statuses);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ class Unblock extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_FOLLOW);
|
||||
self::checkAllowedScope(self::SCOPE_FOLLOW);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -33,7 +33,7 @@ class Unfollow extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_FOLLOW);
|
||||
self::checkAllowedScope(self::SCOPE_FOLLOW);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -33,7 +33,7 @@ class Unmute extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_FOLLOW);
|
||||
self::checkAllowedScope(self::SCOPE_FOLLOW);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
|
||||
namespace Friendica\Module\Api\Mastodon\Accounts;
|
||||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\HTTPInputData;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/accounts/
|
||||
|
@ -31,12 +32,13 @@ class UpdateCredentials extends BaseApi
|
|||
{
|
||||
public static function patch(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$data = Network::postdata();
|
||||
$data = HTTPInputData::process();
|
||||
|
||||
Logger::info('Patch data', ['data' => $data]);
|
||||
|
||||
// @todo Parse the raw data that is in the "multipart/form-data" format
|
||||
self::unsupported('patch');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ class VerifyCredentials extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$self = User::getOwnerDataById($uid);
|
||||
|
|
|
@ -35,7 +35,7 @@ class Announcements extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
|
||||
// @todo Possibly use the message from the pageheader addon for this
|
||||
System::jsonExit([]);
|
||||
|
|
|
@ -50,7 +50,7 @@ class Apps extends BaseApi
|
|||
if (!empty($postdata)) {
|
||||
$postrequest = json_decode($postdata, true);
|
||||
if (!empty($postrequest) && is_array($postrequest)) {
|
||||
$request = array_merge($request, $$postrequest);
|
||||
$request = array_merge($request, $postrequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,6 @@ class Apps extends BaseApi
|
|||
DI::mstdnError()->InternalError();
|
||||
}
|
||||
|
||||
System::jsonExit(DI::mstdnApplication()->createFromApplicationId(DBA::lastInsertId()));
|
||||
System::jsonExit(DI::mstdnApplication()->createFromApplicationId(DBA::lastInsertId())->toArray());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,13 +32,13 @@ class VerifyCredentials extends BaseApi
|
|||
{
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$application = self::getCurrentApplication();
|
||||
|
||||
if (empty($application['id'])) {
|
||||
DI::mstdnError()->Unauthorized();
|
||||
}
|
||||
|
||||
System::jsonExit($application['id']);
|
||||
System::jsonExit(DI::mstdnApplication()->createFromApplicationId($application['id']));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class Blocks extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
@ -77,6 +77,7 @@ class Blocks extends BaseApi
|
|||
|
||||
$followers = DBA::select('user-contact', ['cid'], $condition, $parameters);
|
||||
while ($follower = DBA::fetch($followers)) {
|
||||
self::setBoundaries($follower['cid']);
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($follower['cid'], $uid);
|
||||
}
|
||||
DBA::close($followers);
|
||||
|
@ -85,6 +86,7 @@ class Blocks extends BaseApi
|
|||
array_reverse($accounts);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($accounts);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ class Bookmarks extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = self::getRequest([
|
||||
|
@ -52,7 +52,7 @@ class Bookmarks extends BaseApi
|
|||
|
||||
$params = ['order' => ['uri-id' => true], 'limit' => $request['limit']];
|
||||
|
||||
$condition = ['pinned' => true, 'uid' => $uid];
|
||||
$condition = ['starred' => true, 'uid' => $uid];
|
||||
|
||||
if (!empty($request['max_id'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`uri-id` < ?", $request['max_id']]);
|
||||
|
@ -72,6 +72,7 @@ class Bookmarks extends BaseApi
|
|||
|
||||
$statuses = [];
|
||||
while ($item = Post::fetch($items)) {
|
||||
self::setBoundaries($item['uri-id']);
|
||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid);
|
||||
}
|
||||
DBA::close($items);
|
||||
|
@ -80,6 +81,7 @@ class Bookmarks extends BaseApi
|
|||
array_reverse($statuses);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($statuses);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,11 +29,11 @@ use Friendica\Module\BaseApi;
|
|||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/timelines/conversations/
|
||||
*/
|
||||
class Conversation extends BaseApi
|
||||
class Conversations extends BaseApi
|
||||
{
|
||||
public static function delete(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (!empty($parameters['id'])) {
|
||||
|
@ -52,7 +52,7 @@ class Conversation extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = self::getRequest([
|
||||
|
@ -85,6 +85,7 @@ class Conversation extends BaseApi
|
|||
$conversations = [];
|
||||
|
||||
while ($conv = DBA::fetch($convs)) {
|
||||
self::setBoundaries($conv['id']);
|
||||
$conversations[] = DI::mstdnConversation()->CreateFromConvId($conv['id']);
|
||||
}
|
||||
|
||||
|
@ -94,6 +95,7 @@ class Conversation extends BaseApi
|
|||
array_reverse($conversations);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($conversations);
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Mastodon\Conversation;
|
||||
namespace Friendica\Module\Api\Mastodon\Conversations;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
|
@ -33,7 +33,7 @@ class Read extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (!empty($parameters['id'])) {
|
||||
|
|
|
@ -40,7 +40,7 @@ class Favourited extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
// @todo provide HTTP link header
|
||||
|
@ -70,6 +70,7 @@ class Favourited extends BaseApi
|
|||
|
||||
$statuses = [];
|
||||
while ($item = Post::fetch($items)) {
|
||||
self::setBoundaries($item['thr-parent-id']);
|
||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['thr-parent-id'], $uid);
|
||||
}
|
||||
DBA::close($items);
|
||||
|
@ -78,6 +79,7 @@ class Favourited extends BaseApi
|
|||
array_reverse($statuses);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($statuses);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,12 +29,21 @@ use Friendica\Module\BaseApi;
|
|||
*/
|
||||
class Filters extends BaseApi
|
||||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
|
||||
self::unsupported('post');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $parameters
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
System::jsonError(404, ['error' => 'Record not found']);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
|
||||
System::jsonExit([]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ class FollowRequests extends BaseApi
|
|||
*/
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_FOLLOW);
|
||||
self::checkAllowedScope(self::SCOPE_FOLLOW);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$introduction = DI::intro()->selectFirst(['id' => $parameters['id'], 'uid' => $uid]);
|
||||
|
@ -83,7 +83,7 @@ class FollowRequests extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = self::getRequest([
|
||||
|
@ -92,8 +92,6 @@ class FollowRequests extends BaseApi
|
|||
'limit' => 40, // Maximum number of results to return. Defaults to 40. Paginate using the HTTP Link header.
|
||||
]);
|
||||
|
||||
$baseUrl = DI::baseUrl();
|
||||
|
||||
$introductions = DI::intro()->selectByBoundaries(
|
||||
['`uid` = ? AND NOT `ignore`', $uid],
|
||||
['order' => ['id' => 'DESC']],
|
||||
|
@ -106,6 +104,7 @@ class FollowRequests extends BaseApi
|
|||
|
||||
foreach ($introductions as $key => $introduction) {
|
||||
try {
|
||||
self::setBoundaries($introduction->id);
|
||||
$return[] = DI::mstdnFollowRequest()->createFromIntroduction($introduction);
|
||||
} catch (HTTPException\InternalServerErrorException $exception) {
|
||||
DI::intro()->delete($introduction);
|
||||
|
@ -113,22 +112,7 @@ class FollowRequests extends BaseApi
|
|||
}
|
||||
}
|
||||
|
||||
$base_query = [];
|
||||
if (isset($_GET['limit'])) {
|
||||
$base_query['limit'] = $request['limit'];
|
||||
}
|
||||
|
||||
$links = [];
|
||||
if ($introductions->getTotalCount() > $request['limit']) {
|
||||
$links[] = '<' . $baseUrl->get() . '/api/v1/follow_requests?' . http_build_query($base_query + ['max_id' => $introductions[count($introductions) - 1]->id]) . '>; rel="next"';
|
||||
}
|
||||
|
||||
if (count($introductions)) {
|
||||
$links[] = '<' . $baseUrl->get() . '/api/v1/follow_requests?' . http_build_query($base_query + ['min_id' => $introductions[0]->id]) . '>; rel="prev"';
|
||||
}
|
||||
|
||||
header('Link: ' . implode(', ', $links));
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($return);
|
||||
}
|
||||
}
|
||||
|
|
59
src/Module/Api/Mastodon/Instance/Rules.php
Normal file
59
src/Module/Api/Mastodon/Instance/Rules.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2021, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Mastodon\Instance;
|
||||
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Content\Text\HTML;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\DI;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
||||
/**
|
||||
* Undocumented API endpoint
|
||||
*/
|
||||
class Rules extends BaseApi
|
||||
{
|
||||
/**
|
||||
* @param array $parameters
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
$rules = [];
|
||||
$id = 0;
|
||||
|
||||
if (DI::config()->get('system', 'tosdisplay')) {
|
||||
$html = BBCode::convert(DI::config()->get('system', 'tostext'), false, BBCode::EXTERNAL);
|
||||
|
||||
$msg = HTML::toPlaintext($html, 0, true);
|
||||
foreach (explode("\n", $msg) as $line) {
|
||||
$line = trim($line);
|
||||
if ($line) {
|
||||
$rules[] = ['id' => (string)++$id, 'text' => $line];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System::jsonExit($rules);
|
||||
}
|
||||
}
|
|
@ -33,8 +33,7 @@ class Lists extends BaseApi
|
|||
{
|
||||
public static function delete(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
@ -54,9 +53,8 @@ class Lists extends BaseApi
|
|||
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
|
||||
$uid = self::getCurrentUserID();
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = self::getRequest([
|
||||
'title' => '',
|
||||
|
@ -78,13 +76,16 @@ class Lists extends BaseApi
|
|||
|
||||
public static function put(array $parameters = [])
|
||||
{
|
||||
$data = self::getPutData();
|
||||
$request = self::getRequest([
|
||||
'title' => '', // The title of the list to be updated.
|
||||
'replies_policy' => '', // One of: "followed", "list", or "none".
|
||||
]);
|
||||
|
||||
if (empty($data['title']) || empty($parameters['id'])) {
|
||||
if (empty($request['title']) || empty($parameters['id'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
Group::update($parameters['id'], $data['title']);
|
||||
Group::update($parameters['id'], $request['title']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,7 +94,7 @@ class Lists extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -49,7 +49,7 @@ class Accounts extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
@ -95,6 +95,7 @@ class Accounts extends BaseApi
|
|||
|
||||
$members = DBA::select('group_member', ['contact-id'], $condition, $params);
|
||||
while ($member = DBA::fetch($members)) {
|
||||
self::setBoundaries($member['contact-id']);
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($member['contact-id'], $uid);
|
||||
}
|
||||
DBA::close($members);
|
||||
|
@ -103,6 +104,7 @@ class Accounts extends BaseApi
|
|||
array_reverse($accounts);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($accounts);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class Markers extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
|
||||
self::unsupported('post');
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class Markers extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
|
||||
System::jsonExit([]);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class Media extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
Logger::info('Photo post', ['request' => $_REQUEST, 'files' => $_FILES]);
|
||||
|
@ -55,10 +55,15 @@ class Media extends BaseApi
|
|||
|
||||
public static function put(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$data = self::getPutData();
|
||||
$request = self::getRequest([
|
||||
'file' => [], // The file to be attached, using multipart form data.
|
||||
'thumbnail' => [], // The custom thumbnail of the media to be attached, using multipart form data.
|
||||
'description' => '', // A plain-text description of the media, for accessibility purposes.
|
||||
'focus' => '', // Two floating points (x,y), comma-delimited ranging from -1.0 to 1.0
|
||||
]);
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
|
@ -69,7 +74,7 @@ class Media extends BaseApi
|
|||
DI::mstdnError()->RecordNotFound();
|
||||
}
|
||||
|
||||
Photo::update(['desc' => $data['description'] ?? ''], ['resource-id' => $photo['resource-id']]);
|
||||
Photo::update(['desc' => $request['description']], ['resource-id' => $photo['resource-id']]);
|
||||
|
||||
System::jsonExit(DI::mstdnAttachment()->createFromPhoto($parameters['id']));
|
||||
}
|
||||
|
@ -80,7 +85,7 @@ class Media extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -37,7 +37,7 @@ class Mutes extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
@ -77,6 +77,7 @@ class Mutes extends BaseApi
|
|||
|
||||
$followers = DBA::select('user-contact', ['cid'], $condition, $parameters);
|
||||
while ($follower = DBA::fetch($followers)) {
|
||||
self::setBoundaries($follower['cid']);
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($follower['cid'], $uid);
|
||||
}
|
||||
DBA::close($followers);
|
||||
|
@ -85,6 +86,7 @@ class Mutes extends BaseApi
|
|||
array_reverse($accounts);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($accounts);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,10 @@ use Friendica\Core\System;
|
|||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Notification;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\Verb;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Protocol\Activity;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/notifications/
|
||||
|
@ -39,15 +41,15 @@ class Notifications extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (!empty($parameters['id'])) {
|
||||
$id = $parameters['id'];
|
||||
if (!DBA::exists('notify', ['id' => $id, 'uid' => $uid])) {
|
||||
if (!DBA::exists('notification', ['id' => $id, 'uid' => $uid])) {
|
||||
DI::mstdnError()->RecordNotFound();
|
||||
}
|
||||
System::jsonExit(DI::mstdnNotification()->createFromNotifyId($id));
|
||||
System::jsonExit(DI::mstdnNotification()->createFromNotificationId($id));
|
||||
}
|
||||
|
||||
$request = self::getRequest([
|
||||
|
@ -63,7 +65,7 @@ class Notifications extends BaseApi
|
|||
|
||||
$params = ['order' => ['id' => true], 'limit' => $request['limit']];
|
||||
|
||||
$condition = ['uid' => $uid, 'seen' => false, 'type' => []];
|
||||
$condition = ['uid' => $uid, 'seen' => false];
|
||||
|
||||
if (!empty($request['account_id'])) {
|
||||
$contact = Contact::getById($request['account_id'], ['url']);
|
||||
|
@ -72,17 +74,40 @@ class Notifications extends BaseApi
|
|||
}
|
||||
}
|
||||
|
||||
if (!in_array('follow_request', $request['exclude_types'])) {
|
||||
$condition['type'] = array_merge($condition['type'], [Notification\Type::INTRO]);
|
||||
if (in_array('follow_request', $request['exclude_types'])) {
|
||||
$condition = DBA::mergeConditions($condition,
|
||||
["(`vid` != ? OR `type` != ? OR NOT EXISTS (SELECT `id` FROM `contact` WHERE `id` = `actor-id` AND `pending`))",
|
||||
Verb::getID(Activity::FOLLOW), Post\UserNotification::NOTIF_NONE]);
|
||||
}
|
||||
|
||||
if (!in_array('mention', $request['exclude_types'])) {
|
||||
$condition['type'] = array_merge($condition['type'],
|
||||
[Notification\Type::WALL, Notification\Type::COMMENT, Notification\Type::MAIL, Notification\Type::TAG_SELF, Notification\Type::POKE]);
|
||||
if (in_array('follow', $request['exclude_types'])) {
|
||||
$condition = DBA::mergeConditions($condition,
|
||||
["(`vid` != ? OR `type` != ? OR NOT EXISTS (SELECT `id` FROM `contact` WHERE `id` = `actor-id` AND NOT `pending`))",
|
||||
Verb::getID(Activity::FOLLOW), Post\UserNotification::NOTIF_NONE]);
|
||||
}
|
||||
|
||||
if (!in_array('status', $request['exclude_types'])) {
|
||||
$condition['type'] = array_merge($condition['type'], [Notification\Type::SHARE]);
|
||||
if (in_array('favourite', $request['exclude_types'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["(NOT `vid` IN (?, ?) OR NOT `type` IN (?, ?))",
|
||||
Verb::getID(Activity::LIKE), Verb::getID(Activity::DISLIKE),
|
||||
Post\UserNotification::NOTIF_DIRECT_COMMENT, Post\UserNotification::NOTIF_THREAD_COMMENT]);
|
||||
}
|
||||
|
||||
if (in_array('reblog', $request['exclude_types'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["(NOT `vid` IN (?) OR NOT `type` IN (?, ?))",
|
||||
Verb::getID(Activity::ANNOUNCE),
|
||||
Post\UserNotification::NOTIF_DIRECT_COMMENT, Post\UserNotification::NOTIF_THREAD_COMMENT]);
|
||||
}
|
||||
|
||||
if (in_array('mention', $request['exclude_types'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["(NOT `vid` IN (?) OR NOT `type` IN (?, ?, ?, ?, ?))",
|
||||
Verb::getID(Activity::POST), Post\UserNotification::NOTIF_EXPLICIT_TAGGED,
|
||||
Post\UserNotification::NOTIF_IMPLICIT_TAGGED, Post\UserNotification::NOTIF_DIRECT_COMMENT,
|
||||
Post\UserNotification::NOTIF_DIRECT_THREAD_COMMENT, Post\UserNotification::NOTIF_THREAD_COMMENT]);
|
||||
}
|
||||
|
||||
if (in_array('status', $request['exclude_types'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["(NOT `vid` IN (?) OR NOT `type` IN (?))",
|
||||
Verb::getID(Activity::POST), Post\UserNotification::NOTIF_SHARED]);
|
||||
}
|
||||
|
||||
if (!empty($request['max_id'])) {
|
||||
|
@ -101,15 +126,20 @@ class Notifications extends BaseApi
|
|||
|
||||
$notifications = [];
|
||||
|
||||
$notify = DBA::select('notify', ['id'], $condition, $params);
|
||||
$notify = DBA::select('notification', ['id'], $condition, $params);
|
||||
while ($notification = DBA::fetch($notify)) {
|
||||
$notifications[] = DI::mstdnNotification()->createFromNotifyId($notification['id']);
|
||||
self::setBoundaries($notification['id']);
|
||||
$entry = DI::mstdnNotification()->createFromNotificationId($notification['id']);
|
||||
if (!empty($entry)) {
|
||||
$notifications[] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($request['min_id'])) {
|
||||
array_reverse($notifications);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($notifications);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,10 +32,10 @@ class Clear extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
DBA::update('notify', ['seen' => true], ['uid' => $uid]);
|
||||
DBA::update('notification', ['seen' => true], ['uid' => $uid]);
|
||||
|
||||
System::jsonExit([]);
|
||||
}
|
||||
|
|
|
@ -33,14 +33,14 @@ class Dismiss extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
DBA::update('notify', ['seen' => true], ['uid' => $uid, 'id' => $parameters['id']]);
|
||||
DBA::update('notification', ['seen' => true], ['uid' => $uid, 'id' => $parameters['id']]);
|
||||
|
||||
System::jsonExit([]);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class Preferences extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$user = User::getById($uid, ['language', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']);
|
||||
|
@ -52,7 +52,7 @@ class Preferences extends BaseApi
|
|||
$sensitive = false;
|
||||
$language = $user['language'];
|
||||
$media = DI::pConfig()->get($uid, 'nsfw', 'disable') ? 'show_all' : 'default';
|
||||
$spoilers = DI::pConfig()->get($uid, 'system', 'disable_cw');
|
||||
$spoilers = (bool)DI::pConfig()->get($uid, 'system', 'disable_cw');
|
||||
|
||||
$preferences = new \Friendica\Object\Api\Mastodon\Preferences($visibility, $sensitive, $language, $media, $spoilers);
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class Search extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = self::getRequest([
|
||||
|
@ -162,6 +162,7 @@ class Search extends BaseApi
|
|||
|
||||
$statuses = [];
|
||||
while ($item = Post::fetch($items)) {
|
||||
self::setBoundaries($item['uri-id']);
|
||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid);
|
||||
}
|
||||
DBA::close($items);
|
||||
|
@ -170,6 +171,7 @@ class Search extends BaseApi
|
|||
array_reverse($statuses);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,24 +43,25 @@ class Statuses extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$data = self::getJsonPostData();
|
||||
|
||||
$status = $data['status'] ?? '';
|
||||
$media_ids = $data['media_ids'] ?? [];
|
||||
$in_reply_to_id = $data['in_reply_to_id'] ?? 0;
|
||||
$sensitive = $data['sensitive'] ?? false; // @todo Possibly trigger "nsfw" flag?
|
||||
$spoiler_text = $data['spoiler_text'] ?? '';
|
||||
$visibility = $data['visibility'] ?? '';
|
||||
$scheduled_at = $data['scheduled_at'] ?? ''; // Currently unsupported, but maybe in the future
|
||||
$language = $data['language'] ?? '';
|
||||
$request = self::getRequest([
|
||||
'status' => '', // Text content of the status. If media_ids is provided, this becomes optional. Attaching a poll is optional while status is provided.
|
||||
'media_ids' => [], // Array of Attachment ids to be attached as media. If provided, status becomes optional, and poll cannot be used.
|
||||
'poll' => [], // Poll data. If provided, media_ids cannot be used, and poll[expires_in] must be provided.
|
||||
'in_reply_to_id' => 0, // ID of the status being replied to, if status is a reply
|
||||
'sensitive' => false, // Mark status and attached media as sensitive?
|
||||
'spoiler_text' => '', // Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field.
|
||||
'visibility' => '', // Visibility of the posted status. One of: "public", "unlisted", "private" or "direct".
|
||||
'scheduled_at' => '', // ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future.
|
||||
'language' => '', // ISO 639 language code for this status.
|
||||
]);
|
||||
|
||||
$owner = User::getOwnerDataById($uid);
|
||||
|
||||
// The imput is defined as text. So we can use Markdown for some enhancements
|
||||
$body = Markdown::toBBCode($status);
|
||||
$body = Markdown::toBBCode($request['status']);
|
||||
|
||||
$body = BBCode::expandTags($body);
|
||||
|
||||
|
@ -69,7 +70,7 @@ class Statuses extends BaseApi
|
|||
$item['verb'] = Activity::POST;
|
||||
$item['contact-id'] = $owner['id'];
|
||||
$item['author-id'] = $item['owner-id'] = Contact::getPublicIdByUserId($uid);
|
||||
$item['title'] = $spoiler_text;
|
||||
$item['title'] = $request['spoiler_text'];
|
||||
$item['body'] = $body;
|
||||
|
||||
if (!empty(self::getCurrentApplication()['name'])) {
|
||||
|
@ -80,7 +81,7 @@ class Statuses extends BaseApi
|
|||
$item['app'] = 'API';
|
||||
}
|
||||
|
||||
switch ($visibility) {
|
||||
switch ($request['visibility']) {
|
||||
case 'public':
|
||||
$item['allow_cid'] = '';
|
||||
$item['allow_gid'] = '';
|
||||
|
@ -112,7 +113,7 @@ class Statuses extends BaseApi
|
|||
case 'direct':
|
||||
// Direct messages are currently unsupported
|
||||
DI::mstdnError()->InternalError('Direct messages are currently unsupported');
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
$item['allow_cid'] = $owner['allow_cid'];
|
||||
$item['allow_gid'] = $owner['allow_gid'];
|
||||
|
@ -129,12 +130,12 @@ class Statuses extends BaseApi
|
|||
break;
|
||||
}
|
||||
|
||||
if (!empty($language)) {
|
||||
$item['language'] = json_encode([$language => 1]);
|
||||
if (!empty($request['language'])) {
|
||||
$item['language'] = json_encode([$request['language'] => 1]);
|
||||
}
|
||||
|
||||
if ($in_reply_to_id) {
|
||||
$parent = Post::selectFirst(['uri'], ['uri-id' => $in_reply_to_id, 'uid' => [0, $uid]]);
|
||||
if ($request['in_reply_to_id']) {
|
||||
$parent = Post::selectFirst(['uri'], ['uri-id' => $request['in_reply_to_id'], 'uid' => [0, $uid]]);
|
||||
$item['thr-parent'] = $parent['uri'];
|
||||
$item['gravity'] = GRAVITY_COMMENT;
|
||||
$item['object-type'] = Activity\ObjectType::COMMENT;
|
||||
|
@ -143,16 +144,16 @@ class Statuses extends BaseApi
|
|||
$item['object-type'] = Activity\ObjectType::NOTE;
|
||||
}
|
||||
|
||||
if (!empty($media_ids)) {
|
||||
if (!empty($request['media_ids'])) {
|
||||
$item['object-type'] = Activity\ObjectType::IMAGE;
|
||||
$item['post-type'] = Item::PT_IMAGE;
|
||||
$item['attachments'] = [];
|
||||
|
||||
foreach ($media_ids as $id) {
|
||||
foreach ($request['media_ids'] as $id) {
|
||||
$media = DBA::toArray(DBA::p("SELECT `resource-id`, `scale`, `type`, `desc`, `filename`, `datasize`, `width`, `height` FROM `photo`
|
||||
WHERE `resource-id` IN (SELECT `resource-id` FROM `photo` WHERE `id` = ?) AND `photo`.`uid` = ?
|
||||
ORDER BY `photo`.`width` DESC LIMIT 2", $id, $uid));
|
||||
|
||||
|
||||
if (empty($media)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -162,7 +163,7 @@ class Statuses extends BaseApi
|
|||
$ressources[] = $media[0]['resource-id'];
|
||||
$phototypes = Images::supportedTypes();
|
||||
$ext = $phototypes[$media[0]['type']];
|
||||
|
||||
|
||||
$attachment = ['type' => Post\Media::IMAGE, 'mimetype' => $media[0]['type'],
|
||||
'url' => DI::baseUrl() . '/photo/' . $media[0]['resource-id'] . '-' . $media[0]['scale'] . '.' . $ext,
|
||||
'size' => $media[0]['datasize'],
|
||||
|
@ -170,7 +171,7 @@ class Statuses extends BaseApi
|
|||
'description' => $media[0]['desc'] ?? '',
|
||||
'width' => $media[0]['width'],
|
||||
'height' => $media[0]['height']];
|
||||
|
||||
|
||||
if (count($media) > 1) {
|
||||
$attachment['preview'] = DI::baseUrl() . '/photo/' . $media[1]['resource-id'] . '-' . $media[1]['scale'] . '.' . $ext;
|
||||
$attachment['preview-width'] = $media[1]['width'];
|
||||
|
@ -184,7 +185,7 @@ class Statuses extends BaseApi
|
|||
if (!empty($id)) {
|
||||
$item = Post::selectFirst(['uri-id'], ['id' => $id]);
|
||||
if (!empty($item['uri-id'])) {
|
||||
System::jsonExit(DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid));
|
||||
System::jsonExit(DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,7 +194,7 @@ class Statuses extends BaseApi
|
|||
|
||||
public static function delete(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_READ);
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
@ -218,10 +219,12 @@ class Statuses extends BaseApi
|
|||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], self::getCurrentUserID()));
|
||||
System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ class Bookmark extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -44,6 +44,10 @@ class Context extends BaseApi
|
|||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
$request = self::getRequest([
|
||||
'limit' => 40, // Maximum number of results to return. Defaults to 40.
|
||||
]);
|
||||
|
||||
$id = $parameters['id'];
|
||||
|
||||
$parent = Post::selectFirst(['parent-uri-id'], ['uri-id' => $id]);
|
||||
|
@ -54,8 +58,8 @@ class Context extends BaseApi
|
|||
$parents = [];
|
||||
$children = [];
|
||||
|
||||
$posts = Post::select(['uri-id', 'thr-parent-id'],
|
||||
['parent-uri-id' => $parent['parent-uri-id'], 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]], [], false);
|
||||
$posts = Post::selectPosts(['uri-id', 'thr-parent-id'],
|
||||
['parent-uri-id' => $parent['parent-uri-id'], 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]], []);
|
||||
while ($post = Post::fetch($posts)) {
|
||||
if ($post['uri-id'] == $post['thr-parent-id']) {
|
||||
continue;
|
||||
|
@ -68,24 +72,20 @@ class Context extends BaseApi
|
|||
|
||||
$statuses = ['ancestors' => [], 'descendants' => []];
|
||||
|
||||
$ancestors = [];
|
||||
foreach (self::getParents($id, $parents) as $ancestor) {
|
||||
$ancestors[$ancestor] = DI::mstdnStatus()->createFromUriId($ancestor, $uid);
|
||||
$ancestors = self::getParents($id, $parents);
|
||||
|
||||
asort($ancestors);
|
||||
|
||||
foreach (array_slice($ancestors, 0, $request['limit']) as $ancestor) {
|
||||
$statuses['ancestors'][] = DI::mstdnStatus()->createFromUriId($ancestor, $uid);;
|
||||
}
|
||||
|
||||
ksort($ancestors);
|
||||
foreach ($ancestors as $ancestor) {
|
||||
$statuses['ancestors'][] = $ancestor;
|
||||
}
|
||||
$descendants = self::getChildren($id, $children);
|
||||
|
||||
$descendants = [];
|
||||
foreach (self::getChildren($id, $children) as $descendant) {
|
||||
$descendants[] = DI::mstdnStatus()->createFromUriId($descendant, $uid);
|
||||
}
|
||||
asort($descendants);
|
||||
|
||||
ksort($descendants);
|
||||
foreach ($descendants as $descendant) {
|
||||
$statuses['descendants'][] = $descendant;
|
||||
foreach (array_slice($descendants, 0, $request['limit']) as $descendant) {
|
||||
$statuses['descendants'][] = DI::mstdnStatus()->createFromUriId($descendant, $uid);
|
||||
}
|
||||
|
||||
System::jsonExit($statuses);
|
||||
|
|
|
@ -35,7 +35,7 @@ class Favourite extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -49,7 +49,7 @@ class FavouritedBy extends BaseApi
|
|||
DI::mstdnError()->RecordNotFound();
|
||||
}
|
||||
|
||||
$activities = Post::select(['author-id'], ['thr-parent-id' => $id, 'gravity' => GRAVITY_ACTIVITY, 'verb' => Activity::LIKE], [], false);
|
||||
$activities = Post::selectPosts(['author-id'], ['thr-parent-id' => $id, 'gravity' => GRAVITY_ACTIVITY, 'verb' => Activity::LIKE]);
|
||||
|
||||
$accounts = [];
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class Mute extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
|
@ -34,7 +34,7 @@ class Pin extends BaseApi
|
|||
{
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
self::login(self::SCOPE_WRITE);
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($parameters['id'])) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue