]> git.mxchange.org Git - friendica.git/blob - src/Model/Post/Engagement.php
Add author to the search content / fix sidebar link to channels
[friendica.git] / src / Model / Post / Engagement.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Model\Post;
23
24 use Friendica\Content\Text\BBCode;
25 use Friendica\Core\Logger;
26 use Friendica\Core\Protocol;
27 use Friendica\Database\Database;
28 use Friendica\Database\DBA;
29 use Friendica\DI;
30 use Friendica\Model\Contact;
31 use Friendica\Model\Item;
32 use Friendica\Model\Post;
33 use Friendica\Model\Tag;
34 use Friendica\Model\Verb;
35 use Friendica\Protocol\Activity;
36 use Friendica\Protocol\Relay;
37 use Friendica\Util\DateTimeFormat;
38
39 // Channel
40
41 class Engagement
42 {
43         /**
44          * Store engagement data from an item array
45          *
46          * @param array $item
47          * @return void
48          */
49         public static function storeFromItem(array $item)
50         {
51                 if (in_array($item['verb'], [Activity::FOLLOW, Activity::VIEW, Activity::READ])) {
52                         Logger::debug('Technical activities are not stored', ['uri-id' => $item['uri-id'], 'parent-uri-id' => $item['parent-uri-id'], 'verb' => $item['verb']]);
53                         return;
54                 }
55
56                 $parent = Post::selectFirst(['uri-id', 'created', 'owner-id', 'uid', 'private', 'contact-contact-type', 'language',
57                         'title', 'content-warning', 'body', 'author-name', 'author-nick', 'author-addr', 'owner-name', 'owner-nick', 'owner-addr'],
58                         ['uri-id' => $item['parent-uri-id']]);
59
60                 if ($parent['created'] < DateTimeFormat::utc('now - ' . DI::config()->get('channel', 'engagement_hours') . ' hour')) {
61                         Logger::debug('Post is too old', ['uri-id' => $item['uri-id'], 'parent-uri-id' => $item['parent-uri-id'], 'created' => $parent['created']]);
62                         return;
63                 }
64
65                 $store = ($item['gravity'] != Item::GRAVITY_PARENT);
66
67                 if (!$store) {
68                         $store = Contact::hasFollowers($parent['owner-id']);
69                 }
70
71                 if (!$store) {
72                         $tagList = Relay::getSubscribedTags();
73                         foreach (array_column(Tag::getByURIId($item['parent-uri-id'], [Tag::HASHTAG]), 'name') as $tag) {
74                                 if (in_array($tag, $tagList)) {
75                                         $store = true;
76                                         break;
77                                 }
78                         }
79                 }
80
81                 $mediatype = self::getMediaType($item['parent-uri-id']);
82
83                 if (!$store) {
84                         $mediatype = !empty($mediatype);
85                 }
86
87                 $engagement = [
88                         'uri-id'       => $item['parent-uri-id'],
89                         'owner-id'     => $parent['owner-id'],
90                         'contact-type' => $parent['contact-contact-type'],
91                         'media-type'   => $mediatype,
92                         'language'     => $parent['language'],
93                         'searchtext'   => self::getSearchText($parent),
94                         'created'      => $parent['created'],
95                         'restricted'   => !in_array($item['network'], Protocol::FEDERATED) || ($parent['private'] != Item::PUBLIC),
96                         'comments'     => DBA::count('post', ['parent-uri-id' => $item['parent-uri-id'], 'gravity' => Item::GRAVITY_COMMENT]),
97                         'activities'   => DBA::count('post', [
98                                 "`parent-uri-id` = ? AND `gravity` = ? AND NOT `vid` IN (?, ?, ?)",
99                                 $item['parent-uri-id'], Item::GRAVITY_ACTIVITY,
100                                 Verb::getID(Activity::FOLLOW), Verb::getID(Activity::VIEW), Verb::getID(Activity::READ)
101                         ])
102                 ];
103                 if (!$store && ($engagement['comments'] == 0) && ($engagement['activities'] == 0)) {
104                         Logger::debug('No media, follower, subscribed tags, comments or activities. Engagement not stored', ['fields' => $engagement]);
105                         return;
106                 }
107                 $ret = DBA::insert('post-engagement', $engagement, Database::INSERT_UPDATE);
108                 Logger::debug('Engagement stored', ['fields' => $engagement, 'ret' => $ret]);
109         }
110
111         private static function getSearchText(array $item): string
112         {
113                 $body = $item['title'] . ' ' . $item['content-warning'] . ' ' . $item['body'] . ' ' .
114                         $item['author-name'] . ' ' . $item['author-nick'] . ' ' . $item['author-addr'] . ' ' . 
115                         $item['owner-name'] . ' ' . $item['owner-nick'] . ' ' . $item['owner-addr']; 
116
117                 $body = Post\Media::addAttachmentsToBody($item['uri-id'], $body);
118                 $text = BBCode::toPlaintext($body, false);
119
120                 do {
121                         $oldtext = $text;
122                         $text = str_replace(['  ', "\n", "\r"], ' ', $text);
123                 } while ($oldtext != $text);
124
125                 return $text;
126         }
127
128         private static function getMediaType(int $uri_id): int
129         {
130                 $media = Post\Media::getByURIId($uri_id);
131                 $type  = 0;
132                 foreach ($media as $entry) {
133                         if ($entry['type'] == Post\Media::IMAGE) {
134                                 $type = $type | 1;
135                         } elseif ($entry['type'] == Post\Media::VIDEO) {
136                                 $type = $type | 2;
137                         } elseif ($entry['type'] == Post\Media::AUDIO) {
138                                 $type = $type | 4;
139                         }
140                 }
141                 return $type;
142         }
143
144         /**
145          * Expire old engagement data
146          *
147          * @return void
148          */
149         public static function expire()
150         {
151                 DBA::delete('post-engagement', ["`created` < ?", DateTimeFormat::utc('now - ' . DI::config()->get('channel', 'engagement_hours') . ' hour')]);
152                 Logger::notice('Cleared expired engagements', ['rows' => DBA::affectedRows()]);
153         }
154 }