]> git.mxchange.org Git - friendica.git/commitdiff
Issue 13845: Support "sensitive" attribute
authorMichael <heluecht@pirati.ca>
Sun, 4 Feb 2024 21:45:30 +0000 (21:45 +0000)
committerMichael <heluecht@pirati.ca>
Sun, 4 Feb 2024 21:45:30 +0000 (21:45 +0000)
database.sql
doc/database/db_post-content.md
src/Factory/Api/Mastodon/Status.php
src/Model/Item.php
src/Model/Post/SearchIndex.php
src/Model/Tag.php
src/Protocol/ActivityPub/Processor.php
src/Protocol/ActivityPub/Transmitter.php
static/dbstructure.config.php
static/dbview.config.php
update.php

index c8ab483b44e483f67853d021696da6d00e133f33..d56b45f8784f06b9e2607c6d487672dc158e09b5 100644 (file)
@@ -1,6 +1,6 @@
 -- ------------------------------------------
 -- Friendica 2024.03-dev (Yellow Archangel)
--- DB_UPDATE_VERSION 1550
+-- 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',
        `coord` varchar(255) NOT NULL DEFAULT '' COMMENT 'longitude/latitude pair representing location where this item originated',
        `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',
        `rendered-hash` varchar(32) NOT NULL DEFAULT '' COMMENT '',
        `rendered-html` mediumtext COMMENT 'item.body converted to html',
@@ -2163,6 +2164,7 @@ CREATE VIEW `post-user-view` AS SELECT
        `post-content`.`plink` AS `plink`,
        `post-content`.`location` AS `location`,
        `post-content`.`coord` AS `coord`,
+       `post-content`.`sensitive` AS `sensitive`,
        `post-content`.`app` AS `app`,
        `post-content`.`object-type` AS `object-type`,
        `post-content`.`object` AS `object`,
@@ -2347,6 +2349,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT
        `post-content`.`plink` AS `plink`,
        `post-content`.`location` AS `location`,
        `post-content`.`coord` AS `coord`,
+       `post-content`.`sensitive` AS `sensitive`,
        `post-content`.`app` AS `app`,
        `post-content`.`object-type` AS `object-type`,
        `post-content`.`object` AS `object`,
@@ -2517,6 +2520,7 @@ CREATE VIEW `post-view` AS SELECT
        `post-content`.`plink` AS `plink`,
        `post-content`.`location` AS `location`,
        `post-content`.`coord` AS `coord`,
+       `post-content`.`sensitive` AS `sensitive`,
        `post-content`.`app` AS `app`,
        `post-content`.`object-type` AS `object-type`,
        `post-content`.`object` AS `object`,
@@ -2663,6 +2667,7 @@ CREATE VIEW `post-thread-view` AS SELECT
        `post-content`.`plink` AS `plink`,
        `post-content`.`location` AS `location`,
        `post-content`.`coord` AS `coord`,
+       `post-content`.`sensitive` AS `sensitive`,
        `post-content`.`app` AS `app`,
        `post-content`.`object-type` AS `object-type`,
        `post-content`.`object` AS `object`,
index be45975a724afae905b137ae66f57a945cba56ca..d1ae90f2781b546698c7fc83c944a64fea4bee1e 100644 (file)
@@ -17,6 +17,7 @@ Fields
 | location        | text 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    |       |
+| sensitive       | If true, this post contains sensitive content                                                                             | boolean        | YES  |     | NULL    |       |
 | app             | application which generated this item                                                                                     | varchar(255)   | NO   |     |         |       |
 | rendered-hash   |                                                                                                                           | varchar(32)    | NO   |     |         |       |
 | rendered-html   | item.body converted to html                                                                                               | mediumtext     | YES  |     | NULL    |       |
index e20b457c88bb2d02dc3bf5e65375c3e456650f3b..e001ef80e0ef06bb2a5f75a389c5a73e1b1b7468 100644 (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',
                        '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]]);
                if (!$item) {
                        $mail = DBA::selectFirst('mail', ['id'], ['uri-id' => $uriId, 'uid' => $uid]);
@@ -217,7 +217,7 @@ class Status extends BaseFactory
                        $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']));
 
                $mentions    = $this->mstdnMentionFactory->createFromUriId($uriId)->getArrayCopy();
index 3d356183967249344ae4253cf088bbe375971875..ca63a923ccbe6407766e68b10094b2b5ce0a001c 100644 (file)
@@ -99,7 +99,7 @@ class Item
                'uid', 'id', 'parent', 'guid', 'network', 'gravity',
                'uri-id', 'uri', 'thr-parent-id', 'thr-parent', 'parent-uri-id', 'parent-uri', 'conversation',
                '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',
                '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',
@@ -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);
 
                $inserted = Post::insert($item['uri-id'], $item);
@@ -1319,11 +1328,6 @@ class Item
                        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']];
                if (Post::exists($condition)) {
                        Logger::notice('Item is already inserted - aborting', $condition);
@@ -3467,7 +3471,7 @@ class Item
                }
 
                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::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $sharedSplitAttachments, $body, $s, true, $quote_shared_links);
                        $s = self::addNonVisualAttachments($sharedSplitAttachments['additional'], $item, $s, true);
@@ -3480,7 +3484,7 @@ class Item
                        $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::addLinkAttachment($item['uri-id'], $itemSplitAttachments, $body, $s, false, $shared_links);
                $s = self::addNonVisualAttachments($itemSplitAttachments['additional'], $item, $s, false);
@@ -3516,9 +3520,10 @@ class Item
         *
         * @param string     $s
         * @param PostMedias $PostMedias
+        * @param bool       $sensitive
         * @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) {
                        if (!$PostMedia->preview || ($PostMedia->type !== Post\Media::IMAGE)) {
@@ -3528,9 +3533,10 @@ class Item
                        if ($PostMedia->hasDimensions()) {
                                $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'), [
                                                '$image' => $PostMedia,
+                                               '$sensitive' => $sensitive,
                                                '$allocated_height' => $PostMedia->getAllocatedHeight(),
                                                '$allocated_max_width' => ($PostMedia->previewWidth ?? $PostMedia->width) . 'px',
                                        ]);
index 98a82cae63114332fac44a0b64e09b04fff13aa0..840f86f6ac790d58820e6cf5ac75a830cd4b37a8 100644 (file)
@@ -53,7 +53,7 @@ class SearchIndex
                        'uri-id'     => $uri_id,
                        'owner-id'   => $item['owner-id'],
                        'media-type' => Engagement::getMediaType($uri_id),
-                       'language'   => !empty($item['language']) ? (array_key_first(json_decode($item['language'], true)) ?? L10n::UNDETERMINED_LANGUAGE) : L10n::UNDETERMINED_LANGUAGE,
+                       'language'   => substr(!empty($item['language']) ? (array_key_first(json_decode($item['language'], true)) ?? L10n::UNDETERMINED_LANGUAGE) : L10n::UNDETERMINED_LANGUAGE, 0, 2),
                        'searchtext' => Post\Engagement::getSearchTextForUriId($uri_id, $refresh),
                        'size'       => Engagement::getContentSize($item),
                        'created'    => $item['created'],
index dac0401b2be988bf39a38c2514900595e27ab175..e63a272a753cea7163902d6b49d42429f1db1362 100644 (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]]);
        }
 
+       /**
+        * 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
         *
index 593c1e783622743d0474d60275e5f424372c4f22..9b1c84bbb187cb5c0c00f973a47f5f4d1c844d3c 100644 (file)
@@ -466,6 +466,7 @@ class Processor
                }
 
                $item['uri'] = $activity['id'];
+               $item['sensitive'] = $activity['sensitive'];
 
                if (empty($activity['published']) || empty($activity['updated'])) {
                        DI::logger()->notice('published or updated keys are empty for activity', ['activity' => $activity]);
index baa46e373e1fb5bbf250aa0ceecb4c71dfc94be7..9aa25b3db55e1ff8d57e3bb667159a44c952f46e 100644 (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
         *
@@ -1812,7 +1800,7 @@ class Transmitter
                } else {
                        $data['attributedTo'] = $item['author-link'];
                }
-               $data['sensitive'] = self::isSensitive($item['uri-id']);
+               $data['sensitive'] = (bool)$item['sensitive'];
 
                if (!empty($item['conversation']) && ($item['conversation'] != './')) {
                        $data['conversation'] = $data['context'] = $item['conversation'];
index e9082efc669218cc31e1296ef3dbd905ac3d9284..1b7f7a40deda11011f3e7d7abca22ed0e88b9fd9 100644 (file)
@@ -56,7 +56,7 @@ use Friendica\Database\DBA;
 
 // This file is required several times during the test in DbaDefinition which justifies this condition
 if (!defined('DB_UPDATE_VERSION')) {
-       define('DB_UPDATE_VERSION', 1550);
+       define('DB_UPDATE_VERSION', 1552);
 }
 
 return [
@@ -1307,6 +1307,7 @@ return [
                        "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"],
                        "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"],
                        "rendered-hash" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""],
                        "rendered-html" => ["type" => "mediumtext", "comment" => "item.body converted to html"],
index f0183db81ad3b14b0d0dfb033ed72a03abd7fe33..45ab1121faec56f3a8489c4c1393ed65ff5cd83b 100644 (file)
                        "plink" => ["post-content", "plink"],
                        "location" => ["post-content", "location"],
                        "coord" => ["post-content", "coord"],
+                       "sensitive" => ["post-content", "sensitive"],
                        "app" => ["post-content", "app"],
                        "object-type" => ["post-content", "object-type"],
                        "object" => ["post-content", "object"],
                        "plink" => ["post-content", "plink"],
                        "location" => ["post-content", "location"],
                        "coord" => ["post-content", "coord"],
+                       "sensitive" => ["post-content", "sensitive"],
                        "app" => ["post-content", "app"],
                        "object-type" => ["post-content", "object-type"],
                        "object" => ["post-content", "object"],
                        "plink" => ["post-content", "plink"],
                        "location" => ["post-content", "location"],
                        "coord" => ["post-content", "coord"],
+                       "sensitive" => ["post-content", "sensitive"],
                        "app" => ["post-content", "app"],
                        "object-type" => ["post-content", "object-type"],
                        "object" => ["post-content", "object"],
                        "plink" => ["post-content", "plink"],
                        "location" => ["post-content", "location"],
                        "coord" => ["post-content", "coord"],
+                       "sensitive" => ["post-content", "sensitive"],
                        "app" => ["post-content", "app"],
                        "object-type" => ["post-content", "object-type"],
                        "object" => ["post-content", "object"],
index 74a8ad701581d894512d26c912aa211aacf1dc63..c19bbed3889ff21795869e990dbf4484993d460e 100644 (file)
@@ -1422,3 +1422,10 @@ function pre_update_1550()
        }
        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;
+}