Browse Source

Actually load a magazine

imwald
Nuša Pukšič 9 months ago
parent
commit
6727c790c0
  1. 3
      src/Controller/ArticleController.php
  2. 82
      src/Controller/DefaultController.php
  3. 21
      src/Service/NostrClient.php
  4. 6
      src/Twig/Components/Header.php
  5. 1
      src/Twig/Components/Molecules/CategoryLink.php
  6. 2
      templates/components/Header.html.twig

3
src/Controller/ArticleController.php

@ -261,6 +261,9 @@ class ArticleController extends AbstractController
#[Route('/articles', name: 'articles')] #[Route('/articles', name: 'articles')]
public function latestArticles(EntityManagerInterface $entityManager): Response public function latestArticles(EntityManagerInterface $entityManager): Response
{ {
set_time_limit(300); // 5 minutes
ini_set('max_execution_time', '300');
$articles = $entityManager->getRepository(Article::class) $articles = $entityManager->getRepository(Article::class)
->findBy([], ['createdAt' => 'DESC'], 20); ->findBy([], ['createdAt' => 'DESC'], 20);

82
src/Controller/DefaultController.php

@ -5,9 +5,11 @@ declare(strict_types=1);
namespace App\Controller; namespace App\Controller;
use App\Repository\ArticleRepository; use App\Repository\ArticleRepository;
use App\Service\NostrClient;
use Exception; use Exception;
use Psr\Cache\InvalidArgumentException; use Psr\Cache\InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
@ -17,9 +19,10 @@ use Psr\Log\LoggerInterface;
class DefaultController extends AbstractController class DefaultController extends AbstractController
{ {
public function __construct( public function __construct(
private readonly CacheInterface $redisCache) private readonly CacheInterface $cache,
{ private readonly NostrClient $nostrClient,
} private readonly ParameterBagInterface $params
) {}
/** /**
* @throws Exception * @throws Exception
@ -28,9 +31,12 @@ class DefaultController extends AbstractController
#[Route('/', name: 'home')] #[Route('/', name: 'home')]
public function index(): Response public function index(): Response
{ {
// get newsroom index, loop over categories, pick top three from each and display in sections $npub = $this->params->get('npub');
$mag = $this->redisCache->get('magazine-newsroom-magazine-by-newsroom', function (){ $dTag = $this->params->get('d_tag');
return null; $cacheKey = 'magazine-' . $dTag;
$mag = $this->cache->get($cacheKey, function ($item) use ($npub, $dTag) {
$item->expiresAfter(300); // 5 minutes
return $this->nostrClient->getMagazineIndex($npub, $dTag);
}); });
// Handle case when magazine is not found // Handle case when magazine is not found
@ -56,52 +62,45 @@ class DefaultController extends AbstractController
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
#[Route('/cat/{slug}', name: 'magazine-category')] #[Route('/cat/{slug}', name: 'magazine-category')]
public function magCategory($slug, CacheInterface $redisCache, public function magCategory($slug, ArticleRepository $articleRepository, LoggerInterface $logger): Response
ArticleRepository $articleRepository,
LoggerInterface $logger): Response
{ {
$catIndex = $redisCache->get('magazine-' . $slug, function (){ $npub = $this->params->get('npub');
throw new Exception('Not found'); $cacheKey = 'magazine-' . $slug;
$catIndex = $this->cache->get($cacheKey, function ($item) use ($npub, $slug) {
$item->expiresAfter(300); // 5 minutes
return $this->nostrClient->getMagazineIndex($npub, $slug);
}); });
$list = []; $list = [];
$coordinates = []; // Store full coordinates (kind:author:slug) $coordinates = [];
$category = []; $category = [];
if ($catIndex) {
// Extract category metadata and article coordinates foreach ($catIndex->getTags() as $tag) {
foreach ($catIndex->getTags() as $tag) { if ($tag[0] === 'title') {
if ($tag[0] === 'title') { $category['title'] = $tag[1];
$category['title'] = $tag[1]; }
} if ($tag[0] === 'summary') {
if ($tag[0] === 'summary') { $category['summary'] = $tag[1];
$category['summary'] = $tag[1]; }
} if ($tag[0] === 'a') {
if ($tag[0] === 'a') { $coordinates[] = $tag[1];
$coordinates[] = $tag[1]; // Store the full coordinate }
} }
} }
if (!empty($coordinates)) { if (!empty($coordinates)) {
// Extract slugs for database query
$slugs = array_map(function($coordinate) { $slugs = array_map(function($coordinate) {
$parts = explode(':', $coordinate, 3); $parts = explode(':', $coordinate, 3);
return end($parts); return end($parts);
}, $coordinates); }, $coordinates);
$slugs = array_filter($slugs); // Remove empty values $slugs = array_filter($slugs);
// Use database query instead of Elasticsearch
$articles = $articleRepository->findBySlugsCriteria($slugs); $articles = $articleRepository->findBySlugsCriteria($slugs);
// Create a map of slug => item to remove duplicates
$slugMap = []; $slugMap = [];
foreach ($articles as $item) { foreach ($articles as $item) {
$slug = $item->getSlug(); $slug = $item->getSlug();
if ($slug !== '') { if ($slug !== '') {
// If the slugMap doesn't contain it yet, add it
if (!isset($slugMap[$slug])) { if (!isset($slugMap[$slug])) {
$slugMap[$slug] = $item; $slugMap[$slug] = $item;
} else { } else {
// If it already exists, compare created_at timestamps and save newest
$existingItem = $slugMap[$slug]; $existingItem = $slugMap[$slug];
if ($item->getCreatedAt() > $existingItem->getCreatedAt()) { if ($item->getCreatedAt() > $existingItem->getCreatedAt()) {
$slugMap[$slug] = $item; $slugMap[$slug] = $item;
@ -109,25 +108,6 @@ class DefaultController extends AbstractController
} }
} }
} }
// Find missing coordinates
$missingCoordinates = [];
foreach ($coordinates as $coordinate) {
$parts = explode(':', $coordinate, 3);
if (!isset($slugMap[end($parts)])) {
$missingCoordinates[] = $coordinate;
}
}
// If we have missing articles, log them for now
if (!empty($missingCoordinates)) {
$logger->info('There were missing articles', [
'missing' => $missingCoordinates
]);
// Note: Removed NostrClient fetching logic for simplification
}
// Build ordered list based on original coordinates order
foreach ($coordinates as $coordinate) { foreach ($coordinates as $coordinate) {
$parts = explode(':', $coordinate, 3); $parts = explode(':', $coordinate, 3);
if (isset($slugMap[end($parts)])) { if (isset($slugMap[end($parts)])) {

21
src/Service/NostrClient.php

@ -814,4 +814,25 @@ class NostrClient
return null; return null;
} }
} }
public function getMagazineIndex( $npub, $dTag)
{
$request = $this->createNostrRequest(
kinds: [KindsEnum::PUBLICATION_INDEX],
filters: ['authors' => [$npub], 'tag' => ['#d', [$dTag]]],
);
$response = $request->send();
$this->logger->info('Getting magazine index', ['npub' => $npub, 'dTag' => $dTag, 'response' => $response]);
$events = $this->processResponse($response, function($received) {
$this->logger->info('Received magazine index event', ['item' => $received]);
return $received;
});
if (empty($events)) {
$this->logger->warning('No magazine index found', ['npub' => $npub, 'dTag' => $dTag]);
return null;
}
// Sort by date and return the most recent
usort($events, fn($a, $b) => $b->created_at <=> $a->created_at);
return $events[0];
}
} }

6
src/Twig/Components/Header.php

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Twig\Components; namespace App\Twig\Components;
use Psr\Cache\InvalidArgumentException; use Psr\Cache\InvalidArgumentException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\CacheInterface;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
@ -16,9 +17,10 @@ class Header
/** /**
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
public function __construct(private readonly CacheInterface $cache) public function __construct(private readonly CacheInterface $cache, private readonly ParameterBagInterface $params)
{ {
$mag = $this->cache->get('magazine-newsroom-magazine-by-newsroom', function (){ $dTag = $this->params->get('d_tag');
$mag = $this->cache->get('magazine-' . $dTag, function (){
return null; return null;
}); });

1
src/Twig/Components/Molecules/CategoryLink.php

@ -18,6 +18,7 @@ final class CategoryLink
public function mount($category): void public function mount($category): void
{ {
$parts = explode(':', $category[1]); $parts = explode(':', $category[1]);
$this->slug = $parts[2];
try { try {
$cat = $this->cache->get('magazine-' . $parts[2], function (){ $cat = $this->cache->get('magazine-' . $parts[2], function (){
throw new \Exception('Not found'); throw new \Exception('Not found');

2
templates/components/Header.html.twig

@ -6,7 +6,7 @@
<div class="header__categories" data-menu-target="menu"> <div class="header__categories" data-menu-target="menu">
<ul> <ul>
{% for category in cats %} {% for category in cats %}
<li><twig:Molecules:CategoryLink coordinate="{{ category }}" /></li> <li><twig:Molecules:CategoryLink category="{{ category }}" /></li>
{% endfor %} {% endfor %}
{% if magazine_community_articles %} {% if magazine_community_articles %}
<li> <li>

Loading…
Cancel
Save