2022-11-18 02:16:34 +00:00
|
|
|
from django import forms
|
2022-11-18 15:28:15 +00:00
|
|
|
from django.conf import settings
|
2022-12-15 23:23:54 +00:00
|
|
|
from django.contrib.auth.forms import AuthenticationForm
|
2022-11-18 02:16:34 +00:00
|
|
|
from django.contrib.auth.password_validation import validate_password
|
2022-11-05 20:17:27 +00:00
|
|
|
from django.contrib.auth.views import LoginView, LogoutView
|
2022-11-18 02:16:34 +00:00
|
|
|
from django.shortcuts import get_object_or_404, render
|
2022-12-15 23:23:54 +00:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2022-11-18 02:16:34 +00:00
|
|
|
from django.views.generic import FormView
|
|
|
|
|
2022-11-18 07:09:04 +00:00
|
|
|
from core.models import Config
|
|
|
|
from users.models import Invite, PasswordReset, User
|
2022-11-05 20:17:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Login(LoginView):
|
2022-12-15 23:23:54 +00:00
|
|
|
class form_class(AuthenticationForm):
|
|
|
|
error_messages = {
|
|
|
|
"invalid_login": _("No account was found with that email and password."),
|
|
|
|
"inactive": _("This account is inactive."),
|
|
|
|
}
|
2022-11-05 20:17:27 +00:00
|
|
|
|
|
|
|
template_name = "auth/login.html"
|
|
|
|
|
|
|
|
|
|
|
|
class Logout(LogoutView):
|
|
|
|
pass
|
2022-11-18 02:16:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Signup(FormView):
|
|
|
|
|
|
|
|
template_name = "auth/signup.html"
|
|
|
|
|
|
|
|
class form_class(forms.Form):
|
|
|
|
|
|
|
|
email = forms.EmailField(
|
|
|
|
help_text="We will send a link to this email to set your password and create your account",
|
|
|
|
)
|
|
|
|
|
2022-11-18 07:09:04 +00:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
2022-12-06 02:21:00 +00:00
|
|
|
# Add the invite field if it's enabled
|
2022-11-18 07:09:04 +00:00
|
|
|
if Config.system.signup_invite_only:
|
|
|
|
self.fields["invite_code"] = forms.CharField(
|
|
|
|
help_text="Your invite code from one of our admins"
|
|
|
|
)
|
2022-12-06 02:21:00 +00:00
|
|
|
# Add the policies if they're defined
|
|
|
|
policies = []
|
|
|
|
if Config.system.policy_rules:
|
|
|
|
policies.append("<a href='/pages/rules/'>Server Rules</a>")
|
|
|
|
if Config.system.policy_terms:
|
|
|
|
policies.append("<a href='/pages/terms/'>Terms of Service</a>")
|
|
|
|
if Config.system.policy_privacy:
|
|
|
|
policies.append("<a href='/pages/privacy/'>Privacy Policy</a>")
|
|
|
|
if policies:
|
|
|
|
links = ""
|
|
|
|
for i, policy in enumerate(policies):
|
|
|
|
if i == 0:
|
|
|
|
links += policy
|
|
|
|
elif i == len(policies) - 1:
|
|
|
|
if len(policies) > 2:
|
|
|
|
links += ", and "
|
|
|
|
else:
|
|
|
|
links += " and "
|
|
|
|
links += policy
|
|
|
|
else:
|
|
|
|
links += ", "
|
|
|
|
links += policy
|
|
|
|
self.fields["policy"] = forms.BooleanField(
|
|
|
|
label="Policies",
|
|
|
|
help_text=f"Have you read the {links}, and agree to them?",
|
|
|
|
widget=forms.Select(
|
|
|
|
choices=[(False, "I do not agree"), (True, "I agree")]
|
|
|
|
),
|
|
|
|
)
|
2022-11-18 07:09:04 +00:00
|
|
|
|
2022-11-18 02:16:34 +00:00
|
|
|
def clean_email(self):
|
|
|
|
email = self.cleaned_data.get("email").lower()
|
|
|
|
if not email:
|
|
|
|
return
|
|
|
|
if User.objects.filter(email=email).exists():
|
|
|
|
raise forms.ValidationError("This email already has an account")
|
|
|
|
return email
|
|
|
|
|
2022-11-18 07:09:04 +00:00
|
|
|
def clean_invite_code(self):
|
|
|
|
invite_code = self.cleaned_data["invite_code"].lower().strip()
|
2022-12-06 02:21:00 +00:00
|
|
|
invite = Invite.objects.filter(token=invite_code).first()
|
|
|
|
if not invite:
|
2022-11-18 07:09:04 +00:00
|
|
|
raise forms.ValidationError("That is not a valid invite code")
|
2022-12-06 02:21:00 +00:00
|
|
|
if invite.email and invite.email != self.cleaned_data.get("email"):
|
|
|
|
raise forms.ValidationError(
|
|
|
|
"That is not a valid invite code for this email address"
|
|
|
|
)
|
2022-11-18 07:09:04 +00:00
|
|
|
return invite_code
|
|
|
|
|
2022-11-20 23:03:09 +00:00
|
|
|
def clean(self):
|
|
|
|
if not Config.system.signup_allowed:
|
|
|
|
raise forms.ValidationError("Not accepting new users at this time")
|
|
|
|
|
2022-11-18 02:16:34 +00:00
|
|
|
def form_valid(self, form):
|
|
|
|
user = User.objects.create(email=form.cleaned_data["email"])
|
2022-11-18 15:28:15 +00:00
|
|
|
# Auto-promote the user to admin if that setting is set
|
|
|
|
if settings.AUTO_ADMIN_EMAIL and user.email == settings.AUTO_ADMIN_EMAIL:
|
|
|
|
user.admin = True
|
|
|
|
user.save()
|
2022-11-18 02:16:34 +00:00
|
|
|
PasswordReset.create_for_user(user)
|
2022-11-18 07:09:04 +00:00
|
|
|
if "invite_code" in form.cleaned_data:
|
|
|
|
Invite.objects.filter(token=form.cleaned_data["invite_code"]).delete()
|
2022-11-18 02:16:34 +00:00
|
|
|
return render(
|
|
|
|
self.request,
|
|
|
|
"auth/signup_success.html",
|
|
|
|
{"email": user.email},
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-11-18 02:36:25 +00:00
|
|
|
class TriggerReset(FormView):
|
2022-11-18 02:16:34 +00:00
|
|
|
|
2022-11-18 02:36:25 +00:00
|
|
|
template_name = "auth/trigger_reset.html"
|
|
|
|
|
|
|
|
class form_class(forms.Form):
|
|
|
|
|
|
|
|
email = forms.EmailField(
|
|
|
|
help_text="We will send a reset link to this email",
|
|
|
|
)
|
|
|
|
|
|
|
|
def clean_email(self):
|
|
|
|
email = self.cleaned_data.get("email").lower()
|
|
|
|
if not email:
|
|
|
|
return
|
|
|
|
if not User.objects.filter(email=email).exists():
|
|
|
|
raise forms.ValidationError("This email does not have an account")
|
|
|
|
return email
|
|
|
|
|
|
|
|
def form_valid(self, form):
|
|
|
|
PasswordReset.create_for_user(
|
|
|
|
User.objects.get(email=form.cleaned_data["email"])
|
|
|
|
)
|
|
|
|
return render(
|
|
|
|
self.request,
|
|
|
|
"auth/trigger_reset_success.html",
|
|
|
|
{"email": form.cleaned_data["email"]},
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class PerformReset(FormView):
|
|
|
|
|
|
|
|
template_name = "auth/perform_reset.html"
|
2022-11-18 02:16:34 +00:00
|
|
|
|
|
|
|
class form_class(forms.Form):
|
|
|
|
|
|
|
|
password = forms.CharField(
|
|
|
|
widget=forms.PasswordInput,
|
|
|
|
help_text="Must be at least 8 characters, and contain both letters and numbers.",
|
|
|
|
)
|
|
|
|
|
|
|
|
repeat_password = forms.CharField(
|
|
|
|
widget=forms.PasswordInput,
|
|
|
|
)
|
|
|
|
|
|
|
|
def clean_password(self):
|
|
|
|
password = self.cleaned_data["password"]
|
|
|
|
validate_password(password)
|
|
|
|
return password
|
|
|
|
|
|
|
|
def clean_repeat_password(self):
|
|
|
|
if self.cleaned_data.get("password") != self.cleaned_data.get(
|
|
|
|
"repeat_password"
|
|
|
|
):
|
|
|
|
raise forms.ValidationError("Passwords do not match")
|
|
|
|
return self.cleaned_data.get("repeat_password")
|
|
|
|
|
|
|
|
def dispatch(self, request, token):
|
|
|
|
self.reset = get_object_or_404(PasswordReset, token=token)
|
|
|
|
return super().dispatch(request)
|
|
|
|
|
|
|
|
def form_valid(self, form):
|
|
|
|
self.reset.user.set_password(form.cleaned_data["password"])
|
|
|
|
self.reset.user.save()
|
|
|
|
self.reset.delete()
|
|
|
|
return render(
|
|
|
|
self.request,
|
2022-11-18 02:36:25 +00:00
|
|
|
"auth/perform_reset_success.html",
|
2022-11-18 02:16:34 +00:00
|
|
|
{"email": self.reset.user.email},
|
|
|
|
)
|
|
|
|
|
|
|
|
def get_context_data(self, *args, **kwargs):
|
|
|
|
context = super().get_context_data(*args, **kwargs)
|
|
|
|
context["reset"] = self.reset
|
|
|
|
return context
|