Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/email reminder #378

Open
wants to merge 12 commits into
base: dev
Choose a base branch
from
Open
11 changes: 11 additions & 0 deletions locale/nb/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,17 @@ msgstr ""
"Hvis du ønsker å avbestille billetten din, så kan du gjøre dette ved å "
"besøke følgende adresse"

#: news/templates/email/reminder.html:33
msgid ""
"You've received an update for the event"
msgstr ""
"Du har mottatt en oppdatering for arrangementet"
#: news/templates/email/reminder.txt:4
msgid ""
"You've received an update for the event"
msgstr ""
"Du har mottatt en oppdatering for arrangementet"

#: news/templates/news/admin_article_list.html:13
#: news/templates/news/article_list.html:14
#: web/templates/web/admin_panel.html:15 web/templates/web/header.html:35
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.1.6 on 2021-04-20 12:10

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('make_queue', '0019_add_related_names'),
]

operations = [
migrations.AlterField(
model_name='reservationrule',
name='max_inside_border_crossed',
field=models.FloatField(verbose_name='Hours multiperiod'),
),
]
43 changes: 43 additions & 0 deletions news/forms.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _

from mail import email
from web.multilingual.formfields import MultiLingualFormField, MultiLingualRichTextFormField
from web.multilingual.widgets import MultiLingualTextInput, MultiLingualRichTextUploading
from web.widgets import MazemapSearchInput, SemanticDateTimeInput, SemanticFileInput, SemanticSearchableChoiceInput
from .models import Article, Event, EventTicket, TimePlace

Expand Down Expand Up @@ -61,3 +68,39 @@ class Meta:
"Here you can enter any requests or information you want to provide to the organizers"),
}),
}


class EmailForm(forms.Form):
event = forms.ModelChoiceField(required=False, queryset=Event.objects.all())
time_place = forms.ModelChoiceField(required=False, queryset=TimePlace.objects.all())
subject = MultiLingualFormField(required=True, max_length=190, widget=MultiLingualTextInput)
body = MultiLingualRichTextFormField(required=True, widget=MultiLingualRichTextUploading)

def clean(self):
cleaned_data = super().clean()
event = cleaned_data.get('event')
time_place = cleaned_data.get('time_place')

if not event and not time_place:
raise forms.ValidationError("Event and timeplace cannot both be None.")
if event and time_place:
raise forms.ValidationError("Event and timeplace cannot both be set.")
return cleaned_data
Comment on lines +84 to +88
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is nice if you have add tests that verify that the validation works as intended. I can help in a worksession if you'd like.


def send_email(self):
event = self.cleaned_data.get('event')
time_place = self.cleaned_data.get('time_place')
subject = self.cleaned_data['subject']
body = self.cleaned_data['body']

event_or_time_place = event or time_place
send_mail(
subject,
email.render_text({"body": body, "event_or_time_place": event_or_time_place},
text_template_name='email/reminder.txt'),
settings.EMAIL_HOST_USER,
[ticket.email for ticket in event_or_time_place.tickets.all().filter(active=True)],
html_message=render_to_string('email/reminder.html',
{"body": body, "event_or_time_place": event_or_time_place}
)
)
17 changes: 17 additions & 0 deletions news/migrations/0018_send_email_permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.1.6 on 2021-02-15 14:04

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('news', '0017_use_datetime_instead_of_date_and_time'),
]

operations = [
migrations.AlterModelOptions(
name='timeplace',
options={'ordering': ('start_time',), 'permissions': (('can_send_email', 'Can send email'),)},
),
]
14 changes: 14 additions & 0 deletions news/migrations/0020_empty.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 3.1.6 on 2021-04-19 11:01

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('news', '0019_add_related_names'),
('news', '0018_send_email_permission'),
]

operations = [
]
27 changes: 27 additions & 0 deletions news/migrations/0021_create_emailbase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 3.1.6 on 2021-04-20 12:10

from django.db import migrations, models
import web.modelfields


class Migration(migrations.Migration):

dependencies = [
('news', '0020_added_hyphen_to_fieldname_multiperiod'),
]

operations = [
migrations.CreateModel(
name='EmailBase',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('subject', models.CharField(max_length=60, verbose_name='Subject')),
('body', models.TextField(verbose_name='Body')),
('recipients', web.modelfields.UnlimitedCharField(verbose_name='Recipients')),
],
),
migrations.AlterModelOptions(
name='timeplace',
options={'ordering': ('start_time',)},
),
]
6 changes: 5 additions & 1 deletion news/static/news/css/admin_event_ticket_list.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.copy-button-container {
font-size: large;
margin-bottom: 0.5em;
display: inline;
}

.copy-button-container .copy-token.button {
Expand All @@ -15,4 +15,8 @@
.input-monospace {
font-family: "Courier New", Courier, monospace !important;
width: 100%;
margin-top: 0.5em;
}
.send-email-container {
display: inline;
}
47 changes: 47 additions & 0 deletions news/templates/email/reminder.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{% load static %}
{% load i18n %}

{# CSS styles should be inline, as most email clients don't support external stylesheets, and many don't support <style> tags. #}
{# <Se></Se>e https://css-tricks.com/using-css-in-html-emails-the-real-story/ for more details on what is and isn't supported. #}


<!DOCTYPE html>
{% get_current_language as LANGUAGE_CODE %}
<html lang="{{ LANGUAGE_CODE }}" style="width: 100%; padding: 0; margin: 0;">
<body style="width: 100%; padding: 0; margin: 0;">

<table style="width: 100%; padding: 0; margin: 0; border-width: 0; border-collapse: collapse;">
<thead style="width: 100%; background-color: rgb(34, 43, 52); margin: 0; padding: 0;">
<tr style="padding: 0; margin: 0; width: 100%;">
<th style="padding: 20px;">
<img src="{{ site }}{% static 'web/img/logo_white.svg' %}"
style="width: 500px; max-width: 100%;" alt="MAKE NTNU logo"
/>
</th>
</tr>
</thead>
<tbody style="width: 100%;">
<tr style="width: 100%">
<td style="align-items: center; padding: 0; margin: 0;">
<img src="{{ event_or_time_place.event.image.url }}"
style="width: 100%;" alt="Event image"
/>
</td>
</tr>
<tr style="width: 100%">
<td style="padding: 30px 30px 0 30px; font-size: 30px; font-weight: bold;">
{% trans "You've received an update for the event" %} "{{ event_or_time_place.event.title|default:"Event name" }}":
</td>
</tr>
<tr style="width: 100%">
<td style="padding: 15px 30px 0 30px;">
{% autoescape off %}
{{ body }}
{% endautoescape %}
</td>
</tr>
</tbody>
</table>

</body>
</html>
6 changes: 6 additions & 0 deletions news/templates/email/reminder.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% load i18n %}


{% trans "You've received an update for the event" %} ""{{ event_or_time_place.event.title }}"":

"{{ body }} "
mahoyen marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 9 additions & 1 deletion news/templates/news/admin_event_ticket_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,17 @@ <h1>{{ event.title }}</h1>
<a href="{% url "admin-event" event.pk %}">
<i class="ui angle double left icon"></i>{% trans "Event admin page" %}
</a>

<h3>{% trans "Email Addresses of Ticket Holders" %}</h3>
<div class="emails-container">
<div class="send-email-container">
<a class="ui blue floated button explanation-popup" href="{{ send_email_url }}">
<i class="icons">
<i class="ui envelope open text icon"></i>
<i class="noshadow bottom right corner add icon"></i>
</i>
{% trans "Send email" %}
</a>
</div>
<div class="copy-button-container">
<button class="copy-token ui make-bg-yellow icon button"><i class="clipboard icon"></i></button>
<span data-content="{% trans "Click to copy the email addresses of the active tickets to the clipboard" %}.">
Expand Down
40 changes: 40 additions & 0 deletions news/templates/news/email_edit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{% extends 'web/base.html' %}
{% load static %}
{% load i18n %}

{% block title %}{% trans "Create email" %}{% endblock title %}

{% block head %}
<script type="text/javascript" src="{% static "ckeditor/ckeditor-init.js" %}"></script>
<script type="text/javascript" src="{% static "ckeditor/ckeditor/ckeditor.js" %}"></script>
<script type="text/javascript" src="{% static "news/js/event_type.js" %}"></script>
{% endblock head %}

{% block body %}
<h1 class="ui centered header">
{% block form_header %}{% trans "Create email" %}{% endblock form_header %}
</h1>
<form class="ui form text container" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="field">
<label>{{ form.title.label }}</label>
{{ form.title }}
</div>
<div class="field">
<label>{{ form.content.label }}
<span data-content="{% trans "The main content of the email." %}">
<i class="ui yellow question circle icon"></i>
</span>
</label>
{{ form.content }}
</div>
<input class="ui yellow right floated submit button" type="submit" value="{% trans "Send" %}">
<a href="{% block cancel-url %}{% url "admin-event" form.instance.id %}{% endblock %}" class="ui red right floated button">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the name to the endblock and change the naming style as well.(relevant section)

Suggested change
<a href="{% block cancel-url %}{% url "admin-event" form.instance.id %}{% endblock %}" class="ui red right floated button">
<a href="{% block cancel_url %}{% url "admin-event" form.instance.id %}{% endblock cancel_url %}" class="ui red right floated button">

{% trans "Cancel" context "abort action" %}
</a>
</form>

<script>
$("span[data-content]").popup();
</script>
{% endblock body %}
39 changes: 39 additions & 0 deletions news/templates/news/timeplace_email.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{% extends 'web/base.html' %}
{% load static %}
{% load i18n %}


{% block title %}{% trans "Edit email" %}{% endblock title %}

{% block head %}
{{ form.media }}
{% endblock head %}

{% block body %}
<h1 class="ui centered header">{% block form_header %}{% trans "Edit email" %}{% endblock form_header %}</h1>
<form class="ui form text container" action="" method="POST" enctype="multipart/form-data">
{% for error in form.non_field_errors %}
<div class="ui negative message">
{{ error }}
</div>
{% endfor %}
{% csrf_token %}

<div class="field">
<label>{{ "Subject" }}</label>
{{ form.subject }}
</div>
<div class="field">
<label>{% trans "Body" %}</label>
{{ form.body }}
</div>

<input class="ui right floated make-bg-yellow submit button" type="submit" value="{% trans "Send" %}"/>
<a class="ui right floated red button" href="{% url "admin-event" event.pk %}">
{% trans "Cancel" context "abort action" %}
</a>
</form>
<script>
$("span[data-content]").popup();
</script>
{% endblock body %}
2 changes: 2 additions & 0 deletions news/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@
path('event/<int:pk>/edit/', login_required(views.EditEventView.as_view()), name='event-edit'),
path('event/<int:pk>/tickets/', permission_required("news.change_event")(views.AdminEventTicketView.as_view()), name="event-tickets"),
path('event/<int:pk>/delete/', login_required(views.DeleteEventView.as_view()), name='event-delete'),
path('event/<int:event_pk>/email/', login_required(views.EmailEventView.as_view()), name='event-email'),
path('event/<int:pk>/', views.ViewEventView.as_view(), name='event'),
path('event/<int:event_pk>/register/', login_required(views.EventRegistrationView.as_view()), name="register-event"),
path('timeplace/<int:pk>/edit/', login_required(views.EditTimePlaceView.as_view()), name='timeplace-edit'),
path('timeplace/<int:pk>/duplicate/', login_required(views.DuplicateTimePlaceView.as_view()), name='timeplace-duplicate'),
path('timeplace/<int:event_pk>/new/', login_required(views.CreateTimePlaceView.as_view()), name='timeplace-new'),
path('timeplace/<int:pk>/tickets/', permission_required("news.change_event")(views.AdminTimeplaceTicketView.as_view()), name="timeplace-tickets"),
path('timeplace/<int:pk>/delete/', login_required(views.DeleteTimePlaceView.as_view()), name='timeplace-delete'),
path('timeplace/<int:time_place_pk>/email/', login_required(views.EmailEventView.as_view()), name='timeplace-email'),
path('timeplace/<int:pk>/ical/', SingleTimePlaceFeed(), name='timeplace-ical'),
path('timeplace/<int:timeplace_pk>/register/', login_required(views.EventRegistrationView.as_view()), name="register-timeplace"),
path('ticket/<uuid:pk>/', views.TicketView.as_view(), name="ticket"),
Expand Down
Loading