diff --git a/users/admin.py b/users/admin.py index 8e7c0fa..1d7f9a0 100644 --- a/users/admin.py +++ b/users/admin.py @@ -1,3 +1,4 @@ +from asgiref.sync import async_to_sync from django.contrib import admin from django.db import models from django.utils import formats @@ -30,7 +31,12 @@ class DomainAdmin(admin.ModelAdmin): ] list_filter = ("local", "blocked") search_fields = ("domain", "service_domain") - actions = ["force_outdated", "force_updated", "force_connection_issue"] + actions = [ + "force_outdated", + "force_updated", + "force_connection_issue", + "fetch_nodeinfo", + ] @admin.action(description="Force State: outdated") def force_outdated(self, request, queryset): @@ -47,6 +53,14 @@ class DomainAdmin(admin.ModelAdmin): for instance in queryset: instance.transition_perform("connection_issue") + @admin.action(description="Fetch nodeinfo") + def fetch_nodeinfo(self, request, queryset): + for instance in queryset: + info = async_to_sync(instance.fetch_nodeinfo)() + if info: + instance.nodeinfo = info.dict() + instance.save() + @admin.display(description="Software") def software(self, instance): if instance.nodeinfo: diff --git a/users/models/domain.py b/users/models/domain.py index 5a140ca..11405c9 100644 --- a/users/models/domain.py +++ b/users/models/domain.py @@ -150,13 +150,35 @@ class Domain(StatorModel): """ Fetch the /NodeInfo/2.0 for the domain """ + nodeinfo20_url = f"https://{self.domain}/nodeinfo/2.0" + async with httpx.AsyncClient( timeout=settings.SETUP.REMOTE_TIMEOUT, headers={"User-Agent": settings.TAKAHE_USER_AGENT}, ) as client: try: response = await client.get( - f"https://{self.domain}/nodeinfo/2.0", + f"https://{self.domain}/.well-known/nodeinfo", + follow_redirects=True, + headers={"Accept": "application/json"}, + ) + except httpx.HTTPError: + pass + else: + try: + for link in response.json().get("links", []): + if ( + link.get("rel") + == "http://nodeinfo.diaspora.software/ns/schema/2.0" + ): + nodeinfo20_url = link.get("href", nodeinfo20_url) + break + except json.JSONDecodeError: + pass + + try: + response = await client.get( + nodeinfo20_url, follow_redirects=True, headers={"Accept": "application/json"}, )