Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2022-03-24 09:46:32 -07:00
commit 588d2da2c6
29 changed files with 258 additions and 158 deletions

View file

@ -4,6 +4,7 @@ from django import forms
from bookwyrm import models from bookwyrm import models
from bookwyrm.models.fields import ClearableFileInputWithWarning from bookwyrm.models.fields import ClearableFileInputWithWarning
from .custom_form import CustomForm from .custom_form import CustomForm
from .widgets import ArrayWidget, SelectDateWidget, Select
# pylint: disable=missing-class-docstring # pylint: disable=missing-class-docstring
@ -14,14 +15,6 @@ class CoverForm(CustomForm):
help_texts = {f: None for f in fields} help_texts = {f: None for f in fields}
class ArrayWidget(forms.widgets.TextInput):
# pylint: disable=unused-argument
# pylint: disable=no-self-use
def value_from_datadict(self, data, files, name):
"""get all values for this name"""
return [i for i in data.getlist(name) if i]
class EditionForm(CustomForm): class EditionForm(CustomForm):
class Meta: class Meta:
model = models.Edition model = models.Edition
@ -56,16 +49,16 @@ class EditionForm(CustomForm):
"publishers": forms.TextInput( "publishers": forms.TextInput(
attrs={"aria-describedby": "desc_publishers_help desc_publishers"} attrs={"aria-describedby": "desc_publishers_help desc_publishers"}
), ),
"first_published_date": forms.SelectDateWidget( "first_published_date": SelectDateWidget(
attrs={"aria-describedby": "desc_first_published_date"} attrs={"aria-describedby": "desc_first_published_date"}
), ),
"published_date": forms.SelectDateWidget( "published_date": SelectDateWidget(
attrs={"aria-describedby": "desc_published_date"} attrs={"aria-describedby": "desc_published_date"}
), ),
"cover": ClearableFileInputWithWarning( "cover": ClearableFileInputWithWarning(
attrs={"aria-describedby": "desc_cover"} attrs={"aria-describedby": "desc_cover"}
), ),
"physical_format": forms.Select( "physical_format": Select(
attrs={"aria-describedby": "desc_physical_format"} attrs={"aria-describedby": "desc_physical_format"}
), ),
"physical_format_detail": forms.TextInput( "physical_format_detail": forms.TextInput(

70
bookwyrm/forms/widgets.py Normal file
View file

@ -0,0 +1,70 @@
""" using django model forms """
from django import forms
class ArrayWidget(forms.widgets.TextInput):
"""Inputs for postgres array fields"""
# pylint: disable=unused-argument
# pylint: disable=no-self-use
def value_from_datadict(self, data, files, name):
"""get all values for this name"""
return [i for i in data.getlist(name) if i]
class Select(forms.Select):
"""custom template for select widget"""
template_name = "widgets/select.html"
class SelectDateWidget(forms.SelectDateWidget):
"""
A widget that splits date input into two <select> boxes and a numerical year.
"""
template_name = "widgets/addon_multiwidget.html"
select_widget = Select
def get_context(self, name, value, attrs):
"""sets individual widgets"""
context = super().get_context(name, value, attrs)
date_context = {}
year_name = self.year_field % name
date_context["year"] = forms.NumberInput().get_context(
name=year_name,
value=context["widget"]["value"]["year"],
attrs={
**context["widget"]["attrs"],
"id": f"id_{year_name}",
"class": "input",
},
)
month_choices = list(self.months.items())
if not self.is_required:
month_choices.insert(0, self.month_none_value)
month_name = self.month_field % name
date_context["month"] = self.select_widget(
attrs, choices=month_choices
).get_context(
name=month_name,
value=context["widget"]["value"]["month"],
attrs={**context["widget"]["attrs"], "id": f"id_{month_name}"},
)
day_choices = [(i, i) for i in range(1, 32)]
if not self.is_required:
day_choices.insert(0, self.day_none_value)
day_name = self.day_field % name
date_context["day"] = self.select_widget(
attrs,
choices=day_choices,
).get_context(
name=day_name,
value=context["widget"]["value"]["day"],
attrs={**context["widget"]["attrs"], "id": f"id_{day_name}"},
)
subwidgets = []
for field in self._parse_date_fmt():
subwidgets.append(date_context[field]["widget"])
context["widget"]["subwidgets"] = subwidgets
return context

View file

@ -129,14 +129,6 @@ button:focus-visible .button-invisible-overlay {
} }
/** Tooltips
******************************************************************************/
.tooltip {
width: 100%;
}
/** States /** States
******************************************************************************/ ******************************************************************************/

View file

@ -155,8 +155,7 @@
<label class="label" for="id_first_published_date"> <label class="label" for="id_first_published_date">
{% trans "First published date:" %} {% trans "First published date:" %}
</label> </label>
<input type="date" name="first_published_date" class="input" id="id_first_published_date"{% if form.first_published_date.value %} value="{{ form.first_published_date.value|date:'Y-m-d' }}"{% endif %} aria-describedby="desc_first_published_date"> {{ form.first_published_date }}
{% include 'snippets/form_errors.html' with errors_list=form.first_published_date.errors id="desc_first_published_date" %} {% include 'snippets/form_errors.html' with errors_list=form.first_published_date.errors id="desc_first_published_date" %}
</div> </div>
@ -164,7 +163,7 @@
<label class="label" for="id_published_date"> <label class="label" for="id_published_date">
{% trans "Published date:" %} {% trans "Published date:" %}
</label> </label>
<input type="date" name="published_date" class="input" id="id_published_date"{% if form.published_date.value %} value="{{ form.published_date.value|date:'Y-m-d'}}"{% endif %} aria-describedby="desc_published_date"> {{ form.published_date }}
{% include 'snippets/form_errors.html' with errors_list=form.published_date.errors id="desc_published_date" %} {% include 'snippets/form_errors.html' with errors_list=form.published_date.errors id="desc_published_date" %}
</div> </div>
@ -259,9 +258,7 @@
<label class="label" for="id_physical_format"> <label class="label" for="id_physical_format">
{% trans "Format:" %} {% trans "Format:" %}
</label> </label>
<div class="select"> {{ form.physical_format }}
{{ form.physical_format }}
</div>
{% include 'snippets/form_errors.html' with errors_list=form.physical_format.errors id="desc_physical_format" %} {% include 'snippets/form_errors.html' with errors_list=form.physical_format.errors id="desc_physical_format" %}
</div> </div>

View file

@ -1,11 +0,0 @@
{% load i18n %}
{% trans "Help" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text class="ml-3 is-rounded is-small has-background-body p-0 pb-1" icon="question-circle is-size-6" controls_text=controls_text controls_uid=controls_uid %}
<aside class="tooltip notification is-hidden transition-y is-pulled-left mb-2" id="{{ controls_text }}{% if controls_uid %}-{{ controls_uid }}{% endif %}">
{% trans "Close" as button_text %}
{% include 'snippets/toggle/close_button.html' with label=button_text class="delete" nonbutton=True controls_text=controls_text controls_uid=controls_uid %}
{% block tooltip_content %}{% endblock %}
</aside>

View file

@ -29,9 +29,16 @@
</section> </section>
<section class="block"> <section class="block">
{% trans "Can't find your code?" as button_text %} <form name="fallback" method="GET" action="{% url 'resend-link' %}" autocomplete="off">
{% include "snippets/toggle/open_button.html" with text=button_text controls_text="resend_form" focus="resend_form_header" %} <button
{% include "confirm_email/resend_form.html" with controls_text="resend_form" %} type="submit"
class="button"
data-modal-open="resend_form"
>
{% trans "Can't find your code?" %}
</button>
</form>
{% include "confirm_email/resend_modal.html" with id="resend_form" %}
</section> </section>
</div> </div>
</div> </div>

View file

@ -0,0 +1,10 @@
{% extends 'landing/layout.html' %}
{% load i18n %}
{% block title %}
{% trans "Resend confirmation link" %}
{% endblock %}
{% block content %}
{% include "confirm_email/resend_modal.html" with active=True static=True id="resend-modal" %}
{% endblock %}

View file

@ -1,20 +0,0 @@
{% extends "components/inline_form.html" %}
{% load i18n %}
{% block header %}
{% trans "Resend confirmation link" %}
{% endblock %}
{% block form %}
<form name="resend" method="post" action="{% url 'resend-link' %}">
{% csrf_token %}
<div class="field">
<label class="label" for="email">{% trans "Email address:" %}</label>
<div class="control">
<input type="text" name="email" class="input" required id="email">
</div>
</div>
<div class="control">
<button class="button is-link">{% trans "Resend link" %}</button>
</div>
</form>
{% endblock %}

View file

@ -0,0 +1,44 @@
{% extends "components/modal.html" %}
{% load i18n %}
{% block modal-title %}
{% trans "Resend confirmation link" %}
{% endblock %}
{% block modal-form-open %}
<form name="resend" method="post" action="{% url 'resend-link' %}">
{% endblock %}
{% block modal-body %}
{% csrf_token %}
<div class="field">
<label class="label" for="email">{% trans "Email address:" %}</label>
<div class="control">
<input
type="email"
name="email"
class="input"
id="email"
aria-described-by="id_email_errors"
required
>
{% if error %}
<div id="id_email_errors">
<p class="help is-danger">
{% trans "No user matching this email address found." %}
</p>
</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block modal-footer %}
<div class="control">
<button class="button is-link">{% trans "Resend link" %}</button>
</div>
{% endblock %}
{% block modal-form-close %}
</form>
{% endblock %}

View file

@ -5,7 +5,19 @@
<section class="block"> <section class="block">
<h2 class="title is-4">{% trans "Your Books" %}</h2> <h2 class="title is-4">{% trans "Your Books" %}</h2>
{% if not suggested_books %} {% if not suggested_books %}
<p>{% trans "There are no books here right now! Try searching for a book to get started" %}</p>
<div class="content">
<p>{% trans "There are no books here right now! Try searching for a book to get started" %}</p>
<div class="box has-background-link-light">
<p>{% trans "Do you have book data from another service like GoodReads?" %}</p>
<a href="{% url 'import' %}">
<span class="icon icon-list" aria-hidden="true"></span>
{% trans "Import your reading history" %}
</a>
</div>
</div>
{% else %} {% else %}
{% with active_book=request.GET.book %} {% with active_book=request.GET.book %}
<div class="tab-group"> <div class="tab-group">

View file

@ -14,28 +14,32 @@
<div class="column is-half"> <div class="column is-half">
<div class="field"> <div class="field">
<label class="label is-pulled-left" for="source"> <label class="label" for="source">
{% trans "Data source:" %} {% trans "Data source:" %}
</label> </label>
{% include 'import/tooltip.html' with controls_text="goodreads-tooltip" %}
<div class="select">
<select name="source" id="source" aria-describedby="desc_source">
<option value="Goodreads" {% if current == 'Goodreads' %}selected{% endif %}>
Goodreads (CSV)
</option>
<option value="Storygraph" {% if current == 'Storygraph' %}selected{% endif %}>
Storygraph (CSV)
</option>
<option value="LibraryThing" {% if current == 'LibraryThing' %}selected{% endif %}>
LibraryThing (TSV)
</option>
<option value="OpenLibrary" {% if current == 'OpenLibrary' %}selected{% endif %}>
OpenLibrary (CSV)
</option>
</select>
</div>
<p class="help" id="desc_source">
{% trans 'You can download your Goodreads data from the <a href="https://www.goodreads.com/review/import" target="_blank" rel="noopener noreferrer">Import/Export page</a> of your Goodreads account.' %}
</p>
</div> </div>
<div class="select block">
<select name="source" id="source">
<option value="Goodreads" {% if current == 'Goodreads' %}selected{% endif %}>
Goodreads (CSV)
</option>
<option value="Storygraph" {% if current == 'Storygraph' %}selected{% endif %}>
Storygraph (CSV)
</option>
<option value="LibraryThing" {% if current == 'LibraryThing' %}selected{% endif %}>
LibraryThing (TSV)
</option>
<option value="OpenLibrary" {% if current == 'OpenLibrary' %}selected{% endif %}>
OpenLibrary (CSV)
</option>
</select>
</div>
<div class="field"> <div class="field">
<label class="label" for="id_csv_file">{% trans "Data file:" %}</label> <label class="label" for="id_csv_file">{% trans "Data file:" %}</label>
{{ import_form.csv_file }} {{ import_form.csv_file }}
@ -63,7 +67,7 @@
<div class="content block"> <div class="content block">
<h2 class="title">{% trans "Recent Imports" %}</h2> <h2 class="title">{% trans "Recent Imports" %}</h2>
{% if not jobs %} {% if not jobs %}
<p>{% trans "No recent imports" %}</p> <p><em>{% trans "No recent imports" %}</em></p>
{% endif %} {% endif %}
<ul> <ul>
{% for job in jobs %} {% for job in jobs %}

View file

@ -1,8 +0,0 @@
{% extends 'components/tooltip.html' %}
{% load i18n %}
{% block tooltip_content %}
{% trans 'You can download your Goodreads data from the <a href="https://www.goodreads.com/review/import" target="_blank" rel="noopener noreferrer">Import/Export page</a> of your Goodreads account.' %}
{% endblock %}

View file

@ -14,7 +14,7 @@
{% block panel %} {% block panel %}
<div class="block table-container"> <div class="block table-container">
<table class="table is-striped"> <table class="table is-striped is-fullwidth">
<tr> <tr>
<th> <th>
{% url 'settings-announcements' as url %} {% url 'settings-announcements' as url %}

View file

@ -154,7 +154,7 @@
</summary> </summary>
<div class="table-container"> <div class="table-container">
<table class="table is-striped"> <table class="table is-striped is-fullwidth">
<tr> <tr>
<th> <th>
<label for="id_string_match">{% trans "String match" %}</label> <label for="id_string_match">{% trans "String match" %}</label>

View file

@ -10,26 +10,26 @@
{% block panel %} {% block panel %}
<div class="columns block has-text-centered is-mobile is-multiline"> <div class="columns block has-text-centered is-mobile is-multiline">
<div class="column is-3-desktop is-6-mobile"> <div class="column is-3-desktop is-6-mobile is-flex">
<div class="notification"> <div class="notification is-flex-grow-1">
<h3>{% trans "Total users" %}</h3> <h3>{% trans "Total users" %}</h3>
<p class="title is-5">{{ users|intcomma }}</p> <p class="title is-5">{{ users|intcomma }}</p>
</div> </div>
</div> </div>
<div class="column is-3-desktop is-6-mobile"> <div class="column is-3-desktop is-6-mobil is-flexe">
<div class="notification"> <div class="notification is-flex-grow-1">
<h3>{% trans "Active this month" %}</h3> <h3>{% trans "Active this month" %}</h3>
<p class="title is-5">{{ active_users|intcomma }}</p> <p class="title is-5">{{ active_users|intcomma }}</p>
</div> </div>
</div> </div>
<div class="column is-3-desktop is-6-mobile"> <div class="column is-3-desktop is-6-mobile is-flex">
<div class="notification"> <div class="notification is-flex-grow-1">
<h3>{% trans "Statuses" %}</h3> <h3>{% trans "Statuses" %}</h3>
<p class="title is-5">{{ statuses|intcomma }}</p> <p class="title is-5">{{ statuses|intcomma }}</p>
</div> </div>
</div> </div>
<div class="column is-3-desktop is-6-mobile"> <div class="column is-3-desktop is-6-mobile is-flex">
<div class="notification"> <div class="notification is-flex-grow-1">
<h3>{% trans "Works" %}</h3> <h3>{% trans "Works" %}</h3>
<p class="title is-5">{{ works|intcomma }}</p> <p class="title is-5">{{ works|intcomma }}</p>
</div> </div>
@ -38,8 +38,8 @@
<div class="columns block is-multiline"> <div class="columns block is-multiline">
{% if reports %} {% if reports %}
<div class="column"> <div class="column is-flex">
<a href="{% url 'settings-reports' %}" class="notification is-warning is-block"> <a href="{% url 'settings-reports' %}" class="notification is-warning is-block is-flex-grow-1">
{% blocktrans trimmed count counter=reports with display_count=reports|intcomma %} {% blocktrans trimmed count counter=reports with display_count=reports|intcomma %}
{{ display_count }} open report {{ display_count }} open report
{% plural %} {% plural %}
@ -50,8 +50,8 @@
{% endif %} {% endif %}
{% if pending_domains %} {% if pending_domains %}
<div class="column"> <div class="column is-flex">
<a href="{% url 'settings-link-domain' %}" class="notification is-primary is-block"> <a href="{% url 'settings-link-domain' %}" class="notification is-primary is-block is-flex-grow-1">
{% blocktrans trimmed count counter=pending_domains with display_count=pending_domains|intcomma %} {% blocktrans trimmed count counter=pending_domains with display_count=pending_domains|intcomma %}
{{ display_count }} domain needs review {{ display_count }} domain needs review
{% plural %} {% plural %}
@ -62,8 +62,8 @@
{% endif %} {% endif %}
{% if not site.allow_registration and site.allow_invite_requests and invite_requests %} {% if not site.allow_registration and site.allow_invite_requests and invite_requests %}
<div class="column"> <div class="column is-flex">
<a href="{% url 'settings-invite-requests' %}" class="notification is-block is-success"> <a href="{% url 'settings-invite-requests' %}" class="notification is-block is-success is-flex-grow-1">
{% blocktrans trimmed count counter=invite_requests with display_count=invite_requests|intcomma %} {% blocktrans trimmed count counter=invite_requests with display_count=invite_requests|intcomma %}
{{ display_count }} invite request {{ display_count }} invite request
{% plural %} {% plural %}
@ -74,8 +74,8 @@
{% endif %} {% endif %}
{% if current_version %} {% if current_version %}
<div class="column"> <div class="column is-flex">
<a href="https://docs.joinbookwyrm.com/updating-your-instance.html" class="notification is-block is-warning" target="_blank"> <a href="https://docs.joinbookwyrm.com/updating-your-instance.html" class="notification is-block is-warning is-flex-grow-1" target="_blank">
{% blocktrans trimmed with current=current_version available=available_version %} {% blocktrans trimmed with current=current_version available=available_version %}
An update is available! You're running v{{ current }} and the latest release is {{ available }}. An update is available! You're running v{{ current }} and the latest release is {{ available }}.
{% endblocktrans %} {% endblocktrans %}

View file

@ -25,7 +25,7 @@
</ul> </ul>
</div> </div>
<table class="table is-striped"> <table class="table is-striped is-fullwidth">
<tr> <tr>
{% url 'settings-federation' as url %} {% url 'settings-federation' as url %}
<th> <th>

View file

@ -21,6 +21,7 @@
<div class="field"> <div class="field">
<input type="text" name="address" maxlength="255" class="input" required="" id="id_address" placeholder="190.0.2.0/24" aria-describedby="desc_address"> <input type="text" name="address" maxlength="255" class="input" required="" id="id_address" placeholder="190.0.2.0/24" aria-describedby="desc_address">
<p class="help">{% trans "You can block IP ranges using CIDR syntax." %}</p>
</div> </div>
{% include 'snippets/form_errors.html' with errors_list=form.address.errors id="desc_address" %} {% include 'snippets/form_errors.html' with errors_list=form.address.errors id="desc_address" %}

View file

@ -1,8 +0,0 @@
{% extends 'components/tooltip.html' %}
{% load i18n %}
{% block tooltip_content %}
{% trans "You can block IP ranges using CIDR syntax." %}
{% endblock %}

View file

@ -93,7 +93,7 @@
</ul> </ul>
{% endif %} {% endif %}
</nav> </nav>
<div class="column"> <div class="column is-clipped">
{% block panel %}{% endblock %} {% block panel %}{% endblock %}
</div> </div>
</div> </div>

View file

@ -139,6 +139,13 @@
{% trans "Allow registration" %} {% trans "Allow registration" %}
</label> </label>
</div> </div>
<div class="field">
<label class="label mb-0" for="id_require_confirm_email">
{{ site_form.require_confirm_email }}
{% trans "Require users to confirm email address" %}
</label>
<p class="help" id="desc_require_confirm_email">{% trans "(Recommended if registration is open)" %}</p>
</div>
<div class="field"> <div class="field">
<label class="label" for="id_allow_invite_requests"> <label class="label" for="id_allow_invite_requests">
{{ site_form.allow_invite_requests }} {{ site_form.allow_invite_requests }}
@ -157,13 +164,6 @@
{{ site_form.invite_question_text }} {{ site_form.invite_question_text }}
</label> </label>
</div> </div>
<div class="field">
<label class="label mb-0" for="id_require_confirm_email">
{{ site_form.require_confirm_email }}
{% trans "Require users to confirm email address" %}
</label>
<p class="help" id="desc_require_confirm_email">{% trans "(Recommended if registration is open)" %}</p>
</div>
<div class="field"> <div class="field">
<label class="label" for="id_registration_closed_text">{% trans "Registration closed text:" %}</label> <label class="label" for="id_registration_closed_text">{% trans "Registration closed text:" %}</label>
{{ site_form.registration_closed_text }} {{ site_form.registration_closed_text }}
@ -171,7 +171,7 @@
<div class="field"> <div class="field">
<label class="label" for="id_invite_request_text">{% trans "Invite request text:" %}</label> <label class="label" for="id_invite_request_text">{% trans "Invite request text:" %}</label>
{{ site_form.invite_request_text }} {{ site_form.invite_request_text }}
{% include 'snippets/form_errors.html' with errors_list=site_form.invite_request_text.errors id="desc_invite_request_text" %} {% include 'snippets/form_errors.html' with errors_list=site_form.invite_request_text.errors id="desc_invite_request_text" %}
</div> </div>
</div> </div>

View file

@ -88,7 +88,7 @@
<section class="block content"> <section class="block content">
<h2 class="title is-4">{% trans "Available Themes" %}</h2> <h2 class="title is-4">{% trans "Available Themes" %}</h2>
<div class="table-container"> <div class="table-container">
<table class="table is-striped"> <table class="table is-striped is-fullwidth">
<tr> <tr>
<th> <th>
{% trans "Theme name" %} {% trans "Theme name" %}

View file

@ -33,7 +33,7 @@
</div> </div>
<div class="table-container block"> <div class="table-container block">
<table class="table is-striped"> <table class="table is-striped is-fullwidth">
<tr> <tr>
{% url 'settings-users' as url %} {% url 'settings-users' as url %}
<th> <th>

View file

@ -0,0 +1,9 @@
{% spaceless %}
<div class="field has-addons">
{% for widget in widget.subwidgets %}
<div class="control{% if forloop.last %} is-expanded{% endif %}">
{% include widget.template_name %}
</div>
{% endfor %}
</div>
{% endspaceless %}

View file

@ -0,0 +1,10 @@
<div class="select">
<select
name="{{ widget.name }}"
{% include "django/forms/widgets/attrs.html" %}
>{% for group_name, group_choices, group_index in widget.optgroups %}{% if group_name %}
<optgroup label="{{ group_name }}">{% endif %}{% for option in group_choices %}
{% include option.template_name with widget=option %}{% endfor %}{% if group_name %}
</optgroup>{% endif %}{% endfor %}
</select>
</div>

View file

@ -360,10 +360,17 @@ class RegisterViews(TestCase):
result = view(request) result = view(request)
validate_html(result.render()) validate_html(result.render())
def test_resend_link(self, *_): def test_resend_link_get(self, *_):
"""try again"""
request = self.factory.get("")
request.user = self.anonymous_user
result = views.ResendConfirmEmail.as_view()(request)
validate_html(result.render())
def test_resend_link_post(self, *_):
"""try again""" """try again"""
request = self.factory.post("", {"email": "mouse@mouse.com"}) request = self.factory.post("", {"email": "mouse@mouse.com"})
request.user = self.anonymous_user request.user = self.anonymous_user
with patch("bookwyrm.emailing.send_email.delay") as mock: with patch("bookwyrm.emailing.send_email.delay") as mock:
views.resend_link(request) views.ResendConfirmEmail.as_view()(request)
self.assertEqual(mock.call_count, 1) self.assertEqual(mock.call_count, 1)

View file

@ -71,7 +71,7 @@ urlpatterns = [
views.ConfirmEmailCode.as_view(), views.ConfirmEmailCode.as_view(),
name="confirm-email-code", name="confirm-email-code",
), ),
re_path(r"^resend-link/?$", views.resend_link, name="resend-link"), re_path(r"^resend-link/?$", views.ResendConfirmEmail.as_view(), name="resend-link"),
re_path(r"^logout/?$", views.Logout.as_view(), name="logout"), re_path(r"^logout/?$", views.Logout.as_view(), name="logout"),
re_path( re_path(
r"^password-reset/?$", r"^password-reset/?$",

View file

@ -52,7 +52,8 @@ from .books.links import BookFileLinks, AddFileLink, delete_link
from .landing.about import about, privacy, conduct from .landing.about import about, privacy, conduct
from .landing.landing import Home, Landing from .landing.landing import Home, Landing
from .landing.login import Login, Logout from .landing.login import Login, Logout
from .landing.register import Register, ConfirmEmail, ConfirmEmailCode, resend_link from .landing.register import Register
from .landing.register import ConfirmEmail, ConfirmEmailCode, ResendConfirmEmail
from .landing.password import PasswordResetRequest, PasswordReset from .landing.password import PasswordResetRequest, PasswordReset
# shelves # shelves

View file

@ -1,13 +1,11 @@
""" the good stuff! the books! """ """ the good stuff! the books! """
from re import sub, findall from re import sub, findall
from dateutil.parser import parse as dateparse
from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.postgres.search import SearchRank, SearchVector from django.contrib.postgres.search import SearchRank, SearchVector
from django.db import transaction from django.db import transaction
from django.http import HttpResponseBadRequest from django.http import HttpResponseBadRequest
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.utils.datastructures import MultiValueDictKeyError
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django.views import View from django.views import View
@ -52,7 +50,6 @@ class EditBook(View):
# either of the above cases requires additional confirmation # either of the above cases requires additional confirmation
if data.get("add_author"): if data.get("add_author"):
data = copy_form(data)
return TemplateResponse(request, "book/edit/edit_book.html", data) return TemplateResponse(request, "book/edit/edit_book.html", data)
remove_authors = request.POST.getlist("remove_authors") remove_authors = request.POST.getlist("remove_authors")
@ -118,7 +115,6 @@ class CreateBook(View):
# go to confirm mode # go to confirm mode
if not parent_work_id or data.get("add_author"): if not parent_work_id or data.get("add_author"):
data = copy_form(data)
return TemplateResponse(request, "book/edit/edit_book.html", data) return TemplateResponse(request, "book/edit/edit_book.html", data)
with transaction.atomic(): with transaction.atomic():
@ -139,21 +135,6 @@ class CreateBook(View):
return redirect(f"/book/{book.id}") return redirect(f"/book/{book.id}")
def copy_form(data):
"""helper to re-create the date fields in the form"""
formcopy = data["form"].data.copy()
try:
formcopy["first_published_date"] = dateparse(formcopy["first_published_date"])
except (MultiValueDictKeyError, ValueError):
pass
try:
formcopy["published_date"] = dateparse(formcopy["published_date"])
except (MultiValueDictKeyError, ValueError):
pass
data["form"].data = formcopy
return data
def add_authors(request, data): def add_authors(request, data):
"""helper for adding authors""" """helper for adding authors"""
add_author = [author for author in request.POST.getlist("add_author") if author] add_author = [author for author in request.POST.getlist("add_author") if author]

View file

@ -5,7 +5,6 @@ from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views import View from django.views import View
from django.views.decorators.http import require_POST
from django.views.decorators.debug import sensitive_variables, sensitive_post_parameters from django.views.decorators.debug import sensitive_variables, sensitive_post_parameters
from bookwyrm import emailing, forms, models from bookwyrm import emailing, forms, models
@ -129,12 +128,22 @@ class ConfirmEmail(View):
return ConfirmEmailCode().get(request, code) return ConfirmEmailCode().get(request, code)
@require_POST class ResendConfirmEmail(View):
def resend_link(request): """you probably didn't get the email because celery is slow but you can try this"""
"""resend confirmation link"""
email = request.POST.get("email") def get(self, request, error=False):
user = get_object_or_404(models.User, email=email) """resend link landing page"""
emailing.email_confirmation_email(user) return TemplateResponse(request, "confirm_email/resend.html", {"error": error})
return TemplateResponse(
request, "confirm_email/confirm_email.html", {"valid": True} def post(self, request):
) """resend confirmation link"""
email = request.POST.get("email")
try:
user = models.User.objects.get(email=email)
except models.User.DoesNotExist:
return self.get(request, error=True)
emailing.email_confirmation_email(user)
return TemplateResponse(
request, "confirm_email/confirm_email.html", {"valid": True}
)