From 4f005829954cfc7ee7c7e9c5107f8a1a99ff345b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nu=C5=A1a=20Puk=C5=A1i=C4=8D?= Date: Tue, 10 Dec 2024 15:11:38 +0100 Subject: [PATCH] Translations, author pages --- assets/icons/symfony.svg | 1 + composer.json | 2 + composer.lock | 185 +++++++++++++++++- config/bundles.php | 1 + config/packages/translation.yaml | 7 + src/Controller/ArticleController.php | 12 +- src/Controller/AuthorController.php | 28 +++ src/Controller/DefaultController.php | 6 +- src/Repository/UserEntityRepository.php | 10 +- src/Service/NostrClient.php | 1 + src/Twig/Components/Organisms/CardList.php | 2 +- symfony.lock | 25 +++ .../components/Atoms/NameOrNpub.html.twig | 9 + templates/pages/article.html.twig | 11 +- templates/pages/author.html.twig | 12 ++ translations/.gitignore | 0 translations/messages.en.yaml | 2 + 17 files changed, 301 insertions(+), 13 deletions(-) create mode 100644 assets/icons/symfony.svg create mode 100644 config/packages/translation.yaml create mode 100644 src/Controller/AuthorController.php create mode 100644 templates/components/Atoms/NameOrNpub.html.twig create mode 100644 templates/pages/author.html.twig create mode 100644 translations/.gitignore diff --git a/assets/icons/symfony.svg b/assets/icons/symfony.svg new file mode 100644 index 0000000..93fb329 --- /dev/null +++ b/assets/icons/symfony.svg @@ -0,0 +1 @@ + diff --git a/composer.json b/composer.json index 96ad242..a3a1710 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,9 @@ "symfony/security-bundle": "7.1.*", "symfony/serializer": "7.1.*", "symfony/stimulus-bundle": "^2.22", + "symfony/translation": "7.1.*", "symfony/twig-bundle": "7.1.*", + "symfony/ux-icons": "^2.22", "symfony/ux-live-component": "^2.21", "symfony/yaml": "7.1.*", "twig/extra-bundle": "^2.12|^3.0", diff --git a/composer.lock b/composer.lock index 1089e03..115b23a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3f6c3be0f4791878aa1abbfb292b0c01", + "content-hash": "897e77674e1fcdc323faccc51cf19c34", "packages": [ { "name": "bitwasp/bech32", @@ -6760,6 +6760,100 @@ ], "time": "2024-11-13T13:31:21+00:00" }, + { + "name": "symfony/translation", + "version": "v7.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "b9f72ab14efdb6b772f85041fa12f820dee8d55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/b9f72ab14efdb6b772f85041fa12f820dee8d55f", + "reference": "b9f72ab14efdb6b772f85041fa12f820dee8d55f", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "nikic/php-parser": "^4.18|^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v7.1.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-28T12:35:13+00:00" + }, { "name": "symfony/translation-contracts", "version": "v3.5.1", @@ -7113,6 +7207,95 @@ ], "time": "2024-11-07T15:49:33+00:00" }, + { + "name": "symfony/ux-icons", + "version": "v2.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-icons.git", + "reference": "3a6fd4293fc200530b09960c41941a71354bc5fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-icons/zipball/3a6fd4293fc200530b09960c41941a71354bc5fc", + "reference": "3a6fd4293fc200530b09960c41941a71354bc5fc", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/twig-bundle": "^6.4|^7.0" + }, + "conflict": { + "symfony/flex": "<1.13", + "symfony/ux-twig-component": "<2.21" + }, + "require-dev": { + "psr/log": "^2|^3", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/http-client": "6.4|^7.0", + "symfony/phpunit-bridge": "^6.3|^7.0", + "symfony/ux-twig-component": "^2.14", + "zenstruck/console-test": "^1.5" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\Icons\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Bond", + "email": "kevinbond@gmail.com" + }, + { + "name": "Simon André", + "email": "smn.andre@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Renders local and remote SVG icons in your Twig templates.", + "homepage": "https://symfony.com", + "keywords": [ + "icons", + "svg", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-icons/tree/v2.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-04T11:34:13+00:00" + }, { "name": "symfony/ux-live-component", "version": "v2.22.0", diff --git a/config/bundles.php b/config/bundles.php index 7c2c83b..250549d 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -13,4 +13,5 @@ return [ Symfony\Bundle\MakerBundle\MakerBundle::class => ['all' => true, 'prod' => false], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['all' => true, 'prod' => false], Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], + Symfony\UX\Icons\UXIconsBundle::class => ['all' => true], ]; diff --git a/config/packages/translation.yaml b/config/packages/translation.yaml new file mode 100644 index 0000000..b3f8f9c --- /dev/null +++ b/config/packages/translation.yaml @@ -0,0 +1,7 @@ +framework: + default_locale: en + translator: + default_path: '%kernel.project_dir%/translations' + fallbacks: + - en + providers: diff --git a/src/Controller/ArticleController.php b/src/Controller/ArticleController.php index b753339..55d7eb8 100644 --- a/src/Controller/ArticleController.php +++ b/src/Controller/ArticleController.php @@ -4,8 +4,11 @@ namespace App\Controller; use App\Entity\Article; use App\Entity\User; +use App\Service\NostrClient; use App\Util\CommonMark\Converter; use Doctrine\ORM\EntityManagerInterface; +use League\CommonMark\Exception\CommonMarkException; +use PHPUnit\Exception; use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\InvalidArgumentException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -15,11 +18,11 @@ use Symfony\Component\Routing\Attribute\Route; class ArticleController extends AbstractController { /** - * @throws InvalidArgumentException + * @throws InvalidArgumentException|CommonMarkException */ #[Route('/article/d/{slug}', name: 'article-slug')] public function article(EntityManagerInterface $entityManager, CacheItemPoolInterface $articlesCache, - Converter $converter, $slug): Response + NostrClient $nostrClient, Converter $converter, $slug): Response { $article = null; // check if an item with same eventId already exists in the db @@ -50,6 +53,11 @@ class ArticleController extends AbstractController } // find user by npub + try { + $nostrClient->getMetadata([$article->getPubkey()]); + } catch (\Exception) { + // eh + } $author = $entityManager->getRepository(User::class)->findOneBy(['npub' => $article->getPubkey()]); return $this->render('Pages/article.html.twig', [ diff --git a/src/Controller/AuthorController.php b/src/Controller/AuthorController.php new file mode 100644 index 0000000..7edc651 --- /dev/null +++ b/src/Controller/AuthorController.php @@ -0,0 +1,28 @@ +getRepository(User::class)->findOneBy(['npub' => $npub]); + + $articles = $entityManager->getRepository(Article::class)->findBy(['pubkey' => $npub], ['createdAt' => 'DESC']); + + return $this->render('Pages/author.html.twig', [ + 'author' => $author, + 'articles' => $articles + ]); + } +} diff --git a/src/Controller/DefaultController.php b/src/Controller/DefaultController.php index 9091700..6862799 100644 --- a/src/Controller/DefaultController.php +++ b/src/Controller/DefaultController.php @@ -24,7 +24,11 @@ class DefaultController extends AbstractController #[Route('/', name: 'default')] public function index(): Response { - $list = $this->entityManager->getRepository(Article::class)->findBy([], ['createdAt' => 'DESC'], 10); + $original = $this->entityManager->getRepository(Article::class)->findBy([], ['createdAt' => 'DESC'], 10); + + $list = array_filter($original, function ($obj) { + return !empty($obj->getSlug()); + }); $npubs = array_map(function($obj) { return $obj->getPubkey(); diff --git a/src/Repository/UserEntityRepository.php b/src/Repository/UserEntityRepository.php index 4f0069a..2df090f 100644 --- a/src/Repository/UserEntityRepository.php +++ b/src/Repository/UserEntityRepository.php @@ -4,11 +4,12 @@ namespace App\Repository; use App\Entity\User; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; class UserEntityRepository extends ServiceEntityRepository { - public function __construct(ManagerRegistry $registry) + public function __construct(ManagerRegistry $registry, private readonly EntityManagerInterface $entityManager) { parent::__construct($registry, User::class); } @@ -16,10 +17,11 @@ class UserEntityRepository extends ServiceEntityRepository { $entity = $this->findOneBy(['npub' => $user->getNpub()]); - if (!$entity) { - $this->_em->persist($user); + if ($entity) { + $user->setId($entity->getId()); } + $this->entityManager->persist($user); - return $entity; + return $user; } } diff --git a/src/Service/NostrClient.php b/src/Service/NostrClient.php index ca4b825..5e99f1b 100644 --- a/src/Service/NostrClient.php +++ b/src/Service/NostrClient.php @@ -77,6 +77,7 @@ class NostrClient // TODO make relays configurable $relays = new RelaySet(); $relays->addRelay(new Relay('wss://purplepag.es')); // default metadata aggregator + $relays->addRelay(new Relay('wss://nos.lol')); // default metadata aggregator $request = new Request($relays, $requestMessage); diff --git a/src/Twig/Components/Organisms/CardList.php b/src/Twig/Components/Organisms/CardList.php index 8cfd3ab..fb671de 100644 --- a/src/Twig/Components/Organisms/CardList.php +++ b/src/Twig/Components/Organisms/CardList.php @@ -7,5 +7,5 @@ use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; #[AsTwigComponent] final class CardList { - public array $list; + public array $list; } diff --git a/symfony.lock b/symfony.lock index 4e39912..f6eace2 100644 --- a/symfony.lock +++ b/symfony.lock @@ -174,6 +174,19 @@ "./assets/controllers/hello_controller.js" ] }, + "symfony/translation": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.3", + "ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b" + }, + "files": [ + "config/packages/translation.yaml", + "translations/.gitignore" + ] + }, "symfony/twig-bundle": { "version": "7.1", "recipe": { @@ -187,6 +200,18 @@ "./templates/base.html.twig" ] }, + "symfony/ux-icons": { + "version": "2.22", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.17", + "ref": "803a3bbd5893f9584969ab8670290cdfb6a0a5b5" + }, + "files": [ + "assets/icons/symfony.svg" + ] + }, "symfony/ux-live-component": { "version": "2.21", "recipe": { diff --git a/templates/components/Atoms/NameOrNpub.html.twig b/templates/components/Atoms/NameOrNpub.html.twig new file mode 100644 index 0000000..67a33ad --- /dev/null +++ b/templates/components/Atoms/NameOrNpub.html.twig @@ -0,0 +1,9 @@ + + {% if author.displayName %} + {{ author.displayName }} + {% elseif author.name %} + {{ author.name }} + {% else %} + {{ author.npub }} + {% endif %} + diff --git a/templates/pages/article.html.twig b/templates/pages/article.html.twig index 83ed74a..4a87326 100644 --- a/templates/pages/article.html.twig +++ b/templates/pages/article.html.twig @@ -8,13 +8,16 @@ {% if author %}
- {{ 'text.byline'|trans }} - + {{ 'text.byline'|trans }} + - {{ article.createdAt|date('F j, Y') }}
- {% if article.publishedAt is not null %}{{ article.publishedAt|date('F j, Y') }}{% endif %} + {% if article.publishedAt is not null %} + {{ article.publishedAt|date('F j, Y') }} + {% else %} + {{ article.createdAt|date('F j, Y') }}
+ {% endif %}
{% endif %} diff --git a/templates/pages/author.html.twig b/templates/pages/author.html.twig new file mode 100644 index 0000000..f9291b2 --- /dev/null +++ b/templates/pages/author.html.twig @@ -0,0 +1,12 @@ +{% extends 'base.html.twig' %} + +{% block body %} +

+

+ {{ author.about }} +

+ +
+ +
+{% endblock %} diff --git a/translations/.gitignore b/translations/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml index e69de29..4574c77 100644 --- a/translations/messages.en.yaml +++ b/translations/messages.en.yaml @@ -0,0 +1,2 @@ +text: + byline: 'By'