2021-03-08 16:49:10 +00:00
|
|
|
""" using django model forms """
|
2020-06-03 16:38:30 +00:00
|
|
|
import datetime
|
2020-09-29 17:21:10 +00:00
|
|
|
from collections import defaultdict
|
2020-06-03 16:38:30 +00:00
|
|
|
|
2020-03-23 16:40:09 +00:00
|
|
|
from django import forms
|
2021-04-08 16:05:21 +00:00
|
|
|
from django.forms import ModelForm, PasswordInput, widgets, ChoiceField
|
2020-09-29 17:21:10 +00:00
|
|
|
from django.forms.widgets import Textarea
|
2020-11-28 00:24:53 +00:00
|
|
|
from django.utils import timezone
|
2021-04-04 20:22:36 +00:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2020-01-29 09:05:27 +00:00
|
|
|
|
2020-09-21 15:10:37 +00:00
|
|
|
from bookwyrm import models
|
2020-01-29 09:05:27 +00:00
|
|
|
|
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class CustomForm(ModelForm):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""add css classes to the forms"""
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
def __init__(self, *args, **kwargs):
|
2021-03-08 16:49:10 +00:00
|
|
|
css_classes = defaultdict(lambda: "")
|
|
|
|
css_classes["text"] = "input"
|
|
|
|
css_classes["password"] = "input"
|
|
|
|
css_classes["email"] = "input"
|
|
|
|
css_classes["number"] = "input"
|
|
|
|
css_classes["checkbox"] = "checkbox"
|
|
|
|
css_classes["textarea"] = "textarea"
|
2021-06-18 21:12:56 +00:00
|
|
|
# pylint: disable=super-with-arguments
|
2020-09-29 17:21:10 +00:00
|
|
|
super(CustomForm, self).__init__(*args, **kwargs)
|
|
|
|
for visible in self.visible_fields():
|
2021-03-08 16:49:10 +00:00
|
|
|
if hasattr(visible.field.widget, "input_type"):
|
2020-09-29 17:21:10 +00:00
|
|
|
input_type = visible.field.widget.input_type
|
|
|
|
if isinstance(visible.field.widget, Textarea):
|
2021-03-08 16:49:10 +00:00
|
|
|
input_type = "textarea"
|
2021-09-28 17:21:12 +00:00
|
|
|
visible.field.widget.attrs["rows"] = 5
|
2021-03-08 16:49:10 +00:00
|
|
|
visible.field.widget.attrs["class"] = css_classes[input_type]
|
2020-09-29 17:21:10 +00:00
|
|
|
|
2020-12-22 17:26:40 +00:00
|
|
|
|
2020-12-13 02:13:00 +00:00
|
|
|
# pylint: disable=missing-class-docstring
|
2020-09-29 17:21:10 +00:00
|
|
|
class LoginForm(CustomForm):
|
2020-01-29 09:05:27 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.User
|
2021-03-08 16:49:10 +00:00
|
|
|
fields = ["localname", "password"]
|
2020-01-29 09:05:27 +00:00
|
|
|
help_texts = {f: None for f in fields}
|
|
|
|
widgets = {
|
2021-03-08 16:49:10 +00:00
|
|
|
"password": PasswordInput(),
|
2020-01-29 09:05:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class RegisterForm(CustomForm):
|
2020-01-29 09:05:27 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.User
|
2021-03-08 16:49:10 +00:00
|
|
|
fields = ["localname", "email", "password"]
|
2020-01-29 09:05:27 +00:00
|
|
|
help_texts = {f: None for f in fields}
|
2021-03-08 16:49:10 +00:00
|
|
|
widgets = {"password": PasswordInput()}
|
2020-01-29 09:05:27 +00:00
|
|
|
|
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class RatingForm(CustomForm):
|
2020-04-03 19:43:49 +00:00
|
|
|
class Meta:
|
2021-01-01 19:05:49 +00:00
|
|
|
model = models.ReviewRating
|
2021-03-08 17:48:25 +00:00
|
|
|
fields = ["user", "book", "rating", "privacy"]
|
2020-04-03 19:43:49 +00:00
|
|
|
|
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class ReviewForm(CustomForm):
|
2020-01-29 09:05:27 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.Review
|
2020-12-17 04:10:50 +00:00
|
|
|
fields = [
|
2021-03-08 16:49:10 +00:00
|
|
|
"user",
|
|
|
|
"book",
|
|
|
|
"name",
|
|
|
|
"content",
|
|
|
|
"rating",
|
|
|
|
"content_warning",
|
|
|
|
"sensitive",
|
|
|
|
"privacy",
|
|
|
|
]
|
2020-01-29 09:05:27 +00:00
|
|
|
|
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class CommentForm(CustomForm):
|
2020-03-21 23:50:49 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.Comment
|
2021-03-21 00:39:05 +00:00
|
|
|
fields = [
|
|
|
|
"user",
|
|
|
|
"book",
|
|
|
|
"content",
|
|
|
|
"content_warning",
|
|
|
|
"sensitive",
|
|
|
|
"privacy",
|
|
|
|
"progress",
|
2021-03-21 01:03:20 +00:00
|
|
|
"progress_mode",
|
2021-08-16 20:32:20 +00:00
|
|
|
"reading_status",
|
2021-03-21 00:39:05 +00:00
|
|
|
]
|
2020-03-21 23:50:49 +00:00
|
|
|
|
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class QuotationForm(CustomForm):
|
2020-04-08 16:40:47 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.Quotation
|
2020-12-17 04:10:50 +00:00
|
|
|
fields = [
|
2021-03-08 16:49:10 +00:00
|
|
|
"user",
|
|
|
|
"book",
|
|
|
|
"quote",
|
|
|
|
"content",
|
|
|
|
"content_warning",
|
|
|
|
"sensitive",
|
|
|
|
"privacy",
|
2021-09-05 23:00:40 +00:00
|
|
|
"position",
|
|
|
|
"position_mode",
|
2021-03-08 16:49:10 +00:00
|
|
|
]
|
2020-04-08 16:40:47 +00:00
|
|
|
|
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class ReplyForm(CustomForm):
|
2020-02-18 05:39:08 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.Status
|
2020-12-17 04:10:50 +00:00
|
|
|
fields = [
|
2021-03-08 16:49:10 +00:00
|
|
|
"user",
|
|
|
|
"content",
|
|
|
|
"content_warning",
|
|
|
|
"sensitive",
|
|
|
|
"reply_parent",
|
|
|
|
"privacy",
|
|
|
|
]
|
|
|
|
|
2020-02-18 05:39:08 +00:00
|
|
|
|
2021-01-29 19:14:18 +00:00
|
|
|
class StatusForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.Status
|
2021-09-11 19:07:09 +00:00
|
|
|
fields = ["user", "content", "content_warning", "sensitive", "privacy"]
|
|
|
|
|
|
|
|
|
|
|
|
class DirectForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.Status
|
2021-03-08 16:49:10 +00:00
|
|
|
fields = ["user", "content", "content_warning", "sensitive", "privacy"]
|
2021-01-29 19:14:18 +00:00
|
|
|
|
2020-02-18 05:39:08 +00:00
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class EditUserForm(CustomForm):
|
2020-01-29 09:05:27 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.User
|
2021-03-18 16:06:00 +00:00
|
|
|
fields = [
|
|
|
|
"avatar",
|
|
|
|
"name",
|
|
|
|
"email",
|
|
|
|
"summary",
|
|
|
|
"show_goal",
|
2021-09-08 17:06:26 +00:00
|
|
|
"show_suggested_users",
|
2021-03-21 23:37:52 +00:00
|
|
|
"manually_approves_followers",
|
2021-06-14 23:47:57 +00:00
|
|
|
"default_post_privacy",
|
2021-03-21 23:37:52 +00:00
|
|
|
"discoverable",
|
2021-03-28 22:51:40 +00:00
|
|
|
"preferred_timezone",
|
2021-10-06 19:20:05 +00:00
|
|
|
"preferred_language",
|
2021-03-18 16:06:00 +00:00
|
|
|
]
|
2020-01-29 09:05:27 +00:00
|
|
|
help_texts = {f: None for f in fields}
|
2020-02-18 05:39:08 +00:00
|
|
|
|
2020-02-21 06:19:19 +00:00
|
|
|
|
2021-04-01 15:32:06 +00:00
|
|
|
class LimitedEditUserForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.User
|
|
|
|
fields = [
|
|
|
|
"avatar",
|
|
|
|
"name",
|
|
|
|
"summary",
|
|
|
|
"manually_approves_followers",
|
|
|
|
"discoverable",
|
|
|
|
]
|
|
|
|
help_texts = {f: None for f in fields}
|
|
|
|
|
2021-04-20 01:12:55 +00:00
|
|
|
|
2021-06-14 17:44:25 +00:00
|
|
|
class DeleteUserForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.User
|
|
|
|
fields = ["password"]
|
|
|
|
|
|
|
|
|
2021-04-20 00:16:14 +00:00
|
|
|
class UserGroupForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.User
|
|
|
|
fields = ["groups"]
|
|
|
|
|
2021-04-01 15:32:06 +00:00
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class CoverForm(CustomForm):
|
2020-03-28 22:06:16 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.Book
|
2021-03-08 16:49:10 +00:00
|
|
|
fields = ["cover"]
|
2020-03-28 22:06:16 +00:00
|
|
|
help_texts = {f: None for f in fields}
|
|
|
|
|
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class EditionForm(CustomForm):
|
2020-03-28 22:06:16 +00:00
|
|
|
class Meta:
|
2020-04-02 15:44:53 +00:00
|
|
|
model = models.Edition
|
2020-03-28 22:06:16 +00:00
|
|
|
exclude = [
|
2021-03-08 16:49:10 +00:00
|
|
|
"remote_id",
|
|
|
|
"origin_id",
|
|
|
|
"created_date",
|
|
|
|
"updated_date",
|
|
|
|
"edition_rank",
|
2021-03-08 18:07:02 +00:00
|
|
|
"authors",
|
2021-03-08 16:49:10 +00:00
|
|
|
"parent_work",
|
|
|
|
"shelves",
|
|
|
|
"connector",
|
2021-06-26 15:54:52 +00:00
|
|
|
"search_vector",
|
2020-03-28 22:06:16 +00:00
|
|
|
]
|
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2020-12-22 17:26:40 +00:00
|
|
|
class AuthorForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.Author
|
|
|
|
exclude = [
|
2021-03-08 16:49:10 +00:00
|
|
|
"remote_id",
|
|
|
|
"origin_id",
|
|
|
|
"created_date",
|
|
|
|
"updated_date",
|
2021-06-26 16:05:00 +00:00
|
|
|
"search_vector",
|
2020-12-22 17:26:40 +00:00
|
|
|
]
|
|
|
|
|
2020-03-28 22:06:16 +00:00
|
|
|
|
2020-03-23 16:40:09 +00:00
|
|
|
class ImportForm(forms.Form):
|
|
|
|
csv_file = forms.FileField()
|
2020-06-03 16:38:30 +00:00
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2020-06-03 16:38:30 +00:00
|
|
|
class ExpiryWidget(widgets.Select):
|
|
|
|
def value_from_datadict(self, data, files, name):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""human-readable exiration time buckets"""
|
2020-06-03 16:38:30 +00:00
|
|
|
selected_string = super().value_from_datadict(data, files, name)
|
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
if selected_string == "day":
|
2020-06-03 16:38:30 +00:00
|
|
|
interval = datetime.timedelta(days=1)
|
2021-03-08 16:49:10 +00:00
|
|
|
elif selected_string == "week":
|
2020-06-03 16:38:30 +00:00
|
|
|
interval = datetime.timedelta(days=7)
|
2021-03-08 16:49:10 +00:00
|
|
|
elif selected_string == "month":
|
|
|
|
interval = datetime.timedelta(days=31) # Close enough?
|
|
|
|
elif selected_string == "forever":
|
2020-06-03 16:38:30 +00:00
|
|
|
return None
|
|
|
|
else:
|
2021-09-27 22:57:22 +00:00
|
|
|
return selected_string # This will raise
|
2020-06-03 16:38:30 +00:00
|
|
|
|
2020-11-28 00:24:53 +00:00
|
|
|
return timezone.now() + interval
|
2020-06-03 16:38:30 +00:00
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2021-03-21 01:23:59 +00:00
|
|
|
class InviteRequestForm(CustomForm):
|
2021-03-21 02:14:41 +00:00
|
|
|
def clean(self):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""make sure the email isn't in use by a registered user"""
|
2021-03-21 02:14:41 +00:00
|
|
|
cleaned_data = super().clean()
|
|
|
|
email = cleaned_data.get("email")
|
|
|
|
if email and models.User.objects.filter(email=email).exists():
|
|
|
|
self.add_error("email", _("A user with this email already exists."))
|
|
|
|
|
2021-03-21 01:23:59 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.InviteRequest
|
|
|
|
fields = ["email"]
|
|
|
|
|
|
|
|
|
2020-09-29 17:21:10 +00:00
|
|
|
class CreateInviteForm(CustomForm):
|
2020-06-03 16:38:30 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.SiteInvite
|
2021-04-05 17:17:01 +00:00
|
|
|
exclude = ["code", "user", "times_used", "invitees"]
|
2020-06-03 16:38:30 +00:00
|
|
|
widgets = {
|
2021-03-08 16:49:10 +00:00
|
|
|
"expiry": ExpiryWidget(
|
|
|
|
choices=[
|
|
|
|
("day", _("One Day")),
|
|
|
|
("week", _("One Week")),
|
|
|
|
("month", _("One Month")),
|
|
|
|
("forever", _("Does Not Expire")),
|
|
|
|
]
|
|
|
|
),
|
|
|
|
"use_limit": widgets.Select(
|
2021-09-18 18:33:43 +00:00
|
|
|
choices=[(i, _(f"{i} uses")) for i in [1, 5, 10, 25, 50, 100]]
|
2021-03-08 16:49:10 +00:00
|
|
|
+ [(None, _("Unlimited"))]
|
|
|
|
),
|
2020-06-03 16:38:30 +00:00
|
|
|
}
|
2020-11-10 22:52:04 +00:00
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2020-11-10 22:52:04 +00:00
|
|
|
class ShelfForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.Shelf
|
2021-09-28 23:36:47 +00:00
|
|
|
fields = ["user", "name", "privacy", "description"]
|
2021-01-16 16:18:54 +00:00
|
|
|
|
2021-01-29 23:38:42 +00:00
|
|
|
|
2021-01-16 16:18:54 +00:00
|
|
|
class GoalForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.AnnualGoal
|
2021-03-08 16:49:10 +00:00
|
|
|
fields = ["user", "year", "goal", "privacy"]
|
2021-01-29 23:38:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
class SiteForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.SiteSettings
|
|
|
|
exclude = []
|
2021-01-31 16:08:52 +00:00
|
|
|
|
|
|
|
|
2021-05-19 21:55:01 +00:00
|
|
|
class AnnouncementForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.Announcement
|
|
|
|
exclude = ["remote_id"]
|
|
|
|
|
|
|
|
|
2021-01-31 16:08:52 +00:00
|
|
|
class ListForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.List
|
2021-03-08 16:49:10 +00:00
|
|
|
fields = ["user", "name", "description", "curation", "privacy"]
|
2021-03-09 02:36:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ReportForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.Report
|
|
|
|
fields = ["user", "reporter", "statuses", "note"]
|
2021-04-07 18:52:13 +00:00
|
|
|
|
|
|
|
|
2021-09-08 22:08:22 +00:00
|
|
|
class EmailBlocklistForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.EmailBlocklist
|
|
|
|
fields = ["domain"]
|
|
|
|
|
|
|
|
|
2021-09-17 19:59:16 +00:00
|
|
|
class IPBlocklistForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.IPBlocklist
|
|
|
|
fields = ["address"]
|
|
|
|
|
|
|
|
|
2021-04-07 18:52:13 +00:00
|
|
|
class ServerForm(CustomForm):
|
|
|
|
class Meta:
|
|
|
|
model = models.FederatedServer
|
2021-04-07 19:11:01 +00:00
|
|
|
exclude = ["remote_id"]
|
2021-04-08 16:05:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
class SortListForm(forms.Form):
|
|
|
|
sort_by = ChoiceField(
|
|
|
|
choices=(
|
|
|
|
("order", _("List Order")),
|
|
|
|
("title", _("Book Title")),
|
|
|
|
("rating", _("Rating")),
|
|
|
|
),
|
|
|
|
label=_("Sort By"),
|
|
|
|
)
|
|
|
|
direction = ChoiceField(
|
|
|
|
choices=(
|
|
|
|
("ascending", _("Ascending")),
|
|
|
|
("descending", _("Descending")),
|
|
|
|
),
|
|
|
|
)
|