Merge pull request #13872 from friendica/issue-13845

Issue 13845: Support "sensitive" attribute
This commit is contained in:
Hypolite Petovan 2024-02-06 05:54:26 -05:00 committed by GitHub
commit 9b4ade4542
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 53 additions and 28 deletions

View file

@ -1,6 +1,6 @@
-- ------------------------------------------ -- ------------------------------------------
-- Friendica 2024.03-dev (Yellow Archangel) -- Friendica 2024.03-dev (Yellow Archangel)
-- DB_UPDATE_VERSION 1551 -- DB_UPDATE_VERSION 1552
-- ------------------------------------------ -- ------------------------------------------
@ -1283,6 +1283,7 @@ CREATE TABLE IF NOT EXISTS `post-content` (
`location` varchar(255) NOT NULL DEFAULT '' COMMENT 'text location where this item originated', `location` varchar(255) NOT NULL DEFAULT '' COMMENT 'text location where this item originated',
`coord` varchar(255) NOT NULL DEFAULT '' COMMENT 'longitude/latitude pair representing location where this item originated', `coord` varchar(255) NOT NULL DEFAULT '' COMMENT 'longitude/latitude pair representing location where this item originated',
`language` text COMMENT 'Language information about this post', `language` text COMMENT 'Language information about this post',
`sensitive` boolean COMMENT 'If true, this post contains sensitive content',
`app` varchar(255) NOT NULL DEFAULT '' COMMENT 'application which generated this item', `app` varchar(255) NOT NULL DEFAULT '' COMMENT 'application which generated this item',
`rendered-hash` varchar(32) NOT NULL DEFAULT '' COMMENT '', `rendered-hash` varchar(32) NOT NULL DEFAULT '' COMMENT '',
`rendered-html` mediumtext COMMENT 'item.body converted to html', `rendered-html` mediumtext COMMENT 'item.body converted to html',
@ -2194,6 +2195,7 @@ CREATE VIEW `post-user-view` AS SELECT
`post-content`.`plink` AS `plink`, `post-content`.`plink` AS `plink`,
`post-content`.`location` AS `location`, `post-content`.`location` AS `location`,
`post-content`.`coord` AS `coord`, `post-content`.`coord` AS `coord`,
`post-content`.`sensitive` AS `sensitive`,
`post-content`.`app` AS `app`, `post-content`.`app` AS `app`,
`post-content`.`object-type` AS `object-type`, `post-content`.`object-type` AS `object-type`,
`post-content`.`object` AS `object`, `post-content`.`object` AS `object`,
@ -2378,6 +2380,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT
`post-content`.`plink` AS `plink`, `post-content`.`plink` AS `plink`,
`post-content`.`location` AS `location`, `post-content`.`location` AS `location`,
`post-content`.`coord` AS `coord`, `post-content`.`coord` AS `coord`,
`post-content`.`sensitive` AS `sensitive`,
`post-content`.`app` AS `app`, `post-content`.`app` AS `app`,
`post-content`.`object-type` AS `object-type`, `post-content`.`object-type` AS `object-type`,
`post-content`.`object` AS `object`, `post-content`.`object` AS `object`,
@ -2548,6 +2551,7 @@ CREATE VIEW `post-view` AS SELECT
`post-content`.`plink` AS `plink`, `post-content`.`plink` AS `plink`,
`post-content`.`location` AS `location`, `post-content`.`location` AS `location`,
`post-content`.`coord` AS `coord`, `post-content`.`coord` AS `coord`,
`post-content`.`sensitive` AS `sensitive`,
`post-content`.`app` AS `app`, `post-content`.`app` AS `app`,
`post-content`.`object-type` AS `object-type`, `post-content`.`object-type` AS `object-type`,
`post-content`.`object` AS `object`, `post-content`.`object` AS `object`,
@ -2694,6 +2698,7 @@ CREATE VIEW `post-thread-view` AS SELECT
`post-content`.`plink` AS `plink`, `post-content`.`plink` AS `plink`,
`post-content`.`location` AS `location`, `post-content`.`location` AS `location`,
`post-content`.`coord` AS `coord`, `post-content`.`coord` AS `coord`,
`post-content`.`sensitive` AS `sensitive`,
`post-content`.`app` AS `app`, `post-content`.`app` AS `app`,
`post-content`.`object-type` AS `object-type`, `post-content`.`object-type` AS `object-type`,
`post-content`.`object` AS `object`, `post-content`.`object` AS `object`,

View file

@ -17,6 +17,7 @@ Fields
| location | text location where this item originated | varchar(255) | NO | | | | | location | text location where this item originated | varchar(255) | NO | | | |
| coord | longitude/latitude pair representing location where this item originated | varchar(255) | NO | | | | | coord | longitude/latitude pair representing location where this item originated | varchar(255) | NO | | | |
| language | Language information about this post | text | YES | | NULL | | | language | Language information about this post | text | YES | | NULL | |
| sensitive | If true, this post contains sensitive content | boolean | YES | | NULL | |
| app | application which generated this item | varchar(255) | NO | | | | | app | application which generated this item | varchar(255) | NO | | | |
| rendered-hash | | varchar(32) | NO | | | | | rendered-hash | | varchar(32) | NO | | | |
| rendered-html | item.body converted to html | mediumtext | YES | | NULL | | | rendered-html | item.body converted to html | mediumtext | YES | | NULL | |

View file

@ -112,7 +112,7 @@ class Status extends BaseFactory
{ {
$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', $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', 'edited', 'commented', 'received', 'changed', 'network', 'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity', 'featured', 'has-media', 'quote-uri-id', 'created', 'edited', 'commented', 'received', 'changed', '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', 'allow_cid', 'deny_cid', 'allow_gid', 'deny_gid']; 'delivery_queue_count', 'delivery_queue_done','delivery_queue_failed', 'allow_cid', 'deny_cid', 'allow_gid', 'deny_gid', 'sensitive'];
$item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]); $item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
if (!$item) { if (!$item) {
$mail = DBA::selectFirst('mail', ['id'], ['uri-id' => $uriId, 'uid' => $uid]); $mail = DBA::selectFirst('mail', ['id'], ['uri-id' => $uriId, 'uid' => $uid]);
@ -217,7 +217,7 @@ class Status extends BaseFactory
$item['featured'] $item['featured']
); );
$sensitive = $this->dba->exists('tag-view', ['uri-id' => $uriId, 'name' => 'nsfw', 'type' => TagModel::HASHTAG]); $sensitive = (bool)$item['sensitive'];
$application = new \Friendica\Object\Api\Mastodon\Application($item['app'] ?: ContactSelector::networkToName($item['network'], $item['author-link'])); $application = new \Friendica\Object\Api\Mastodon\Application($item['app'] ?: ContactSelector::networkToName($item['network'], $item['author-link']));
$mentions = $this->mstdnMentionFactory->createFromUriId($uriId)->getArrayCopy(); $mentions = $this->mstdnMentionFactory->createFromUriId($uriId)->getArrayCopy();

View file

@ -99,7 +99,7 @@ class Item
'uid', 'id', 'parent', 'guid', 'network', 'gravity', 'uid', 'id', 'parent', 'guid', 'network', 'gravity',
'uri-id', 'uri', 'thr-parent-id', 'thr-parent', 'parent-uri-id', 'parent-uri', 'conversation', 'uri-id', 'uri', 'thr-parent-id', 'thr-parent', 'parent-uri-id', 'parent-uri', 'conversation',
'commented', 'created', 'edited', 'received', 'verb', 'object-type', 'postopts', 'plink', 'commented', 'created', 'edited', 'received', 'verb', 'object-type', 'postopts', 'plink',
'wall', 'private', 'starred', 'origin', 'parent-origin', 'title', 'body', 'language', 'wall', 'private', 'starred', 'origin', 'parent-origin', 'title', 'body', 'language', 'sensitive',
'content-warning', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object', 'content-warning', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object',
'quote-uri', 'quote-uri-id', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'mention', 'global', 'quote-uri', 'quote-uri-id', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'mention', 'global',
'author-id', 'author-link', 'author-alias', 'author-name', 'author-avatar', 'author-network', 'author-updated', 'author-gsid', 'author-baseurl', 'author-addr', 'author-uri-id', 'author-id', 'author-link', 'author-alias', 'author-name', 'author-avatar', 'author-network', 'author-updated', 'author-gsid', 'author-baseurl', 'author-addr', 'author-uri-id',
@ -119,7 +119,7 @@ class Item
const DELIVER_FIELDLIST = [ const DELIVER_FIELDLIST = [
'uid', 'id', 'parent', 'uri-id', 'uri', 'thr-parent', 'parent-uri', 'guid', 'uid', 'id', 'parent', 'uri-id', 'uri', 'thr-parent', 'parent-uri', 'guid',
'parent-guid', 'conversation', 'received', 'created', 'edited', 'verb', 'object-type', 'object', 'target', 'parent-guid', 'conversation', 'received', 'created', 'edited', 'verb', 'object-type', 'object', 'target',
'private', 'title', 'body', 'raw-body', 'language', 'location', 'coord', 'app', 'private', 'title', 'body', 'raw-body', 'language', 'location', 'coord', 'app', 'sensitive',
'inform', 'deleted', 'extid', 'post-type', 'post-reason', 'gravity', 'inform', 'deleted', 'extid', 'post-type', 'post-reason', 'gravity',
'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
'author-id', 'author-addr', 'author-link', 'author-name', 'author-avatar', 'owner-id', 'owner-link', 'contact-uid', 'author-id', 'author-addr', 'author-link', 'author-name', 'author-avatar', 'owner-id', 'owner-link', 'contact-uid',
@ -1280,6 +1280,15 @@ class Item
} }
} }
// Store tags from the body if this hadn't been handled previously in the protocol classes
if (!Tag::existsForPost($item['uri-id'])) {
Tag::storeFromBody($item['uri-id'], $item['body']);
}
if (in_array($item['gravity'], [self::GRAVITY_PARENT, self::GRAVITY_COMMENT]) && (!isset($item['sensitive']) || is_null($item['sensitive']))) {
$item['sensitive'] = Tag::existsTagForPost($item['uri-id'], 'nsfw');
}
$item['language'] = self::getLanguage($item); $item['language'] = self::getLanguage($item);
$inserted = Post::insert($item['uri-id'], $item); $inserted = Post::insert($item['uri-id'], $item);
@ -1319,11 +1328,6 @@ class Item
Post\DeliveryData::insert($item['uri-id'], $delivery_data); Post\DeliveryData::insert($item['uri-id'], $delivery_data);
} }
// Store tags from the body if this hadn't been handled previously in the protocol classes
if (!Tag::existsForPost($item['uri-id'])) {
Tag::storeFromBody($item['uri-id'], $item['body']);
}
$condition = ['uri-id' => $item['uri-id'], 'uid' => $item['uid']]; $condition = ['uri-id' => $item['uri-id'], 'uid' => $item['uid']];
if (Post::exists($condition)) { if (Post::exists($condition)) {
Logger::notice('Item is already inserted - aborting', $condition); Logger::notice('Item is already inserted - aborting', $condition);
@ -3467,7 +3471,7 @@ class Item
} }
if (!empty($sharedSplitAttachments)) { if (!empty($sharedSplitAttachments)) {
$s = self::addGallery($s, $sharedSplitAttachments['visual']); $s = self::addGallery($s, $sharedSplitAttachments['visual'], (bool)$item['sensitive']);
$s = self::addVisualAttachments($sharedSplitAttachments['visual'], $shared_item, $s, true); $s = self::addVisualAttachments($sharedSplitAttachments['visual'], $shared_item, $s, true);
$s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $sharedSplitAttachments, $body, $s, true, $quote_shared_links); $s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $sharedSplitAttachments, $body, $s, true, $quote_shared_links);
$s = self::addNonVisualAttachments($sharedSplitAttachments['additional'], $item, $s, true); $s = self::addNonVisualAttachments($sharedSplitAttachments['additional'], $item, $s, true);
@ -3480,7 +3484,7 @@ class Item
$s = substr($s, 0, $pos); $s = substr($s, 0, $pos);
} }
$s = self::addGallery($s, $itemSplitAttachments['visual']); $s = self::addGallery($s, $itemSplitAttachments['visual'], (bool)$item['sensitive']);
$s = self::addVisualAttachments($itemSplitAttachments['visual'], $item, $s, false); $s = self::addVisualAttachments($itemSplitAttachments['visual'], $item, $s, false);
$s = self::addLinkAttachment($item['uri-id'], $itemSplitAttachments, $body, $s, false, $shared_links); $s = self::addLinkAttachment($item['uri-id'], $itemSplitAttachments, $body, $s, false, $shared_links);
$s = self::addNonVisualAttachments($itemSplitAttachments['additional'], $item, $s, false); $s = self::addNonVisualAttachments($itemSplitAttachments['additional'], $item, $s, false);
@ -3516,9 +3520,10 @@ class Item
* *
* @param string $s * @param string $s
* @param PostMedias $PostMedias * @param PostMedias $PostMedias
* @param bool $sensitive
* @return string * @return string
*/ */
private static function addGallery(string $s, PostMedias $PostMedias): string private static function addGallery(string $s, PostMedias $PostMedias, bool $sensitive): string
{ {
foreach ($PostMedias as $PostMedia) { foreach ($PostMedias as $PostMedia) {
if (!$PostMedia->preview || ($PostMedia->type !== Post\Media::IMAGE)) { if (!$PostMedia->preview || ($PostMedia->type !== Post\Media::IMAGE)) {
@ -3528,9 +3533,10 @@ class Item
if ($PostMedia->hasDimensions()) { if ($PostMedia->hasDimensions()) {
$pattern = '#<a href="' . preg_quote($PostMedia->url) . '">(.*?)"></a>#'; $pattern = '#<a href="' . preg_quote($PostMedia->url) . '">(.*?)"></a>#';
$s = preg_replace_callback($pattern, function () use ($PostMedia) { $s = preg_replace_callback($pattern, function () use ($PostMedia, $sensitive) {
return Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/single_with_height_allocation.tpl'), [ return Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/single_with_height_allocation.tpl'), [
'$image' => $PostMedia, '$image' => $PostMedia,
'$sensitive' => $sensitive,
'$allocated_height' => $PostMedia->getAllocatedHeight(), '$allocated_height' => $PostMedia->getAllocatedHeight(),
'$allocated_max_width' => ($PostMedia->previewWidth ?? $PostMedia->width) . 'px', '$allocated_max_width' => ($PostMedia->previewWidth ?? $PostMedia->width) . 'px',
]); ]);

View file

@ -378,6 +378,18 @@ class Tag
return DBA::exists('post-tag', ['uri-id' => $uriId, 'type' => [self::HASHTAG, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]]); return DBA::exists('post-tag', ['uri-id' => $uriId, 'type' => [self::HASHTAG, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]]);
} }
/**
* Check for a given hashtag on a given post
*
* @param integer $uriId
* @param string $tag
* @return boolean
*/
public static function existsTagForPost(int $uriId, string $tag): bool
{
return DBA::exists('tag-view', ['uri-id' => $uriId, 'type' => self::HASHTAG, 'name' => $tag]);
}
/** /**
* Remove tag/mention * Remove tag/mention
* *

View file

@ -466,6 +466,7 @@ class Processor
} }
$item['uri'] = $activity['id']; $item['uri'] = $activity['id'];
$item['sensitive'] = $activity['sensitive'];
if (empty($activity['published']) || empty($activity['updated'])) { if (empty($activity['published']) || empty($activity['updated'])) {
DI::logger()->notice('published or updated keys are empty for activity', ['activity' => $activity]); DI::logger()->notice('published or updated keys are empty for activity', ['activity' => $activity]);

View file

@ -1697,18 +1697,6 @@ class Transmitter
}); });
} }
/**
* Returns if the post contains sensitive content ("nsfw")
*
* @param integer $uri_id URI id
* @return boolean Whether URI id was found
* @throws \Exception
*/
private static function isSensitive(int $uri_id): bool
{
return DBA::exists('tag-view', ['uri-id' => $uri_id, 'name' => 'nsfw', 'type' => Tag::HASHTAG]);
}
/** /**
* Creates event data * Creates event data
* *
@ -1812,7 +1800,7 @@ class Transmitter
} else { } else {
$data['attributedTo'] = $item['author-link']; $data['attributedTo'] = $item['author-link'];
} }
$data['sensitive'] = self::isSensitive($item['uri-id']); $data['sensitive'] = (bool)$item['sensitive'];
if (!empty($item['conversation']) && ($item['conversation'] != './')) { if (!empty($item['conversation']) && ($item['conversation'] != './')) {
$data['conversation'] = $data['context'] = $item['conversation']; $data['conversation'] = $data['context'] = $item['conversation'];

View file

@ -56,7 +56,7 @@ use Friendica\Database\DBA;
// This file is required several times during the test in DbaDefinition which justifies this condition // This file is required several times during the test in DbaDefinition which justifies this condition
if (!defined('DB_UPDATE_VERSION')) { if (!defined('DB_UPDATE_VERSION')) {
define('DB_UPDATE_VERSION', 1551); define('DB_UPDATE_VERSION', 1552);
} }
return [ return [
@ -1307,6 +1307,7 @@ return [
"location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "text location where this item originated"], "location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "text location where this item originated"],
"coord" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "longitude/latitude pair representing location where this item originated"], "coord" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "longitude/latitude pair representing location where this item originated"],
"language" => ["type" => "text", "comment" => "Language information about this post"], "language" => ["type" => "text", "comment" => "Language information about this post"],
"sensitive" => ["type" => "boolean", "comment" => "If true, this post contains sensitive content"],
"app" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "application which generated this item"], "app" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "application which generated this item"],
"rendered-hash" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""], "rendered-hash" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""],
"rendered-html" => ["type" => "mediumtext", "comment" => "item.body converted to html"], "rendered-html" => ["type" => "mediumtext", "comment" => "item.body converted to html"],

View file

@ -225,6 +225,7 @@
"plink" => ["post-content", "plink"], "plink" => ["post-content", "plink"],
"location" => ["post-content", "location"], "location" => ["post-content", "location"],
"coord" => ["post-content", "coord"], "coord" => ["post-content", "coord"],
"sensitive" => ["post-content", "sensitive"],
"app" => ["post-content", "app"], "app" => ["post-content", "app"],
"object-type" => ["post-content", "object-type"], "object-type" => ["post-content", "object-type"],
"object" => ["post-content", "object"], "object" => ["post-content", "object"],
@ -407,6 +408,7 @@
"plink" => ["post-content", "plink"], "plink" => ["post-content", "plink"],
"location" => ["post-content", "location"], "location" => ["post-content", "location"],
"coord" => ["post-content", "coord"], "coord" => ["post-content", "coord"],
"sensitive" => ["post-content", "sensitive"],
"app" => ["post-content", "app"], "app" => ["post-content", "app"],
"object-type" => ["post-content", "object-type"], "object-type" => ["post-content", "object-type"],
"object" => ["post-content", "object"], "object" => ["post-content", "object"],
@ -575,6 +577,7 @@
"plink" => ["post-content", "plink"], "plink" => ["post-content", "plink"],
"location" => ["post-content", "location"], "location" => ["post-content", "location"],
"coord" => ["post-content", "coord"], "coord" => ["post-content", "coord"],
"sensitive" => ["post-content", "sensitive"],
"app" => ["post-content", "app"], "app" => ["post-content", "app"],
"object-type" => ["post-content", "object-type"], "object-type" => ["post-content", "object-type"],
"object" => ["post-content", "object"], "object" => ["post-content", "object"],
@ -719,6 +722,7 @@
"plink" => ["post-content", "plink"], "plink" => ["post-content", "plink"],
"location" => ["post-content", "location"], "location" => ["post-content", "location"],
"coord" => ["post-content", "coord"], "coord" => ["post-content", "coord"],
"sensitive" => ["post-content", "sensitive"],
"app" => ["post-content", "app"], "app" => ["post-content", "app"],
"object-type" => ["post-content", "object-type"], "object-type" => ["post-content", "object-type"],
"object" => ["post-content", "object"], "object" => ["post-content", "object"],

View file

@ -1422,3 +1422,10 @@ function pre_update_1550()
} }
return Update::SUCCESS; return Update::SUCCESS;
} }
function update_1552()
{
DBA::e("UPDATE `post-content` INNER JOIN `post-tag` ON `post-tag`.`uri-id` = `post-content`.`uri-id` INNER JOIN `tag` ON `tag`.`id` = `post-tag`.`tid` SET `sensitive` = ? WHERE `name` = ?", true, 'nsfw');
return Update::SUCCESS;
}