diff options
author | Andrew Godwin | 2022-11-05 14:17:27 -0600 |
---|---|---|
committer | Andrew Godwin | 2022-11-05 14:17:27 -0600 |
commit | d77dcf62b4005a0f36ef2fa7ba6d3651d2ef38d7 (patch) | |
tree | dd356a933b8179a22e5da6e938acd96a175ac0d6 /users/views | |
download | takahe-d77dcf62b4005a0f36ef2fa7ba6d3651d2ef38d7.tar.gz takahe-d77dcf62b4005a0f36ef2fa7ba6d3651d2ef38d7.tar.bz2 takahe-d77dcf62b4005a0f36ef2fa7ba6d3651d2ef38d7.zip |
Initial commit (users and statuses)
Diffstat (limited to 'users/views')
-rw-r--r-- | users/views/__init__.py | 1 | ||||
-rw-r--r-- | users/views/auth.py | 15 | ||||
-rw-r--r-- | users/views/identity.py | 132 |
3 files changed, 148 insertions, 0 deletions
diff --git a/users/views/__init__.py b/users/views/__init__.py new file mode 100644 index 0000000..1e88b4e --- /dev/null +++ b/users/views/__init__.py @@ -0,0 +1 @@ +from .auth import * # noqa diff --git a/users/views/auth.py b/users/views/auth.py new file mode 100644 index 0000000..f9e6ce1 --- /dev/null +++ b/users/views/auth.py @@ -0,0 +1,15 @@ +from django.contrib.auth.forms import AuthenticationForm +from django.contrib.auth.views import LoginView, LogoutView + +from core.forms import FormHelper + + +class Login(LoginView): + class form_class(AuthenticationForm): + helper = FormHelper(submit_text="Login") + + template_name = "auth/login.html" + + +class Logout(LogoutView): + pass diff --git a/users/views/identity.py b/users/views/identity.py new file mode 100644 index 0000000..63b7fb8 --- /dev/null +++ b/users/views/identity.py @@ -0,0 +1,132 @@ +from django import forms +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.http import Http404, JsonResponse +from django.shortcuts import redirect +from django.utils.decorators import method_decorator +from django.views.generic import FormView, TemplateView, View + +from core.forms import FormHelper +from users.models import Identity +from users.shortcuts import by_handle_or_404 + + +class ViewIdentity(TemplateView): + + template_name = "identity/view.html" + + def get_context_data(self, handle): + identity = by_handle_or_404(self.request, handle, local=False) + statuses = identity.statuses.all()[:100] + return { + "identity": identity, + "statuses": statuses, + } + + +@method_decorator(login_required, name="dispatch") +class SelectIdentity(TemplateView): + + template_name = "identity/select.html" + + def get_context_data(self): + return { + "identities": Identity.objects.filter(users__pk=self.request.user.pk), + } + + +@method_decorator(login_required, name="dispatch") +class CreateIdentity(FormView): + + template_name = "identity/create.html" + + class form_class(forms.Form): + handle = forms.CharField() + name = forms.CharField() + + helper = FormHelper(submit_text="Create") + + def clean_handle(self): + # Remove any leading @ + value = self.cleaned_data["handle"].lstrip("@") + # Don't allow custom domains here quite yet + if "@" in value: + raise forms.ValidationError( + "You are not allowed an @ sign in your handle" + ) + # Ensure there is a domain on the end + if "@" not in value: + value += "@" + settings.DEFAULT_DOMAIN + # Check for existing users + if Identity.objects.filter(handle=value).exists(): + raise forms.ValidationError("This handle is already taken") + return value + + def form_valid(self, form): + new_identity = Identity.objects.create( + handle=form.cleaned_data["handle"], + name=form.cleaned_data["name"], + local=True, + ) + new_identity.users.add(self.request.user) + new_identity.generate_keypair() + return redirect(new_identity.urls.view) + + +class Actor(View): + """ + Returns the AP Actor object + """ + + def get(self, request, handle): + identity = by_handle_or_404(self.request, handle) + return JsonResponse( + { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + ], + "id": f"https://{settings.DEFAULT_DOMAIN}{identity.urls.actor}", + "type": "Person", + "preferredUsername": "alice", + "inbox": f"https://{settings.DEFAULT_DOMAIN}{identity.urls.inbox}", + "publicKey": { + "id": f"https://{settings.DEFAULT_DOMAIN}{identity.urls.actor}#main-key", + "owner": f"https://{settings.DEFAULT_DOMAIN}{identity.urls.actor}", + "publicKeyPem": identity.public_key, + }, + } + ) + + +class Webfinger(View): + """ + Services webfinger requests + """ + + def get(self, request): + resource = request.GET.get("resource") + if not resource.startswith("acct:"): + raise Http404("Not an account resource") + handle = resource[5:] + identity = by_handle_or_404(request, handle) + return JsonResponse( + { + "subject": f"acct:{identity.handle}", + "aliases": [ + f"https://{settings.DEFAULT_DOMAIN}/@{identity.short_handle}", + ], + "links": [ + { + "rel": "http://webfinger.net/rel/profile-page", + "type": "text/html", + "href": f"https://{settings.DEFAULT_DOMAIN}{identity.urls.view}", + }, + { + "rel": "self", + "type": "application/activity+json", + "href": f"https://{settings.DEFAULT_DOMAIN}{identity.urls.actor}", + }, + ], + } + ) |