Skip to content

Commit 90a8415

Browse files
mein Namealphatownsman
authored andcommitted
about page
1 parent 4516c94 commit 90a8415

File tree

9 files changed

+195
-3
lines changed

9 files changed

+195
-3
lines changed

catalog/apps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ def ready(self):
1212
from journal import models as journal_models # noqa
1313

1414
# register cron jobs
15-
from catalog.jobs import DiscoverGenerator, PodcastUpdater # noqa
15+
from catalog.jobs import DiscoverGenerator, PodcastUpdater, CatalogStats # noqa
1616

1717
init_catalog_audit_log()

catalog/jobs/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from .discover import DiscoverGenerator
22
from .podcast import PodcastUpdater
3+
from .stats import CatalogStats
34

45
__all__ = [
56
"DiscoverGenerator",
67
"PodcastUpdater",
8+
"CatalogStats",
79
]

catalog/jobs/stats.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from datetime import timedelta
2+
3+
from django.core.cache import cache
4+
from loguru import logger
5+
6+
from catalog.common.models import item_categories
7+
from catalog.search.views import visible_categories
8+
from common.models import BaseJob, JobManager
9+
10+
11+
@JobManager.register
12+
class CatalogStats(BaseJob):
13+
"""Calculate and cache statistics for the about page."""
14+
15+
interval = timedelta(minutes=30) # Update stats every 30 minutes
16+
CACHE_KEY = "catalog_stats"
17+
18+
def run(self):
19+
logger.info("StatsJob: Calculating item counts")
20+
stats = []
21+
for cat in visible_categories(None) or item_categories().keys():
22+
count = 0
23+
for cls in item_categories()[cat]:
24+
count += cls.objects.filter().count()
25+
stats.append({"label": cat.label, "value": cat.value, "count": count})
26+
cache.set(self.CACHE_KEY, stats, 3600 * 24 * 7)
27+
logger.info(f"StatsJob: Cached stats: {stats}")

common/templates/_footer.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
{% for link in site_links %}<a target="_blank" rel="noopener" href="{{ link.url }}">{{ link.title }}</a>{% endfor %}
66
<!-- <a href="/pages/rules/">{% trans 'Rules' %}</a> -->
77
<!-- <a href="/pages/terms/">{% trans 'Terms' %}</a> -->
8+
<a href="{% url 'common:about' %}">{% trans 'About' %}</a>
89
<a href="{% url 'users:announcements' %}">{% trans 'Announcements' %}</a>
910
<a href="{% url 'common:developer' %}">{% trans 'Developer' %}</a>
1011
<a title="{{ neodb_version }}"

common/templates/common/about.html

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
{% load static %}
2+
{% load i18n %}
3+
{% load l10n %}
4+
{% load mastodon %}
5+
{% load thumb %}
6+
{% get_current_language as LANGUAGE_CODE %}
7+
<!DOCTYPE html>
8+
<html lang="{{ LANGUAGE_CODE }}">
9+
<head>
10+
<meta charset="UTF-8">
11+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
12+
<title>{% translate "About" %} - {{ site_name }}</title>
13+
{% include "common_libs.html" %}
14+
</head>
15+
<body>
16+
{% include "_header.html" %}
17+
<main class="container">
18+
<article class="about" style="max-width:60em;margin:auto">
19+
<section>
20+
<h1>{{ site_name }}</h1>
21+
<div class="instance-info">
22+
<p>{{ site_description }}</p>
23+
{% if site_intro %}
24+
<div hx-get="{{ site_intro }}" hx-trigger="load" hx-swap="outerHTML">
25+
<i class="fa-solid fa-compact-disc fa-spin loading"></i>
26+
</div>
27+
{% endif %}
28+
<dl>
29+
<dt>{% translate "Instance Name" %}</dt>
30+
<dd>
31+
{{ site_name }}
32+
</dd>
33+
<dt>{% translate "Domain" %}</dt>
34+
<dd>
35+
{{ site_domain }}
36+
</dd>
37+
<dt>{% translate "Version" %}</dt>
38+
<dd>
39+
<a href="https://neodb.net" target="_blank" rel="noopener">{{ neodb_version }}</a>
40+
</dd>
41+
<dt>{% translate "Registration" %}</dt>
42+
<dd>
43+
{% if invite_only %}
44+
{% translate "Invite Only" %}
45+
{% else %}
46+
{% translate "Open Registration" %}
47+
{% endif %}
48+
</dd>
49+
</dl>
50+
</div>
51+
</section>
52+
<section>
53+
<h2>{% translate "Statistics" %}</h2>
54+
<div class="stats">
55+
{% if catalog_stats %}
56+
<dl>
57+
{% for category in catalog_stats %}
58+
<dt>{% translate category.label %}</dt>
59+
<dd>
60+
{{ category.count|default:"0"|localize }}
61+
</dd>
62+
{% endfor %}
63+
{% if instance_info_stats %}
64+
<dt>{% translate "Users" %}</dt>
65+
<dd>
66+
{{ instance_info_stats.user_count|default:"0"|localize }}
67+
</dd>
68+
<dt>{% translate "Statuses" %}</dt>
69+
<dd>
70+
{{ instance_info_stats.status_count|default:"0"|localize }}
71+
</dd>
72+
<dt>{% translate "Known Fediverse Instances" %}</dt>
73+
<dd>
74+
{{ instance_info_stats.domain_count|default:"0"|localize }}
75+
</dd>
76+
{% endif %}
77+
{% if neodb_peers %}
78+
<dt>{% translate "Known NeoDB Instances" %}</dt>
79+
<dd>
80+
{% for peer in neodb_peers %}
81+
<a href="{{ peer.url }}" target="_blank">{{ peer.name }}</a>
82+
<br>
83+
{% endfor %}
84+
</dd>
85+
{% endif %}
86+
</dl>
87+
{% else %}
88+
<p>{% translate "Statistics are being calculated. Please check back in a few minutes." %}</p>
89+
{% endif %}
90+
</div>
91+
</section>
92+
{% if staff_users or admin_users %}
93+
<section>
94+
{% if admin_users %}
95+
<div class="user-list admin-users">
96+
<h2>{% translate "Administrators" %}</h2>
97+
<ul>
98+
{% for user in admin_users %}
99+
<li>
100+
<a href="{{ user.url }}" class="user-link">
101+
<img src="{{ user.avatar }}"
102+
alt="{{ user.username }}"
103+
class="avatar"
104+
width="32"
105+
height="32">
106+
<span class="username">{{ user.display_name|default:user.username }}</span>
107+
</a>
108+
</li>
109+
{% endfor %}
110+
</ul>
111+
</div>
112+
{% endif %}
113+
{% if staff_users %}
114+
<div class="user-list staff-users">
115+
<h2>{% translate "Moderators" %}</h2>
116+
<ul>
117+
{% for user in staff_users %}
118+
<li>
119+
<a href="{{ user.url }}" class="user-link">
120+
<img src="{{ user.avatar }}"
121+
alt="{{ user.username }}"
122+
class="avatar"
123+
width="32"
124+
height="32">
125+
<span class="username">{{ user.display_name|default:user.username }}</span>
126+
</a>
127+
</li>
128+
{% endfor %}
129+
</ul>
130+
</div>
131+
{% endif %}
132+
</section>
133+
{% endif %}
134+
</article>
135+
</main>
136+
{% include "_footer.html" %}
137+
</body>
138+
</html>

common/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
path("site/share", share, name="share"),
1111
path("site/manifest.json", manifest, name="manifest"),
1212
path("site/opensearch.xml", opensearch, name="opensearch"),
13+
path("about/", about, name="about"),
1314
path("me/", me, name="me"),
1415
path("nodeinfo/<str:version>/", nodeinfo2),
1516
path("developer/", console, name="developer"),

common/views.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
from catalog.views import search as catalog_search
1111
from journal.views import search as journal_search
1212
from social.views import search as timeline_search
13+
from takahe.models import Domain
1314
from takahe.utils import Takahe
15+
from users.models.user import User
1416

1517
from .api import api
1618

@@ -245,6 +247,27 @@ def oauth_authorization_server(request):
245247
return JsonResponse(metadata)
246248

247249

250+
def about(request):
251+
context = {
252+
"neodb_version": settings.NEODB_VERSION,
253+
}
254+
context["catalog_stats"] = cache.get("catalog_stats") or []
255+
context["instance_info_stats"] = cache.get("instance_info_stats") or {}
256+
context["invite_only"] = settings.INVITE_ONLY
257+
context["admin_users"] = User.objects.filter(is_superuser=True, is_active=True)
258+
context["staff_users"] = User.objects.filter(
259+
is_staff=True, is_superuser=False, is_active=True
260+
)
261+
peers = []
262+
for peer in Takahe.get_neodb_peers():
263+
d = Domain.objects.filter(domain=peer).first()
264+
if d:
265+
name = (d.nodeinfo or {}).get("metadata", {}).get("nodeName", peer)
266+
peers.append({"name": name, "url": f"https://{peer}"})
267+
context["neodb_peers"] = peers
268+
return render(request, "common/about.html", context)
269+
270+
248271
def signup(request, code: str | None = None):
249272
if request.user.is_authenticated:
250273
return redirect(reverse("common:home"))

misc/nginx.conf.d/neodb-dev.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ server {
112112
location ~* ^/\.well-known/oauth- {
113113
proxy_pass http://neodb;
114114
}
115-
location ~* ^/(static|@|\.well-known|actor|inbox|api/v1|api/v2|oauth|tags|settings|media|proxy|admin|djadmin|pages|about|impressum) {
115+
location ~* ^/(static|@|\.well-known|actor|inbox|api/v1|api/v2|oauth|tags|settings|media|proxy|admin|djadmin|pages|impressum) {
116116
proxy_pass http://takahe;
117117
}
118118
location /mcp/ {

misc/nginx.conf.d/neodb.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ server {
125125
location ~* ^/\.well-known/oauth- {
126126
proxy_pass http://neodb;
127127
}
128-
location ~* ^/(@|\.well-known|actor|inbox|api/v1|api/v2|oauth|tags|settings|media|proxy|admin|djadmin|pages|about|impressum) {
128+
location ~* ^/(@|\.well-known|actor|inbox|api/v1|api/v2|oauth|tags|settings|media|proxy|admin|djadmin|pages|impressum) {
129129
proxy_pass http://takahe;
130130
}
131131
location /mcp/ {

0 commit comments

Comments
 (0)