]> git.mxchange.org Git - friendica.git/blob - src/Module/Settings/Channels.php
User defined channels can now have got individual language definitions
[friendica.git] / src / Module / Settings / Channels.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2024, 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\Module\Settings;
23
24 use Friendica\App;
25 use Friendica\Content\Conversation\Factory;
26 use Friendica\Content\Conversation\Repository\UserDefinedChannel;
27 use Friendica\Core\L10n;
28 use Friendica\Core\Renderer;
29 use Friendica\Core\Session\Capability\IHandleUserSessions;
30 use Friendica\Model\Circle;
31 use Friendica\Model\User;
32 use Friendica\Module\BaseSettings;
33 use Friendica\Module\Response;
34 use Friendica\Network\HTTPException;
35 use Friendica\Util\Profiler;
36 use Psr\Log\LoggerInterface;
37
38 class Channels extends BaseSettings
39 {
40         /** @var UserDefinedChannel */
41         private $channel;
42         /** @var Factory\UserDefinedChannel */
43         private $userDefinedChannel;
44
45         public function __construct(Factory\UserDefinedChannel $userDefinedChannel, UserDefinedChannel $channel, App\Page $page, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
46         {
47                 parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
48
49                 $this->userDefinedChannel = $userDefinedChannel;
50                 $this->channel            = $channel;
51         }
52
53         protected function post(array $request = [])
54         {
55                 $uid = $this->session->getLocalUserId();
56                 if (!$uid) {
57                         throw new HTTPException\ForbiddenException($this->t('Permission denied.'));
58                 }
59
60                 if (empty($request['edit_channel']) && empty($request['add_channel'])) {
61                         return;
62                 }
63
64                 self::checkFormSecurityTokenRedirectOnError('/settings/channels', 'settings_channels');
65
66                 $channel_languages = User::getWantedLanguages($uid);
67
68                 if (!empty($request['add_channel'])) {
69                         if (!array_diff((array)$request['new_languages'], $channel_languages)) {
70                                 $request['new_languages'] = null;
71                         }
72
73                         $channel = $this->userDefinedChannel->createFromTableRow([
74                                 'label'            => $request['new_label'],
75                                 'description'      => $request['new_description'],
76                                 'access-key'       => substr(mb_strtolower($request['new_access_key']), 0, 1),
77                                 'uid'              => $uid,
78                                 'circle'           => (int)$request['new_circle'],
79                                 'include-tags'     => $this->cleanTags($request['new_include_tags']),
80                                 'exclude-tags'     => $this->cleanTags($request['new_exclude_tags']),
81                                 'full-text-search' => $request['new_text_search'],
82                                 'media-type'       => ($request['new_image'] ? 1 : 0) | ($request['new_video'] ? 2 : 0) | ($request['new_audio'] ? 4 : 0),
83                                 'languages'        => $request['new_languages'],
84                         ]);
85                         $saved = $this->channel->save($channel);
86                         $this->logger->debug('New channel added', ['saved' => $saved]);
87                         return;
88                 }
89
90                 foreach (array_keys((array)$request['label']) as $id) {
91                         if ($request['delete'][$id]) {
92                                 $success = $this->channel->deleteById($id, $uid);
93                                 $this->logger->debug('Channel deleted', ['id' => $id, 'success' => $success]);
94                                 continue;
95                         }
96
97                         if (!array_diff((array)$request['languages'][$id], $channel_languages)) {
98                                 $request['languages'][$id] = null;
99                         }
100
101                         $channel = $this->userDefinedChannel->createFromTableRow([
102                                 'id'               => $id,
103                                 'label'            => $request['label'][$id],
104                                 'description'      => $request['description'][$id],
105                                 'access-key'       => substr(mb_strtolower($request['access_key'][$id]), 0, 1),
106                                 'uid'              => $uid,
107                                 'circle'           => (int)$request['circle'][$id],
108                                 'include-tags'     => $this->cleanTags($request['include_tags'][$id]),
109                                 'exclude-tags'     => $this->cleanTags($request['exclude_tags'][$id]),
110                                 'full-text-search' => $request['text_search'][$id],
111                                 'media-type'       => ($request['image'][$id] ? 1 : 0) | ($request['video'][$id] ? 2 : 0) | ($request['audio'][$id] ? 4 : 0),
112                                 'languages'        => $request['languages'][$id],
113                         ]);
114                         $saved = $this->channel->save($channel);
115                         $this->logger->debug('Save channel', ['id' => $id, 'saved' => $saved]);
116                 }
117         }
118
119         protected function content(array $request = []): string
120         {
121                 parent::content();
122
123                 $uid = $this->session->getLocalUserId();
124                 if (!$uid) {
125                         throw new HTTPException\ForbiddenException($this->t('Permission denied.'));
126                 }
127
128                 $circles = [
129                         0  => $this->l10n->t('Global Community'),
130                         -3 => $this->l10n->t('Network'),
131                         -1 => $this->l10n->t('Following'),
132                         -2 => $this->l10n->t('Followers'),
133                 ];
134
135                 foreach (Circle::getByUserId($uid) as $circle) {
136                         $circles[$circle['id']] = $circle['name'];
137                 }
138
139                 $languages = $this->l10n->getLanguageCodes(true);
140                 $channel_languages = User::getWantedLanguages($uid);
141
142                 $channels = [];
143                 foreach ($this->channel->selectByUid($uid) as $channel) {
144                         if (!empty($request['id'])) {
145                                 $open = $channel->code == $request['id'];
146                         } elseif (!empty($request['new_label'])) {
147                                 $open = $channel->label == $request['new_label'];
148                         } else {
149                                 $open = false;
150                         }
151
152                         $channels[] = [
153                                 'id'           => $channel->code,
154                                 'open'         => $open,
155                                 'label'        => ["label[$channel->code]", $this->t('Label'), $channel->label, '', $this->t('Required')],
156                                 'description'  => ["description[$channel->code]", $this->t("Description"), $channel->description],
157                                 'access_key'   => ["access_key[$channel->code]", $this->t("Access Key"), $channel->accessKey],
158                                 'circle'       => ["circle[$channel->code]", $this->t('Circle/Channel'), $channel->circle, '', $circles],
159                                 'include_tags' => ["include_tags[$channel->code]", $this->t("Include Tags"), str_replace(',', ', ', $channel->includeTags)],
160                                 'exclude_tags' => ["exclude_tags[$channel->code]", $this->t("Exclude Tags"), str_replace(',', ', ', $channel->excludeTags)],
161                                 'text_search'  => ["text_search[$channel->code]", $this->t("Full Text Search"), $channel->fullTextSearch],
162                                 'image'        => ["image[$channel->code]", $this->t("Images"), $channel->mediaType & 1],
163                                 'video'        => ["video[$channel->code]", $this->t("Videos"), $channel->mediaType & 2],
164                                 'audio'        => ["audio[$channel->code]", $this->t("Audio"), $channel->mediaType & 4],
165                                 'languages'    => ["languages[$channel->code][]", $this->t('Languages'), $channel->languages ?? $channel_languages, $this->t('Select all languages that you want to see in this channel.'), $languages, 'multiple'],
166                                 'delete'       => ["delete[$channel->code]", $this->t("Delete channel") . ' (' . $channel->label . ')', false, $this->t("Check to delete this entry from the channel list")]
167                         ];
168                 }
169
170                 $t = Renderer::getMarkupTemplate('settings/channels.tpl');
171                 return Renderer::replaceMacros($t, [
172                         'open'         => count($channels) == 0,
173                         'label'        => ["new_label", $this->t('Label'), '', $this->t('Short name for the channel. It is displayed on the channels widget.'), $this->t('Required')],
174                         'description'  => ["new_description", $this->t("Description"), '', $this->t('This should describe the content of the channel in a few word.')],
175                         'access_key'   => ["new_access_key", $this->t("Access Key"), '', $this->t('When you want to access this channel via an access key, you can define it here. Pay attention to not use an already used one.')],
176                         'circle'       => ['new_circle', $this->t('Circle/Channel'), 0, $this->t('Select a circle or channel, that your channel should be based on.'), $circles],
177                         'include_tags' => ["new_include_tags", $this->t("Include Tags"), '', $this->t('Comma separated list of tags. A post will be used when it contains any of the listed tags.')],
178                         'exclude_tags' => ["new_exclude_tags", $this->t("Exclude Tags"), '', $this->t('Comma separated list of tags. If a post contain any of these tags, then it will not be part of nthis channel.')],
179                         'text_search'  => ["new_text_search", $this->t("Full Text Search"), '', $this->t('Search terms for the body, supports the "boolean mode" operators from MariaDB. See the help for a complete list of operators and additional keywords: %s', '<a href="help/Channels">help/Channels</a>')],
180                         'image'        => ['new_image', $this->t("Images"), false, $this->t("Check to display images in the channel.")],
181                         'video'        => ["new_video", $this->t("Videos"), false, $this->t("Check to display videos in the channel.")],
182                         'audio'        => ["new_audio", $this->t("Audio"), false, $this->t("Check to display audio in the channel.")],
183                         'languages'    => ["new_languages[]", $this->t('Languages'), $channel_languages, $this->t('Select all languages that you want to see in this channel.'), $languages, 'multiple'],
184                         '$l10n'        => [
185                                 'title'          => $this->t('Channels'),
186                                 'intro'          => $this->t('This page can be used to define your own channels.'),
187                                 'addtitle'       => $this->t('Add new entry to the channel list'),
188                                 'addsubmit'      => $this->t('Add'),
189                                 'savechanges'    => $this->t('Save'),
190                                 'currenttitle'   => $this->t('Current Entries in the channel list'),
191                                 'thurl'          => $this->t('Blocked server domain pattern'),
192                                 'threason'       => $this->t('Reason for the block'),
193                                 'delentry'       => $this->t('Delete entry from the channel list'),
194                                 'confirm_delete' => $this->t('Delete entry from the channel list?'),
195                         ],
196                         '$entries' => $channels,
197                         '$baseurl' => $this->baseUrl,
198
199                         '$form_security_token' => self::getFormSecurityToken('settings_channels'),
200                 ]);
201         }
202
203         private function cleanTags(string $tag_list): string
204         {
205                 $tags = [];
206
207                 $tagitems = explode(',', mb_strtolower($tag_list));
208                 foreach ($tagitems as $tag) {
209                         $tag = trim($tag, '# ');
210                         if (!empty($tag)) {
211                                 $tags[] = preg_replace('#\s#u', '', $tag);
212                         }
213                 }
214                 return implode(',', $tags);
215         }
216 }