Skip to content

Commit

Permalink
Merge pull request #2320 from DemocracyClub/remove-social-auth
Browse files Browse the repository at this point in the history
Remove social auth
  • Loading branch information
symroe authored May 25, 2024
2 parents f530568 + ba79037 commit d157a36
Show file tree
Hide file tree
Showing 20 changed files with 252 additions and 172 deletions.
2 changes: 1 addition & 1 deletion requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ cffi>=1.7
coverage>=3.6
cryptography==40.0.1
decorator==5.1.1
django-allauth==0.54.0
django-appconf==1.0.5
django-braces==1.15.0
django-celery-results==2.5.0
Expand All @@ -24,6 +23,7 @@ django-extensions==3.2.1
django-filter==23.1
django-model-utils==4.3.1
django-pipeline==2.1.0
django-sesame==3.2.2
django-storages==1.13.2
django-svelte==0.2.1
django-webtest==1.9.10
Expand Down
46 changes: 0 additions & 46 deletions ynr/account_adapter.py

This file was deleted.

2 changes: 1 addition & 1 deletion ynr/apps/elections/templates/elections/ballot_view.html
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ <h1>Candidates for {{ ballot.post.label }} on <br>{{ ballot.election.election_da

{% elif not user.is_authenticated %}
<p>
<a href="{% url 'account_login' %}?next={{ request.path }}" class="button">
<a href="{% url 'wombles:login' %}?next={{ request.path }}" class="button">
Sign in to add a new candidate
</a>
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ <h2>Improve this data!</h2>
<a href="{% url 'photo-upload' person.id %}" class="button">Upload candidate photo</a>
{% endif %}
{% else %}
<a href="{% url 'account_login' %}?next={{ redirect_after_login }}" class="button">Log in to edit</a>
<a href="{% url 'wombles:login' %}?next={{ redirect_after_login }}" class="button">Log in to edit</a>
{% endif %}
{% else %}
<h2>Edits disabled</h2>
Expand Down
42 changes: 42 additions & 0 deletions ynr/apps/wombles/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from django import forms
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError


class LoginForm(forms.Form):
"""
Login form for a User.
"""

email = forms.EmailField(required=True)

def clean_email(self):
"""
Normalize the entered email
"""
email = self.cleaned_data["email"]
return User.objects.normalize_email(email)


class UserProfileForm(forms.ModelForm):
class Meta:
model = User
fields = ("username",)

username = forms.CharField(
max_length=50,
help_text="Your username is displayed publicly. We don't accept email addresses or '@' symbols",
)

def clean_username(self):
username = self.cleaned_data["username"]

if "@" in username:
raise ValidationError(
"Usernames can't be email addresses or contain an '@' symbol"
)

user = User.objects.filter(username__iexact=username)
if user:
raise ValidationError("A user with that username already exists.")
return username
14 changes: 14 additions & 0 deletions ynr/apps/wombles/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.deprecation import MiddlewareMixin


class CheckProfileDetailsMiddleware(MiddlewareMixin):
def process_request(self, request):
if request.user.is_authenticated and not request.user.username:
add_profile_url = reverse("wombles:add_profile_details")

if request.path != add_profile_url:
return redirect(add_profile_url)

return None
7 changes: 7 additions & 0 deletions ynr/apps/wombles/templates/wombles/authenticate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block content %}

<h1>Something went wrong</h1>
<p>Your authentication token may have timed out. Please request a new magic link from the <a href="{% url 'wombles:login' %}">login page</a> and try again.</p>

{% endblock %}
3 changes: 3 additions & 0 deletions ynr/apps/wombles/templates/wombles/email/login_message.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Use the following URL to authenticate with the Democracy Club candidates site:

{{ authenticate_url }}
32 changes: 32 additions & 0 deletions ynr/apps/wombles/templates/wombles/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{% extends "base.html" %}

{% block title %}
Log in
{% endblock %}

{% block content %}
{% if messages %}
<aside class="ds-status" aria-label="Status">
<ul class="ds-stack">
{% for message in messages %}
<li {% if message.tags %}class=" {{ message.tags }} ds-status-message ds-status-{{ message.level_tag }} " {% endif %}> {{ message }} </li>
{% endfor %}
</ul>
</aside>
{% else %}
<h1>Login</h1>

<p>Please enter your email, and we will send you a magic link URL to authenticate your account.</p>
<form method="post">
{% csrf_token %}
<div>
{{ form.as_p }}
</div>
<button type="submit" class="ds-button">Login</button>
</form>
<p>Contributions to this site are made public and form part of an openly licenced database.
<a href="{% url "help-about" %}">Find out more about our data licencing</a>.</p>

{% endif %}

{% endblock %}
9 changes: 9 additions & 0 deletions ynr/apps/wombles/templates/wombles/logout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block content %}

<h1>You have logged out</h1>
<p>Next time you want to log in, request a new magic link from the <a href="{% url 'wombles:login:login' %}">login
page</a>.</p>


{% endblock %}
2 changes: 1 addition & 1 deletion ynr/apps/wombles/templates/wombles/my_profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

{% block content %}
<h1>My profile</h1>
<p>Your username is {{ user.username }} and your contact email is {{ user.email }}.</p>
<p>Your username is <strong>{{ user.username }}</strong> and your contact email is {{ user.email }}.</p>
<p>When you create an account we create an API key for you, this lets you use <a href="{% url "api-home" %}">our API</a>.</p>
<p>Your API key is <code>{{ user.auth_token.key }}</code>.</p>

Expand Down
11 changes: 11 additions & 0 deletions ynr/apps/wombles/templates/wombles/update_profile.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% extends "base.html" %}

{% block content %}
<form method="POST">
<h1>Update Profile</h1>
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="ds-button">Save</button>
</form>

{% endblock %}
25 changes: 24 additions & 1 deletion ynr/apps/wombles/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
from django.contrib.auth import views as auth_views
from django.urls import path, re_path

from .views import MyProfile, SingleWombleView, WombleTagsView, WombleTagView
from .views import (
AuthenticateView,
LoginView,
MyProfile,
SingleWombleView,
UpdateProfileDetailsView,
WombleTagsView,
WombleTagView,
)

app_name = "wombles"

urlpatterns = [
path("me", MyProfile.as_view(), name="my_profile"),
Expand All @@ -11,4 +22,16 @@
re_path(
r"^(?P<pk>[\d]+)/$", SingleWombleView.as_view(), name="single_womble"
),
path("login/", LoginView.as_view(), name="login"),
path(
"logout/",
auth_views.LogoutView.as_view(template_name="wombles/logout.html"),
name="logout",
),
path("authenticate/", AuthenticateView.as_view(), name="authenticate"),
path(
"details",
UpdateProfileDetailsView.as_view(),
name="add_profile_details",
),
]
94 changes: 93 additions & 1 deletion ynr/apps/wombles/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
from candidates.models import LoggedAction
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.db.models import Count
from django.views.generic import DetailView, ListView, TemplateView
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.template.loader import render_to_string
from django.urls import reverse
from django.views.generic import (
DetailView,
FormView,
ListView,
TemplateView,
UpdateView,
)
from sesame.utils import get_query_string, get_user
from wombles.forms import LoginForm, UserProfileForm
from wombles.models import WombleTags


Expand Down Expand Up @@ -56,3 +70,81 @@ def get_queryset(self):
"wombleprofile_set__tags",
"wombleprofile_set__user__loggedaction_set",
)


class LoginView(FormView):
form_class = LoginForm
template_name = "wombles/login.html"

def form_valid(self, form):
"""
Create or retrieve a user trigger the send login email
"""
user, created = User.objects.get_or_create(
email=form.cleaned_data["email"]
)
if created:
user.set_unusable_password()
user.save()

self.send_login_url(user=user)
messages.success(
self.request,
"Thank you, please check your email for your magic link to log in to your account.",
fail_silently=True,
)
return HttpResponseRedirect(self.get_success_url())

def send_login_url(self, user):
"""
Send an email to the user with a link to authenticate and log in
"""
querystring = get_query_string(user=user)
domain = self.request.get_host()
path = reverse("wombles:authenticate")
url = f"{self.request.scheme}://{domain}{path}{querystring}"
subject = "Your magic link to log in to the Democracy Club API"
txt = render_to_string(
template_name="wombles/email/login_message.txt",
context={
"authenticate_url": url,
"subject": subject,
},
)
return user.email_user(subject=subject, message=txt)

def get_success_url(self):
"""
Redirect to same page where success message will be displayed
"""
return reverse("wombles:login")


class AuthenticateView(TemplateView):
template_name = "wombles/authenticate.html"

def get(self, request, *args, **kwargs):
"""
Attempts to get user from the request, log them in, and redirect them to
their profile page. Renders an error message if django-sesame fails to
get a user from the request.
"""
user = get_user(request)
if not user:
return super().get(request, *args, **kwargs)

login(request, user)
if not user.username:
return redirect("wombles:add_profile_details")
return redirect("/")


class UpdateProfileDetailsView(UpdateView):
form_class = UserProfileForm
template_name = "wombles/update_profile.html"

def get_object(self, queryset=None):
return self.request.user

def get_success_url(self):
return reverse("wombles:my_profile")
17 changes: 0 additions & 17 deletions ynr/forms.py

This file was deleted.

11 changes: 0 additions & 11 deletions ynr/helpers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import errno
import os

from django.core import validators

# Mimic the behaviour of 'mkdir -p', which just tries to ensure that
# the directory (including any missing parent components of the path)
# exists. This is from http://stackoverflow.com/a/600612/223092
Expand All @@ -16,12 +14,3 @@ def mkdir_p(path):
pass
else:
raise


allauth_validators = [
validators.RegexValidator(
regex=r"\@",
message="Usernames are made public, so shouldn't be email addresses",
inverse_match=True,
)
]
Loading

0 comments on commit d157a36

Please sign in to comment.