from django import forms from django.contrib import messages from django.core.files import File from django.core.validators import RegexValidator from django.db import models from django.shortcuts import get_object_or_404, redirect from django.utils.decorators import method_decorator from django.views.generic import FormView, TemplateView from core.models import Config from users.decorators import admin_required from users.models import Domain, User class DomainValidator(RegexValidator): ul = "\u00a1-\uffff" # Unicode letters range (must not be a raw string). # Host patterns hostname_re = ( r"[a-z" + ul + r"0-9](?:[a-z" + ul + r"0-9-]{0,61}[a-z" + ul + r"0-9])?" ) # Max length for domain name labels is 63 characters per RFC 1034 sec. 3.1 domain_re = r"(?:\.(?!-)[a-z" + ul + r"0-9-]{1,63}(?documentation for help on common changes\nWARNING: Do not put untrusted code in here!", widget=forms.Textarea, required=False, ) single_user = forms.CharField( label="Single User Profile Redirect", help_text="If provided, redirect the homepage of this domain to this identity's profile for logged-out users\nUse the identity's full handle - for example, takahe@jointakahe.org", required=False, ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["domain"].disabled = True self.fields["service_domain"].disabled = True def clean_domain(self): return self.cleaned_data["domain"] def clean_service_domain(self): return self.cleaned_data["service_domain"] def clean_single_user(self): return self.cleaned_data["single_user"].lstrip("@") def dispatch(self, request, domain): self.domain = get_object_or_404( Domain.objects.filter(local=True), domain=domain ) return super().dispatch(request) def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) context["domain"] = self.domain return context def form_valid(self, form): self.domain.public = form.cleaned_data["public"] self.domain.default = form.cleaned_data["default"] self.domain.notes = form.cleaned_data["notes"] or None self.domain.save() self.domain.users.set(form.cleaned_data["users"]) if self.domain.default: Domain.objects.exclude(pk=self.domain.pk).update(default=False) Config.set_domain(self.domain, "hide_login", form.cleaned_data["hide_login"]) Config.set_domain(self.domain, "site_name", form.cleaned_data["site_name"]) if isinstance(form.cleaned_data["site_icon"], File): Config.set_domain(self.domain, "site_icon", form.cleaned_data["site_icon"]) Config.set_domain(self.domain, "custom_css", form.cleaned_data["custom_css"]) Config.set_domain(self.domain, "single_user", form.cleaned_data["single_user"]) messages.success(self.request, f"Domain {self.domain} saved.") return redirect(Domain.urls.root) def get_initial(self): return { "domain": self.domain.domain, "service_domain": self.domain.service_domain, "notes": self.domain.notes, "public": self.domain.public, "default": self.domain.default, "users": "\n".join(sorted(user.email for user in self.domain.users.all())), "site_name": self.domain.config_domain.site_name, "site_icon": self.domain.config_domain.site_icon, "hide_login": self.domain.config_domain.hide_login, "custom_css": self.domain.config_domain.custom_css, "single_user": self.domain.config_domain.single_user, } @method_decorator(admin_required, name="dispatch") class DomainDelete(TemplateView): template_name = "admin/domain_delete.html" def dispatch(self, request, domain): self.domain = get_object_or_404( Domain.objects.filter(public=True), domain=domain ) return super().dispatch(request) def get_context_data(self): return { "domain": self.domain, "num_identities": self.domain.identities.count(), "section": "domains", } def post(self, request): if self.domain.identities.exists(): raise ValueError("Tried to delete domain with identities!") self.domain.delete() return redirect("admin_domains")