Browse Source

RSS: move and refactor stubs

imwald
Nuša Pukšič 3 weeks ago
parent
commit
03abdf11e3
  1. 117
      src/Controller/Admin/AdminRssController.php
  2. 2
      src/Service/RSS/RssFeedService.php
  3. 36
      src/Service/RSS/RssToNostrConverter.php
  4. 2
      src/Service/RSS/TagMatchingService.php
  5. 0
      templates/admin/rss_review.html.twig
  6. 0
      templates/admin/rss_submit.html.twig

117
src/Controller/Admin/AdminRssController.php

@ -0,0 +1,117 @@ @@ -0,0 +1,117 @@
<?php
namespace App\Controller\Admin;
use App\Service\RSS\RssFeedService;
use App\Service\RSS\RssToNostrConverter;
use App\Util\NostrKeyUtil;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Event;
use App\Enum\KindsEnum;
class AdminRssController extends AbstractController
{
#[Route('/admin/rss/submit', name: 'admin_rss_submit', methods: ['GET', 'POST'])]
public function submitRssFeed(Request $request, RssFeedService $rssFeedService, EntityManagerInterface $entityManager): Response
{
// Fetch magazines (Event entities) with type=magazine and owned by the user
$user = $this->getUser();
if (!$user) {
throw $this->createAccessDeniedException('You must be logged in to access this page.');
}
$pubkey = NostrKeyUtil::npubToHex($user->getUserIdentifier());
$magazines = $entityManager->getRepository(Event::class)->findBy([
'kind' => KindsEnum::PUBLICATION_INDEX,
'pubkey' => $pubkey,
]);
$filteredMagazines = array_filter($magazines, function ($mag) {
$tags = $mag->getTags();
$isMagType = false;
$isTopLevel = false;
$hasSource = false;
foreach ($tags as $tag) {
if ($tag[0] === 'type' && $tag[1] === 'magazine') {
$isMagType = true;
}
if ($tag[0] === 'a' && $isTopLevel === false) {
$parts = explode(':', $tag[1]);
if ($parts[0] == (string)KindsEnum::PUBLICATION_INDEX->value) {
$isTopLevel = true;
}
}
if ($tag[0] === 'source' && !empty($tag[1])) {
$hasSource = true;
}
}
// Optionally, filter by user ownership if needed
return $isMagType && $isTopLevel && $hasSource;
});
$form = $this->createFormBuilder()
->add('feedUrl', TextType::class, [
'label' => 'RSS Feed URL',
'required' => true,
])
->add('magazine', TextType::class, [
'label' => 'Magazine (optional)',
'required' => false,
])
->getForm();
$form->handleRequest($request);
$articles = [];
if ($form->isSubmitted() && $form->isValid()) {
$feedUrl = $form->get('feedUrl')->getData();
$magazineSlug = $form->get('magazine')->getData();
$feed = $rssFeedService->fetchFeed($feedUrl);
$articles = $feed['items'] ?? [];
$request->getSession()->set('rss_articles', $articles);
$request->getSession()->set('selected_magazine', $magazineSlug);
return $this->redirectToRoute('admin_rss_review');
}
return $this->render('admin/rss_submit.html.twig', [
'form' => $form->createView(),
'magazines' => $filteredMagazines,
]);
}
#[Route('/admin/rss/review', name: 'admin_rss_review', methods: ['GET', 'POST'])]
public function reviewRssArticles(Request $request, RssToNostrConverter $converter): Response
{
$articles = $request->getSession()->get('rss_articles', []);
$drafts = [];
foreach ($articles as $item) {
$drafts[] = $converter->convertToNostrEvent($item);
}
if ($request->isMethod('POST')) {
$toSign = $request->request->all('sign');
$signed = [];
foreach ($toSign as $idx) {
if (isset($drafts[$idx])) {
// Here, you would sign and persist the article
// For now, just collect for confirmation
$signed[] = $drafts[$idx];
}
}
// TODO: Persist signed articles as needed
$this->addFlash('success', count($signed) . ' articles signed and published.');
$request->getSession()->remove('rss_articles');
return $this->redirectToRoute('admin_rss_submit');
}
return $this->render('admin/rss_review.html.twig', [
'drafts' => $drafts,
]);
}
// Add a route for signing and persisting selected articles as needed
}

2
src/Service/RssFeedService.php → src/Service/RSS/RssFeedService.php

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
<?php
namespace App\Service;
namespace App\Service\RSS;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

36
src/Service/RssToNostrConverter.php → src/Service/RSS/RssToNostrConverter.php

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
<?php
namespace App\Service;
namespace App\Service\RSS;
use App\Entity\Nzine;
use App\Enum\KindsEnum;
use App\Service\EncryptionService;
use Psr\Log\LoggerInterface;
use swentel\nostr\Event\Event;
use swentel\nostr\Sign\Sign;
@ -24,28 +24,12 @@ class RssToNostrConverter @@ -24,28 +24,12 @@ class RssToNostrConverter
* Convert an RSS item to a Nostr longform event (kind 30023)
*
* @param array $rssItem The RSS item data
* @param array|null $matchedCategory The matched nzine category (null if no match)
* @param Nzine $nzine The nzine entity
* @param string|null $categoryIndexEventId The event ID of the category index (for 'a' tag)
* @return Event The created and signed Nostr event
*/
public function convertToNostrEvent(
array $rssItem,
?array $matchedCategory,
Nzine $nzine,
?string $categoryIndexEventId = null
array $rssItem
): Event {
$bot = $nzine->getNzineBot();
if (!$bot) {
throw new \RuntimeException('Nzine bot not found');
}
$bot->setEncryptionService($this->encryptionService);
$privateKey = $bot->getNsec();
if (!$privateKey) {
throw new \RuntimeException('Bot private key not found');
}
$privateKey = 'your-private-key'; // Replace with actual private key retrieval logic
// Create the event
$event = new Event();
@ -80,11 +64,6 @@ class RssToNostrConverter @@ -80,11 +64,6 @@ class RssToNostrConverter
$event->addTag(['published_at', (string) $rssItem['pubDate']->getTimestamp()]);
}
// Add category tag (t tag) - only if category matched
if ($matchedCategory && isset($matchedCategory['slug'])) {
$event->addTag(['t', $matchedCategory['slug']]);
}
// Add source tag for original article URL
if (!empty($rssItem['link'])) {
$event->addTag(['source', $rssItem['link']]);
@ -95,12 +74,6 @@ class RssToNostrConverter @@ -95,12 +74,6 @@ class RssToNostrConverter
$event->addTag(['r', $rssItem['link']]);
}
// Add reference to category index if provided and category matched
if ($categoryIndexEventId && $matchedCategory && isset($matchedCategory['slug'])) {
$npub = $nzine->getNpub();
$event->addTag(['a', KindsEnum::PUBLICATION_INDEX->value . ':' . $npub . ':' . $matchedCategory['slug']]);
}
// Add client tag to indicate source
$event->addTag(['client', 'newsroom-rss-aggregator']);
@ -111,7 +84,6 @@ class RssToNostrConverter @@ -111,7 +84,6 @@ class RssToNostrConverter
$this->logger->info('Created Nostr event from RSS item', [
'title' => $rssItem['title'],
'slug' => $slug,
'category' => $matchedCategory['name'] ?? null,
]);
return $event;

2
src/Service/TagMatchingService.php → src/Service/RSS/TagMatchingService.php

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
<?php
namespace App\Service;
namespace App\Service\RSS;
use Psr\Log\LoggerInterface;

0
templates/admin/rss_review.html.twig

0
templates/admin/rss_submit.html.twig

Loading…
Cancel
Save