Merge pull request #1933 from bookwyrm-social/announcements

Cleans up code for announcements
This commit is contained in:
Mouse Reeve 2022-02-15 10:40:56 -08:00 committed by GitHub
commit a07239c6a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 292 additions and 158 deletions

View file

@ -0,0 +1,29 @@
# Generated by Django 3.2.11 on 2022-02-11 18:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0133_alter_listitem_notes"),
]
operations = [
migrations.AddField(
model_name="announcement",
name="display_type",
field=models.CharField(
choices=[
("white-ter", "None"),
("primary-light", "Primary"),
("success-light", "Success"),
("link-light", "Link"),
("warning-light", "Warning"),
("danger-light", "Danger"),
],
default="white-ter",
max_length=20,
),
),
]

View file

@ -2,10 +2,21 @@
from django.db import models from django.db import models
from django.db.models import Q from django.db.models import Q
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
DisplayTypes = [
("white-ter", _("None")),
("primary-light", _("Primary")),
("success-light", _("Success")),
("link-light", _("Link")),
("warning-light", _("Warning")),
("danger-light", _("Danger")),
]
class Announcement(BookWyrmModel): class Announcement(BookWyrmModel):
"""The admin has something to say""" """The admin has something to say"""
@ -16,6 +27,13 @@ class Announcement(BookWyrmModel):
start_date = models.DateTimeField(blank=True, null=True) start_date = models.DateTimeField(blank=True, null=True)
end_date = models.DateTimeField(blank=True, null=True) end_date = models.DateTimeField(blank=True, null=True)
active = models.BooleanField(default=True) active = models.BooleanField(default=True)
display_type = models.CharField(
max_length=20,
blank=False,
null=False,
choices=DisplayTypes,
default="white-ter",
)
@classmethod @classmethod
def active_announcements(cls): def active_announcements(cls):

View file

@ -319,7 +319,7 @@ details.details-panel summary {
position: relative; position: relative;
} }
details.details-panel summary .details-close { details summary .details-close {
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
@ -327,7 +327,7 @@ details.details-panel summary .details-close {
transition: transform 0.2s ease; transition: transform 0.2s ease;
} }
details[open].details-panel summary .details-close { details[open] summary .details-close {
transform: rotate(0deg); transform: rotate(0deg);
} }

View file

@ -6,15 +6,14 @@
{% block content %} {% block content %}
<header class="block content"> <header class="block">
<h1 class="title"> <h1 class="title">
{% blocktrans with title=book|book_title %} {% blocktrans with title=book|book_title %}
Links for "<em>{{ title }}</em>" Links for "<em>{{ title }}</em>"
{% endblocktrans %} {% endblocktrans %}
</h1> </h1>
</header>
<nav class="breadcrumb subtitle" aria-label="breadcrumbs"> <nav class="breadcrumb subtitle" aria-label="breadcrumbs">
<ul> <ul>
<li><a href="{% url 'book' book.id %}">{{ book|book_title }}</a></li> <li><a href="{% url 'book' book.id %}">{{ book|book_title }}</a></li>
<li class="is-active"> <li class="is-active">
@ -23,7 +22,8 @@
</a> </a>
</li> </li>
</ul> </ul>
</nav> </nav>
</header>
<section class="block content"> <section class="block content">
<div class="table-container"> <div class="table-container">

View file

@ -1,17 +1,20 @@
{% extends 'settings/layout.html' %} {% extends 'settings/layout.html' %}
{% load i18n %}{% load humanize %} {% load i18n %}
{% load humanize %}
{% block title %}{% trans "Announcement" %} - {{ announcement.preview }}{% endblock %} {% block title %}{% trans "Announcement" %} - {{ announcement.preview }}{% endblock %}
{% block header %} {% block header %}
{% trans "Announcement" %} {% trans "Announcement" %}
<a href="{% url 'settings-announcements' %}" class="has-text-weight-normal help">{% trans "Back to list" %}</a>
{% endblock %} {% endblock %}
{% block edit-button %} {% block edit-button %}
{% trans "Edit Announcement" as button_text %}
<div class="field has-addons"> <div class="field has-addons">
<div class="control"> <div class="control">
{% include 'snippets/toggle/open_button.html' with controls_text="edit_announcement" icon_with_text="pencil" text=button_text focus="edit_announcement_header" %} <a class="button" href="{% url 'settings-announcements-edit' announcement.id %}">
<span class="icon icon-pencil m-0-mobile" aria-hidden="true"></span>
<span class="is-sr-only-mobile">{% trans "Edit" %}</span>
</a>
</div> </div>
<form class="control" action="{% url 'settings-announcements-delete' announcement.id %}" method="post"> <form class="control" action="{% url 'settings-announcements-delete' announcement.id %}" method="post">
{% csrf_token %} {% csrf_token %}
@ -23,12 +26,20 @@
</div> </div>
{% endblock %} {% endblock %}
{% block breadcrumbs %}
<nav class="breadcrumb subtitle" aria-label="breadcrumbs">
<ul>
<li><a href="{% url 'settings-announcements' %}">{% trans "Announcements" %}</a></li>
<li class="is-active">
<a href="#" aria-current="page">
{{ announcement.preview|truncatechars:30 }}
</a>
</li>
</ul>
</nav>
{% endblock %}
{% block panel %} {% block panel %}
<form name="edit-announcement" method="post" action="{% url 'settings-announcements' announcement.id %}" class="block">
{% include 'settings/announcements/announcement_form.html' with controls_text="edit_announcement" %}
</form>
<div class="block content"> <div class="block content">
<dl> <dl>
<dt class="is-pulled-left mr-5 has-text-weight-bold">{% trans "Visible:" %}</dt> <dt class="is-pulled-left mr-5 has-text-weight-bold">{% trans "Visible:" %}</dt>

View file

@ -1,80 +0,0 @@
{% extends 'components/inline_form.html' %}
{% load i18n %}
{% block header %}
{% if announcement %}
{% trans "Edit Announcement" %}
{% else %}
{% trans "Create Announcement" %}
{% endif %}
{% endblock %}
{% block form %}
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<p>
<label class="label" for="id_preview">
{% trans "Preview:" %}
</label>
{{ form.preview }}
{% include 'snippets/form_errors.html' with errors_list=form.preview.errors id="desc_preview" %}
</p>
<p>
<label class="label" for="id_content">
{% trans "Content:" %}
</label>
{{ form.content }}
{% include 'snippets/form_errors.html' with errors_list=form.content.errors id="desc_content" %}
</p>
<p>
<label class="label" for="id_event_date">
{% trans "Event date:" %}
</label>
<input type="date" name="event_date" value="{{ form.event_date.value|date:'Y-m-d' }}" class="input" id="id_event_date">
{% include 'snippets/form_errors.html' with errors_list=form.event_date.errors id="desc_event_date" %}
</p>
<hr aria-hidden="true">
<div class="columns">
<div class="column">
<p>
<label class="label" for="id_start_date">
{% trans "Start date:" %}
</label>
<input type="date" name="start_date" class="input" value="{{ form.start_date.value|date:'Y-m-d' }}" id="id_start_date">
{% include 'snippets/form_errors.html' with errors_list=form.start_date.errors id="desc_start_date" %}
</p>
</div>
<div class="column">
<p>
<label class="label" for="id_end_date">
{% trans "End date:" %}
</label>
<input type="date" name="end_date" class="input" id="id_end_date" value="{{ form.end_date.value|date:'Y-m-d' }}">
{% include 'snippets/form_errors.html' with errors_list=form.end_date.errors id="desc_end_date" %}
</p>
</div>
<div class="column is-narrow">
<p>
<label class="label" for="id_active">
{% trans "Active:" %}
</label>
{{ form.active }}
{% include 'snippets/form_errors.html' with errors_list=form.active.errors id="desc_active" %}
</p>
</div>
</div>
<div class="field has-addons">
<div class="control">
<button type="submit" class="button is-primary">
{% trans "Save" %}
</button>
</div>
</div>
{% endblock %}

View file

@ -5,16 +5,15 @@
{% block header %}{% trans "Announcements" %}{% endblock %} {% block header %}{% trans "Announcements" %}{% endblock %}
{% block edit-button %} {% block edit-button %}
{% trans "Create Announcement" as button_text %} <a href="{% url 'settings-announcements-edit' %}">
{% include 'snippets/toggle/open_button.html' with controls_text="create_announcement" icon_with_text="plus" text=button_text focus="create_announcement_header" %} {% trans "Create Announcement" as text %}
<span class="icon icon-plus" title="{{ text }}" aria-hidden="true"></span>
<span class="is-sr-only-mobile">{{ text }}</span>
</a>
{% endblock %} {% endblock %}
{% block panel %} {% block panel %}
<form name="create-announcement" method="post" action="{% url 'settings-announcements' %}" class="block"> <div class="block table-container">
{% include 'settings/announcements/announcement_form.html' with controls_text="create_announcement" %}
</form>
<div class="block">
<table class="table is-striped"> <table class="table is-striped">
<tr> <tr>
<th> <th>
@ -38,6 +37,9 @@
{% trans "Status" as text %} {% trans "Status" as text %}
{% include 'snippets/table-sort-header.html' with field="active" sort=sort text=text %} {% include 'snippets/table-sort-header.html' with field="active" sort=sort text=text %}
</th> </th>
<th>
{% trans "Actions" %}
</th>
</tr> </tr>
{% for announcement in announcements %} {% for announcement in announcements %}
<tr> <tr>
@ -46,6 +48,15 @@
<td>{{ announcement.start_date|naturaltime|default:'' }}</td> <td>{{ announcement.start_date|naturaltime|default:'' }}</td>
<td>{{ announcement.end_date|naturaltime|default:'' }}</td> <td>{{ announcement.end_date|naturaltime|default:'' }}</td>
<td>{% if announcement.active %}{% trans "active" %}{% else %}{% trans "inactive" %}{% endif %}</td> <td>{% if announcement.active %}{% trans "active" %}{% else %}{% trans "inactive" %}{% endif %}</td>
<td>
<form class="control" action="{% url 'settings-announcements-delete' announcement.id %}" method="post">
{% csrf_token %}
<button type="submit" class="button is-danger is-light is-small">
<span class="icon icon-x m-0-mobile" aria-hidden="true"></span>
<span class="is-sr-only-mobile">{% trans "Delete" %}</span>
</button>
</form>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
{% if not announcements %} {% if not announcements %}

View file

@ -0,0 +1,125 @@
{% extends 'settings/layout.html' %}
{% load i18n %}
{% block header %}
{% if announcement %}
{% trans "Edit Announcement" %}
{% else %}
{% trans "Create Announcement" %}
{% endif %}
{% endblock %}
{% block breadcrumbs %}
<nav class="breadcrumb subtitle" aria-label="breadcrumbs">
<ul>
<li><a href="{% url 'settings-announcements' %}">{% trans "Announcements" %}</a></li>
{% if announcement %}
<li>
<a href="{% url 'settings-announcements' announcement.id %}">
{{ announcement.preview|truncatechars:30 }}
</a>
</li>
{% endif %}
<li class="is-active">
<a href="#" aria-current="page">
Edit
</a>
</li>
</ul>
</nav>
{% endblock %}
{% block panel %}
<form
name="edit-announcement"
method="POST"
{% if announcement.id %}
action="{% url 'settings-announcements-edit' announcement.id %}"
{% else %}
action="{% url 'settings-announcements-edit' %}"
{% endif %}
class="block"
>
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<h2 class="title is-4">{% trans "Announcement content" %}</h2>
<div class="box">
<p class="field">
<label class="label" for="id_preview">
{% trans "Summary:" %}
</label>
{{ form.preview }}
{% include 'snippets/form_errors.html' with errors_list=form.preview.errors id="desc_preview" %}
</p>
<p class="field">
<label class="label" for="id_content">
{% trans "Details:" %}
</label>
{{ form.content }}
{% include 'snippets/form_errors.html' with errors_list=form.content.errors id="desc_content" %}
</p>
<p class="field">
<label class="label" for="id_event_date">
{% trans "Event date:" %}
</label>
<input type="date" name="event_date" value="{{ form.event_date.value|date:'Y-m-d' }}" class="input" id="id_event_date">
{% include 'snippets/form_errors.html' with errors_list=form.event_date.errors id="desc_event_date" %}
</p>
</div>
<h2 class="title is-4">{% trans "Display settings" %}</h2>
<div class="box">
<div class="columns">
<div class="column">
<p>
<label class="label" for="id_start_date">
{% trans "Start date:" %}
</label>
<input type="date" name="start_date" class="input" value="{{ form.start_date.value|date:'Y-m-d' }}" id="id_start_date">
{% include 'snippets/form_errors.html' with errors_list=form.start_date.errors id="desc_start_date" %}
</p>
</div>
<div class="column">
<p>
<label class="label" for="id_end_date">
{% trans "End date:" %}
</label>
<input type="date" name="end_date" class="input" id="id_end_date" value="{{ form.end_date.value|date:'Y-m-d' }}">
{% include 'snippets/form_errors.html' with errors_list=form.end_date.errors id="desc_end_date" %}
</p>
</div>
<div class="column is-narrow">
<label class="label" for="id_active">
{% trans "Color:" %}
</label>
<div class="select">
{{ form.display_type }}
</div>
{% include 'snippets/form_errors.html' with errors_list=form.active.errors id="desc_display_type" %}
</div>
</div>
<p class="field">
<label class="label" for="id_active">
{% trans "Active:" %}
{{ form.active }}
</label>
{% include 'snippets/form_errors.html' with errors_list=form.active.errors id="desc_active" %}
</p>
</div>
<div class="field has-addons">
<div class="control">
<button type="submit" class="button is-primary">
{% trans "Save" %}
</button>
</div>
</div>
</form>
{% endblock %}

View file

@ -9,6 +9,7 @@
<div class="columns is-mobile"> <div class="columns is-mobile">
<div class="column"> <div class="column">
<h1 class="title">{% block header %}{% endblock %}</h1> <h1 class="title">{% block header %}{% endblock %}</h1>
{% block breadcrumbs %}{% endblock %}
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
{% block edit-button %}{% endblock %} {% block edit-button %}{% endblock %}
@ -16,6 +17,7 @@
</div> </div>
</header> </header>
<div class="block columns"> <div class="block columns">
<nav class="menu column is-one-quarter"> <nav class="menu column is-one-quarter">
<h2 class="menu-label"> <h2 class="menu-label">

View file

@ -1,32 +1,29 @@
{% load humanize %}{% load i18n %}{% load utilities %} {% load humanize %}{% load i18n %}{% load utilities %}
{% with announcement.id|uuid as uuid %} {% with announcement.id|uuid as uuid %}
<aside <aside
class="notification mb-1 p-3{% if not admin_mode %} is-hidden{% endif %} transition-y" class="notification mb-1 p-3{% if not admin_mode %} is-hidden{% endif %} transition-y has-background-{{ announcement.display_type }}"
{% if not admin_mode %}data-hide="hide_announcement_{{ announcement.id }}"{% endif %} {% if not admin_mode %}data-hide="hide_announcement_{{ announcement.id }}"{% endif %}
> >
<div class="columns mb-0 is-mobile"> <details>
<div class="column pb-0"> <summary>
{% if announcement.event_date %} {% if announcement.event_date %}
<strong>{{ announcement.event_date|naturalday|title }}:</strong> <strong>{{ announcement.event_date|naturalday|title }}:</strong>
{% endif %} {% endif %}
{{ announcement.preview }}
</div> {{ announcement.preview|safe }}
{% if announcement.content %} {% if announcement.content %}
<div class="column is-narrow pb-0"> <span class="details-close mt-4 mr-4 icon icon-x is-small" aria-hidden></span>
{% trans "Open" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text controls_text="announcement" class="is-small" controls_uid=uuid icon_with_text="arrow-down" %}
{% trans "Close" as button_text %}
{% include 'snippets/toggle/close_button.html' with text=button_text controls_text="announcement" class="is-small" controls_uid=uuid icon_with_text="arrow-up" %}
</div>
{% endif %} {% endif %}
</div> </summary>
{% if announcement.content %} {% if announcement.content %}
<div class="mb-2 mt-2 {% if not pressed %}is-hidden{% endif %}" id="announcement_{{ uuid }}"> <div class="mb-2 mt-2" id="announcement_{{ uuid }}">
<div class="box is-shadowless mb-0"> <div class="box is-shadowless mb-0">
{{ announcement.content|safe }} {{ announcement.content|safe }}
</div> </div>
</div> </div>
{% endif %} {% endif %}
</details>
<div class="is-flex mt-0 help"> <div class="is-flex mt-0 help">
<p>{% blocktrans with user_path=announcement.user.local_path username=announcement.user.display_name %}Posted by <a href="{{ user_path }}">{{ username }}</a>{% endblocktrans %}</p> <p>{% blocktrans with user_path=announcement.user.local_path username=announcement.user.display_name %}Posted by <a href="{{ user_path }}">{{ username }}</a>{% endblocktrans %}</p>
{% if not admin_mode %} {% if not admin_mode %}

View file

@ -74,11 +74,12 @@ class AnnouncementViews(TestCase):
def test_create_announcement(self): def test_create_announcement(self):
"""create a new announcement""" """create a new announcement"""
view = views.Announcements.as_view() view = views.EditAnnouncement.as_view()
form = forms.AnnouncementForm() form = forms.AnnouncementForm()
form.data["preview"] = "hi hi" form.data["preview"] = "hi hi"
form.data["start_date"] = "2021-05-20" form.data["start_date"] = "2021-05-20"
form.data["user"] = self.local_user.id form.data["user"] = self.local_user.id
form.data["display_type"] = "warning-light"
request = self.factory.post("", form.data) request = self.factory.post("", form.data)
request.user = self.local_user request.user = self.local_user
@ -97,11 +98,12 @@ class AnnouncementViews(TestCase):
announcement = models.Announcement.objects.create( announcement = models.Announcement.objects.create(
preview="hi", user=self.local_user preview="hi", user=self.local_user
) )
view = views.Announcement.as_view() view = views.EditAnnouncement.as_view()
form = forms.AnnouncementForm(instance=announcement) form = forms.AnnouncementForm(instance=announcement)
form.data["preview"] = "hi hi" form.data["preview"] = "hi hi"
form.data["start_date"] = "2021-05-20" form.data["start_date"] = "2021-05-20"
form.data["user"] = self.local_user.id form.data["user"] = self.local_user.id
form.data["display_type"] = "warning-light"
request = self.factory.post("", form.data) request = self.factory.post("", form.data)
request.user = self.local_user request.user = self.local_user

View file

@ -93,6 +93,16 @@ urlpatterns = [
views.Announcement.as_view(), views.Announcement.as_view(),
name="settings-announcements", name="settings-announcements",
), ),
re_path(
r"^settings/announcements/create/?$",
views.EditAnnouncement.as_view(),
name="settings-announcements-edit",
),
re_path(
r"^settings/announcements/(?P<announcement_id>\d+)/edit/?$",
views.EditAnnouncement.as_view(),
name="settings-announcements-edit",
),
re_path( re_path(
r"^settings/announcements/(?P<announcement_id>\d+)/delete/?$", r"^settings/announcements/(?P<announcement_id>\d+)/delete/?$",
views.delete_announcement, views.delete_announcement,

View file

@ -1,6 +1,7 @@
""" make sure all our nice views are available """ """ make sure all our nice views are available """
# site admin # site admin
from .admin.announcements import Announcements, Announcement, delete_announcement from .admin.announcements import Announcements, Announcement
from .admin.announcements import EditAnnouncement, delete_announcement
from .admin.dashboard import Dashboard from .admin.dashboard import Dashboard
from .admin.federation import Federation, FederatedServer from .admin.federation import Federation, FederatedServer
from .admin.federation import AddFederatedServer, ImportServerBlocklist from .admin.federation import AddFederatedServer, ImportServerBlocklist

View file

@ -45,23 +45,6 @@ class Announcements(View):
request, "settings/announcements/announcements.html", data request, "settings/announcements/announcements.html", data
) )
def post(self, request):
"""edit the site settings"""
form = forms.AnnouncementForm(request.POST)
if form.is_valid():
form.save()
# reset the create form
form = forms.AnnouncementForm()
data = {
"announcements": Paginator(
models.Announcement.objects.order_by("-created_date"), PAGE_LENGTH
).get_page(request.GET.get("page")),
"form": form,
}
return TemplateResponse(
request, "settings/announcements/announcements.html", data
)
@method_decorator(login_required, name="dispatch") @method_decorator(login_required, name="dispatch")
@method_decorator( @method_decorator(
@ -76,26 +59,51 @@ class Announcement(View):
announcement = get_object_or_404(models.Announcement, id=announcement_id) announcement = get_object_or_404(models.Announcement, id=announcement_id)
data = { data = {
"announcement": announcement, "announcement": announcement,
"form": forms.AnnouncementForm(instance=announcement),
} }
return TemplateResponse( return TemplateResponse(
request, "settings/announcements/announcement.html", data request, "settings/announcements/announcement.html", data
) )
def post(self, request, announcement_id):
"""edit announcement""" @method_decorator(login_required, name="dispatch")
@method_decorator(
permission_required("bookwyrm.edit_instance_settings", raise_exception=True),
name="dispatch",
)
class EditAnnouncement(View):
"""Create of edit an announcement"""
def get(self, request, announcement_id=None):
"""announcement forms"""
announcement = None
if announcement_id:
announcement = get_object_or_404(models.Announcement, id=announcement_id) announcement = get_object_or_404(models.Announcement, id=announcement_id)
data = {
"announcement": announcement,
"form": forms.AnnouncementForm(instance=announcement),
}
return TemplateResponse(
request, "settings/announcements/edit_announcement.html", data
)
def post(self, request, announcement_id=None):
"""edit announcement"""
announcement = None
if announcement_id:
announcement = get_object_or_404(models.Announcement, id=announcement_id)
form = forms.AnnouncementForm(request.POST, instance=announcement) form = forms.AnnouncementForm(request.POST, instance=announcement)
if form.is_valid(): if not form.is_valid():
announcement = form.save()
form = forms.AnnouncementForm(instance=announcement)
data = { data = {
"announcement": announcement, "announcement": announcement,
"form": form, "form": form,
} }
return TemplateResponse( return TemplateResponse(
request, "settings/announcements/announcement.html", data request, "settings/announcements/edit_announcement.html", data
) )
announcement = form.save()
return redirect("settings-announcements", announcement.id)
@login_required @login_required