""" responds to various requests to /.well-know """ from dateutil.relativedelta import relativedelta from django.http import HttpResponseNotFound from django.http import JsonResponse from django.shortcuts import get_object_or_404 from django.template.response import TemplateResponse from django.utils import timezone from django.views.decorators.http import require_GET from bookwyrm import models from bookwyrm.settings import DOMAIN, VERSION, LANGUAGE_CODE @require_GET def webfinger(request): """allow other servers to ask about a user""" resource = request.GET.get("resource") if not resource or not resource.startswith("acct:"): return HttpResponseNotFound() username = resource.replace("acct:", "") user = get_object_or_404(models.User, username__iexact=username) href = user.moved_to if user.moved_to else user.remote_id return JsonResponse( { "subject": f"acct:{user.username}", "links": [ { "rel": "self", "type": "application/activity+json", "href": href, }, { "rel": "http://ostatus.org/schema/1.0/subscribe", "template": f"https://{DOMAIN}/ostatus_subscribe?acct={{uri}}", }, ], } ) @require_GET def nodeinfo_pointer(_): """direct servers to nodeinfo""" return JsonResponse( { "links": [ { "rel": "http://nodeinfo.diaspora.software/ns/schema/2.0", "href": f"https://{DOMAIN}/nodeinfo/2.0", } ] } ) @require_GET def nodeinfo(_): """basic info about the server""" status_count = models.Status.objects.filter(user__local=True, deleted=False).count() user_count = models.User.objects.filter(is_active=True, local=True).count() month_ago = timezone.now() - relativedelta(months=1) last_month_count = models.User.objects.filter( is_active=True, local=True, last_active_date__gt=month_ago ).count() six_months_ago = timezone.now() - relativedelta(months=6) six_month_count = models.User.objects.filter( is_active=True, local=True, last_active_date__gt=six_months_ago ).count() site = models.SiteSettings.get() return JsonResponse( { "version": "2.0", "software": {"name": "bookwyrm", "version": VERSION}, "protocols": ["activitypub"], "usage": { "users": { "total": user_count, "activeMonth": last_month_count, "activeHalfyear": six_month_count, }, "localPosts": status_count, }, "openRegistrations": site.allow_registration, } ) @require_GET def instance_info(_): """let's talk about your cool unique instance""" user_count = models.User.objects.filter(is_active=True, local=True).count() status_count = models.Status.objects.filter(user__local=True, deleted=False).count() site = models.SiteSettings.get() logo = site.logo_url return JsonResponse( { "uri": DOMAIN, "title": site.name, "short_description": site.instance_short_description, "description": site.instance_description, "version": VERSION, "stats": { "user_count": user_count, "status_count": status_count, }, "thumbnail": logo, "languages": [LANGUAGE_CODE[:2]], "registrations": site.allow_registration, "approval_required": not site.allow_registration and site.allow_invite_requests, "email": site.admin_email, } ) @require_GET def peers(_): """list of federated servers this instance connects with""" names = models.FederatedServer.objects.filter(status="federated").values_list( "server_name", flat=True ) return JsonResponse(list(names), safe=False) @require_GET def host_meta(request): """meta of the host""" return TemplateResponse(request, "host_meta.xml", {"DOMAIN": DOMAIN}) @require_GET def opensearch(request): """Open Search xml spec""" site = models.SiteSettings.get() image = site.favicon_url return TemplateResponse( request, "opensearch.xml", {"image": image, "DOMAIN": DOMAIN} )