1
0
Fork 0

Merge branch 'develop' into mastodon-timeline-temporal-paging

This commit is contained in:
Hank Grabowski 2023-02-27 20:20:40 -05:00
commit 6ffd3a3f8c
45 changed files with 798 additions and 138 deletions

View file

@ -73,7 +73,12 @@ class Avatar
return $fields;
}
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
try {
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
} catch (\Exception $exception) {
Logger::notice('Avatar is invalid', ['avatar' => $avatar, 'exception' => $exception]);
return $fields;
}
$img_str = $fetchResult->getBody();
if (empty($img_str)) {

View file

@ -437,7 +437,7 @@ class BBCode
* @param boolean $no_link_desc No link description
* @return string with replaced body
*/
public static function removeAttachment(string $body, bool $no_link_desc = false): string
public static function replaceAttachment(string $body, bool $no_link_desc = false): string
{
return preg_replace_callback("/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism",
function ($match) use ($body, $no_link_desc) {
@ -454,6 +454,17 @@ class BBCode
}, $body);
}
/**
* Remove [attachment] BBCode
*
* @param string $body
* @return string with removed attachment
*/
public static function removeAttachment(string $body): string
{
return trim(preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body));
}
/**
* Converts a BBCode text into plaintext
*
@ -469,7 +480,7 @@ class BBCode
$text = preg_replace("/\[img.*?\[\/img\]/ism", ' ', $text);
// Remove attachment
$text = self::removeAttachment($text);
$text = self::replaceAttachment($text);
$naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls);
@ -1583,9 +1594,9 @@ class BBCode
/// @todo Have a closer look at the different html modes
// Handle attached links or videos
if (in_array($simple_html, [self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) {
$text = self::removeAttachment($text);
$text = self::replaceAttachment($text);
} elseif (!in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::CONNECTORS])) {
$text = self::removeAttachment($text, true);
$text = self::replaceAttachment($text, true);
} else {
$text = self::convertAttachment($text, $simple_html, $try_oembed, [], $uriid);
}

View file

@ -168,7 +168,7 @@ class StorageManager
return $data['storage_config'];
} catch (InternalServerErrorException $exception) {
throw new StorageException(sprintf('Failed calling hook::storage_config for backend %s', $name), $exception);
throw new StorageException(sprintf('Failed calling hook::storage_config for backend %s', $name), $exception->__toString());
}
}
}
@ -208,7 +208,7 @@ class StorageManager
$this->backendInstances[$name] = new Type\SystemResource();
break;
case Type\ExternalResource::getName():
$this->backendInstances[$name] = new Type\ExternalResource();
$this->backendInstances[$name] = new Type\ExternalResource($this->logger);
break;
default:
$data = [
@ -223,7 +223,7 @@ class StorageManager
$this->backendInstances[$data['name'] ?? $name] = $data['storage'];
} catch (InternalServerErrorException $exception) {
throw new StorageException(sprintf('Failed calling hook::storage_instance for backend %s', $name), $exception);
throw new StorageException(sprintf('Failed calling hook::storage_instance for backend %s', $name), $exception->__toString());
}
break;
}

View file

@ -22,12 +22,12 @@
namespace Friendica\Core\Storage\Type;
use Exception;
use Friendica\Core\Logger;
use Friendica\Core\Storage\Exception\ReferenceStorageException;
use Friendica\Core\Storage\Capability\ICanReadFromStorage;
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
use Friendica\Util\HTTPSignature;
use Psr\Log\LoggerInterface;
/**
* External resource storage class
@ -39,6 +39,14 @@ class ExternalResource implements ICanReadFromStorage
{
const NAME = 'ExternalResource';
/** @var LoggerInterface */
protected $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* @inheritDoc
*/
@ -57,10 +65,11 @@ class ExternalResource implements ICanReadFromStorage
try {
$fetchResult = HTTPSignature::fetchRaw($data->url, $data->uid, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
} catch (Exception $exception) {
$this->logger->notice('URL is invalid', ['url' => $data->url, 'error' => $exception]);
throw new ReferenceStorageException(sprintf('External resource failed to get %s', $reference), $exception->getCode(), $exception);
}
if (!empty($fetchResult) && $fetchResult->isSuccess()) {
Logger::debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => $data->uid, 'url' => $data->url]);
$this->logger->debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => $data->uid, 'url' => $data->url]);
return $fetchResult->getBody();
} else {
if (empty($fetchResult)) {

View file

@ -64,7 +64,7 @@ class Notification extends BaseFactory
if ($Notification->targetUriId) {
try {
$status = $this->mstdnStatusFactory->createFromUriId($Notification->targetUriId, $Notification->uid, $display_quotes);
} catch (\Throwable $th) {
} catch (\Exception $exception) {
$status = null;
}
} else {

View file

@ -38,14 +38,14 @@ class Relationship extends BaseFactory
public function createFromContactId(int $contactId, int $uid): RelationshipEntity
{
$cdata = Contact::getPublicAndUserContactID($contactId, $uid);
if (!empty($cdata)) {
$cid = $cdata['user'];
$pcid = $cdata['public'];
} else {
$pcid = $cid = $contactId;
}
$pcid = !empty($cdata['public']) ? $cdata['public'] : $contactId;
$cid = !empty($cdata['user']) ? $cdata['user'] : $contactId;
return new RelationshipEntity($pcid, Contact::getById($cid),
Contact\User::isBlocked($cid, $uid), Contact\User::isIgnored($cid, $uid));
return new RelationshipEntity(
$pcid,
Contact::getById($cid),
Contact\User::isBlocked($cid, $uid),
Contact\User::isIgnored($cid, $uid)
);
}
}

View file

@ -33,6 +33,8 @@ use Friendica\Model\Post;
use Friendica\Model\Tag as TagModel;
use Friendica\Model\Verb;
use Friendica\Network\HTTPException;
use Friendica\Object\Api\Mastodon\Status\FriendicaDeliveryData;
use Friendica\Object\Api\Mastodon\Status\FriendicaExtension;
use Friendica\Protocol\Activity;
use Friendica\Protocol\ActivityPub;
use ImagickException;
@ -97,7 +99,8 @@ class Status extends BaseFactory
public function createFromUriId(int $uriId, int $uid = 0, bool $display_quote = false, bool $reblog = true, bool $in_reply_status = true): \Friendica\Object\Api\Mastodon\Status
{
$fields = ['uri-id', 'uid', 'author-id', 'causer-id', 'author-uri-id', 'author-link', 'causer-uri-id', 'post-reason', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id',
'created', 'network', 'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity', 'featured', 'has-media', 'quote-uri-id'];
'created', 'network', 'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity', 'featured', 'has-media', 'quote-uri-id',
'delivery_queue_count', 'delivery_queue_done','delivery_queue_failed'];
$item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
if (!$item) {
$mail = DBA::selectFirst('mail', ['id'], ['uri-id' => $uriId, 'uid' => $uid]);
@ -266,8 +269,8 @@ class Status extends BaseFactory
if ($is_reshare) {
try {
$reshare = $this->createFromUriId($uriId, $uid, $display_quote, false, false)->toArray();
} catch (\Throwable $th) {
Logger::info('Reshare not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Reshare not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
$reshare = [];
}
} else {
@ -277,15 +280,18 @@ class Status extends BaseFactory
if ($in_reply_status && ($item['gravity'] == Item::GRAVITY_COMMENT)) {
try {
$in_reply = $this->createFromUriId($item['thr-parent-id'], $uid, $display_quote, false, false)->toArray();
} catch (\Throwable $th) {
Logger::info('Reply post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Reply post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
$in_reply = [];
}
} else {
$in_reply = [];
}
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare, $quote, $poll);
$delivery_data = new FriendicaDeliveryData($item['delivery_queue_count'], $item['delivery_queue_done'], $item['delivery_queue_failed']);
$friendica = new FriendicaExtension($item['title'], $counts->dislikes, $delivery_data);
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare, $friendica, $quote, $poll);
}
/**
@ -309,8 +315,8 @@ class Status extends BaseFactory
if (!empty($quote_id)) {
try {
$quote = $this->createFromUriId($quote_id, $uid, false, false, false)->toArray();
} catch (\Throwable $th) {
Logger::info('Quote not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Quote not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
$quote = [];
}
} else {
@ -349,7 +355,8 @@ class Status extends BaseFactory
$attachments = [];
$in_reply = [];
$reshare = [];
$friendica = new FriendicaExtension('', 0, new FriendicaDeliveryData(0, 0, 0));
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare);
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare, $friendica);
}
}

View file

@ -189,17 +189,22 @@ class APContact
if (empty($data)) {
$local_owner = [];
$curlResult = HTTPSignature::fetchRaw($url);
$failed = empty($curlResult) || empty($curlResult->getBody()) ||
(!$curlResult->isSuccess() && ($curlResult->getReturnCode() != 410));
try {
$curlResult = HTTPSignature::fetchRaw($url);
$failed = empty($curlResult) || empty($curlResult->getBody()) ||
(!$curlResult->isSuccess() && ($curlResult->getReturnCode() != 410));
if (!$failed) {
$data = json_decode($curlResult->getBody(), true);
$failed = empty($data) || !is_array($data);
}
if (!$failed) {
$data = json_decode($curlResult->getBody(), true);
$failed = empty($data) || !is_array($data);
}
if (!$failed && ($curlResult->getReturnCode() == 410)) {
$data = ['@context' => ActivityPub::CONTEXT, 'id' => $url, 'type' => 'Tombstone'];
if (!$failed && ($curlResult->getReturnCode() == 410)) {
$data = ['@context' => ActivityPub::CONTEXT, 'id' => $url, 'type' => 'Tombstone'];
}
} catch (\Exception $exception) {
Logger::notice('Error fetching url', ['url' => $url, 'exception' => $exception]);
$failed = true;
}
if ($failed) {

View file

@ -2216,16 +2216,21 @@ class Contact
if (($contact['avatar'] != $avatar) || empty($contact['blurhash'])) {
$update_fields = ['avatar' => $avatar];
if (!Network::isLocalLink($avatar)) {
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
try {
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
$img_str = $fetchResult->getBody();
if (!empty($img_str)) {
$image = new Image($img_str, Images::getMimeTypeByData($img_str));
if ($image->isValid()) {
$update_fields['blurhash'] = $image->getBlurHash();
} else {
return;
$img_str = $fetchResult->getBody();
if (!empty($img_str)) {
$image = new Image($img_str, Images::getMimeTypeByData($img_str));
if ($image->isValid()) {
$update_fields['blurhash'] = $image->getBlurHash();
} else {
return;
}
}
} catch (\Exception $exception) {
Logger::notice('Error fetching avatar', ['avatar' => $avatar, 'exception' => $exception]);
return;
}
} elseif (!empty($contact['blurhash'])) {
$update_fields['blurhash'] = null;

View file

@ -210,8 +210,6 @@ class Item
}
}
Post\Media::insertFromAttachmentData($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
@ -220,6 +218,10 @@ class Item
$content_fields['raw-body'] = self::setHashtags($content_fields['raw-body']);
Post\Media::insertFromRelevantUrl($item['uri-id'], $content_fields['raw-body'], $fields['body'], $item['author-network']);
Post\Media::insertFromAttachmentData($item['uri-id'], $fields['body']);
$content_fields['raw-body'] = BBCode::removeAttachment($content_fields['raw-body']);
Post\Content::update($item['uri-id'], $content_fields);
}
@ -1143,8 +1145,6 @@ class Item
$item['body'] = BBCode::removeSharedData($item['body']);
}
Post\Media::insertFromAttachmentData($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']);
@ -1152,6 +1152,10 @@ class Item
$author = Contact::getById($item['author-id'], ['network']);
Post\Media::insertFromRelevantUrl($item['uri-id'], $item['raw-body'], $item['body'], $author['network'] ?? '');
Post\Media::insertFromAttachmentData($item['uri-id'], $item['body']);
$item['body'] = BBCode::removeAttachment($item['body']);
$item['raw-body'] = BBCode::removeAttachment($item['raw-body']);
// Check for hashtags in the body and repair or add hashtag links
$item['body'] = self::setHashtags($item['body']);
@ -3003,8 +3007,9 @@ class Item
$fields = ['uri-id', 'uri', 'body', 'title', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink', 'network', 'has-media', 'quote-uri-id', 'post-type'];
$shared_uri_id = 0;
$shared_links = [];
$shared_uri_id = 0;
$shared_links = [];
$quote_shared_links = [];
$shared = DI::contentItem()->getSharedPost($item, $fields);
if (!empty($shared['post'])) {
@ -3023,7 +3028,14 @@ class Item
$shared_links[] = strtolower($media[0]['url']);
}
$quote_uri_id = $shared_item['uri-id'] ?? 0;
if (!empty($shared_item['uri-id'])) {
$data = BBCode::getAttachmentData($shared_item['body']);
if (!empty($data['url'])) {
$quote_shared_links[] = $data['url'];
}
$quote_uri_id = $shared_item['uri-id'];
}
}
}
@ -3098,7 +3110,7 @@ class Item
if (!empty($shared_attachments)) {
$s = self::addVisualAttachments($shared_attachments, $shared_item, $s, true);
$s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $shared_attachments, $body, $s, true, []);
$s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $shared_attachments, $body, $s, true, $quote_shared_links);
$s = self::addNonVisualAttachments($shared_attachments, $item, $s, true);
$body = BBCode::removeSharedData($body);
}
@ -3418,7 +3430,7 @@ class Item
DI::profiler()->stopRecording();
if (isset($data['url']) && !in_array(strtolower($data['url']), $ignore_links)) {
if (!empty($data['description']) || !empty($data['image']) || !empty($data['preview'])) {
if (!empty($data['description']) || !empty($data['image']) || !empty($data['preview']) || (!empty($data['title']) && !Strings::compareLink($data['title'], $data['url']))) {
$parts = parse_url($data['url']);
if (!empty($parts['scheme']) && !empty($parts['host'])) {
if (empty($data['provider_name'])) {

View file

@ -125,8 +125,13 @@ class Link
{
$timeout = DI::config()->get('system', 'xrd_timeout');
$curlResult = HTTPSignature::fetchRaw($url, 0, [HttpClientOptions::TIMEOUT => $timeout, HttpClientOptions::ACCEPT_CONTENT => $accept]);
if (empty($curlResult) || !$curlResult->isSuccess()) {
try {
$curlResult = HTTPSignature::fetchRaw($url, 0, [HttpClientOptions::TIMEOUT => $timeout, HttpClientOptions::ACCEPT_CONTENT => $accept]);
if (empty($curlResult) || !$curlResult->isSuccess()) {
return [];
}
} catch (\Exception $exception) {
Logger::notice('Error fetching url', ['url' => $url, 'exception' => $exception]);
return [];
}
$fields = ['mimetype' => $curlResult->getHeader('Content-Type')[0]];

View file

@ -68,18 +68,18 @@ class Media
*
* @param array $media
* @param bool $force
* @return void
* @return bool
*/
public static function insert(array $media, bool $force = false)
public static function insert(array $media, bool $force = false): bool
{
if (empty($media['url']) || empty($media['uri-id']) || !isset($media['type'])) {
Logger::warning('Incomplete media data', ['media' => $media]);
return;
return false;
}
if (DBA::exists('post-media', ['uri-id' => $media['uri-id'], 'preview' => $media['url']])) {
Logger::info('Media already exists as preview', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
return;
return false;
}
// "document" has got the lowest priority. So when the same file is both attached as document
@ -87,12 +87,12 @@ class Media
$found = DBA::selectFirst('post-media', ['type'], ['uri-id' => $media['uri-id'], 'url' => $media['url']]);
if (!$force && !empty($found) && (($found['type'] != self::DOCUMENT) || ($media['type'] == self::DOCUMENT))) {
Logger::info('Media already exists', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
return;
return false;
}
if (!ItemURI::exists($media['uri-id'])) {
Logger::info('Media referenced URI ID not found', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
return;
return false;
}
$media = self::unsetEmptyFields($media);
@ -114,6 +114,7 @@ class Media
} else {
Logger::info('Nothing to update', ['media' => $media]);
}
return $result;
}
/**
@ -573,9 +574,14 @@ class Media
if (preg_match_all("/\[url\](https?:.*?)\[\/url\]/ism", $body, $matches)) {
foreach ($matches[1] as $url) {
Logger::info('Got page url (link without description)', ['uri-id' => $uriid, 'url' => $url]);
self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
if ($network == Protocol::DFRN) {
$result = self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
if ($result && ($network == Protocol::DFRN)) {
self::revertHTMLType($uriid, $url, $fullbody);
Logger::debug('Revert HTML type', ['uri-id' => $uriid, 'url' => $url]);
} elseif ($result) {
Logger::debug('Media had been added', ['uri-id' => $uriid, 'url' => $url]);
} else {
Logger::debug('Media had not been added', ['uri-id' => $uriid, 'url' => $url]);
}
}
}
@ -584,9 +590,14 @@ class Media
if (preg_match_all("/\[url\=(https?:.*?)\].*?\[\/url\]/ism", $body, $matches)) {
foreach ($matches[1] as $url) {
Logger::info('Got page url (link with description)', ['uri-id' => $uriid, 'url' => $url]);
self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
if ($network == Protocol::DFRN) {
$result = self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
if ($result && ($network == Protocol::DFRN)) {
self::revertHTMLType($uriid, $url, $fullbody);
Logger::debug('Revert HTML type', ['uri-id' => $uriid, 'url' => $url]);
} elseif ($result) {
Logger::debug('Media has been added', ['uri-id' => $uriid, 'url' => $url]);
} else {
Logger::debug('Media has not been added', ['uri-id' => $uriid, 'url' => $url]);
}
}
}
@ -705,6 +716,25 @@ class Media
return DBA::exists('post-media', $condition);
}
/**
* Delete media by uri-id and media type
*
* @param int $uri_id URI id
* @param array $types Media types
* @return bool Whether media attachment exists
* @throws \Exception
*/
public static function deleteByURIId(int $uri_id, array $types = []): bool
{
$condition = ['uri-id' => $uri_id];
if (!empty($types)) {
$condition = DBA::mergeConditions($condition, ['type' => $types]);
}
return DBA::delete('post-media', $condition);
}
/**
* Split the attachment media in the three segments "visual", "link" and "additional"
*
@ -830,7 +860,7 @@ class Media
}
$original_body = $body;
$body = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body);
$body = BBCode::removeAttachment($body);
foreach (self::getByURIId($uriid, $types) as $media) {
if (Item::containsLink($body, $media['preview'] ?? $media['url'], $media['type'])) {

View file

@ -120,8 +120,8 @@ class Statuses extends BaseApi
self::setBoundaries($item['uri-id']);
try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
}
}
DBA::close($items);

View file

@ -77,8 +77,8 @@ class Bookmarks extends BaseApi
self::setBoundaries($item['uri-id']);
try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
}
}
DBA::close($items);

View file

@ -79,8 +79,8 @@ class Favourited extends BaseApi
self::setBoundaries($item['thr-parent-id']);
try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['thr-parent-id'], $uid, $display_quotes);
} catch (\Throwable $th) {
Logger::info('Post not fetchable', ['uri-id' => $item['thr-parent-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['thr-parent-id'], 'uid' => $uid, 'exception' => $exception]);
}
}
DBA::close($items);

View file

@ -117,7 +117,7 @@ class Accounts extends BaseApi
self::setBoundaries($member['contact-id']);
try {
$accounts[] = DI::mstdnAccount()->createFromContactId($member['contact-id'], $uid);
} catch (\Throwable $th) {
} catch (\Exception $exception) {
}
}
DBA::close($members);

View file

@ -183,8 +183,8 @@ class Search extends BaseApi
self::setBoundaries($item['uri-id']);
try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
}
}
DBA::close($items);

View file

@ -45,10 +45,11 @@ class Context extends BaseApi
}
$request = $this->getRequest([
'max_id' => 0, // Return results older than this id
'since_id' => 0, // Return results newer than this id
'min_id' => 0, // Return results immediately newer than this id
'limit' => 40, // Maximum number of results to return. Defaults to 40.
'max_id' => 0, // Return results older than this id
'since_id' => 0, // Return results newer than this id
'min_id' => 0, // Return results immediately newer than this id
'limit' => 40, // Maximum number of results to return. Defaults to 40.
'show_all' => false, // shows posts for all users including blocked and ignored users
], $request);
$id = $this->parameters['id'];
@ -73,6 +74,13 @@ class Context extends BaseApi
$condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $request['min_id']]);
$params['order'] = ['uri-id'];
}
if (!empty($uid) && !$request['show_all']) {
$condition = DBA::mergeConditions(
$condition,
["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored`))", $uid]
);
}
$posts = Post::selectPosts(['uri-id', 'thr-parent-id'], $condition, $params);
while ($post = Post::fetch($posts)) {

View file

@ -104,8 +104,8 @@ class ListTimeline extends BaseApi
self::setBoundaries($item['uri-id']);
try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
}
}
DBA::close($items);

View file

@ -99,8 +99,8 @@ class PublicTimeline extends BaseApi
self::setBoundaries($item['uri-id']);
try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
}
}
DBA::close($items);

View file

@ -120,8 +120,8 @@ class Tag extends BaseApi
self::setBoundaries($item['uri-id']);
try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
}
}
DBA::close($items);

View file

@ -57,8 +57,8 @@ class Statuses extends BaseApi
while ($status = Post::fetch($statuses)) {
try {
$trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) {
Logger::info('Post not fetchable', ['uri-id' => $status['uri-id'], 'uid' => $uid, 'error' => $th]);
} catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $status['uri-id'], 'uid' => $uid, 'exception' => $exception]);
}
}
DBA::close($statuses);

View file

@ -115,6 +115,8 @@ class Edit extends BaseModule
$lockstate = 'unlock';
}
$item['body'] = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']);
$jotplugins = '';
Hook::callAll('jot_tool', $jotplugins);

View file

@ -83,13 +83,18 @@ class Proxy extends BaseModule
$request['url'] = str_replace(' ', '+', $request['url']);
// Fetch the content with the local user
$fetchResult = HTTPSignature::fetchRaw($request['url'], DI::userSession()->getLocalUserId(), [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE], 'timeout' => 10]);
$img_str = $fetchResult->getBody();
try {
$fetchResult = HTTPSignature::fetchRaw($request['url'], DI::userSession()->getLocalUserId(), [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE], 'timeout' => 10]);
$img_str = $fetchResult->getBody();
if (!$fetchResult->isSuccess() || empty($img_str)) {
Logger::notice('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]);
if (!$fetchResult->isSuccess() || empty($img_str)) {
Logger::notice('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]);
self::responseError();
// stop.
}
} catch (\Exception $exception) {
Logger::notice('Error fetching image', ['image' => $request['url'], 'exception' => $exception]);
self::responseError();
// stop.
}
Logger::debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => DI::userSession()->getLocalUserId(), 'image' => $request['url']]);

View file

@ -84,14 +84,14 @@ class Instance extends BaseDataTransferObject
{
$register_policy = intval($config->get('config', 'register_policy'));
$this->uri = $baseUrl;
$this->uri = $baseUrl->getHost();
$this->title = $config->get('config', 'sitename');
$this->short_description = $this->description = $config->get('config', 'info');
$this->email = implode(',', User::getAdminEmailList());
$this->version = '2.8.0 (compatible; Friendica ' . App::VERSION . ')';
$this->urls = null; // Not supported
$this->stats = new Stats($config, $database);
$this->thumbnail = $baseUrl . 'images/friendica-banner.jpg';
$this->thumbnail = $baseUrl . '/images/friendica-banner.jpg';
$this->languages = [$config->get('system', 'language')];
$this->max_toot_chars = (int)$config->get('config', 'api_import_size', $config->get('config', 'max_import_size'));
$this->registrations = ($register_policy != Register::CLOSED);

View file

@ -39,9 +39,9 @@ class Contact extends BaseDataTransferObject
/**
* @param string $email
* @param Account $account
* @param Account|null $account
*/
public function __construct(string $email, Account $account)
public function __construct(string $email, ?Account $account)
{
$this->email = $email;
$this->account = $account;

View file

@ -31,13 +31,13 @@ use Friendica\BaseDataTransferObject;
class UserStats extends BaseDataTransferObject
{
/** @var int */
protected $active_monthly = 0;
protected $active_month = 0;
/**
* @param $active_monthly
* @param int $active_month
*/
public function __construct($active_monthly)
public function __construct(int $active_month)
{
$this->active_monthly = $active_monthly;
$this->active_month = $active_month;
}
}

View file

@ -105,7 +105,7 @@ class Status extends BaseDataTransferObject
* @param array $item
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public function __construct(array $item, Account $account, Counts $counts, UserAttributes $userAttributes, bool $sensitive, Application $application, array $mentions, array $tags, Card $card, array $attachments, array $in_reply, array $reblog, array $quote = null, array $poll = null)
public function __construct(array $item, Account $account, Counts $counts, UserAttributes $userAttributes, bool $sensitive, Application $application, array $mentions, array $tags, Card $card, array $attachments, array $in_reply, array $reblog, FriendicaExtension $friendica, array $quote = null, array $poll = null)
{
$this->id = (string)$item['uri-id'];
$this->created_at = DateTimeFormat::utc($item['created'], DateTimeFormat::JSON);
@ -151,7 +151,7 @@ class Status extends BaseDataTransferObject
$this->emojis = [];
$this->card = $card->toArray() ?: null;
$this->poll = $poll;
$this->friendica = new FriendicaExtension($item['title'], $counts->dislikes);
$this->friendica = $friendica;
}
/**

View file

@ -0,0 +1,55 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Object\Api\Mastodon\Status;
use Friendica\BaseDataTransferObject;
/**
* Class FriendicaDeliveryData
*
* Additional fields on Mastodon Statuses for storing Friendica delivery data
*
* @see https://docs.joinmastodon.org/entities/status
*/
class FriendicaDeliveryData extends BaseDataTransferObject
{
/** @var int|null */
protected $delivery_queue_count;
/** @var int|null */
protected $delivery_queue_done;
/** @var int|null */
protected $delivery_queue_failed;
/**
* Creates a FriendicaDeliveryData object
*
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public function __construct(?int $delivery_queue_count, ?int $delivery_queue_done, ?int $delivery_queue_failed)
{
$this->delivery_queue_count = $delivery_queue_count;
$this->delivery_queue_done = $delivery_queue_done;
$this->delivery_queue_failed = $delivery_queue_failed;
}
}

View file

@ -35,6 +35,8 @@ class FriendicaExtension extends BaseDataTransferObject
/** @var string */
protected $title;
/** @var FriendicaDeliveryData */
protected $delivery_data;
/** @var int */
protected $dislikes_count;
@ -42,11 +44,13 @@ class FriendicaExtension extends BaseDataTransferObject
* Creates a status count object
*
* @param string $title
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @param int $dislikes_count
* @param FriendicaDeliveryData $delivery_data
*/
public function __construct(string $title, int $dislikes_count)
public function __construct(string $title, int $dislikes_count, FriendicaDeliveryData $delivery_data)
{
$this->title = $title;
$this->delivery_data = $delivery_data;
$this->dislikes_count = $dislikes_count;
}
}

View file

@ -718,7 +718,7 @@ class Image
if ($image->isImagick()) {
try {
$colors = $image->image->getImagePixelColor($x, $y)->getColor();
} catch (\Throwable $th) {
} catch (\Exception $exception) {
return '';
}
$row[] = [$colors['r'], $colors['g'], $colors['b']];

View file

@ -242,6 +242,7 @@ class Processor
$item['changed'] = DateTimeFormat::utcNow();
$item['edited'] = DateTimeFormat::utc($activity['updated']);
Post\Media::deleteByURIId($item['uri-id'], [Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE]);
$item = self::processContent($activity, $item);
if (empty($item)) {
Queue::remove($activity);
@ -570,7 +571,12 @@ class Processor
*/
public static function isActivityGone(string $url): bool
{
$curlResult = HTTPSignature::fetchRaw($url, 0);
try {
$curlResult = HTTPSignature::fetchRaw($url, 0);
} catch (\Exception $exception) {
Logger::notice('Error fetching url', ['url' => $url, 'exception' => $exception]);
return true;
}
if (Network::isUrlBlocked($url)) {
return true;

View file

@ -1675,7 +1675,7 @@ class Transmitter
if ($type == 'Page') {
// When we transmit "Page" posts we have to remove the attachment.
// The attachment contains the link that we already transmit in the "url" field.
$body = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body);
$body = BBCode::removeAttachment($body);
}
$body = BBCode::setMentionsToNicknames($body);
@ -1707,7 +1707,7 @@ class Transmitter
$richbody = DI::contentItem()->addSharedPost($item, $richbody);
}
}
$richbody = BBCode::removeAttachment($richbody);
$richbody = BBCode::replaceAttachment($richbody);
$data['contentMap'][$language] = BBCode::convertForUriId($item['uri-id'], $richbody, BBCode::EXTERNAL);
}

View file

@ -422,7 +422,12 @@ class HTTPSignature
*/
public static function fetch(string $request, int $uid): array
{
$curlResult = self::fetchRaw($request, $uid);
try {
$curlResult = self::fetchRaw($request, $uid);
} catch (\Exception $exception) {
Logger::notice('Error fetching url', ['url' => $request, 'exception' => $exception]);
return [];
}
if (empty($curlResult)) {
return [];