Browse Source

Topics

imwald
Nuša Pukšič 3 months ago
parent
commit
9e53d9ac05
  1. 17
      src/Controller/Administration/ArticleManagementController.php
  2. 66
      src/Controller/ArticleController.php
  3. 9
      templates/admin/articles.html.twig
  4. 29
      templates/pages/topics.html.twig

17
src/Controller/Administration/ArticleManagementController.php

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Controller\Administration; namespace App\Controller\Administration;
use App\Service\RedisCacheService; use App\Service\RedisCacheService;
use Elastica\Query;
use FOS\ElasticaBundle\Finder\PaginatedFinderInterface; use FOS\ElasticaBundle\Finder\PaginatedFinderInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\DependencyInjection\Attribute\Autowire;
@ -20,6 +21,7 @@ class ArticleManagementController extends AbstractController
public function listArticles( public function listArticles(
#[Autowire(service: 'fos_elastica.finder.articles')] PaginatedFinderInterface $finder, #[Autowire(service: 'fos_elastica.finder.articles')] PaginatedFinderInterface $finder,
#[Autowire(service: 'fos_elastica.index.articles')] \Elastica\Index $index,
RedisCacheService $redisCacheService RedisCacheService $redisCacheService
): Response ): Response
{ {
@ -41,9 +43,24 @@ class ArticleManagementController extends AbstractController
if (count($articles) >= 50) break; if (count($articles) >= 50) break;
} }
} }
// Separate query for aggregations
$aggQuery = new Query([
'size' => 0,
'aggs' => [
'tags' => [
'terms' => [
'field' => 'topics',
'size' => 50
]
]
]
]);
$aggResults = $index->search($aggQuery);
$tagCounts = $aggResults->getAggregations()['tags']['buckets'] ?? [];
return $this->render('admin/articles.html.twig', [ return $this->render('admin/articles.html.twig', [
'articles' => $articles, 'articles' => $articles,
'indexes' => [], 'indexes' => [],
'tagCounts' => $tagCounts,
]); ]);
} }

66
src/Controller/ArticleController.php

@ -9,6 +9,7 @@ use App\Service\NostrClient;
use App\Service\RedisCacheService; use App\Service\RedisCacheService;
use App\Util\CommonMark\Converter; use App\Util\CommonMark\Converter;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use FOS\ElasticaBundle\Finder\PaginatedFinderInterface;
use League\CommonMark\Exception\CommonMarkException; use League\CommonMark\Exception\CommonMarkException;
use nostriphant\NIP19\Bech32; use nostriphant\NIP19\Bech32;
use nostriphant\NIP19\Data\NAddr; use nostriphant\NIP19\Data\NAddr;
@ -17,6 +18,7 @@ use Psr\Cache\InvalidArgumentException;
use swentel\nostr\Event\Event; use swentel\nostr\Event\Event;
use swentel\nostr\Key\Key; use swentel\nostr\Key\Key;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@ -356,4 +358,68 @@ class ArticleController extends AbstractController
return $data; return $data;
} }
#[Route('/topics', name: 'topics')]
public function topics(
Request $request,
#[Autowire(service: 'fos_elastica.finder.articles')] PaginatedFinderInterface $finder
): Response {
$topics = [
'bitcoin-crypto' => [
'name' => 'Bitcoin & Crypto',
'tags' => ['bitcoin', 'bitkoin', 'lightning', 'decentralization', 'freedom', 'privacy', 'sovereignty']
],
'nostr' => [
'name' => 'Nostr',
'tags' => ['nostr', 'grownostr']
],
'christianity' => [
'name' => 'Christianity',
'tags' => ['jesus', 'christian', 'christianity', 'bible', 'trustjesus', 'biblestr']
],
'travel' => [
'name' => 'Travel',
'tags' => ['travel', 'europe']
],
'photography' => [
'name' => 'Photography',
'tags' => ['photography']
],
'ai' => [
'name' => 'AI',
'tags' => ['ai']
],
'philosophy' => [
'name' => 'Philosophy',
'tags' => ['philosophy']
],
'art' => [
'name' => 'Art',
'tags' => ['art']
]
];
$selectedTopic = $request->query->get('topic');
$articles = [];
if ($selectedTopic && isset($topics[$selectedTopic])) {
$tags = $topics[$selectedTopic]['tags'];
$query = [
'size' => 10,
'sort' => [['createdAt' => ['order' => 'desc']]],
'query' => [
'terms' => [
'topics' => $tags
]
]
];
$results = $finder->find($query);
$articles = array_slice($results, 0, 10);
}
return $this->render('pages/topics.html.twig', [
'topics' => $topics,
'selectedTopic' => $selectedTopic,
'articles' => $articles,
]);
}
} }

9
templates/admin/articles.html.twig

@ -42,4 +42,13 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<h2>Most Frequent Tags</h2>
<ul>
{% for tag in tagCounts %}
<li>{{ tag.key }} ({{ tag.doc_count }})</li>
{% else %}
<li>No tags found.</li>
{% endfor %}
</ul>
{% endblock %} {% endblock %}

29
templates/pages/topics.html.twig

@ -0,0 +1,29 @@
{% extends 'layout.html.twig' %}
{% block body %}
<h1>Explore Topics</h1>
<p>Select a topic to view the 10 most recent articles related to it.</p>
<div class="topics-list">
{% for key, topic in topics %}
<a href="{{ path('topics', {'topic': key}) }}" class="topic-button {{ selectedTopic == key ? 'active' : '' }}">
{{ topic.name }}
</a>
{% endfor %}
</div>
{% if selectedTopic and articles %}
<h2>Recent Articles in {{ topics[selectedTopic].name }}</h2>
<div class="articles-list">
{% for article in articles %}
<div class="article-item">
<h3><a href="{{ path('article-slug', {slug: article.slug|url_encode}) }}">{{ article.title }}</a></h3>
<p>{{ article.summary|slice(0, 150) }}{% if article.summary|length > 150 %}...{% endif %}</p>
<small>Published: {{ article.createdAt|date('Y-m-d H:i') }}</small>
</div>
{% endfor %}
</div>
{% elseif selectedTopic %}
<p>No articles found for this topic.</p>
{% endif %}
{% endblock %}
Loading…
Cancel
Save