Browse Source

Interests

imwald
Nuša Pukšič 3 months ago
parent
commit
4397f5afc8
  1. 38
      src/Controller/ForumController.php
  2. 1
      src/Enum/KindsEnum.php
  3. 34
      src/Service/NostrClient.php
  4. 4
      templates/event/index.html.twig
  5. 25
      templates/forum/index.html.twig

38
src/Controller/ForumController.php

@ -4,7 +4,10 @@ declare(strict_types=1);
namespace App\Controller; namespace App\Controller;
use App\Entity\User;
use App\Service\NostrClient;
use App\Util\ForumTopics; use App\Util\ForumTopics;
use App\Util\NostrKeyUtil;
use Elastica\Aggregation\Filters as FiltersAgg; use Elastica\Aggregation\Filters as FiltersAgg;
use Elastica\Query; use Elastica\Query;
use Elastica\Query\BoolQuery; use Elastica\Query\BoolQuery;
@ -25,7 +28,8 @@ class ForumController extends AbstractController
public function index( public function index(
#[Autowire(service: 'fos_elastica.index.articles')] \Elastica\Index $index, #[Autowire(service: 'fos_elastica.index.articles')] \Elastica\Index $index,
CacheInterface $cache, CacheInterface $cache,
Request $request Request $request,
NostrClient $nostrClient
): Response { ): Response {
// Optional: small cache so we don’t hammer ES on every page view // Optional: small cache so we don’t hammer ES on every page view
//$categoriesWithCounts = $cache->get('forum.index.counts.v2', function (ItemInterface $item) use ($index) { //$categoriesWithCounts = $cache->get('forum.index.counts.v2', function (ItemInterface $item) use ($index) {
@ -36,8 +40,40 @@ class ForumController extends AbstractController
// return $this->hydrateCategoryCounts(self::TOPICS, $counts); // return $this->hydrateCategoryCounts(self::TOPICS, $counts);
//}); //});
$categoriesWithCounts = $this->hydrateCategoryCounts(ForumTopics::TOPICS, $counts); $categoriesWithCounts = $this->hydrateCategoryCounts(ForumTopics::TOPICS, $counts);
$userInterests = null;
/** @var User $user */
$user = $this->getUser();
if (!!$user) {
try {
$pubkey = NostrKeyUtil::npubToHex($user->getNpub());
$interests = $nostrClient->getUserInterests($pubkey);
if (!empty($interests)) {
$userInterests = $this->hydrateCategoryCounts(ForumTopics::TOPICS, $counts);
// Filter to only include subcategories that have tags in interests
foreach ($userInterests as $catKey => $cat) {
$subs = [];
foreach ($cat['subcategories'] as $subKey => $sub) {
$subTags = array_map('strtolower', $sub['tags']);
if (array_intersect($subTags, $interests)) {
$subs[$subKey] = $sub;
}
}
if (!empty($subs)) {
$userInterests[$catKey]['subcategories'] = $subs;
} else {
unset($userInterests[$catKey]);
}
}
}
} catch (\Exception $e) {
// Ignore errors, just don't show user interests
}
}
return $this->render('forum/index.html.twig', [ return $this->render('forum/index.html.twig', [
'topics' => $categoriesWithCounts, 'topics' => $categoriesWithCounts,
'userInterests' => $userInterests,
]); ]);
} }

1
src/Enum/KindsEnum.php

@ -11,6 +11,7 @@ enum KindsEnum: int
case REPOST = 6; // Only wraps kind 1, NIP-18, will not implement case REPOST = 6; // Only wraps kind 1, NIP-18, will not implement
case GENERIC_REPOST = 16; // Generic repost, original kind signalled in a "k" tag, NIP-18 case GENERIC_REPOST = 16; // Generic repost, original kind signalled in a "k" tag, NIP-18
case FILE_METADATA = 1063; // NIP-94 case FILE_METADATA = 1063; // NIP-94
case INTERESTS = 10015; // NIP-51
case COMMENTS = 1111; case COMMENTS = 1111;
case HTTP_AUTH = 27235; // NIP-98, HTTP Auth case HTTP_AUTH = 27235; // NIP-98, HTTP Auth
case CURATION_SET = 30004; // NIP-51 case CURATION_SET = 30004; // NIP-51

34
src/Service/NostrClient.php

@ -1072,4 +1072,38 @@ class NostrClient
return null; return null;
} }
} }
/**
* Fetch the latest interest list (kind 10015) for a pubkey and return the 't' tags.
*/
public function getUserInterests(string $pubkey): array
{
$request = $this->createNostrRequest(
kinds: [10015],
filters: ['authors' => [$pubkey]],
relaySet: $this->defaultRelaySet
);
$events = $this->processResponse($request->send(), function($received) use ($pubkey) {
$this->logger->info('Getting interests for pubkey', ['pubkey' => $pubkey, 'item' => $received]);
return $received;
});
if (empty($events)) {
return [];
}
// Sort by created_at descending and take the latest
usort($events, fn($a, $b) => $b->created_at <=> $a->created_at);
$latest = $events[0];
$tTags = [];
foreach ($latest->tags as $tag) {
if (is_array($tag) && isset($tag[0]) && $tag[0] === 't' && isset($tag[1])) {
$tTags[] = strtolower(trim($tag[1]));
}
}
return $tTags;
}
} }

4
templates/event/index.html.twig

@ -172,6 +172,10 @@
{% endif %} {% endif %}
</div> </div>
<pre>
{{ event|json_encode(constant('JSON_PRETTY_PRINT')) }}
</pre>
</div> </div>
{% endblock %} {% endblock %}

25
templates/forum/index.html.twig

@ -3,6 +3,31 @@
{% block body %} {% block body %}
<twig:Atoms:PageHeading heading="Topics" tagline="Explore your interests"/> <twig:Atoms:PageHeading heading="Topics" tagline="Explore your interests"/>
{% if userInterests %}
<section class="d-flex gap-3 center ln-section--newsstand">
<div class="container mt-5 mb-5">
<h2>Your Interests</h2>
</div>
</section>
<div class="subcategories-grid">
{% for catKey, category in userInterests %}
{% for subKey, sub in category.subcategories %}
<div class="sub-card">
<h3><a href="{{ path('forum_topic', {'key': catKey ~ '-' ~ subKey}) }}">{{ sub.name }}</a></h3>
<div class="d-flex flex-row">
<div class="tags m-0">
{% for tag in sub.tags %}
<a class="tag" href="{{ path('forum_tag', {'tag': tag}) }}">{{ tag }}</a>
{% endfor %}
</div>
<div class="count">{{ sub.count|default(0) }}</div>
</div>
</div>
{% endfor %}
{% endfor %}
</div>
{% endif %}
{% for catKey, category in topics %} {% for catKey, category in topics %}
<section class="d-flex gap-3 center ln-section--newsstand"> <section class="d-flex gap-3 center ln-section--newsstand">
<div class="container mt-5 mb-5"> <div class="container mt-5 mb-5">

Loading…
Cancel
Save