2021-03-08 16:49:10 +00:00
|
|
|
""" responds to various requests to /.well-know """
|
2020-11-01 19:09:16 +00:00
|
|
|
|
2020-11-01 17:16:49 +00:00
|
|
|
from dateutil.relativedelta import relativedelta
|
2020-11-01 18:42:48 +00:00
|
|
|
from django.http import HttpResponseNotFound
|
2020-02-15 19:31:35 +00:00
|
|
|
from django.http import JsonResponse
|
2021-09-27 23:04:40 +00:00
|
|
|
from django.shortcuts import get_object_or_404
|
2021-03-29 21:36:24 +00:00
|
|
|
from django.template.response import TemplateResponse
|
2020-11-28 00:24:53 +00:00
|
|
|
from django.utils import timezone
|
2021-03-13 18:58:54 +00:00
|
|
|
from django.views.decorators.http import require_GET
|
2020-02-15 19:31:35 +00:00
|
|
|
|
2020-09-21 15:10:37 +00:00
|
|
|
from bookwyrm import models
|
2021-10-05 15:00:13 +00:00
|
|
|
from bookwyrm.settings import DOMAIN, VERSION, MEDIA_FULL_URL, STATIC_FULL_URL
|
2020-02-15 19:31:35 +00:00
|
|
|
|
|
|
|
|
2021-03-13 18:58:54 +00:00
|
|
|
@require_GET
|
2020-02-15 19:31:35 +00:00
|
|
|
def webfinger(request):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""allow other servers to ask about a user"""
|
2021-03-08 16:49:10 +00:00
|
|
|
resource = request.GET.get("resource")
|
2021-03-13 18:58:54 +00:00
|
|
|
if not resource or not resource.startswith("acct:"):
|
2020-11-01 18:42:48 +00:00
|
|
|
return HttpResponseNotFound()
|
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
username = resource.replace("acct:", "")
|
2021-09-27 23:04:40 +00:00
|
|
|
user = get_object_or_404(models.User, username__iexact=username)
|
2021-03-08 16:49:10 +00:00
|
|
|
|
|
|
|
return JsonResponse(
|
|
|
|
{
|
2021-09-18 18:32:00 +00:00
|
|
|
"subject": f"acct:{user.username}",
|
2021-03-08 16:49:10 +00:00
|
|
|
"links": [
|
|
|
|
{
|
|
|
|
"rel": "self",
|
|
|
|
"type": "application/activity+json",
|
|
|
|
"href": user.remote_id,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
}
|
|
|
|
)
|
2020-02-15 19:31:35 +00:00
|
|
|
|
|
|
|
|
2021-03-13 18:58:54 +00:00
|
|
|
@require_GET
|
|
|
|
def nodeinfo_pointer(_):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""direct servers to nodeinfo"""
|
2021-03-08 16:49:10 +00:00
|
|
|
return JsonResponse(
|
|
|
|
{
|
|
|
|
"links": [
|
|
|
|
{
|
|
|
|
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.0",
|
2021-09-18 18:32:00 +00:00
|
|
|
"href": f"https://{DOMAIN}/nodeinfo/2.0",
|
2021-03-08 16:49:10 +00:00
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
2020-02-15 19:31:35 +00:00
|
|
|
|
2020-03-29 07:05:09 +00:00
|
|
|
|
2021-03-13 18:58:54 +00:00
|
|
|
@require_GET
|
|
|
|
def nodeinfo(_):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""basic info about the server"""
|
2021-09-11 14:52:56 +00:00
|
|
|
status_count = models.Status.objects.filter(user__local=True, deleted=False).count()
|
|
|
|
user_count = models.User.objects.filter(is_active=True, local=True).count()
|
2020-11-01 17:16:49 +00:00
|
|
|
|
2020-11-28 00:24:53 +00:00
|
|
|
month_ago = timezone.now() - relativedelta(months=1)
|
2020-11-01 17:16:49 +00:00
|
|
|
last_month_count = models.User.objects.filter(
|
2021-09-11 14:52:56 +00:00
|
|
|
is_active=True, local=True, last_active_date__gt=month_ago
|
2020-11-01 17:16:49 +00:00
|
|
|
).count()
|
|
|
|
|
2020-11-28 00:24:53 +00:00
|
|
|
six_months_ago = timezone.now() - relativedelta(months=6)
|
2020-11-01 17:16:49 +00:00
|
|
|
six_month_count = models.User.objects.filter(
|
2021-09-11 14:52:56 +00:00
|
|
|
is_active=True, local=True, last_active_date__gt=six_months_ago
|
2020-11-01 17:16:49 +00:00
|
|
|
).count()
|
2020-11-08 05:07:07 +00:00
|
|
|
|
|
|
|
site = models.SiteSettings.get()
|
2021-03-08 16:49:10 +00:00
|
|
|
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,
|
2020-02-15 19:40:21 +00:00
|
|
|
},
|
2021-03-08 16:49:10 +00:00
|
|
|
"openRegistrations": site.allow_registration,
|
|
|
|
}
|
|
|
|
)
|
2020-02-15 19:40:21 +00:00
|
|
|
|
|
|
|
|
2021-03-13 18:58:54 +00:00
|
|
|
@require_GET
|
|
|
|
def instance_info(_):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""let's talk about your cool unique instance"""
|
2021-09-11 14:52:56 +00:00
|
|
|
user_count = models.User.objects.filter(is_active=True, local=True).count()
|
|
|
|
status_count = models.Status.objects.filter(user__local=True, deleted=False).count()
|
2020-11-08 05:07:07 +00:00
|
|
|
|
|
|
|
site = models.SiteSettings.get()
|
2021-10-05 15:00:13 +00:00
|
|
|
logo = get_image_url(site.logo, "logo.png")
|
2021-03-08 16:49:10 +00:00
|
|
|
return JsonResponse(
|
|
|
|
{
|
|
|
|
"uri": DOMAIN,
|
|
|
|
"title": site.name,
|
2021-09-10 18:44:01 +00:00
|
|
|
"short_description": site.instance_short_description,
|
2021-03-08 16:49:10 +00:00
|
|
|
"description": site.instance_description,
|
2021-09-10 18:44:01 +00:00
|
|
|
"version": VERSION,
|
2021-03-08 16:49:10 +00:00
|
|
|
"stats": {
|
|
|
|
"user_count": user_count,
|
|
|
|
"status_count": status_count,
|
|
|
|
},
|
2021-09-10 18:44:01 +00:00
|
|
|
"thumbnail": logo,
|
2021-03-08 16:49:10 +00:00
|
|
|
"languages": ["en"],
|
|
|
|
"registrations": site.allow_registration,
|
2021-09-11 14:52:56 +00:00
|
|
|
"approval_required": site.allow_registration and site.allow_invite_requests,
|
2021-09-10 18:44:01 +00:00
|
|
|
"email": site.admin_email,
|
2021-03-08 16:49:10 +00:00
|
|
|
}
|
|
|
|
)
|
2020-03-29 07:05:09 +00:00
|
|
|
|
|
|
|
|
2021-03-13 18:58:54 +00:00
|
|
|
@require_GET
|
|
|
|
def peers(_):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""list of federated servers this instance connects with"""
|
2021-09-11 20:30:27 +00:00
|
|
|
names = models.FederatedServer.objects.filter(status="federated").values_list(
|
|
|
|
"server_name", flat=True
|
2021-09-11 14:52:56 +00:00
|
|
|
)
|
2020-03-29 22:51:43 +00:00
|
|
|
return JsonResponse(list(names), safe=False)
|
2021-03-29 21:36:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
@require_GET
|
|
|
|
def host_meta(request):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""meta of the host"""
|
2021-03-29 21:36:24 +00:00
|
|
|
return TemplateResponse(request, "host_meta.xml", {"DOMAIN": DOMAIN})
|
2021-09-10 23:47:59 +00:00
|
|
|
|
2021-09-28 02:05:13 +00:00
|
|
|
|
2021-09-10 23:47:59 +00:00
|
|
|
@require_GET
|
|
|
|
def opensearch(request):
|
|
|
|
"""Open Search xml spec"""
|
2021-09-28 02:28:50 +00:00
|
|
|
site = models.SiteSettings.get()
|
2021-10-05 15:00:13 +00:00
|
|
|
image = get_image_url(site.favicon, "favicon.png")
|
2021-09-28 02:38:54 +00:00
|
|
|
return TemplateResponse(
|
2021-10-05 15:00:13 +00:00
|
|
|
request, "opensearch.xml", {"image": image, "DOMAIN": DOMAIN}
|
2021-09-28 02:38:54 +00:00
|
|
|
)
|
2021-10-05 15:00:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_image_url(obj, fallback):
|
|
|
|
"""helper for loading the full path to an image"""
|
|
|
|
if obj:
|
|
|
|
return f"{MEDIA_FULL_URL}{obj}"
|
|
|
|
return f"{STATIC_FULL_URL}images/{fallback}"
|