diff --git a/src/Controller/ArticleController.php b/src/Controller/ArticleController.php index 0fce05b..3e91261 100644 --- a/src/Controller/ArticleController.php +++ b/src/Controller/ArticleController.php @@ -261,6 +261,9 @@ class ArticleController extends AbstractController #[Route('/articles', name: 'articles')] public function latestArticles(EntityManagerInterface $entityManager): Response { + set_time_limit(300); // 5 minutes + ini_set('max_execution_time', '300'); + $articles = $entityManager->getRepository(Article::class) ->findBy([], ['createdAt' => 'DESC'], 20); diff --git a/src/Controller/DefaultController.php b/src/Controller/DefaultController.php index c753803..85aa328 100644 --- a/src/Controller/DefaultController.php +++ b/src/Controller/DefaultController.php @@ -5,9 +5,11 @@ declare(strict_types=1); namespace App\Controller; use App\Repository\ArticleRepository; +use App\Service\NostrClient; use Exception; use Psr\Cache\InvalidArgumentException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -17,9 +19,10 @@ use Psr\Log\LoggerInterface; class DefaultController extends AbstractController { public function __construct( - private readonly CacheInterface $redisCache) - { - } + private readonly CacheInterface $cache, + private readonly NostrClient $nostrClient, + private readonly ParameterBagInterface $params + ) {} /** * @throws Exception @@ -28,9 +31,12 @@ class DefaultController extends AbstractController #[Route('/', name: 'home')] public function index(): Response { - // get newsroom index, loop over categories, pick top three from each and display in sections - $mag = $this->redisCache->get('magazine-newsroom-magazine-by-newsroom', function (){ - return null; + $npub = $this->params->get('npub'); + $dTag = $this->params->get('d_tag'); + $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 @@ -56,52 +62,45 @@ class DefaultController extends AbstractController * @throws InvalidArgumentException */ #[Route('/cat/{slug}', name: 'magazine-category')] - public function magCategory($slug, CacheInterface $redisCache, - ArticleRepository $articleRepository, - LoggerInterface $logger): Response + public function magCategory($slug, ArticleRepository $articleRepository, LoggerInterface $logger): Response { - $catIndex = $redisCache->get('magazine-' . $slug, function (){ - throw new Exception('Not found'); + $npub = $this->params->get('npub'); + $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 = []; - $coordinates = []; // Store full coordinates (kind:author:slug) + $coordinates = []; $category = []; - - // Extract category metadata and article coordinates - foreach ($catIndex->getTags() as $tag) { - if ($tag[0] === 'title') { - $category['title'] = $tag[1]; - } - if ($tag[0] === 'summary') { - $category['summary'] = $tag[1]; - } - if ($tag[0] === 'a') { - $coordinates[] = $tag[1]; // Store the full coordinate + if ($catIndex) { + foreach ($catIndex->getTags() as $tag) { + if ($tag[0] === 'title') { + $category['title'] = $tag[1]; + } + if ($tag[0] === 'summary') { + $category['summary'] = $tag[1]; + } + if ($tag[0] === 'a') { + $coordinates[] = $tag[1]; + } } } if (!empty($coordinates)) { - // Extract slugs for database query $slugs = array_map(function($coordinate) { $parts = explode(':', $coordinate, 3); return end($parts); }, $coordinates); - $slugs = array_filter($slugs); // Remove empty values - - // Use database query instead of Elasticsearch + $slugs = array_filter($slugs); $articles = $articleRepository->findBySlugsCriteria($slugs); - - // Create a map of slug => item to remove duplicates $slugMap = []; foreach ($articles as $item) { $slug = $item->getSlug(); if ($slug !== '') { - // If the slugMap doesn't contain it yet, add it if (!isset($slugMap[$slug])) { $slugMap[$slug] = $item; } else { - // If it already exists, compare created_at timestamps and save newest $existingItem = $slugMap[$slug]; if ($item->getCreatedAt() > $existingItem->getCreatedAt()) { $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) { $parts = explode(':', $coordinate, 3); if (isset($slugMap[end($parts)])) { diff --git a/src/Service/NostrClient.php b/src/Service/NostrClient.php index 2bd5d08..c9e35c8 100644 --- a/src/Service/NostrClient.php +++ b/src/Service/NostrClient.php @@ -814,4 +814,25 @@ class NostrClient 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]; + } } diff --git a/src/Twig/Components/Header.php b/src/Twig/Components/Header.php index 7d9f132..cb2d972 100644 --- a/src/Twig/Components/Header.php +++ b/src/Twig/Components/Header.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Twig\Components; use Psr\Cache\InvalidArgumentException; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Contracts\Cache\CacheInterface; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; @@ -16,9 +17,10 @@ class Header /** * @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; }); diff --git a/src/Twig/Components/Molecules/CategoryLink.php b/src/Twig/Components/Molecules/CategoryLink.php index aac327c..d3dc120 100644 --- a/src/Twig/Components/Molecules/CategoryLink.php +++ b/src/Twig/Components/Molecules/CategoryLink.php @@ -18,6 +18,7 @@ final class CategoryLink public function mount($category): void { $parts = explode(':', $category[1]); + $this->slug = $parts[2]; try { $cat = $this->cache->get('magazine-' . $parts[2], function (){ throw new \Exception('Not found'); diff --git a/templates/components/Header.html.twig b/templates/components/Header.html.twig index dfa6d59..ac4feff 100644 --- a/templates/components/Header.html.twig +++ b/templates/components/Header.html.twig @@ -6,7 +6,7 @@