From d68572ea44ccf76bdff8e951df94074702d8cac4 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 19 Sep 2023 09:05:28 +0000 Subject: [PATCH 01/57] Channels can now be created by users --- database.sql | 20 +++- doc/database.md | 1 + doc/database/db_channel.md | 36 +++++++ src/Content/Conversation/Entity/Timeline.php | 41 +++++-- src/Content/Conversation/Factory/Timeline.php | 39 ++++++- .../Conversation/Repository/Channel.php | 100 ++++++++++++++++++ src/DI.php | 8 ++ src/Module/Conversation/Channel.php | 9 +- src/Module/Conversation/Community.php | 5 +- src/Module/Conversation/Network.php | 16 +-- src/Module/Conversation/Timeline.php | 42 +++++++- src/Module/Update/Channel.php | 2 +- src/Module/Update/Network.php | 2 +- static/dbstructure.config.php | 20 +++- 14 files changed, 306 insertions(+), 35 deletions(-) create mode 100644 doc/database/db_channel.md create mode 100644 src/Content/Conversation/Repository/Channel.php diff --git a/database.sql b/database.sql index 329381b95..8598f6fe6 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2023.09-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1534 +-- DB_UPDATE_VERSION 1535 -- ------------------------------------------ @@ -492,6 +492,24 @@ CREATE TABLE IF NOT EXISTS `cache` ( INDEX `k_expires` (`k`,`expires`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Stores temporary data'; +-- +-- TABLE channel +-- +CREATE TABLE IF NOT EXISTS `channel` ( + `id` int unsigned NOT NULL auto_increment COMMENT '', + `uid` mediumint unsigned NOT NULL COMMENT 'User id', + `label` varchar(64) NOT NULL COMMENT 'Channel label', + `description` varchar(64) COMMENT 'Channel description', + `access-key` varchar(1) COMMENT 'Access key', + `include-tags` varchar(255) COMMENT 'Comma separated list of tags that will be included in the channel', + `exclude-tags` varchar(255) COMMENT 'Comma separated list of tags that aren\'t allowed in the channel', + `full-text-search` varchar(255) COMMENT 'Full text search pattern, see https://mariadb.com/kb/en/full-text-index-overview/#in-boolean-mode', + `media-type` smallint unsigned COMMENT 'Filtered media types', + PRIMARY KEY(`id`), + INDEX `uid` (`uid`), + FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='User defined Channels'; + -- -- TABLE config -- diff --git a/doc/database.md b/doc/database.md index 25b9baefb..516be3bae 100644 --- a/doc/database.md +++ b/doc/database.md @@ -17,6 +17,7 @@ Database Tables | [arrived-activity](help/database/db_arrived-activity) | Id of arrived activities | | [attach](help/database/db_attach) | file attachments | | [cache](help/database/db_cache) | Stores temporary data | +| [channel](help/database/db_channel) | User defined Channels | | [config](help/database/db_config) | main configuration storage | | [contact](help/database/db_contact) | contact table | | [contact-relation](help/database/db_contact-relation) | Contact relations | diff --git a/doc/database/db_channel.md b/doc/database/db_channel.md new file mode 100644 index 000000000..1d5bfc73e --- /dev/null +++ b/doc/database/db_channel.md @@ -0,0 +1,36 @@ +Table channel +=========== + +User defined Channels + +Fields +------ + +| Field | Description | Type | Null | Key | Default | Extra | +| ---------------- | ------------------------------------------------------------------------------------------------- | ------------------ | ---- | --- | ------- | -------------- | +| id | | int unsigned | NO | PRI | NULL | auto_increment | +| uid | User id | mediumint unsigned | NO | | NULL | | +| label | Channel label | varchar(64) | NO | | NULL | | +| description | Channel description | varchar(64) | YES | | NULL | | +| access-key | Access key | varchar(1) | YES | | NULL | | +| include-tags | Comma separated list of tags that will be included in the channel | varchar(255) | YES | | NULL | | +| exclude-tags | Comma separated list of tags that aren't allowed in the channel | varchar(255) | YES | | NULL | | +| full-text-search | Full text search pattern, see https://mariadb.com/kb/en/full-text-index-overview/#in-boolean-mode | varchar(255) | YES | | NULL | | +| media-type | Filtered media types | smallint unsigned | YES | | NULL | | + +Indexes +------------ + +| Name | Fields | +| ------- | ------ | +| PRIMARY | id | +| uid | uid | + +Foreign Keys +------------ + +| Field | Target Table | Target Field | +|-------|--------------|--------------| +| uid | [user](help/database/db_user) | uid | + +Return to [database documentation](help/database) diff --git a/src/Content/Conversation/Entity/Timeline.php b/src/Content/Conversation/Entity/Timeline.php index b9ab1e1a0..ce9e3c62f 100644 --- a/src/Content/Conversation/Entity/Timeline.php +++ b/src/Content/Conversation/Entity/Timeline.php @@ -22,11 +22,15 @@ namespace Friendica\Content\Conversation\Entity; /** - * @property-read string $code Channel code - * @property-read string $label Channel label - * @property-read string $description Channel description - * @property-read string $accessKey Access key - * @property-read string $path Path + * @property-read string $code Channel code + * @property-read string $label Channel label + * @property-read string $description Channel description + * @property-read string $accessKey Access key + * @property-read string $path Path + * @property-read int $uid User of the channel + * @property-read string $includeTags The tags to include in the channel + * @property-read string $excludeTags The tags to exclude in the channel + * @property-read string $fullTextSearch full text search pattern */ final class Timeline extends \Friendica\BaseEntity { @@ -56,13 +60,28 @@ final class Timeline extends \Friendica\BaseEntity protected $accessKey; /** @var string */ protected $path; + /** @var int */ + protected $uid; + /** @var string */ + protected $includeTags; + /** @var string */ + protected $excludeTags; + /** @var string */ + protected $fullTextSearch; + /** @var int */ + protected $mediaType; - public function __construct(string $code, string $label, string $description, string $accessKey, string $path = null) + public function __construct(string $code = null, string $label = null, string $description = null, string $accessKey = null, string $path = null, int $uid = null, string $includeTags = null, string $excludeTags = null, string $fullTextSearch = null, int $mediaType = null) { - $this->code = $code; - $this->label = $label; - $this->description = $description; - $this->accessKey = $accessKey; - $this->path = $path; + $this->code = $code; + $this->label = $label; + $this->description = $description; + $this->accessKey = $accessKey; + $this->path = $path; + $this->uid = $uid; + $this->includeTags = $includeTags; + $this->excludeTags = $excludeTags; + $this->fullTextSearch = $fullTextSearch; + $this->mediaType = $mediaType; } } diff --git a/src/Content/Conversation/Factory/Timeline.php b/src/Content/Conversation/Factory/Timeline.php index 817f61713..0e4c0b76d 100644 --- a/src/Content/Conversation/Factory/Timeline.php +++ b/src/Content/Conversation/Factory/Timeline.php @@ -21,27 +21,48 @@ namespace Friendica\Content\Conversation\Factory; +use Friendica\Capabilities\ICanCreateFromTableRow; use Friendica\Content\Conversation\Collection\Timelines; use Friendica\Model\User; use Friendica\Content\Conversation\Entity\Timeline as TimelineEntity; +use Friendica\Content\Conversation\Repository\Channel; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\L10n; use Friendica\Module\Conversation\Community; use Psr\Log\LoggerInterface; -final class Timeline extends \Friendica\BaseFactory +final class Timeline extends \Friendica\BaseFactory implements ICanCreateFromTableRow { /** @var L10n */ protected $l10n; /** @var IManageConfigValues The config */ protected $config; + /** @var Channel */ + protected $channel; - public function __construct(L10n $l10n, LoggerInterface $logger, IManageConfigValues $config) + public function __construct(Channel $channel, L10n $l10n, LoggerInterface $logger, IManageConfigValues $config) { parent::__construct($logger); - $this->l10n = $l10n; - $this->config = $config; + $this->channel = $channel; + $this->l10n = $l10n; + $this->config = $config; + } + + public function createFromTableRow(array $row): TimelineEntity + { + return new TimelineEntity( + $row['id'] ?? null, + $row['label'], + $row['description'] ?? null, + $row['access-key'] ?? null, + null, + $row['uid'], + $row['include-tags'] ?? null, + $row['exclude-tags'] ?? null, + $row['full-text-search'] ?? null, + $row['media-type'] ?? null, + ); } /** @@ -65,6 +86,11 @@ final class Timeline extends \Friendica\BaseFactory new TimelineEntity(TimelineEntity::AUDIO, $this->l10n->t('Audio'), $this->l10n->t('Posts with audio'), 'd'), new TimelineEntity(TimelineEntity::VIDEO, $this->l10n->t('Videos'), $this->l10n->t('Posts with videos'), 'v'), ]; + + foreach ($this->channel->selectByUid($uid) as $channel) { + $tabs[] = $channel; + } + return new Timelines($tabs); } @@ -113,8 +139,11 @@ final class Timeline extends \Friendica\BaseFactory return in_array($selectedTab, [TimelineEntity::LOCAL, TimelineEntity::GLOBAL]); } - public function isChannel(string $selectedTab): bool + public function isChannel(string $selectedTab, int $uid): bool { + if (is_numeric($selectedTab) && $uid && $this->channel->existsById($selectedTab, $uid)) { + return true; + } return in_array($selectedTab, [TimelineEntity::WHATSHOT, TimelineEntity::FORYOU, TimelineEntity::FOLLOWERS, TimelineEntity::SHARERSOFSHARERS, TimelineEntity::IMAGE, TimelineEntity::VIDEO, TimelineEntity::AUDIO, TimelineEntity::LANGUAGE]); } } diff --git a/src/Content/Conversation/Repository/Channel.php b/src/Content/Conversation/Repository/Channel.php new file mode 100644 index 000000000..a88a2f577 --- /dev/null +++ b/src/Content/Conversation/Repository/Channel.php @@ -0,0 +1,100 @@ +. + * + */ + +namespace Friendica\Content\Conversation\Repository; + +use Friendica\BaseCollection; +use Friendica\Content\Conversation\Entity\Timeline as EntityTimeline; +use Friendica\Content\Conversation\Factory\Timeline; +use Friendica\Database\Database; +use Psr\Log\LoggerInterface; + +class Channel extends \Friendica\BaseRepository +{ + protected static $table_name = 'channel'; + + public function __construct(Database $database, LoggerInterface $logger, Timeline $factory) + { + parent::__construct($database, $logger, $factory); + } + + /** + * Fetch a single user channel + * + * @param int $id + * @param int $uid + * @return EntityTimeline + * @throws \Friendica\Network\HTTPException\NotFoundException + */ + public function selectById(int $id, int $uid): EntityTimeline + { + return $this->_selectOne(['id' => $id, 'uid' => $uid]); + } + + /** + * Checks if the provided channel id exists for this user + * + * @param integer $id + * @param integer $uid + * @return boolean + */ + public function existsById(int $id, int $uid): bool + { + return $this->exists(['id' => $id, 'uid' => $uid]); + } + + /** + * Fetch all user channels + * + * @param integer $uid + * @return BaseCollection + */ + public function selectByUid(int $uid): BaseCollection + { + return $this->_select(['uid' => $uid]); + } + + public function save(EntityTimeline $Channel): EntityTimeline + { + $fields = [ + 'label' => $Channel->label, + 'description' => $Channel->description, + 'access-key' => $Channel->accessKey, + 'uid' => $Channel->uid, + 'include-tags' => $Channel->includeTags, + 'exclude-tags' => $Channel->excludeTags, + 'full-text-search' => $Channel->fullTextSearch, + 'media-type' => $Channel->mediaType, + ]; + + if ($Channel->code) { + $this->db->update(self::$table_name, $fields, ['uid' => $Channel->uid, 'id' => $Channel->code]); + } else { + $this->db->insert(self::$table_name, $fields, Database::INSERT_IGNORE); + + $newChannelId = $this->db->lastInsertId(); + + $Channel = $this->selectById($newChannelId, $Channel->uid); + } + + return $Channel; + } +} diff --git a/src/DI.php b/src/DI.php index 681c8fcbc..7c221b5ef 100644 --- a/src/DI.php +++ b/src/DI.php @@ -555,6 +555,14 @@ abstract class DI return self::$dice->create(Content\Conversation\Factory\Timeline::class); } + /** + * @return Content\Conversation\Repository\Channel + */ + public static function ChannelRepository() + { + return self::$dice->create(Content\Conversation\Repository\Channel::class); + } + /** * @return Contact\Introduction\Repository\Introduction */ diff --git a/src/Module/Conversation/Channel.php b/src/Module/Conversation/Channel.php index 35c988ce7..9bb3a4233 100644 --- a/src/Module/Conversation/Channel.php +++ b/src/Module/Conversation/Channel.php @@ -27,6 +27,7 @@ use Friendica\Content\BoundariesPager; use Friendica\Content\Conversation; use Friendica\Content\Conversation\Entity\Timeline as TimelineEntity; use Friendica\Content\Conversation\Factory\Timeline as TimelineFactory; +use Friendica\Content\Conversation\Repository\Channel as RepositoryChannel; use Friendica\Content\Feature; use Friendica\Content\Nav; use Friendica\Content\Text\HTML; @@ -57,9 +58,9 @@ class Channel extends Timeline /** @var SystemMessages */ protected $systemMessages; - public function __construct(TimelineFactory $timeline, Conversation $conversation, App\Page $page, SystemMessages $systemMessages, Mode $mode, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + public function __construct(RepositoryChannel $channel, TimelineFactory $timeline, Conversation $conversation, App\Page $page, SystemMessages $systemMessages, Mode $mode, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) { - parent::__construct($mode, $session, $database, $pConfig, $config, $cache, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + parent::__construct($channel, $mode, $session, $database, $pConfig, $config, $cache, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); $this->timeline = $timeline; $this->conversation = $conversation; @@ -109,7 +110,7 @@ class Channel extends Timeline $o .= $this->conversation->statusEditor([], 0, true); } - if ($this->timeline->isChannel($this->selectedTab)) { + if ($this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId())) { $items = $this->getChannelItems(); $order = 'created'; } else { @@ -155,7 +156,7 @@ class Channel extends Timeline $this->selectedTab = TimelineEntity::FORYOU; } - if (!$this->timeline->isChannel($this->selectedTab) && !$this->timeline->isCommunity($this->selectedTab)) { + if (!$this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId()) && !$this->timeline->isCommunity($this->selectedTab)) { throw new HTTPException\BadRequestException($this->l10n->t('Channel not available.')); } diff --git a/src/Module/Conversation/Community.php b/src/Module/Conversation/Community.php index 42f562096..75f937d35 100644 --- a/src/Module/Conversation/Community.php +++ b/src/Module/Conversation/Community.php @@ -28,6 +28,7 @@ use Friendica\Content\BoundariesPager; use Friendica\Content\Conversation; use Friendica\Content\Conversation\Entity\Timeline as TimelineEntity; use Friendica\Content\Conversation\Factory\Timeline as TimelineFactory; +use Friendica\Content\Conversation\Repository\Channel; use Friendica\Content\Feature; use Friendica\Content\Nav; use Friendica\Content\Text\HTML; @@ -69,9 +70,9 @@ class Community extends Timeline /** @var SystemMessages */ protected $systemMessages; - public function __construct(TimelineFactory $timeline, Conversation $conversation, App\Page $page, SystemMessages $systemMessages, Mode $mode, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + public function __construct(Channel $channel, TimelineFactory $timeline, Conversation $conversation, App\Page $page, SystemMessages $systemMessages, Mode $mode, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) { - parent::__construct($mode, $session, $database, $pConfig, $config, $cache, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + parent::__construct($channel, $mode, $session, $database, $pConfig, $config, $cache, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); $this->timeline = $timeline; $this->conversation = $conversation; diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index 21ead331f..04f3f232f 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -27,6 +27,7 @@ use Friendica\Content\BoundariesPager; use Friendica\Content\Conversation; use Friendica\Content\Conversation\Entity\Timeline as TimelineEntity; use Friendica\Content\Conversation\Factory\Timeline as TimelineFactory; +use Friendica\Content\Conversation\Repository\Channel; use Friendica\Content\Feature; use Friendica\Content\GroupManager; use Friendica\Content\Nav; @@ -96,9 +97,9 @@ class Network extends Timeline /** @var TimelineFactory */ protected $timeline; - public function __construct(App $app, TimelineFactory $timeline, SystemMessages $systemMessages, Mode $mode, Conversation $conversation, App\Page $page, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + public function __construct(Channel $channel, App $app, TimelineFactory $timeline, SystemMessages $systemMessages, Mode $mode, Conversation $conversation, App\Page $page, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) { - parent::__construct($mode, $session, $database, $pConfig, $config, $cache, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + parent::__construct($channel, $mode, $session, $database, $pConfig, $config, $cache, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); $this->app = $app; $this->timeline = $timeline; @@ -125,7 +126,7 @@ class Network extends Timeline $o = ''; - if ($this->timeline->isChannel($this->selectedTab)) { + if ($this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId())) { if (!in_array($this->selectedTab, [TimelineEntity::FOLLOWERS, TimelineEntity::FORYOU]) && $this->config->get('system', 'community_no_sharer')) { $this->page['aside'] .= $this->getNoSharerWidget($module); } @@ -274,7 +275,6 @@ class Network extends Timeline */ private function getTabsHTML() { - // @todo user confgurable selection of tabs $tabs = $this->getTabArray($this->timeline->getNetworkFeeds($this->args->getCommand()), 'network'); $network_timelines = $this->pConfig->get($this->session->getLocalUserId(), 'system', 'network_timelines', []); @@ -289,7 +289,7 @@ class Network extends Timeline if (!empty($network_timelines)) { $tabs = []; - foreach (array_keys($arr['tabs']) as $tab) { + foreach (array_column($arr['tabs'], 'code') as $tab) { if (in_array($tab, $network_timelines)) { $tabs[] = $arr['tabs'][$tab]; } @@ -313,11 +313,11 @@ class Network extends Timeline if (!$this->selectedTab) { $this->selectedTab = self::getTimelineOrderBySession($this->session, $this->pConfig); - } elseif (!$this->timeline->isChannel($this->selectedTab) && !$this->timeline->isCommunity($this->selectedTab)) { + } elseif (!$this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId()) && !$this->timeline->isCommunity($this->selectedTab)) { throw new HTTPException\BadRequestException($this->l10n->t('Network feed not available.')); } - if (($this->network || $this->circleId || $this->groupContactId) && ($this->timeline->isChannel($this->selectedTab) || $this->timeline->isCommunity($this->selectedTab))) { + if (($this->network || $this->circleId || $this->groupContactId) && ($this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId()) || $this->timeline->isCommunity($this->selectedTab))) { $this->selectedTab = TimelineEntity::RECEIVED; } @@ -342,7 +342,7 @@ class Network extends Timeline $this->mention = false; } elseif (in_array($this->selectedTab, [TimelineEntity::RECEIVED, TimelineEntity::STAR]) || $this->timeline->isCommunity($this->selectedTab)) { $this->order = 'received'; - } elseif (($this->selectedTab == TimelineEntity::CREATED) || $this->timeline->isChannel($this->selectedTab)) { + } elseif (($this->selectedTab == TimelineEntity::CREATED) || $this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId())) { $this->order = 'created'; } else { $this->order = 'commented'; diff --git a/src/Module/Conversation/Timeline.php b/src/Module/Conversation/Timeline.php index 1a4d98e61..9c53634ea 100644 --- a/src/Module/Conversation/Timeline.php +++ b/src/Module/Conversation/Timeline.php @@ -26,6 +26,7 @@ use Friendica\App\Mode; use Friendica\BaseModule; use Friendica\Content\Conversation\Collection\Timelines; use Friendica\Content\Conversation\Entity\Timeline as TimelineEntity; +use Friendica\Content\Conversation\Repository\Channel; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -79,11 +80,14 @@ class Timeline extends BaseModule protected $config; /** @var ICanCache */ protected $cache; + /** @var Channel */ + protected $channel; - public function __construct(Mode $mode, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + public function __construct(Channel $channel, Mode $mode, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + $this->channel = $channel; $this->mode = $mode; $this->session = $session; $this->database = $database; @@ -176,6 +180,7 @@ class Timeline extends BaseModule $path = $tab->path ?? $prefix . '/' . $tab->code; } $tabs[$tab->code] = [ + 'code' => $tab->code, 'label' => $tab->label, 'url' => $path, 'sel' => $this->selectedTab == $tab->code ? 'active' : '', @@ -300,6 +305,8 @@ class Timeline extends BaseModule $condition = ["`media-type` & ?", 4]; } elseif ($this->selectedTab == TimelineEntity::LANGUAGE) { $condition = ["JSON_EXTRACT(JSON_KEYS(language), '$[0]') = ?", $this->l10n->convertCodeForLanguageDetection(User::getLanguageCode($uid))]; + } elseif (is_numeric($this->selectedTab)) { + $condition = $this->getUserChannelConditions($this->selectedTab, $this->session->getLocalUserId()); } if ($this->selectedTab != TimelineEntity::LANGUAGE) { @@ -359,6 +366,39 @@ class Timeline extends BaseModule return $items; } + private function getUserChannelConditions(int $id, int $uid): array + { + $channel = $this->channel->selectById($id, $uid); + if (empty($channel)) { + return []; + } + + $condition = []; + + if (!empty($channel->fullTextSearch)) { + $first = $this->database->selectFirst('post-engagement', ['uri-id']); + $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-content` WHERE `uri-id` >= ? AND MATCH (`title`, `content-warning`, `body`) AGAINST (? IN BOOLEAN MODE))", $first['uri-id'], $channel->fullTextSearch]); + } + + if (!empty($channel->includeTags)) { + $search = explode(',', mb_strtolower($channel->includeTags)); + $placeholders = substr(str_repeat("?, ", count($search)), 0, -2); + $condition = DBA::mergeConditions($condition, array_merge(["`uri-id` IN (SELECT `uri-id` FROM `post-tag` INNER JOIN `tag` ON `tag`.`id` = `post-tag`.`tid` WHERE `post-tag`.`type` = 1 AND `name` IN (" . $placeholders . "))"], $search)); + } + + if (!empty($channel->excludeTags)) { + $search = explode(',', mb_strtolower($channel->excludeTags)); + $placeholders = substr(str_repeat("?, ", count($search)), 0, -2); + $condition = DBA::mergeConditions($condition, array_merge(["NOT `uri-id` IN (SELECT `uri-id` FROM `post-tag` INNER JOIN `tag` ON `tag`.`id` = `post-tag`.`tid` WHERE `post-tag`.`type` = 1 AND `name` IN (" . $placeholders . "))"], $search)); + } + + if (!empty($channel->mediaType)) { + $condition = DBA::mergeConditions($condition, ["`media-type` & ?", $channel->mediaType]); + } + + return $condition; + } + private function addLanguageCondition(int $uid, array $condition): array { $conditions = []; diff --git a/src/Module/Update/Channel.php b/src/Module/Update/Channel.php index ac35d9c26..0abe036d6 100644 --- a/src/Module/Update/Channel.php +++ b/src/Module/Update/Channel.php @@ -38,7 +38,7 @@ class Channel extends ChannelModule $o = ''; if ($this->update || $this->force) { - if ($this->timeline->isChannel($this->selectedTab)) { + if ($this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId())) { $items = $this->getChannelItems(); } else { $items = $this->getCommunityItems(); diff --git a/src/Module/Update/Network.php b/src/Module/Update/Network.php index e8a2dce07..612d4079c 100644 --- a/src/Module/Update/Network.php +++ b/src/Module/Update/Network.php @@ -41,7 +41,7 @@ class Network extends NetworkModule System::htmlUpdateExit($o); } - if ($this->timeline->isChannel($this->selectedTab)) { + if ($this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId())) { $items = $this->getChannelItems(); } elseif ($this->timeline->isCommunity($this->selectedTab)) { $items = $this->getCommunityItems(); diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 606173b81..e918a4491 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -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', 1534); + define('DB_UPDATE_VERSION', 1535); } return [ @@ -551,6 +551,24 @@ return [ "k_expires" => ["k", "expires"], ] ], + "channel" => [ + "comment" => "User defined Channels", + "fields" => [ + "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "foreign" => ["user" => "uid"], "comment" => "User id"], + "label" => ["type" => "varchar(64)", "not null" => "1", "comment" => "Channel label"], + "description" => ["type" => "varchar(64)", "comment" => "Channel description"], + "access-key" => ["type" => "varchar(1)", "comment" => "Access key"], + "include-tags" => ["type" => "varchar(255)", "comment" => "Comma separated list of tags that will be included in the channel"], + "exclude-tags" => ["type" => "varchar(255)", "comment" => "Comma separated list of tags that aren't allowed in the channel"], + "full-text-search" => ["type" => "varchar(255)", "comment" => "Full text search pattern, see https://mariadb.com/kb/en/full-text-index-overview/#in-boolean-mode"], + "media-type" => ["type" => "smallint unsigned", "comment" => "Filtered media types"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid" => ["uid"], + ] + ], "config" => [ "comment" => "main configuration storage", "fields" => [ From a2f119e18ea276776a46d3deafe9b2bd89bbfcef Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 19 Sep 2023 09:09:20 +0000 Subject: [PATCH 02/57] Fix code standards --- src/Content/Conversation/Repository/Channel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Content/Conversation/Repository/Channel.php b/src/Content/Conversation/Repository/Channel.php index a88a2f577..7c4fe1dcd 100644 --- a/src/Content/Conversation/Repository/Channel.php +++ b/src/Content/Conversation/Repository/Channel.php @@ -38,7 +38,7 @@ class Channel extends \Friendica\BaseRepository /** * Fetch a single user channel - * + * * @param int $id * @param int $uid * @return EntityTimeline From 00eb6b01ff62fbb98e1e619a35cc160df3c828ff Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 19 Sep 2023 09:23:27 +0000 Subject: [PATCH 03/57] Fix selected timelines --- src/Module/Conversation/Network.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index 04f3f232f..095b2cceb 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -289,9 +289,9 @@ class Network extends Timeline if (!empty($network_timelines)) { $tabs = []; - foreach (array_column($arr['tabs'], 'code') as $tab) { - if (in_array($tab, $network_timelines)) { - $tabs[] = $arr['tabs'][$tab]; + foreach ($arr['tabs'] as $tab) { + if (in_array($tab['code'], $network_timelines)) { + $tabs[] = $tab; } } } else { From 5056c95d60a3e2e891ab1da0196d52d2c8f80712 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 19 Sep 2023 10:20:15 +0000 Subject: [PATCH 04/57] Show network elements in the channel widget --- src/Content/Conversation/Factory/Timeline.php | 5 +++++ src/Content/Widget.php | 4 ++++ src/Module/Conversation/Network.php | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Content/Conversation/Factory/Timeline.php b/src/Content/Conversation/Factory/Timeline.php index 0e4c0b76d..2a6e12330 100644 --- a/src/Content/Conversation/Factory/Timeline.php +++ b/src/Content/Conversation/Factory/Timeline.php @@ -134,6 +134,11 @@ final class Timeline extends \Friendica\BaseFactory implements ICanCreateFromTab return new Timelines($tabs); } + public function isNetwork(string $selectedTab): bool + { + return in_array($selectedTab, [TimelineEntity::COMMENTED, TimelineEntity::RECEIVED, TimelineEntity::CREATED, TimelineEntity::MENTION, TimelineEntity::STAR]); + } + public function isCommunity(string $selectedTab): bool { return in_array($selectedTab, [TimelineEntity::LOCAL, TimelineEntity::GLOBAL]); diff --git a/src/Content/Widget.php b/src/Content/Widget.php index 1f73f0449..486bada7d 100644 --- a/src/Content/Widget.php +++ b/src/Content/Widget.php @@ -560,6 +560,10 @@ class Widget { $channels = []; + foreach (DI::TimelineFactory()->getNetworkFeeds('') as $channel) { + $channels[] = ['ref' => $channel->code, 'name' => $channel->label]; + } + foreach (DI::TimelineFactory()->getChannelsForUser($uid) as $channel) { $channels[] = ['ref' => $channel->code, 'name' => $channel->label]; } diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index 095b2cceb..c05a06d39 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -313,7 +313,7 @@ class Network extends Timeline if (!$this->selectedTab) { $this->selectedTab = self::getTimelineOrderBySession($this->session, $this->pConfig); - } elseif (!$this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId()) && !$this->timeline->isCommunity($this->selectedTab)) { + } elseif (!$this->timeline->isNetwork($this->selectedTab) && !$this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId()) && !$this->timeline->isCommunity($this->selectedTab)) { throw new HTTPException\BadRequestException($this->l10n->t('Network feed not available.')); } From 63921ccfcac6e0c6be6964e811eb0536b6b2a419 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 19 Sep 2023 14:23:02 +0000 Subject: [PATCH 05/57] Changed class names --- src/Content/Conversation/Repository/Channel.php | 8 ++++---- src/Module/Conversation/Channel.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Content/Conversation/Repository/Channel.php b/src/Content/Conversation/Repository/Channel.php index 7c4fe1dcd..c067c5d7a 100644 --- a/src/Content/Conversation/Repository/Channel.php +++ b/src/Content/Conversation/Repository/Channel.php @@ -22,7 +22,7 @@ namespace Friendica\Content\Conversation\Repository; use Friendica\BaseCollection; -use Friendica\Content\Conversation\Entity\Timeline as EntityTimeline; +use Friendica\Content\Conversation\Entity\Timeline as TimelineEntity; use Friendica\Content\Conversation\Factory\Timeline; use Friendica\Database\Database; use Psr\Log\LoggerInterface; @@ -41,10 +41,10 @@ class Channel extends \Friendica\BaseRepository * * @param int $id * @param int $uid - * @return EntityTimeline + * @return TimelineEntity * @throws \Friendica\Network\HTTPException\NotFoundException */ - public function selectById(int $id, int $uid): EntityTimeline + public function selectById(int $id, int $uid): TimelineEntity { return $this->_selectOne(['id' => $id, 'uid' => $uid]); } @@ -72,7 +72,7 @@ class Channel extends \Friendica\BaseRepository return $this->_select(['uid' => $uid]); } - public function save(EntityTimeline $Channel): EntityTimeline + public function save(TimelineEntity $Channel): TimelineEntity { $fields = [ 'label' => $Channel->label, diff --git a/src/Module/Conversation/Channel.php b/src/Module/Conversation/Channel.php index 9bb3a4233..3affa1a15 100644 --- a/src/Module/Conversation/Channel.php +++ b/src/Module/Conversation/Channel.php @@ -27,7 +27,7 @@ use Friendica\Content\BoundariesPager; use Friendica\Content\Conversation; use Friendica\Content\Conversation\Entity\Timeline as TimelineEntity; use Friendica\Content\Conversation\Factory\Timeline as TimelineFactory; -use Friendica\Content\Conversation\Repository\Channel as RepositoryChannel; +use Friendica\Content\Conversation\Repository\Channel as ChannelRepository; use Friendica\Content\Feature; use Friendica\Content\Nav; use Friendica\Content\Text\HTML; @@ -58,7 +58,7 @@ class Channel extends Timeline /** @var SystemMessages */ protected $systemMessages; - public function __construct(RepositoryChannel $channel, TimelineFactory $timeline, Conversation $conversation, App\Page $page, SystemMessages $systemMessages, Mode $mode, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + public function __construct(ChannelRepository $channel, TimelineFactory $timeline, Conversation $conversation, App\Page $page, SystemMessages $systemMessages, Mode $mode, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) { parent::__construct($channel, $mode, $session, $database, $pConfig, $config, $cache, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); From 42e22ed91bc6193ad63e82002139a664b753c1f0 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 20 Sep 2023 21:39:05 +0000 Subject: [PATCH 06/57] Channel frontend added --- .../Conversation/Repository/Channel.php | 12 ++ src/Module/Settings/Channels.php | 170 ++++++++++++++++++ static/routes.config.php | 1 + view/templates/settings/channels.tpl | 41 +++++ 4 files changed, 224 insertions(+) create mode 100644 src/Module/Settings/Channels.php create mode 100644 view/templates/settings/channels.tpl diff --git a/src/Content/Conversation/Repository/Channel.php b/src/Content/Conversation/Repository/Channel.php index c067c5d7a..ba2e26c46 100644 --- a/src/Content/Conversation/Repository/Channel.php +++ b/src/Content/Conversation/Repository/Channel.php @@ -61,6 +61,18 @@ class Channel extends \Friendica\BaseRepository return $this->exists(['id' => $id, 'uid' => $uid]); } + /** + * Delete the given channel + * + * @param integer $id + * @param integer $uid + * @return boolean + */ + public function deleteById(int $id, int $uid): bool + { + return $this->db->delete('channel', ['id' => $id, 'uid' => $uid]); + } + /** * Fetch all user channels * diff --git a/src/Module/Settings/Channels.php b/src/Module/Settings/Channels.php new file mode 100644 index 000000000..1c5e8b286 --- /dev/null +++ b/src/Module/Settings/Channels.php @@ -0,0 +1,170 @@ +. + * + */ + +namespace Friendica\Module\Settings; + +use Friendica\App; +use Friendica\Content\Conversation\Factory\Timeline; +use Friendica\Content\Conversation\Repository\Channel; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Module\BaseSettings; +use Friendica\Module\Response; +use Friendica\Network\HTTPException; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +class Channels extends BaseSettings +{ + /** @var Channel */ + private $channel; + /** @var Timeline */ + private $timeline; + + public function __construct(Timeline $timeline, Channel $channel, App\Page $page, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->timeline = $timeline; + $this->channel = $channel; + } + + protected function post(array $request = []) + { + $uid = $this->session->getLocalUserId(); + if (!$uid) { + throw new HTTPException\ForbiddenException($this->t('Permission denied.')); + } + + if (empty($request['edit_channel']) && empty($request['add_channel'])) { + return; + } + + self::checkFormSecurityTokenRedirectOnError('/settings/channels', 'settings_channels'); + + if (!empty($request['add_channel'])) { + $channel = $this->timeline->createFromTableRow([ + 'label' => $request['new_label'], + 'description' => $request['new_description'], + 'access-key' => substr(mb_strtolower($request['new_access_key']), 0, 1), + 'uid' => $uid, + 'include-tags' => $this->cleanTags($request['new_include_tags']), + 'exclude-tags' => $this->cleanTags($request['new_exclude_tags']), + 'full-text-search' => null, // Currently not supported for performance reasons + 'media-type' => ($request['new_image'] ? 1 : 0) | ($request['new_video'] ? 2 : 0) | ($request['new_audio'] ? 4 : 0), + ]); + $saved = $this->channel->save($channel); + $this->logger->debug('New channel added', ['saved' => $saved]); + return; + } + + foreach (array_keys($request['label']) as $id) { + if ($request['delete'][$id]) { + $success = $this->channel->deleteById($id, $uid); + $this->logger->debug('Channel deleted', ['id' => $id, 'success' => $success]); + continue; + } + + $channel = $this->timeline->createFromTableRow([ + 'id' => $id, + 'label' => $request['label'][$id], + 'description' => $request['description'][$id], + 'access-key' => substr(mb_strtolower($request['access_key'][$id]), 0, 1), + 'uid' => $uid, + 'include-tags' => $this->cleanTags($request['include_tags'][$id]), + 'exclude-tags' => $this->cleanTags($request['exclude_tags'][$id]), + 'full-text-search' => null, // Currently not supported for performance reasons + 'media-type' => ($request['image'][$id] ? 1 : 0) | ($request['video'][$id] ? 2 : 0) | ($request['audio'][$id] ? 4 : 0), + ]); + $saved = $this->channel->save($channel); + $this->logger->debug('Save channel', ['id' => $id, 'saved' => $saved]); + } + + $this->baseUrl->redirect('/settings/channels'); + } + + protected function content(array $request = []): string + { + parent::content(); + + $uid = $this->session->getLocalUserId(); + if (!$uid) { + throw new HTTPException\ForbiddenException($this->t('Permission denied.')); + } + + $blocklistform = []; + foreach ($this->channel->selectByUid($uid) as $channel) { + $blocklistform[] = [ + 'label' => ["label[$channel->code]", $this->t('Label'), $channel->label, '', $this->t('Required')], + 'description' => ["description[$channel->code]", $this->t("Description"), $channel->description], + 'access_key' => ["access_key[$channel->code]", $this->t("Access Key"), $channel->accessKey], + 'include_tags' => ["include_tags[$channel->code]", $this->t("Include Tags"), $channel->includeTags], + 'exclude_tags' => ["exclude_tags[$channel->code]", $this->t("Exclude Tags"), $channel->excludeTags], + 'image' => ["image[$channel->code]", $this->t("Images"), $channel->mediaType & 1], + 'video' => ["video[$channel->code]", $this->t("Videos"), $channel->mediaType & 2], + 'audio' => ["audio[$channel->code]", $this->t("Audio"), $channel->mediaType & 4], + 'delete' => ["delete[$channel->code]", $this->t("Delete channel") . ' (' . $channel->label . ')', false, $this->t("Check to delete this entry from the channel list")] + ]; + } + + $t = Renderer::getMarkupTemplate('settings/channels.tpl'); + return Renderer::replaceMacros($t, [ + 'label' => ["new_label", $this->t('Label'), '', $this->t('Short name for the channel. It is displayed on the channels widget.'), $this->t('Required')], + 'description' => ["new_description", $this->t("Description"), '', $this->t('This should describe the content of the channel in a few word.')], + '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 attentioon to not use an already used one.')], + '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.')], + '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.')], + 'image' => ['new_image', $this->t("Images"), false, $this->t("Check to display images in the channel.")], + 'video' => ["new_video", $this->t("Videos"), false, $this->t("Check to display videos in the channel.")], + 'audio' => ["new_audio", $this->t("Audio"), false, $this->t("Check to display audio in the channel.")], + '$l10n' => [ + 'title' => $this->t('Channels'), + 'intro' => $this->t('This page can be used to define your own channels.'), + 'addtitle' => $this->t('Add new entry to the channel list'), + 'addsubmit' => $this->t('Add'), + 'savechanges' => $this->t('Save'), + 'currenttitle' => $this->t('Current Entries in the channel list'), + 'thurl' => $this->t('Blocked server domain pattern'), + 'threason' => $this->t('Reason for the block'), + 'delentry' => $this->t('Delete entry from the channel list'), + 'confirm_delete' => $this->t('Delete entry from the channel list?'), + ], + '$entries' => $blocklistform, + '$baseurl' => $this->baseUrl, + + '$form_security_token' => self::getFormSecurityToken('settings_channels'), + ]); + } + + private function cleanTags(string $tag_list): string + { + $tags = []; + $tagitems = explode(',', mb_strtolower($tag_list)); + foreach ($tagitems as $tag) { + $tag = trim($tag, '# '); + if (!empty($tag)) { + $tags[] = $tag; + } + } + return implode(',', $tags); + } +} diff --git a/static/routes.config.php b/static/routes.config.php index afad469fd..1b708140c 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -651,6 +651,7 @@ return [ '/{open}' => [Module\Settings\Account::class, [R::GET, R::POST]], ], '/addons[/{addon}]' => [Module\Settings\Addons::class, [R::GET, R::POST]], + '/channels' => [Module\Settings\Channels::class, [R::GET, R::POST]], '/connectors[/{connector}]' => [Module\Settings\Connectors::class, [R::GET, R::POST]], '/delegation[/{action}/{user_id}]' => [Module\Settings\Delegation::class, [R::GET, R::POST]], '/display' => [Module\Settings\Display::class, [R::GET, R::POST]], diff --git a/view/templates/settings/channels.tpl b/view/templates/settings/channels.tpl new file mode 100644 index 000000000..b4543cd56 --- /dev/null +++ b/view/templates/settings/channels.tpl @@ -0,0 +1,41 @@ +
+

{{$l10n.title}}

+

{{$l10n.intro}}

+

{{$l10n.addtitle}}

+
+ + {{include file="field_input.tpl" field=$label}} + {{include file="field_input.tpl" field=$description}} + {{include file="field_input.tpl" field=$access_key}} + {{include file="field_input.tpl" field=$include_tags}} + {{include file="field_input.tpl" field=$exclude_tags}} + {{include file="field_checkbox.tpl" field=$image}} + {{include file="field_checkbox.tpl" field=$video}} + {{include file="field_checkbox.tpl" field=$audio}} +
+ +
+
+ + {{if $entries}} +

{{$l10n.currenttitle}}

+
+ + {{foreach $entries as $e}} + {{include file="field_input.tpl" field=$e.label}} + {{include file="field_input.tpl" field=$e.description}} + {{include file="field_input.tpl" field=$e.access_key}} + {{include file="field_input.tpl" field=$e.include_tags}} + {{include file="field_input.tpl" field=$e.exclude_tags}} + {{include file="field_checkbox.tpl" field=$e.image}} + {{include file="field_checkbox.tpl" field=$e.video}} + {{include file="field_checkbox.tpl" field=$e.audio}} + {{include file="field_checkbox.tpl" field=$e.delete}} +
+ {{/foreach}} +
+ +
+ {{/if}} +
+
From c9f74cc55fa13359e7e33cc4d566707c4f600074 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 20 Sep 2023 21:42:37 +0000 Subject: [PATCH 07/57] Code standards --- src/Module/Settings/Channels.php | 3 +- view/lang/C/messages.po | 199 ++++++++++++++++++++++--------- 2 files changed, 147 insertions(+), 55 deletions(-) diff --git a/src/Module/Settings/Channels.php b/src/Module/Settings/Channels.php index 1c5e8b286..490d9f9ab 100644 --- a/src/Module/Settings/Channels.php +++ b/src/Module/Settings/Channels.php @@ -136,7 +136,7 @@ class Channels extends BaseSettings 'image' => ['new_image', $this->t("Images"), false, $this->t("Check to display images in the channel.")], 'video' => ["new_video", $this->t("Videos"), false, $this->t("Check to display videos in the channel.")], 'audio' => ["new_audio", $this->t("Audio"), false, $this->t("Check to display audio in the channel.")], - '$l10n' => [ + '$l10n' => [ 'title' => $this->t('Channels'), 'intro' => $this->t('This page can be used to define your own channels.'), 'addtitle' => $this->t('Add new entry to the channel list'), @@ -158,6 +158,7 @@ class Channels extends BaseSettings private function cleanTags(string $tag_list): string { $tags = []; + $tagitems = explode(',', mb_strtolower($tag_list)); foreach ($tagitems as $tag) { $tag = trim($tag, '# '); diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 6ca0fe4da..64ef38e5c 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2023.09-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-18 05:30+0000\n" +"POT-Creation-Date: 2023-09-20 21:42+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -68,6 +68,7 @@ msgstr "" #: src/Module/Register.php:90 src/Module/Register.php:206 #: src/Module/Register.php:245 src/Module/Search/Directory.php:37 #: src/Module/Settings/Account.php:50 src/Module/Settings/Account.php:408 +#: src/Module/Settings/Channels.php:55 src/Module/Settings/Channels.php:111 #: src/Module/Settings/Delegation.php:41 src/Module/Settings/Delegation.php:71 #: src/Module/Settings/Display.php:73 src/Module/Settings/Display.php:160 #: src/Module/Settings/Profile/Photo/Crop.php:165 @@ -384,7 +385,7 @@ msgstr "" #: mod/notes.php:57 src/Content/Text/HTML.php:859 #: src/Module/Admin/Storage.php:142 src/Module/Filer/SaveTag.php:74 -#: src/Module/Post/Edit.php:129 +#: src/Module/Post/Edit.php:129 src/Module/Settings/Channels.php:144 msgid "Save" msgstr "" @@ -449,7 +450,7 @@ msgstr "" msgid "%1$s was tagged in %2$s by %3$s" msgstr "" -#: mod/photos.php:582 src/Module/Conversation/Community.php:159 +#: mod/photos.php:582 src/Module/Conversation/Community.php:160 #: src/Module/Directory.php:48 src/Module/Profile/Photos.php:295 #: src/Module/Search/Index.php:65 msgid "Public access denied." @@ -793,7 +794,7 @@ msgstr "" msgid "All contacts" msgstr "" -#: src/BaseModule.php:433 src/Content/Conversation/Factory/Timeline.php:62 +#: src/BaseModule.php:433 src/Content/Conversation/Factory/Timeline.php:83 #: src/Content/Widget.php:239 src/Core/ACL.php:195 src/Module/Contact.php:415 #: src/Module/PermissionTooltip.php:127 src/Module/PermissionTooltip.php:149 msgid "Followers" @@ -1513,117 +1514,120 @@ msgstr "" msgid "View in context" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:59 +#: src/Content/Conversation/Factory/Timeline.php:80 msgid "For you" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:59 +#: src/Content/Conversation/Factory/Timeline.php:80 msgid "Posts from contacts you interact with and who interact with you" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:60 +#: src/Content/Conversation/Factory/Timeline.php:81 msgid "What's Hot" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:60 +#: src/Content/Conversation/Factory/Timeline.php:81 msgid "Posts with a lot of interactions" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:61 +#: src/Content/Conversation/Factory/Timeline.php:82 #, php-format msgid "Posts in %s" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:62 +#: src/Content/Conversation/Factory/Timeline.php:83 msgid "Posts from your followers that you don't follow" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:63 +#: src/Content/Conversation/Factory/Timeline.php:84 msgid "Sharers of sharers" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:63 +#: src/Content/Conversation/Factory/Timeline.php:84 msgid "Posts from accounts that are followed by accounts that you follow" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:64 +#: src/Content/Conversation/Factory/Timeline.php:85 +#: src/Module/Settings/Channels.php:122 src/Module/Settings/Channels.php:136 msgid "Images" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:64 +#: src/Content/Conversation/Factory/Timeline.php:85 msgid "Posts with images" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:65 +#: src/Content/Conversation/Factory/Timeline.php:86 +#: src/Module/Settings/Channels.php:124 src/Module/Settings/Channels.php:138 msgid "Audio" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:65 +#: src/Content/Conversation/Factory/Timeline.php:86 msgid "Posts with audio" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:66 +#: src/Content/Conversation/Factory/Timeline.php:87 +#: src/Module/Settings/Channels.php:123 src/Module/Settings/Channels.php:137 msgid "Videos" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:66 +#: src/Content/Conversation/Factory/Timeline.php:87 msgid "Posts with videos" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:85 +#: src/Content/Conversation/Factory/Timeline.php:110 msgid "Local Community" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:85 +#: src/Content/Conversation/Factory/Timeline.php:110 msgid "Posts from local users on this server" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:89 +#: src/Content/Conversation/Factory/Timeline.php:114 msgid "Global Community" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:89 +#: src/Content/Conversation/Factory/Timeline.php:114 msgid "Posts from users of the whole federated network" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:103 +#: src/Content/Conversation/Factory/Timeline.php:128 msgid "Latest Activity" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:103 +#: src/Content/Conversation/Factory/Timeline.php:128 msgid "Sort by latest activity" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:104 +#: src/Content/Conversation/Factory/Timeline.php:129 msgid "Latest Posts" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:104 +#: src/Content/Conversation/Factory/Timeline.php:129 msgid "Sort by post received date" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:105 +#: src/Content/Conversation/Factory/Timeline.php:130 msgid "Latest Creation" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:105 +#: src/Content/Conversation/Factory/Timeline.php:130 msgid "Sort by post creation date" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:106 +#: src/Content/Conversation/Factory/Timeline.php:131 #: src/Module/Settings/Profile/Index.php:260 msgid "Personal" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:106 +#: src/Content/Conversation/Factory/Timeline.php:131 msgid "Posts that mention or involve you" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:107 src/Object/Post.php:380 +#: src/Content/Conversation/Factory/Timeline.php:132 src/Object/Post.php:380 msgid "Starred" msgstr "" -#: src/Content/Conversation/Factory/Timeline.php:107 +#: src/Content/Conversation/Factory/Timeline.php:132 msgid "Favourite Posts" msgstr "" @@ -2362,7 +2366,8 @@ msgstr "" msgid "All" msgstr "" -#: src/Content/Widget.php:573 src/Module/Settings/Display.php:266 +#: src/Content/Widget.php:577 src/Module/Settings/Channels.php:140 +#: src/Module/Settings/Display.php:266 msgid "Channels" msgstr "" @@ -5842,6 +5847,7 @@ msgstr "" #: src/Module/Moderation/Blocklist/Server/Index.php:116 #: src/Module/Moderation/Item/Delete.php:67 src/Module/Register.php:148 #: src/Module/Security/TwoFactor/Verify.php:101 +#: src/Module/Settings/Channels.php:117 src/Module/Settings/Channels.php:131 #: src/Module/Settings/TwoFactor/Index.php:140 #: src/Module/Settings/TwoFactor/Verify.php:155 msgid "Required" @@ -5937,7 +5943,7 @@ msgid "Contact not found." msgstr "" #: src/Module/Circle.php:102 src/Module/Contact/Contacts.php:66 -#: src/Module/Conversation/Network.php:232 +#: src/Module/Conversation/Network.php:233 msgid "Invalid contact." msgstr "" @@ -6249,7 +6255,7 @@ msgstr[0] "" msgstr[1] "" #: src/Module/Contact/Follow.php:70 src/Module/Contact/Redir.php:62 -#: src/Module/Contact/Redir.php:222 src/Module/Conversation/Community.php:165 +#: src/Module/Contact/Redir.php:222 src/Module/Conversation/Community.php:166 #: src/Module/Debug/ItemBody.php:38 src/Module/Diaspora/Receive.php:57 #: src/Module/Item/Display.php:96 src/Module/Item/Feed.php:59 #: src/Module/Item/Follow.php:41 src/Module/Item/Ignore.php:41 @@ -6699,35 +6705,35 @@ msgstr "" msgid "Unable to unfollow this contact, please contact your administrator" msgstr "" -#: src/Module/Conversation/Channel.php:121 -#: src/Module/Conversation/Community.php:125 src/Module/Search/Index.php:152 +#: src/Module/Conversation/Channel.php:122 +#: src/Module/Conversation/Community.php:126 src/Module/Search/Index.php:152 #: src/Module/Search/Index.php:194 msgid "No results." msgstr "" -#: src/Module/Conversation/Channel.php:159 +#: src/Module/Conversation/Channel.php:160 msgid "Channel not available." msgstr "" -#: src/Module/Conversation/Community.php:91 +#: src/Module/Conversation/Community.php:92 msgid "" "This community stream shows all public posts received by this node. They may " "not reflect the opinions of this node’s users." msgstr "" -#: src/Module/Conversation/Community.php:179 +#: src/Module/Conversation/Community.php:180 msgid "Community option not available." msgstr "" -#: src/Module/Conversation/Community.php:195 +#: src/Module/Conversation/Community.php:196 msgid "Not available." msgstr "" -#: src/Module/Conversation/Network.php:218 +#: src/Module/Conversation/Network.php:219 msgid "No such circle" msgstr "" -#: src/Module/Conversation/Network.php:222 +#: src/Module/Conversation/Network.php:223 #, php-format msgid "Circle: %s" msgstr "" @@ -6736,15 +6742,15 @@ msgstr "" msgid "Network feed not available." msgstr "" -#: src/Module/Conversation/Timeline.php:158 +#: src/Module/Conversation/Timeline.php:162 msgid "Own Contacts" msgstr "" -#: src/Module/Conversation/Timeline.php:162 +#: src/Module/Conversation/Timeline.php:166 msgid "Include" msgstr "" -#: src/Module/Conversation/Timeline.php:163 +#: src/Module/Conversation/Timeline.php:167 msgid "Hide" msgstr "" @@ -7113,6 +7119,7 @@ msgstr "" #: src/Module/Friendica.php:102 #: src/Module/Moderation/Blocklist/Server/Index.php:87 #: src/Module/Moderation/Blocklist/Server/Index.php:111 +#: src/Module/Settings/Channels.php:147 msgid "Reason for the block" msgstr "" @@ -7860,6 +7867,7 @@ msgstr "" #: src/Module/Moderation/Blocklist/Server/Index.php:86 #: src/Module/Moderation/Blocklist/Server/Index.php:110 +#: src/Module/Settings/Channels.php:146 msgid "Blocked server domain pattern" msgstr "" @@ -9901,6 +9909,97 @@ msgstr "" msgid "No Addon settings configured" msgstr "" +#: src/Module/Settings/Channels.php:117 src/Module/Settings/Channels.php:131 +msgid "Label" +msgstr "" + +#: src/Module/Settings/Channels.php:118 src/Module/Settings/Channels.php:132 +#: src/Module/Settings/TwoFactor/AppSpecific.php:134 +msgid "Description" +msgstr "" + +#: src/Module/Settings/Channels.php:119 src/Module/Settings/Channels.php:133 +msgid "Access Key" +msgstr "" + +#: src/Module/Settings/Channels.php:120 src/Module/Settings/Channels.php:134 +msgid "Include Tags" +msgstr "" + +#: src/Module/Settings/Channels.php:121 src/Module/Settings/Channels.php:135 +msgid "Exclude Tags" +msgstr "" + +#: src/Module/Settings/Channels.php:125 +msgid "Delete channel" +msgstr "" + +#: src/Module/Settings/Channels.php:125 +msgid "Check to delete this entry from the channel list" +msgstr "" + +#: src/Module/Settings/Channels.php:131 +msgid "Short name for the channel. It is displayed on the channels widget." +msgstr "" + +#: src/Module/Settings/Channels.php:132 +msgid "This should describe the content of the channel in a few word." +msgstr "" + +#: src/Module/Settings/Channels.php:133 +msgid "" +"When you want to access this channel via an access key, you can define it " +"here. Pay attentioon to not use an already used one." +msgstr "" + +#: src/Module/Settings/Channels.php:134 +msgid "" +"Comma separated list of tags. A post will be used when it contains any of " +"the listed tags." +msgstr "" + +#: src/Module/Settings/Channels.php:135 +msgid "" +"Comma separated list of tags. If a post contain any of these tags, then it " +"will not be part of nthis channel." +msgstr "" + +#: src/Module/Settings/Channels.php:136 +msgid "Check to display images in the channel." +msgstr "" + +#: src/Module/Settings/Channels.php:137 +msgid "Check to display videos in the channel." +msgstr "" + +#: src/Module/Settings/Channels.php:138 +msgid "Check to display audio in the channel." +msgstr "" + +#: src/Module/Settings/Channels.php:141 +msgid "This page can be used to define your own channels." +msgstr "" + +#: src/Module/Settings/Channels.php:142 +msgid "Add new entry to the channel list" +msgstr "" + +#: src/Module/Settings/Channels.php:143 src/Module/Settings/Delegation.php:181 +msgid "Add" +msgstr "" + +#: src/Module/Settings/Channels.php:145 +msgid "Current Entries in the channel list" +msgstr "" + +#: src/Module/Settings/Channels.php:148 +msgid "Delete entry from the channel list" +msgstr "" + +#: src/Module/Settings/Channels.php:149 +msgid "Delete entry from the channel list?" +msgstr "" + #: src/Module/Settings/Connectors.php:120 msgid "Failed to connect with email account using the settings provided." msgstr "" @@ -10166,10 +10265,6 @@ msgstr "" msgid "Potential Delegates" msgstr "" -#: src/Module/Settings/Delegation.php:181 -msgid "Add" -msgstr "" - #: src/Module/Settings/Delegation.php:182 msgid "No entries." msgstr "" @@ -10688,10 +10783,6 @@ msgid "" "see it again!" msgstr "" -#: src/Module/Settings/TwoFactor/AppSpecific.php:134 -msgid "Description" -msgstr "" - #: src/Module/Settings/TwoFactor/AppSpecific.php:135 msgid "Last Used" msgstr "" From 073da9735dabe974679ba4042c2ff73d64d0ecb9 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 21 Sep 2023 06:49:07 +0000 Subject: [PATCH 08/57] Channels are now added to the settings menu --- src/Module/BaseSettings.php | 7 +++++++ view/lang/C/messages.po | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/Module/BaseSettings.php b/src/Module/BaseSettings.php index f3acb19a2..495c175bd 100644 --- a/src/Module/BaseSettings.php +++ b/src/Module/BaseSettings.php @@ -121,6 +121,13 @@ class BaseSettings extends BaseModule 'accesskey' => 'i', ]; + $tabs[] = [ + 'label' => $this->t('Channels'), + 'url' => 'settings/channels', + 'selected' => static::class == Settings\Display::class ? 'active' : '', + 'accesskey' => '', + ]; + $tabs[] = [ 'label' => $this->t('Social Networks'), 'url' => 'settings/connectors', diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 64ef38e5c..12f4b9140 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2023.09-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-20 21:42+0000\n" +"POT-Creation-Date: 2023-09-21 06:47+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -2103,7 +2103,7 @@ msgid "Manage other pages" msgstr "" #: src/Content/Nav.php:327 src/Module/Admin/Addons/Details.php:114 -#: src/Module/Admin/Themes/Details.php:93 src/Module/BaseSettings.php:175 +#: src/Module/Admin/Themes/Details.php:93 src/Module/BaseSettings.php:182 #: src/Module/Welcome.php:52 view/theme/frio/theme.php:242 msgid "Settings" msgstr "" @@ -2366,8 +2366,8 @@ msgstr "" msgid "All" msgstr "" -#: src/Content/Widget.php:577 src/Module/Settings/Channels.php:140 -#: src/Module/Settings/Display.php:266 +#: src/Content/Widget.php:577 src/Module/BaseSettings.php:125 +#: src/Module/Settings/Channels.php:140 src/Module/Settings/Display.php:266 msgid "Channels" msgstr "" @@ -3900,7 +3900,7 @@ msgid "Administration" msgstr "" #: src/Module/Admin/Addons/Details.php:112 src/Module/Admin/Addons/Index.php:68 -#: src/Module/BaseAdmin.php:92 src/Module/BaseSettings.php:132 +#: src/Module/BaseAdmin.php:92 src/Module/BaseSettings.php:139 msgid "Addons" msgstr "" @@ -5768,27 +5768,27 @@ msgstr "" msgid "Display" msgstr "" -#: src/Module/BaseSettings.php:125 src/Module/Settings/Connectors.php:204 +#: src/Module/BaseSettings.php:132 src/Module/Settings/Connectors.php:204 msgid "Social Networks" msgstr "" -#: src/Module/BaseSettings.php:139 src/Module/Settings/Delegation.php:172 +#: src/Module/BaseSettings.php:146 src/Module/Settings/Delegation.php:172 msgid "Manage Accounts" msgstr "" -#: src/Module/BaseSettings.php:146 +#: src/Module/BaseSettings.php:153 msgid "Connected apps" msgstr "" -#: src/Module/BaseSettings.php:153 +#: src/Module/BaseSettings.php:160 msgid "Remote servers" msgstr "" -#: src/Module/BaseSettings.php:160 src/Module/Settings/UserExport.php:98 +#: src/Module/BaseSettings.php:167 src/Module/Settings/UserExport.php:98 msgid "Export personal data" msgstr "" -#: src/Module/BaseSettings.php:167 +#: src/Module/BaseSettings.php:174 msgid "Remove account" msgstr "" From fac76a33df6ea81717fc1b553257adbc7d8f8b39 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 21 Sep 2023 20:43:14 +0000 Subject: [PATCH 09/57] Improved timeline menu --- src/Content/Widget.php | 14 ++++-- src/Module/Conversation/Network.php | 13 +---- src/Module/Settings/Display.php | 47 ++++++++++++++++--- .../theme/frio/templates/settings/display.tpl | 22 ++++++++- 4 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/Content/Widget.php b/src/Content/Widget.php index 486bada7d..7078c4fe0 100644 --- a/src/Content/Widget.php +++ b/src/Content/Widget.php @@ -560,16 +560,24 @@ class Widget { $channels = []; + $enabled = DI::pConfig()->get($uid, 'system', 'enabled_timelines', []); + foreach (DI::TimelineFactory()->getNetworkFeeds('') as $channel) { - $channels[] = ['ref' => $channel->code, 'name' => $channel->label]; + if (empty($enabled) || in_array($channel->code, $enabled)) { + $channels[] = ['ref' => $channel->code, 'name' => $channel->label]; + } } foreach (DI::TimelineFactory()->getChannelsForUser($uid) as $channel) { - $channels[] = ['ref' => $channel->code, 'name' => $channel->label]; + if (empty($enabled) || in_array($channel->code, $enabled)) { + $channels[] = ['ref' => $channel->code, 'name' => $channel->label]; + } } foreach (DI::TimelineFactory()->getCommunities(true) as $community) { - $channels[] = ['ref' => $community->code, 'name' => $community->label]; + if (empty($enabled) || in_array($community->code, $enabled)) { + $channels[] = ['ref' => $community->code, 'name' => $community->label]; + } } return self::filter( diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index 656383b70..40a1b731b 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -118,25 +118,14 @@ class Network extends Timeline $module = 'network'; - $this->page['aside'] .= Widget::channels($module, $this->selectedTab, $this->session->getLocalUserId()); - $this->page['aside'] .= Widget::accountTypes($module, $this->accountTypeString); - $arr = ['query' => $this->args->getQueryString()]; Hook::callAll('network_content_init', $arr); $o = ''; if ($this->timeline->isChannel($this->selectedTab, $this->session->getLocalUserId())) { - if (!in_array($this->selectedTab, [TimelineEntity::FOLLOWERS, TimelineEntity::FORYOU]) && $this->config->get('system', 'community_no_sharer')) { - $this->page['aside'] .= $this->getNoSharerWidget($module); - } - $items = $this->getChannelItems(); } elseif ($this->timeline->isCommunity($this->selectedTab)) { - if ($this->session->getLocalUserId() && $this->config->get('system', 'community_no_sharer')) { - $this->page['aside'] .= $this->getNoSharerWidget($module); - } - $items = $this->getCommunityItems(); } else { $items = $this->getItems(); @@ -146,6 +135,8 @@ class Network extends Timeline $this->page['aside'] .= GroupManager::widget($module . '/group', $this->session->getLocalUserId(), $this->groupContactId); $this->page['aside'] .= Widget::postedByYear($module . '/archive', $this->session->getLocalUserId(), false); $this->page['aside'] .= Widget::networks($module, !$this->groupContactId ? $this->network : ''); + $this->page['aside'] .= Widget::accountTypes($module, $this->accountTypeString); + $this->page['aside'] .= Widget::channels($module, $this->selectedTab, $this->session->getLocalUserId()); $this->page['aside'] .= Widget\SavedSearches::getHTML($this->args->getQueryString()); $this->page['aside'] .= Widget::fileAs('filed', ''); diff --git a/src/Module/Settings/Display.php b/src/Module/Settings/Display.php index 71c4caed5..bbae7d599 100644 --- a/src/Module/Settings/Display.php +++ b/src/Module/Settings/Display.php @@ -80,7 +80,8 @@ class Display extends BaseSettings $theme = !empty($request['theme']) ? trim($request['theme']) : $user['theme']; $mobile_theme = !empty($request['mobile_theme']) ? trim($request['mobile_theme']) : ''; $enable_smile = !empty($request['enable_smile']) ? intval($request['enable_smile']) : 0; - $network_timelines = !empty($request['network_timelines']) ? $request['network_timelines'] : []; + $enable = !empty($request['enable']) ? $request['enable'] : []; + $bookmark = !empty($request['bookmark']) ? $request['bookmark'] : []; $channel_languages = !empty($request['channel_languages']) ? $request['channel_languages'] : []; $first_day_of_week = !empty($request['first_day_of_week']) ? intval($request['first_day_of_week']) : 0; $calendar_default_view = !empty($request['calendar_default_view']) ? trim($request['calendar_default_view']) : 'month'; @@ -98,6 +99,20 @@ class Display extends BaseSettings } } + $enabled_timelines = []; + foreach ($enable as $code => $enabled) { + if ($enabled) { + $enabled_timelines[] = $code; + } + } + + $network_timelines = []; + foreach ($bookmark as $code => $bookmarked) { + if ($bookmarked) { + $network_timelines[] = $code; + } + } + $itemspage_network = !empty($request['itemspage_network']) ? intval($request['itemspage_network']) : $this->config->get('system', 'itemspage_network'); @@ -127,6 +142,7 @@ class Display extends BaseSettings $this->pConfig->set($uid, 'system', 'preview_mode' , $preview_mode); $this->pConfig->set($uid, 'system', 'network_timelines' , $network_timelines); + $this->pConfig->set($uid, 'system', 'enabled_timelines' , $enabled_timelines); $this->pConfig->set($uid, 'channel', 'languages' , $channel_languages); $this->pConfig->set($uid, 'calendar', 'first_day_of_week' , $first_day_of_week); @@ -224,10 +240,21 @@ class Display extends BaseSettings BBCode::PREVIEW_LARGE => $this->t('Large Image'), ]; - $network_timelines = $this->pConfig->get($uid, 'system', 'network_timelines', array_keys($this->getAvailableTimelines($uid, true))); + $bookmarked_timelines = $this->pConfig->get($uid, 'system', 'network_timelines', array_keys($this->getAvailableTimelines($uid, true))); + $enabled_timelines = $this->pConfig->get($uid, 'system', 'enabled_timelines', array_keys($this->getAvailableTimelines($uid, false))); + $channel_languages = $this->pConfig->get($uid, 'channel', 'languages', [User::getLanguageCode($uid)]); $languages = $this->l10n->getAvailableLanguages(true); - $timelines = $this->getAvailableTimelines($uid); + + $timelines = []; + foreach ($this->getAvailableTimelines($uid) as $code => $timeline) { + $timelines[] = [ + 'label' => $timeline['label'], + 'description' => $timeline['description'], + 'enable' => ["enable[$code]", '', in_array($code, $enabled_timelines)], + 'bookmark' => ["bookmark[$code]", '', in_array($code, $bookmarked_timelines)], + ]; + } $first_day_of_week = $this->pConfig->get($uid, 'calendar', 'first_day_of_week', 0); $weekdays = [ @@ -284,7 +311,13 @@ class Display extends BaseSettings '$stay_local' => ['stay_local' , $this->t('Stay local'), $stay_local, $this->t("Don't go to a remote system when following a contact link.")], '$preview_mode' => ['preview_mode' , $this->t('Link preview mode'), $preview_mode, $this->t('Appearance of the link preview that is added to each post with a link.'), $preview_modes, false], - '$network_timelines' => ['network_timelines[]', $this->t('Timelines for the network page:'), $network_timelines, $this->t('Select all the timelines that you want to see on your network page.'), $timelines, 'multiple'], + '$timeline_label' => $this->t('Label'), + '$timeline_descriptiom' => $this->t('Description'), + '$timeline_enable' => $this->t('Enable'), + '$timeline_bookmark' => $this->t('Bookmark'), + '$timelines' => $timelines, + '$timeline_explanation' => $this->t('Enable timelines that you want to see in the channels widget. Bookmark timelines that you want to see in the top menu.'), + '$channel_languages' => ['channel_languages[]', $this->t('Channel languages:'), $channel_languages, $this->t('Select all languages that you want to see in your channels.'), $languages, 'multiple'], '$first_day_of_week' => ['first_day_of_week' , $this->t('Beginning of week:') , $first_day_of_week , '', $weekdays , false], @@ -297,7 +330,7 @@ class Display extends BaseSettings $timelines = []; foreach ($this->timeline->getNetworkFeeds('') as $channel) { - $timelines[$channel->code] = $this->t('%s: %s', $channel->label, $channel->description); + $timelines[$channel->code] = ['label' => $channel->label, 'description' => $channel->description]; } if ($only_network) { @@ -305,11 +338,11 @@ class Display extends BaseSettings } foreach ($this->timeline->getChannelsForUser($uid) as $channel) { - $timelines[$channel->code] = $this->t('%s: %s', $channel->label, $channel->description); + $timelines[$channel->code] = ['label' => $channel->label, 'description' => $channel->description]; } foreach ($this->timeline->getCommunities(true) as $community) { - $timelines[$community->code] = $this->t('%s: %s', $community->label, $community->description); + $timelines[$community->code] = ['label' => $community->label, 'description' => $community->description]; } return $timelines; diff --git a/view/theme/frio/templates/settings/display.tpl b/view/theme/frio/templates/settings/display.tpl index f361fe953..41dd11c10 100644 --- a/view/theme/frio/templates/settings/display.tpl +++ b/view/theme/frio/templates/settings/display.tpl @@ -84,7 +84,27 @@
- {{include file="field_select.tpl" field=$network_timelines}} + {{$timeline_explanation}} + + + + + + + + + + + {{foreach $timelines as $t}} + + + + + + + {{/foreach}} + +
{{$timeline_label}}{{$timeline_descriptiom}}{{$timeline_enable}}{{$timeline_bookmark}}
{{$t.label}}{{$t.description}}{{include file="field_checkbox.tpl" field=$t.enable}}{{include file="field_checkbox.tpl" field=$t.bookmark}}