Merge pull request #392 from eventcally/issues/391

Add newsletter functionality #391
This commit is contained in:
Daniel Grams 2023-03-28 23:24:30 +02:00 committed by GitHub
commit a2269a9123
25 changed files with 754 additions and 253 deletions

View File

@ -1,5 +1,5 @@
[flake8]
extend-ignore = E501, E203
extend-ignore = E501, E203, E711
exclude =
.git,
.github,

View File

@ -35,6 +35,19 @@ jobs:
# Maps tcp port 5432 on service container to the host
- 5432:5432
redis:
# Docker Hub image
image: redis
# Set health checks to wait until redis has started
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps port 6379 on service container to the host
- 6379:6379
steps:
- name: Check out repository code
uses: actions/checkout@v2
@ -53,6 +66,7 @@ jobs:
run: pytest --cov=project --splits 4 --group ${{ matrix.group }}
env:
TEST_DATABASE_URL: postgresql://postgres:postgres@localhost/eventcally_tests
TEST_REDIS_URL: redis://localhost:6379
- name: Upload coverage
uses: actions/upload-artifact@v2

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2023-03-24 21:24+0100\n"
"POT-Creation-Date: 2023-03-28 17:04+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -208,7 +208,7 @@ msgstr ""
msgid "Legal notice"
msgstr ""
#: project/forms/admin.py:13 project/templates/_macros.html:1395
#: project/forms/admin.py:13 project/templates/_macros.html:1397
#: project/templates/layout.html:302
#: project/templates/widget/event_suggestion/create.html:204
#: project/views/admin_unit.py:73 project/views/root.py:69
@ -225,6 +225,7 @@ msgid "Start page"
msgstr ""
#: project/forms/admin.py:17 project/forms/oauth2_client.py:24
#: project/forms/user.py:13
msgid "Save"
msgstr ""
@ -285,7 +286,7 @@ msgstr ""
msgid "Update organization"
msgstr ""
#: project/forms/admin.py:63
#: project/forms/admin.py:63 project/forms/admin.py:70
msgid "Recipient"
msgstr ""
@ -293,6 +294,22 @@ msgstr ""
msgid "Send test mail synchronously"
msgstr ""
#: project/forms/admin.py:72 project/forms/admin.py:78
msgid "Test recipient"
msgstr ""
#: project/forms/admin.py:73
msgid "All users with enabled newsletter setting"
msgstr ""
#: project/forms/admin.py:79
msgid "Message"
msgstr ""
#: project/forms/admin.py:80
msgid "Send newsletter"
msgstr ""
#: project/forms/admin_unit.py:15 project/forms/event_place.py:12
#: project/forms/organizer.py:12
msgid "Street"
@ -342,7 +359,7 @@ msgstr ""
msgid "The short name is used to create a unique identifier for your events"
msgstr ""
#: project/forms/admin_unit.py:41 project/templates/_macros.html:1531
#: project/forms/admin_unit.py:41 project/templates/_macros.html:1533
msgid "Short name must contain only letters numbers or underscore"
msgstr ""
@ -355,20 +372,21 @@ msgstr ""
#: project/forms/admin_unit.py:48 project/forms/admin_unit_member.py:11
#: project/forms/admin_unit_member.py:23 project/forms/admin_unit_member.py:28
#: project/forms/event.py:107 project/forms/event_suggestion.py:38
#: project/forms/organizer.py:27 project/templates/_macros.html:235
#: project/templates/_macros.html:1491 project/templates/admin/admin.html:27
#: project/forms/organizer.py:27 project/templates/_macros.html:237
#: project/templates/_macros.html:1493 project/templates/admin/admin.html:27
#: project/templates/admin/email.html:4 project/templates/admin/email.html:66
#: project/templates/admin/users.html:19
msgid "Email"
msgstr ""
#: project/forms/admin_unit.py:49 project/forms/event.py:108
#: project/forms/event_suggestion.py:31 project/forms/organizer.py:28
#: project/templates/_macros.html:288
#: project/templates/_macros.html:290
msgid "Phone"
msgstr ""
#: project/forms/admin_unit.py:50 project/forms/event.py:109
#: project/forms/organizer.py:29 project/templates/_macros.html:296
#: project/forms/organizer.py:29 project/templates/_macros.html:298
msgid "Fax"
msgstr ""
@ -566,16 +584,16 @@ msgstr ""
msgid "All-day"
msgstr ""
#: project/forms/event.py:54 project/templates/_macros.html:1711
#: project/forms/event.py:54 project/templates/_macros.html:1713
#: project/templates/widget/event_suggestion/create.html:240
msgid "Recurring event"
msgstr ""
#: project/forms/event.py:61 project/templates/_macros.html:1252
#: project/forms/event.py:61 project/templates/_macros.html:1254
msgid "The start must be before the end."
msgstr ""
#: project/forms/event.py:67 project/templates/_macros.html:1269
#: project/forms/event.py:67 project/templates/_macros.html:1271
msgid "An event can last a maximum of 14 days."
msgstr ""
@ -609,7 +627,7 @@ msgstr ""
msgid "Enter a link where tickets can be purchased."
msgstr ""
#: project/forms/event.py:136 project/templates/_macros.html:217
#: project/forms/event.py:136 project/templates/_macros.html:219
msgid "Tags"
msgstr ""
@ -659,7 +677,7 @@ msgstr ""
msgid "If the participants needs to register for the event."
msgstr ""
#: project/forms/event.py:170 project/templates/_macros.html:249
#: project/forms/event.py:170 project/templates/_macros.html:251
#: project/templates/layout.html:110
msgid "Booked up"
msgstr ""
@ -739,8 +757,8 @@ msgid ""
" course it works without it."
msgstr ""
#: project/forms/event.py:242 project/templates/_macros.html:396
#: project/templates/_macros.html:559
#: project/forms/event.py:242 project/templates/_macros.html:398
#: project/templates/_macros.html:561
msgid "Previous start date"
msgstr ""
@ -786,7 +804,7 @@ msgstr ""
#: project/forms/event.py:286 project/forms/event.py:295
#: project/forms/event.py:368 project/forms/event_suggestion.py:50
#: project/templates/_macros.html:436 project/templates/_macros.html:599
#: project/templates/_macros.html:438 project/templates/_macros.html:601
#: project/templates/event/create.html:284
#: project/templates/event/update.html:166
#: project/templates/event_place/create.html:31
@ -805,8 +823,8 @@ msgstr ""
#: project/forms/event.py:302 project/forms/event.py:311
#: project/forms/event.py:376 project/forms/event.py:439
#: project/forms/event_suggestion.py:60 project/templates/_macros.html:473
#: project/templates/_macros.html:636 project/templates/event/create.html:253
#: project/forms/event_suggestion.py:60 project/templates/_macros.html:475
#: project/templates/_macros.html:638 project/templates/event/create.html:253
#: project/templates/event/update.html:156
#: project/templates/organizer/create.html:27
#: project/templates/organizer/delete.html:13
@ -891,7 +909,7 @@ msgstr ""
msgid "PublicStatus.published"
msgstr ""
#: project/forms/event.py:402 project/templates/_macros.html:255
#: project/forms/event.py:402 project/templates/_macros.html:257
msgid "PublicStatus.draft"
msgstr ""
@ -904,7 +922,7 @@ msgstr ""
msgid "Update event"
msgstr ""
#: project/forms/event.py:423 project/templates/_macros.html:1224
#: project/forms/event.py:423 project/templates/_macros.html:1226
#: project/templates/event/actions.html:66
#: project/templates/event/delete.html:6
msgid "Delete event"
@ -925,7 +943,7 @@ msgid "Keyword"
msgstr ""
#: project/forms/event.py:436 project/forms/event_date.py:21
#: project/forms/planing.py:19 project/templates/_macros.html:369
#: project/forms/planing.py:19 project/templates/_macros.html:371
msgid "Category"
msgstr ""
@ -934,7 +952,7 @@ msgid "Find events"
msgstr ""
#: project/forms/event_date.py:24 project/forms/planing.py:22
#: project/templates/_macros.html:303
#: project/templates/_macros.html:305
#: project/templates/admin_unit/create.html:38
#: project/templates/admin_unit/update.html:39
#: project/templates/event_place/create.html:40
@ -1077,7 +1095,7 @@ msgid "Weekdays"
msgstr ""
#: project/forms/reference.py:11 project/forms/reference_request.py:16
#: project/templates/_macros.html:489 project/templates/_macros.html:652
#: project/templates/_macros.html:491 project/templates/_macros.html:654
#: project/templates/admin_unit/create.html:28
#: project/templates/admin_unit/update.html:29
#: project/templates/layout.html:242
@ -1105,7 +1123,7 @@ msgstr ""
msgid "Delete request"
msgstr ""
#: project/forms/reference_request.py:28 project/templates/_macros.html:1407
#: project/forms/reference_request.py:28 project/templates/_macros.html:1409
#: project/templates/event_suggestion/review_status.html:18
#: project/templates/reference_request/review_status.html:12
msgid "Review status"
@ -1163,43 +1181,53 @@ msgstr ""
msgid "Deny"
msgstr ""
#: project/forms/user.py:9 project/templates/admin/admin.html:31
#: project/templates/admin/newsletter.html:4
#: project/templates/admin/newsletter.html:93
msgid "Newsletter"
msgstr ""
#: project/forms/user.py:10
msgid "Information about new features and improvements."
msgstr ""
#: project/forms/widgets.py:154
msgid "This field is required."
msgstr ""
#: project/templates/_macros.html:147
#: project/templates/_macros.html:149
msgid "Show on Google Maps"
msgstr ""
#: project/templates/_macros.html:226
#: project/templates/_macros.html:228
msgid "Link"
msgstr ""
#: project/templates/_macros.html:282
#: project/templates/_macros.html:284
msgid "Verified"
msgstr ""
#: project/templates/_macros.html:346
#, python-format
msgid "Created at %(created_at)s by %(created_by)s."
msgstr ""
#: project/templates/_macros.html:348
#, python-format
msgid "Created at %(created_at)s."
msgid "Created at %(created_at)s by %(created_by)s."
msgstr ""
#: project/templates/_macros.html:353
#: project/templates/_macros.html:350
#, python-format
msgid "Last updated at %(updated_at)s by %(updated_by)s."
msgid "Created at %(created_at)s."
msgstr ""
#: project/templates/_macros.html:355
#, python-format
msgid "Last updated at %(updated_at)s by %(updated_by)s."
msgstr ""
#: project/templates/_macros.html:357
#, python-format
msgid "Last updated at %(updated_at)s."
msgstr ""
#: project/templates/_macros.html:385 project/templates/_macros.html:555
#: project/templates/_macros.html:387 project/templates/_macros.html:557
#: project/templates/event/actions.html:25
#: project/templates/event/create.html:230
#: project/templates/event/update.html:122
@ -1207,63 +1235,63 @@ msgstr ""
msgid "Event"
msgstr ""
#: project/templates/_macros.html:391 project/templates/_macros.html:920
#: project/templates/_macros.html:393 project/templates/_macros.html:922
msgid "Date"
msgstr ""
#: project/templates/_macros.html:418 project/templates/_macros.html:577
#: project/templates/_macros.html:1476 project/templates/event/actions.html:51
#: project/templates/_macros.html:420 project/templates/_macros.html:579
#: project/templates/_macros.html:1478 project/templates/event/actions.html:51
msgid "Share"
msgstr ""
#: project/templates/_macros.html:422 project/templates/_macros.html:581
#: project/templates/_macros.html:1506
#: project/templates/_macros.html:424 project/templates/_macros.html:583
#: project/templates/_macros.html:1508
msgid "Add to calendar"
msgstr ""
#: project/templates/_macros.html:430 project/templates/_macros.html:592
#: project/templates/_macros.html:432 project/templates/_macros.html:594
#: project/templates/event/report.html:4
msgid "Report event"
msgstr ""
#: project/templates/_macros.html:457 project/templates/_macros.html:618
#: project/templates/_macros.html:459 project/templates/_macros.html:620
msgid "Show directions"
msgstr ""
#: project/templates/_macros.html:462 project/templates/_macros.html:623
#: project/templates/_macros.html:464 project/templates/_macros.html:625
msgid "The event takes place online."
msgstr ""
#: project/templates/_macros.html:464 project/templates/_macros.html:625
#: project/templates/_macros.html:466 project/templates/_macros.html:627
msgid "The event takes place both offline and online."
msgstr ""
#: project/templates/_macros.html:585 project/templates/layout.html:168
#: project/templates/_macros.html:587 project/templates/layout.html:168
#: project/templates/user/favorite_events.html:4
msgid "Favorite events"
msgstr ""
#: project/templates/_macros.html:679 project/templates/event_date/list.html:5
#: project/templates/_macros.html:681 project/templates/event_date/list.html:5
#: project/templates/event_date/list.html:299
#: project/templates/reference_request/review.html:32
msgid "Event Dates"
msgstr ""
#: project/templates/_macros.html:771
#: project/templates/_macros.html:773
msgid "Search location on Google"
msgstr ""
#: project/templates/_macros.html:837
#: project/templates/_macros.html:839
#, python-format
msgid "%(count)d event dates"
msgstr ""
#: project/templates/_macros.html:860 project/templates/_macros.html:862
#: project/templates/_macros.html:862 project/templates/_macros.html:864
#: project/templates/event_date/list.html:321
msgid "First"
msgstr ""
#: project/templates/_macros.html:865 project/templates/_macros.html:867
#: project/templates/_macros.html:867 project/templates/_macros.html:869
#: project/templates/event_date/list.html:322
#: project/templates/widget/event_suggestion/create.html:193
#: project/templates/widget/event_suggestion/create.html:218
@ -1274,12 +1302,12 @@ msgstr ""
msgid "Previous"
msgstr ""
#: project/templates/_macros.html:869
#: project/templates/_macros.html:871
#, python-format
msgid "Page %(page)d of %(pages)d (%(total)d total)"
msgstr ""
#: project/templates/_macros.html:871 project/templates/_macros.html:873
#: project/templates/_macros.html:873 project/templates/_macros.html:875
#: project/templates/event_date/list.html:324
#: project/templates/widget/event_suggestion/create.html:194
#: project/templates/widget/event_suggestion/create.html:219
@ -1289,88 +1317,88 @@ msgstr ""
msgid "Next"
msgstr ""
#: project/templates/_macros.html:876 project/templates/_macros.html:878
#: project/templates/_macros.html:878 project/templates/_macros.html:880
#: project/templates/event_date/list.html:325
msgid "Last"
msgstr ""
#: project/templates/_macros.html:943
#: project/templates/_macros.html:945
msgid "Radius"
msgstr ""
#: project/templates/_macros.html:1153
#: project/templates/_macros.html:1155
msgid "Edit image"
msgstr ""
#: project/templates/_macros.html:1174
#: project/templates/_macros.html:1176
msgid "Close"
msgstr ""
#: project/templates/_macros.html:1175
#: project/templates/_macros.html:1177
msgid "Okay"
msgstr ""
#: project/templates/_macros.html:1187
#: project/templates/_macros.html:1189
msgid "Choose image file"
msgstr ""
#: project/templates/_macros.html:1223 project/templates/event/actions.html:65
#: project/templates/_macros.html:1225 project/templates/event/actions.html:65
#: project/templates/event/delete.html:12
msgid "Edit event"
msgstr ""
#: project/templates/_macros.html:1226 project/templates/manage/events.html:66
#: project/templates/_macros.html:1228 project/templates/manage/events.html:66
msgid "More"
msgstr ""
#: project/templates/_macros.html:1273
#: project/templates/_macros.html:1275
msgid "Please enter a valid time, between 00:00 and 23:59."
msgstr ""
#: project/templates/_macros.html:1301
#: project/templates/_macros.html:1303
#, python-format
msgid "Just use %(term)s"
msgstr ""
#: project/templates/_macros.html:1367
#: project/templates/_macros.html:1369
msgid "Event suggestion"
msgstr ""
#: project/templates/_macros.html:1485
#: project/templates/_macros.html:1487
msgid "Link copied"
msgstr ""
#: project/templates/_macros.html:1485
#: project/templates/_macros.html:1487
msgid "Copy link"
msgstr ""
#: project/templates/_macros.html:1514
#: project/templates/_macros.html:1516
msgid "Google calendar"
msgstr ""
#: project/templates/_macros.html:1515
#: project/templates/_macros.html:1517
msgid "Apple calendar"
msgstr ""
#: project/templates/_macros.html:1516
#: project/templates/_macros.html:1518
msgid "Yahoo calendar"
msgstr ""
#: project/templates/_macros.html:1517
#: project/templates/_macros.html:1519
msgid "Other calendar"
msgstr ""
#: project/templates/_macros.html:1712
#: project/templates/_macros.html:1714
msgid "Remove event date"
msgstr ""
#: project/templates/_macros.html:1741 project/templates/event/create.html:176
#: project/templates/_macros.html:1743 project/templates/event/create.html:176
#: project/templates/event/update.html:99
#: project/templates/widget/event_suggestion/create.html:129
msgid "Enter organizer"
msgstr ""
#: project/templates/_macros.html:1765
#: project/templates/_macros.html:1767
msgid "Enter list name"
msgstr ""
@ -1414,6 +1442,7 @@ msgstr ""
#: project/templates/admin/admin.html:3 project/templates/admin/admin.html:9
#: project/templates/admin/admin_units.html:10
#: project/templates/admin/email.html:65
#: project/templates/admin/newsletter.html:92
#: project/templates/admin/settings.html:10
#: project/templates/admin/users.html:10 project/templates/layout.html:171
msgid "Admin"
@ -1501,8 +1530,7 @@ msgstr ""
msgid "Organization invitations"
msgstr ""
#: project/templates/admin/admin.html:15 project/templates/admin/email.html:4
#: project/templates/admin/email.html:66
#: project/templates/admin/admin.html:15
#: project/templates/admin/settings.html:4
#: project/templates/admin/settings.html:11
#: project/templates/admin_unit/update.html:6
@ -1528,18 +1556,24 @@ msgid "Switch organization"
msgstr ""
#: project/templates/developer/read.html:4 project/templates/layout.html:310
#: project/templates/profile.html:29
#: project/templates/profile.html:33
msgid "Developer"
msgstr ""
#: project/templates/profile.html:23
#: project/templates/user/notifications.html:4
#: project/templates/user/notifications.html:8
msgid "Notifications"
msgstr ""
#: project/templates/profile.html:27
msgid "Applications"
msgstr ""
#: project/templates/oauth2_client/list.html:4
#: project/templates/oauth2_client/list.html:11
#: project/templates/oauth2_client/read.html:11
#: project/templates/profile.html:33
#: project/templates/profile.html:37
msgid "OAuth2 clients"
msgstr ""
@ -1560,7 +1594,7 @@ msgstr ""
msgid "Edit"
msgstr ""
#: project/templates/admin/email.html:47 project/views/admin.py:119
#: project/templates/admin/email.html:47 project/views/admin.py:122
msgid "Mail sent successfully"
msgstr ""
@ -1572,6 +1606,10 @@ msgstr ""
msgid "Send test mail asynchronously"
msgstr ""
#: project/templates/admin/newsletter.html:59
msgid "Mails sent successfully"
msgstr ""
#: project/templates/admin_unit/create.html:58
#: project/templates/admin_unit/update.html:59
#: project/templates/event/create.html:347
@ -1626,6 +1664,10 @@ msgstr ""
msgid "this is a message from %(site_name)s."
msgstr ""
#: project/templates/email/newsletter.html:7
msgid "Notification settings"
msgstr ""
#: project/templates/email/organization_invitation_accepted_notice.html:4
#, python-format
msgid ""
@ -2035,20 +2077,26 @@ msgstr ""
msgid "Preview"
msgstr ""
#: project/views/admin.py:55
#: project/views/admin.py:58
msgid "Organization successfully updated"
msgstr ""
#: project/views/admin.py:79 project/views/manage.py:361
#: project/views/admin.py:82 project/views/manage.py:361
#: project/views/user.py:27
msgid "Settings successfully updated"
msgstr ""
#: project/views/admin.py:108
#: project/views/admin.py:111
#, python-format
msgid "Test mail from %(site_name)s"
msgstr ""
#: project/views/admin.py:152
#: project/views/admin.py:150
#, python-format
msgid "Newsletter from %(site_name)s"
msgstr ""
#: project/views/admin.py:200
msgid "User successfully updated"
msgstr ""

View File

@ -0,0 +1,31 @@
"""empty message
Revision ID: 47c334ba5b86
Revises: 3f77c8693ae3
Create Date: 2023-03-26 23:03:44.678745
"""
import sqlalchemy as sa
import sqlalchemy_utils
from alembic import op
from project import dbtypes
# revision identifiers, used by Alembic.
revision = "47c334ba5b86"
down_revision = "3f77c8693ae3"
branch_labels = None
depends_on = None
def upgrade():
op.add_column(
"user",
sa.Column(
"newsletter_enabled", sa.Boolean(), server_default="1", nullable=False
),
)
def downgrade():
op.drop_column("user", "newsletter_enabled")

View File

@ -7,6 +7,6 @@ from project.views.utils import send_mail
base=getattr(app, "celery_http_task_cls"),
priority=0,
)
def send_mail_task(recipient, subject, template):
def send_mail_task(recipient, subject, template, **context):
with force_locale():
send_mail(recipient, subject, template)
send_mail(recipient, subject, template, **context)

View File

@ -1,6 +1,6 @@
from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm
from wtforms import BooleanField, SubmitField, TextAreaField
from wtforms import BooleanField, RadioField, SubmitField, TextAreaField
from wtforms.fields.html5 import EmailField
from wtforms.validators import DataRequired, Optional
@ -63,3 +63,18 @@ class AdminTestEmailForm(FlaskForm):
recipient = EmailField(lazy_gettext("Recipient"), validators=[DataRequired()])
submit = SubmitField(lazy_gettext("Send test mail synchronously"))
class AdminNewsletterForm(FlaskForm):
recipient_choice = RadioField(
lazy_gettext("Recipient"),
choices=[
(1, lazy_gettext("Test recipient")),
(2, lazy_gettext("All users with enabled newsletter setting")),
],
default=1,
coerce=int,
)
test_recipient = EmailField(lazy_gettext("Test recipient"), validators=[Optional()])
message = TextAreaField(lazy_gettext("Message"), validators=[DataRequired()])
submit = SubmitField(lazy_gettext("Send newsletter"))

13
project/forms/user.py Normal file
View File

@ -0,0 +1,13 @@
from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm
from wtforms import BooleanField, SubmitField
from wtforms.validators import Optional
class NotificationForm(FlaskForm):
newsletter_enabled = BooleanField(
lazy_gettext("Newsletter"),
description=lazy_gettext("Information about new features and improvements."),
validators=[Optional()],
)
submit = SubmitField(lazy_gettext("Save"))

View File

@ -199,6 +199,14 @@ class User(db.Model, UserMixin):
secondary="user_favoriteevents",
backref=backref("favored_by_users", lazy=True),
)
newsletter_enabled = deferred(
Column(
Boolean(),
nullable=True,
default=True,
server_default="1",
)
)
def get_user_id(self):
return self.id

View File

@ -70,6 +70,8 @@
</label>
{% endfor %}
</div>
{% elif 'ri' in kwargs and kwargs['ri'] == 'radio' %}
{{ render_radio_buttons(field) }}
{% else %}
{% if 'class' in kwargs %}
{% set _dummy=kwargs.pop('class') %}

View File

@ -27,6 +27,10 @@
{{ _('Email') }}
<i class="fa fa-caret-right"></i>
</a>
<a href="{{ url_for('admin_newsletter') }}" class="list-group-item">
{{ _('Newsletter') }}
<i class="fa fa-caret-right"></i>
</a>
</div>
{% endblock %}

View File

@ -1,7 +1,7 @@
{% extends "layout.html" %}
{% from "_macros.html" import render_field, render_field_with_errors %}
{%- block title -%}
{{ _('Settings') }}
{{ _('Email') }}
{%- endblock -%}
{% block header %}
<script>
@ -63,7 +63,7 @@
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ url_for('admin') }}">{{ _('Admin') }}</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ _('Settings') }}</li>
<li class="breadcrumb-item active" aria-current="page">{{ _('Email') }}</li>
</ol>
</nav>

View File

@ -0,0 +1,123 @@
{% extends "layout.html" %}
{% from "_macros.html" import render_field, render_field_with_errors, render_radio_buttons %}
{%- block title -%}
{{ _('Newsletter') }}
{%- endblock -%}
{% block header %}
<script>
function update_progress_bar(completed, count, progressbar_id='#progressbar') {
var progress = count > 0 ? Math.round((completed/count)*100) : 0;
console.log('' + progress + '%');
var progressbar = $(progressbar_id);
progressbar.css('width', '' + progress + '%');
progressbar.attr("ariaValueNow", progress);
progressbar.html("" + progress + '%');
}
function submit_async() {
update_progress_bar(0, 0);
handle_request_start();
$.ajax({
url: "{{ url_for('admin_newsletter', async=1) }}",
type: "post",
dataType: "json",
data: $("#newsletter_form").serialize(),
error: function(xhr, status, error) {
handle_request_error(xhr, status, error);
},
success: function (data) {
poll(data["result_id"]);
}
});
}
function poll(result_id) {
$.ajax({
url: "{{ url_for('admin_newsletter') }}",
type: "get",
dataType: "json",
data: "poll=" + result_id,
error: function(xhr, status, error) {
handle_request_error(xhr, status, error);
},
success: function (data) {
update_progress_bar(data["completed"], data["count"]);
if (!data["ready"]) {
setTimeout(function() {
poll(result_id);
}, 500);
return;
}
if (!data["successful"]) {
console.error(data);
handle_request_error(null, JSON.stringify(data), data);
return;
}
$("#success_message").text("{{ _('Mails sent successfully') }} (" + data["completed"] + ")");
handle_request_success();
}
});
}
$( function() {
$("#newsletter_form").submit(function(e){
e.stopPropagation();
submit_async();
return false;
});
$('label[for=test_recipient]').append(' *');
$('input[name=recipient_choice]').on('change', function() {
switch ($(this).val()) {
case '1':
$('#test_recipient').attr("required", true);
$('#test_recipient_container').show();
break;
case '2':
$('#test_recipient').attr("required", false);
$('#test_recipient_container').hide();
break;
}
});
});
</script>
{% endblock %}
{% block content %}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ url_for('admin') }}">{{ _('Admin') }}</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ _('Newsletter') }}</li>
</ol>
</nav>
<form id="newsletter_form" action="" method="POST">
{{ form.hidden_tag() }}
<div class="my-4">
{{ render_field_with_errors(form.recipient_choice, ri='radio') }}
</div>
<div id="test_recipient_container">
{{ render_field_with_errors(form.test_recipient) }}
</div>
{{ render_field_with_errors(form.message) }}
{{ render_field(form.submit) }}
</form>
<p>
<div id="result_container" style="display: none;">
<div id="success_message" class="alert alert-success"></div>
</div>
<div id="spinner" style="display: none;">
<div class="progress">
<div id="progressbar" class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="alert alert-danger m-3" role="alert" id="error_alert" style="display: none;"></div>
</p>
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends "email/layout.html" %}
{% block content %}
<p>
{{ message|safe }}
</p>
<p>
<a href="{{ url_for('user_notifications', _external=True) }}" target="_blank" rel="noopener noreferrer">{{ _('Notification settings') }}</a>
</p>
{% endblock %}

View File

@ -0,0 +1,3 @@
{{ message|safe }}
{{ _('Notification settings') }}: {{ url_for('user_notifications', _external=True) }}

View File

@ -19,6 +19,10 @@
<h2>{{ _('Settings') }}</h2>
<div class="list-group">
<a href="{{ url_for('user_notifications') }}" class="list-group-item">
{{ _('Notifications') }}
<i class="fa fa-caret-right"></i>
</a>
<a href="{{ url_for('oauth2_tokens') }}" class="list-group-item">
{{ _('Applications') }}
<i class="fa fa-caret-right"></i>

View File

@ -0,0 +1,16 @@
{% extends "layout.html" %}
{% from "_macros.html" import render_field_with_errors, render_field %}
{%- block title -%}
{{ _('Notifications') }}
{%- endblock -%}
{% block content %}
<h1>{{ _('Notifications') }}</h1>
<form action="" method="POST">
{{ form.hidden_tag() }}
{{ render_field_with_errors(form.newsletter_enabled, ri="switch") }}
{{ render_field(form.submit) }}
</form>
{% endblock %}

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2023-03-24 21:24+0100\n"
"POT-Creation-Date: 2023-03-28 17:04+0200\n"
"PO-Revision-Date: 2020-06-07 18:51+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: de\n"
@ -209,7 +209,7 @@ msgstr "Nutzungsbedingungen"
msgid "Legal notice"
msgstr "Impressum"
#: project/forms/admin.py:13 project/templates/_macros.html:1395
#: project/forms/admin.py:13 project/templates/_macros.html:1397
#: project/templates/layout.html:302
#: project/templates/widget/event_suggestion/create.html:204
#: project/views/admin_unit.py:73 project/views/root.py:69
@ -226,6 +226,7 @@ msgid "Start page"
msgstr "Startseite"
#: project/forms/admin.py:17 project/forms/oauth2_client.py:24
#: project/forms/user.py:13
msgid "Save"
msgstr "Speichern"
@ -294,7 +295,7 @@ msgstr ""
msgid "Update organization"
msgstr "Organisation aktualisieren"
#: project/forms/admin.py:63
#: project/forms/admin.py:63 project/forms/admin.py:70
msgid "Recipient"
msgstr "Empfänger"
@ -302,6 +303,22 @@ msgstr "Empfänger"
msgid "Send test mail synchronously"
msgstr "Test-Mail synchron senden"
#: project/forms/admin.py:72 project/forms/admin.py:78
msgid "Test recipient"
msgstr "Test-Empfänger"
#: project/forms/admin.py:73
msgid "All users with enabled newsletter setting"
msgstr "Alle Nutzer mit aktiviertem Newsletter"
#: project/forms/admin.py:79
msgid "Message"
msgstr "Nachricht"
#: project/forms/admin.py:80
msgid "Send newsletter"
msgstr "Newsletter senden"
#: project/forms/admin_unit.py:15 project/forms/event_place.py:12
#: project/forms/organizer.py:12
msgid "Street"
@ -354,7 +371,7 @@ msgstr ""
"eindeutig zu identifizieren. Der Kurzname darf nur Buchstaben, Nummern "
"und Unterstriche enthalten."
#: project/forms/admin_unit.py:41 project/templates/_macros.html:1531
#: project/forms/admin_unit.py:41 project/templates/_macros.html:1533
msgid "Short name must contain only letters numbers or underscore"
msgstr "Der Kurzname darf nur Buchstaben, Nummern und Unterstriche enthalten"
@ -367,20 +384,21 @@ msgstr "Link URL"
#: project/forms/admin_unit.py:48 project/forms/admin_unit_member.py:11
#: project/forms/admin_unit_member.py:23 project/forms/admin_unit_member.py:28
#: project/forms/event.py:107 project/forms/event_suggestion.py:38
#: project/forms/organizer.py:27 project/templates/_macros.html:235
#: project/templates/_macros.html:1491 project/templates/admin/admin.html:27
#: project/forms/organizer.py:27 project/templates/_macros.html:237
#: project/templates/_macros.html:1493 project/templates/admin/admin.html:27
#: project/templates/admin/email.html:4 project/templates/admin/email.html:66
#: project/templates/admin/users.html:19
msgid "Email"
msgstr "Email"
#: project/forms/admin_unit.py:49 project/forms/event.py:108
#: project/forms/event_suggestion.py:31 project/forms/organizer.py:28
#: project/templates/_macros.html:288
#: project/templates/_macros.html:290
msgid "Phone"
msgstr "Telefon"
#: project/forms/admin_unit.py:50 project/forms/event.py:109
#: project/forms/organizer.py:29 project/templates/_macros.html:296
#: project/forms/organizer.py:29 project/templates/_macros.html:298
msgid "Fax"
msgstr "Fax"
@ -589,16 +607,16 @@ msgstr "Gib an, wann der Termin endet. Ein Termin darf maximal 14 Tage dauern."
msgid "All-day"
msgstr "Ganztägig"
#: project/forms/event.py:54 project/templates/_macros.html:1711
#: project/forms/event.py:54 project/templates/_macros.html:1713
#: project/templates/widget/event_suggestion/create.html:240
msgid "Recurring event"
msgstr "Serientermin"
#: project/forms/event.py:61 project/templates/_macros.html:1252
#: project/forms/event.py:61 project/templates/_macros.html:1254
msgid "The start must be before the end."
msgstr "Der Start muss vor dem Ende sein."
#: project/forms/event.py:67 project/templates/_macros.html:1269
#: project/forms/event.py:67 project/templates/_macros.html:1271
msgid "An event can last a maximum of 14 days."
msgstr "Eine Veranstaltung darf maximal 14 Tage dauern."
@ -634,7 +652,7 @@ msgstr "Ticket Link"
msgid "Enter a link where tickets can be purchased."
msgstr "Gib einen Link ein, über den Tickets gekauft werden können."
#: project/forms/event.py:136 project/templates/_macros.html:217
#: project/forms/event.py:136 project/templates/_macros.html:219
msgid "Tags"
msgstr "Stichworte"
@ -687,7 +705,7 @@ msgstr "Anmeldung erforderlich"
msgid "If the participants needs to register for the event."
msgstr "Wenn sich die Teilnehmer für die Veranstaltung anmelden müssen."
#: project/forms/event.py:170 project/templates/_macros.html:249
#: project/forms/event.py:170 project/templates/_macros.html:251
#: project/templates/layout.html:110
msgid "Booked up"
msgstr "Ausgebucht"
@ -773,8 +791,8 @@ msgstr ""
"Wir empfehlen dir, ein Foto für die Veranstaltung hochzuladen. Es macht "
"schon deutlich mehr her, aber es geht natürlich auch ohne."
#: project/forms/event.py:242 project/templates/_macros.html:396
#: project/templates/_macros.html:559
#: project/forms/event.py:242 project/templates/_macros.html:398
#: project/templates/_macros.html:561
msgid "Previous start date"
msgstr "Vorheriges Startdatum"
@ -826,7 +844,7 @@ msgstr "Ungültiger Mitveranstalter."
#: project/forms/event.py:286 project/forms/event.py:295
#: project/forms/event.py:368 project/forms/event_suggestion.py:50
#: project/templates/_macros.html:436 project/templates/_macros.html:599
#: project/templates/_macros.html:438 project/templates/_macros.html:601
#: project/templates/event/create.html:284
#: project/templates/event/update.html:166
#: project/templates/event_place/create.html:31
@ -845,8 +863,8 @@ msgstr "Neuen Ort eingeben"
#: project/forms/event.py:302 project/forms/event.py:311
#: project/forms/event.py:376 project/forms/event.py:439
#: project/forms/event_suggestion.py:60 project/templates/_macros.html:473
#: project/templates/_macros.html:636 project/templates/event/create.html:253
#: project/forms/event_suggestion.py:60 project/templates/_macros.html:475
#: project/templates/_macros.html:638 project/templates/event/create.html:253
#: project/templates/event/update.html:156
#: project/templates/organizer/create.html:27
#: project/templates/organizer/delete.html:13
@ -935,7 +953,7 @@ msgstr "Öffentlicher Status"
msgid "PublicStatus.published"
msgstr "Veröffentlicht"
#: project/forms/event.py:402 project/templates/_macros.html:255
#: project/forms/event.py:402 project/templates/_macros.html:257
msgid "PublicStatus.draft"
msgstr "Entwurf"
@ -948,7 +966,7 @@ msgstr "Wähle den öffentlichen Status der Veranstaltung."
msgid "Update event"
msgstr "Veranstaltung aktualisieren"
#: project/forms/event.py:423 project/templates/_macros.html:1224
#: project/forms/event.py:423 project/templates/_macros.html:1226
#: project/templates/event/actions.html:66
#: project/templates/event/delete.html:6
msgid "Delete event"
@ -969,7 +987,7 @@ msgid "Keyword"
msgstr "Stichwort"
#: project/forms/event.py:436 project/forms/event_date.py:21
#: project/forms/planing.py:19 project/templates/_macros.html:369
#: project/forms/planing.py:19 project/templates/_macros.html:371
msgid "Category"
msgstr "Kategorie"
@ -978,7 +996,7 @@ msgid "Find events"
msgstr "Veranstaltungen finden"
#: project/forms/event_date.py:24 project/forms/planing.py:22
#: project/templates/_macros.html:303
#: project/templates/_macros.html:305
#: project/templates/admin_unit/create.html:38
#: project/templates/admin_unit/update.html:39
#: project/templates/event_place/create.html:40
@ -1125,7 +1143,7 @@ msgid "Weekdays"
msgstr "Wochentage"
#: project/forms/reference.py:11 project/forms/reference_request.py:16
#: project/templates/_macros.html:489 project/templates/_macros.html:652
#: project/templates/_macros.html:491 project/templates/_macros.html:654
#: project/templates/admin_unit/create.html:28
#: project/templates/admin_unit/update.html:29
#: project/templates/layout.html:242
@ -1153,7 +1171,7 @@ msgstr "Anfrage speichern"
msgid "Delete request"
msgstr "Anfrage löschen"
#: project/forms/reference_request.py:28 project/templates/_macros.html:1407
#: project/forms/reference_request.py:28 project/templates/_macros.html:1409
#: project/templates/event_suggestion/review_status.html:18
#: project/templates/reference_request/review_status.html:12
msgid "Review status"
@ -1211,43 +1229,53 @@ msgstr "Erlauben"
msgid "Deny"
msgstr "Ablehnen"
#: project/forms/user.py:9 project/templates/admin/admin.html:31
#: project/templates/admin/newsletter.html:4
#: project/templates/admin/newsletter.html:93
msgid "Newsletter"
msgstr "Newsletter"
#: project/forms/user.py:10
msgid "Information about new features and improvements."
msgstr "Informationen über neue Features und Verbesserungen."
#: project/forms/widgets.py:154
msgid "This field is required."
msgstr "Dieses Feld ist erforderlich."
#: project/templates/_macros.html:147
#: project/templates/_macros.html:149
msgid "Show on Google Maps"
msgstr "Auf Google Maps anzeigen"
#: project/templates/_macros.html:226
#: project/templates/_macros.html:228
msgid "Link"
msgstr "Link"
#: project/templates/_macros.html:282
#: project/templates/_macros.html:284
msgid "Verified"
msgstr "Verifiziert"
#: project/templates/_macros.html:346
#: project/templates/_macros.html:348
#, python-format
msgid "Created at %(created_at)s by %(created_by)s."
msgstr "Erstellt am %(created_at)s von %(created_by)s."
#: project/templates/_macros.html:348
#: project/templates/_macros.html:350
#, python-format
msgid "Created at %(created_at)s."
msgstr "Erstellt am %(created_at)s."
#: project/templates/_macros.html:353
#: project/templates/_macros.html:355
#, python-format
msgid "Last updated at %(updated_at)s by %(updated_by)s."
msgstr "Zuletzt aktualisiert am %(updated_at)s von %(updated_by)s."
#: project/templates/_macros.html:355
#: project/templates/_macros.html:357
#, python-format
msgid "Last updated at %(updated_at)s."
msgstr "Zuletzt aktualisiert am %(updated_at)s."
#: project/templates/_macros.html:385 project/templates/_macros.html:555
#: project/templates/_macros.html:387 project/templates/_macros.html:557
#: project/templates/event/actions.html:25
#: project/templates/event/create.html:230
#: project/templates/event/update.html:122
@ -1255,65 +1283,65 @@ msgstr "Zuletzt aktualisiert am %(updated_at)s."
msgid "Event"
msgstr "Veranstaltung"
#: project/templates/_macros.html:391 project/templates/_macros.html:920
#: project/templates/_macros.html:393 project/templates/_macros.html:922
msgid "Date"
msgstr "Datum"
#: project/templates/_macros.html:418 project/templates/_macros.html:577
#: project/templates/_macros.html:1476 project/templates/event/actions.html:51
#: project/templates/_macros.html:420 project/templates/_macros.html:579
#: project/templates/_macros.html:1478 project/templates/event/actions.html:51
msgid "Share"
msgstr "Teilen"
#: project/templates/_macros.html:422 project/templates/_macros.html:581
#: project/templates/_macros.html:1506
#: project/templates/_macros.html:424 project/templates/_macros.html:583
#: project/templates/_macros.html:1508
msgid "Add to calendar"
msgstr "Zum Kalender"
#: project/templates/_macros.html:430 project/templates/_macros.html:592
#: project/templates/_macros.html:432 project/templates/_macros.html:594
#: project/templates/event/report.html:4
msgid "Report event"
msgstr "Veranstaltung melden"
#: project/templates/_macros.html:457 project/templates/_macros.html:618
#: project/templates/_macros.html:459 project/templates/_macros.html:620
msgid "Show directions"
msgstr "Anreise planen"
#: project/templates/_macros.html:462 project/templates/_macros.html:623
#: project/templates/_macros.html:464 project/templates/_macros.html:625
msgid "The event takes place online."
msgstr "Die Veranstaltung findet online statt."
#: project/templates/_macros.html:464 project/templates/_macros.html:625
#: project/templates/_macros.html:466 project/templates/_macros.html:627
msgid "The event takes place both offline and online."
msgstr ""
"Die Veranstaltung findet sowohl als Präsenzveranstaltung als auch online "
"statt."
#: project/templates/_macros.html:585 project/templates/layout.html:168
#: project/templates/_macros.html:587 project/templates/layout.html:168
#: project/templates/user/favorite_events.html:4
msgid "Favorite events"
msgstr "Merkzettel"
#: project/templates/_macros.html:679 project/templates/event_date/list.html:5
#: project/templates/_macros.html:681 project/templates/event_date/list.html:5
#: project/templates/event_date/list.html:299
#: project/templates/reference_request/review.html:32
msgid "Event Dates"
msgstr "Termine"
#: project/templates/_macros.html:771
#: project/templates/_macros.html:773
msgid "Search location on Google"
msgstr "Ort bei Google suchen"
#: project/templates/_macros.html:837
#: project/templates/_macros.html:839
#, python-format
msgid "%(count)d event dates"
msgstr "%(count)d Termine"
#: project/templates/_macros.html:860 project/templates/_macros.html:862
#: project/templates/_macros.html:862 project/templates/_macros.html:864
#: project/templates/event_date/list.html:321
msgid "First"
msgstr "Letzte"
#: project/templates/_macros.html:865 project/templates/_macros.html:867
#: project/templates/_macros.html:867 project/templates/_macros.html:869
#: project/templates/event_date/list.html:322
#: project/templates/widget/event_suggestion/create.html:193
#: project/templates/widget/event_suggestion/create.html:218
@ -1324,12 +1352,12 @@ msgstr "Letzte"
msgid "Previous"
msgstr "Zurück"
#: project/templates/_macros.html:869
#: project/templates/_macros.html:871
#, python-format
msgid "Page %(page)d of %(pages)d (%(total)d total)"
msgstr "Seite %(page)d von %(pages)d (%(total)d insgesamt)"
#: project/templates/_macros.html:871 project/templates/_macros.html:873
#: project/templates/_macros.html:873 project/templates/_macros.html:875
#: project/templates/event_date/list.html:324
#: project/templates/widget/event_suggestion/create.html:194
#: project/templates/widget/event_suggestion/create.html:219
@ -1339,88 +1367,88 @@ msgstr "Seite %(page)d von %(pages)d (%(total)d insgesamt)"
msgid "Next"
msgstr "Weiter"
#: project/templates/_macros.html:876 project/templates/_macros.html:878
#: project/templates/_macros.html:878 project/templates/_macros.html:880
#: project/templates/event_date/list.html:325
msgid "Last"
msgstr "Erste"
#: project/templates/_macros.html:943
#: project/templates/_macros.html:945
msgid "Radius"
msgstr "Umkreis"
#: project/templates/_macros.html:1153
#: project/templates/_macros.html:1155
msgid "Edit image"
msgstr "Bild bearbeiten"
#: project/templates/_macros.html:1174
#: project/templates/_macros.html:1176
msgid "Close"
msgstr "Schließen"
#: project/templates/_macros.html:1175
#: project/templates/_macros.html:1177
msgid "Okay"
msgstr "OK"
#: project/templates/_macros.html:1187
#: project/templates/_macros.html:1189
msgid "Choose image file"
msgstr "Bild-Datei auswählen"
#: project/templates/_macros.html:1223 project/templates/event/actions.html:65
#: project/templates/_macros.html:1225 project/templates/event/actions.html:65
#: project/templates/event/delete.html:12
msgid "Edit event"
msgstr "Veranstaltung bearbeiten"
#: project/templates/_macros.html:1226 project/templates/manage/events.html:66
#: project/templates/_macros.html:1228 project/templates/manage/events.html:66
msgid "More"
msgstr "Mehr"
#: project/templates/_macros.html:1273
#: project/templates/_macros.html:1275
msgid "Please enter a valid time, between 00:00 and 23:59."
msgstr "Bitte gib eine gültige Uhrzeit zwischen 00:00 und 23:59 ein."
#: project/templates/_macros.html:1301
#: project/templates/_macros.html:1303
#, python-format
msgid "Just use %(term)s"
msgstr "Verwende einfach %(term)s"
#: project/templates/_macros.html:1367
#: project/templates/_macros.html:1369
msgid "Event suggestion"
msgstr "Veranstaltungsvorschlag"
#: project/templates/_macros.html:1485
#: project/templates/_macros.html:1487
msgid "Link copied"
msgstr "Link kopiert"
#: project/templates/_macros.html:1485
#: project/templates/_macros.html:1487
msgid "Copy link"
msgstr "Link kopieren"
#: project/templates/_macros.html:1514
#: project/templates/_macros.html:1516
msgid "Google calendar"
msgstr "Google Kalender"
#: project/templates/_macros.html:1515
#: project/templates/_macros.html:1517
msgid "Apple calendar"
msgstr "Apple Kalender"
#: project/templates/_macros.html:1516
#: project/templates/_macros.html:1518
msgid "Yahoo calendar"
msgstr "Yahoo Kalender"
#: project/templates/_macros.html:1517
#: project/templates/_macros.html:1519
msgid "Other calendar"
msgstr "Anderer Kalender"
#: project/templates/_macros.html:1712
#: project/templates/_macros.html:1714
msgid "Remove event date"
msgstr "Termin entfernen"
#: project/templates/_macros.html:1741 project/templates/event/create.html:176
#: project/templates/_macros.html:1743 project/templates/event/create.html:176
#: project/templates/event/update.html:99
#: project/templates/widget/event_suggestion/create.html:129
msgid "Enter organizer"
msgstr "Veranstalter eingeben"
#: project/templates/_macros.html:1765
#: project/templates/_macros.html:1767
msgid "Enter list name"
msgstr "Listenname eingeben"
@ -1464,6 +1492,7 @@ msgstr "Profil"
#: project/templates/admin/admin.html:3 project/templates/admin/admin.html:9
#: project/templates/admin/admin_units.html:10
#: project/templates/admin/email.html:65
#: project/templates/admin/newsletter.html:92
#: project/templates/admin/settings.html:10
#: project/templates/admin/users.html:10 project/templates/layout.html:171
msgid "Admin"
@ -1551,8 +1580,7 @@ msgstr "Beziehungen"
msgid "Organization invitations"
msgstr "Organisationseinladungen"
#: project/templates/admin/admin.html:15 project/templates/admin/email.html:4
#: project/templates/admin/email.html:66
#: project/templates/admin/admin.html:15
#: project/templates/admin/settings.html:4
#: project/templates/admin/settings.html:11
#: project/templates/admin_unit/update.html:6
@ -1578,18 +1606,24 @@ msgid "Switch organization"
msgstr "Organisation wechseln"
#: project/templates/developer/read.html:4 project/templates/layout.html:310
#: project/templates/profile.html:29
#: project/templates/profile.html:33
msgid "Developer"
msgstr "Entwickler"
#: project/templates/profile.html:23
#: project/templates/user/notifications.html:4
#: project/templates/user/notifications.html:8
msgid "Notifications"
msgstr "Benachrichtigungen"
#: project/templates/profile.html:27
msgid "Applications"
msgstr "Apps"
#: project/templates/oauth2_client/list.html:4
#: project/templates/oauth2_client/list.html:11
#: project/templates/oauth2_client/read.html:11
#: project/templates/profile.html:33
#: project/templates/profile.html:37
msgid "OAuth2 clients"
msgstr "OAuth2 Clients"
@ -1610,7 +1644,7 @@ msgstr "Benutzer"
msgid "Edit"
msgstr "Bearbeiten"
#: project/templates/admin/email.html:47 project/views/admin.py:119
#: project/templates/admin/email.html:47 project/views/admin.py:122
msgid "Mail sent successfully"
msgstr "Mail erfolgreich gesendet"
@ -1622,6 +1656,10 @@ msgstr "Test-Mail"
msgid "Send test mail asynchronously"
msgstr "Test-Mail asynchron senden"
#: project/templates/admin/newsletter.html:59
msgid "Mails sent successfully"
msgstr "Mails erfolgreich gesendet"
#: project/templates/admin_unit/create.html:58
#: project/templates/admin_unit/update.html:59
#: project/templates/event/create.html:347
@ -1676,6 +1714,10 @@ msgstr "Moin"
msgid "this is a message from %(site_name)s."
msgstr "das ist eine Nachricht von %(site_name)s."
#: project/templates/email/newsletter.html:7
msgid "Notification settings"
msgstr "Benachrichtigungseinstellungen"
#: project/templates/email/organization_invitation_accepted_notice.html:4
#, python-format
msgid ""
@ -2096,20 +2138,26 @@ msgstr "Optionale Details"
msgid "Preview"
msgstr "Vorschau"
#: project/views/admin.py:55
#: project/views/admin.py:58
msgid "Organization successfully updated"
msgstr "Organisation erfolgreich aktualisiert"
#: project/views/admin.py:79 project/views/manage.py:361
#: project/views/admin.py:82 project/views/manage.py:361
#: project/views/user.py:27
msgid "Settings successfully updated"
msgstr "Einstellungen erfolgreich aktualisiert"
#: project/views/admin.py:108
#: project/views/admin.py:111
#, python-format
msgid "Test mail from %(site_name)s"
msgstr "Test-Mail von %(site_name)s"
#: project/views/admin.py:152
#: project/views/admin.py:150
#, python-format
msgid "Newsletter from %(site_name)s"
msgstr "Newsletter von %(site_name)s"
#: project/views/admin.py:200
msgid "User successfully updated"
msgstr "Nutzer erfolgreich aktualisiert"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2023-03-24 21:24+0100\n"
"POT-Creation-Date: 2023-03-28 17:04+0200\n"
"PO-Revision-Date: 2021-04-30 15:04+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n"
@ -209,7 +209,7 @@ msgstr ""
msgid "Legal notice"
msgstr ""
#: project/forms/admin.py:13 project/templates/_macros.html:1395
#: project/forms/admin.py:13 project/templates/_macros.html:1397
#: project/templates/layout.html:302
#: project/templates/widget/event_suggestion/create.html:204
#: project/views/admin_unit.py:73 project/views/root.py:69
@ -226,6 +226,7 @@ msgid "Start page"
msgstr ""
#: project/forms/admin.py:17 project/forms/oauth2_client.py:24
#: project/forms/user.py:13
msgid "Save"
msgstr ""
@ -286,7 +287,7 @@ msgstr ""
msgid "Update organization"
msgstr ""
#: project/forms/admin.py:63
#: project/forms/admin.py:63 project/forms/admin.py:70
msgid "Recipient"
msgstr ""
@ -294,6 +295,22 @@ msgstr ""
msgid "Send test mail synchronously"
msgstr ""
#: project/forms/admin.py:72 project/forms/admin.py:78
msgid "Test recipient"
msgstr ""
#: project/forms/admin.py:73
msgid "All users with enabled newsletter setting"
msgstr ""
#: project/forms/admin.py:79
msgid "Message"
msgstr ""
#: project/forms/admin.py:80
msgid "Send newsletter"
msgstr ""
#: project/forms/admin_unit.py:15 project/forms/event_place.py:12
#: project/forms/organizer.py:12
msgid "Street"
@ -343,7 +360,7 @@ msgstr ""
msgid "The short name is used to create a unique identifier for your events"
msgstr ""
#: project/forms/admin_unit.py:41 project/templates/_macros.html:1531
#: project/forms/admin_unit.py:41 project/templates/_macros.html:1533
msgid "Short name must contain only letters numbers or underscore"
msgstr ""
@ -356,20 +373,21 @@ msgstr ""
#: project/forms/admin_unit.py:48 project/forms/admin_unit_member.py:11
#: project/forms/admin_unit_member.py:23 project/forms/admin_unit_member.py:28
#: project/forms/event.py:107 project/forms/event_suggestion.py:38
#: project/forms/organizer.py:27 project/templates/_macros.html:235
#: project/templates/_macros.html:1491 project/templates/admin/admin.html:27
#: project/forms/organizer.py:27 project/templates/_macros.html:237
#: project/templates/_macros.html:1493 project/templates/admin/admin.html:27
#: project/templates/admin/email.html:4 project/templates/admin/email.html:66
#: project/templates/admin/users.html:19
msgid "Email"
msgstr ""
#: project/forms/admin_unit.py:49 project/forms/event.py:108
#: project/forms/event_suggestion.py:31 project/forms/organizer.py:28
#: project/templates/_macros.html:288
#: project/templates/_macros.html:290
msgid "Phone"
msgstr ""
#: project/forms/admin_unit.py:50 project/forms/event.py:109
#: project/forms/organizer.py:29 project/templates/_macros.html:296
#: project/forms/organizer.py:29 project/templates/_macros.html:298
msgid "Fax"
msgstr ""
@ -567,16 +585,16 @@ msgstr ""
msgid "All-day"
msgstr ""
#: project/forms/event.py:54 project/templates/_macros.html:1711
#: project/forms/event.py:54 project/templates/_macros.html:1713
#: project/templates/widget/event_suggestion/create.html:240
msgid "Recurring event"
msgstr ""
#: project/forms/event.py:61 project/templates/_macros.html:1252
#: project/forms/event.py:61 project/templates/_macros.html:1254
msgid "The start must be before the end."
msgstr ""
#: project/forms/event.py:67 project/templates/_macros.html:1269
#: project/forms/event.py:67 project/templates/_macros.html:1271
msgid "An event can last a maximum of 14 days."
msgstr ""
@ -610,7 +628,7 @@ msgstr ""
msgid "Enter a link where tickets can be purchased."
msgstr ""
#: project/forms/event.py:136 project/templates/_macros.html:217
#: project/forms/event.py:136 project/templates/_macros.html:219
msgid "Tags"
msgstr ""
@ -660,7 +678,7 @@ msgstr ""
msgid "If the participants needs to register for the event."
msgstr ""
#: project/forms/event.py:170 project/templates/_macros.html:249
#: project/forms/event.py:170 project/templates/_macros.html:251
#: project/templates/layout.html:110
msgid "Booked up"
msgstr ""
@ -740,8 +758,8 @@ msgid ""
" course it works without it."
msgstr ""
#: project/forms/event.py:242 project/templates/_macros.html:396
#: project/templates/_macros.html:559
#: project/forms/event.py:242 project/templates/_macros.html:398
#: project/templates/_macros.html:561
msgid "Previous start date"
msgstr ""
@ -787,7 +805,7 @@ msgstr ""
#: project/forms/event.py:286 project/forms/event.py:295
#: project/forms/event.py:368 project/forms/event_suggestion.py:50
#: project/templates/_macros.html:436 project/templates/_macros.html:599
#: project/templates/_macros.html:438 project/templates/_macros.html:601
#: project/templates/event/create.html:284
#: project/templates/event/update.html:166
#: project/templates/event_place/create.html:31
@ -806,8 +824,8 @@ msgstr ""
#: project/forms/event.py:302 project/forms/event.py:311
#: project/forms/event.py:376 project/forms/event.py:439
#: project/forms/event_suggestion.py:60 project/templates/_macros.html:473
#: project/templates/_macros.html:636 project/templates/event/create.html:253
#: project/forms/event_suggestion.py:60 project/templates/_macros.html:475
#: project/templates/_macros.html:638 project/templates/event/create.html:253
#: project/templates/event/update.html:156
#: project/templates/organizer/create.html:27
#: project/templates/organizer/delete.html:13
@ -892,7 +910,7 @@ msgstr ""
msgid "PublicStatus.published"
msgstr ""
#: project/forms/event.py:402 project/templates/_macros.html:255
#: project/forms/event.py:402 project/templates/_macros.html:257
msgid "PublicStatus.draft"
msgstr ""
@ -905,7 +923,7 @@ msgstr ""
msgid "Update event"
msgstr ""
#: project/forms/event.py:423 project/templates/_macros.html:1224
#: project/forms/event.py:423 project/templates/_macros.html:1226
#: project/templates/event/actions.html:66
#: project/templates/event/delete.html:6
msgid "Delete event"
@ -926,7 +944,7 @@ msgid "Keyword"
msgstr ""
#: project/forms/event.py:436 project/forms/event_date.py:21
#: project/forms/planing.py:19 project/templates/_macros.html:369
#: project/forms/planing.py:19 project/templates/_macros.html:371
msgid "Category"
msgstr ""
@ -935,7 +953,7 @@ msgid "Find events"
msgstr ""
#: project/forms/event_date.py:24 project/forms/planing.py:22
#: project/templates/_macros.html:303
#: project/templates/_macros.html:305
#: project/templates/admin_unit/create.html:38
#: project/templates/admin_unit/update.html:39
#: project/templates/event_place/create.html:40
@ -1078,7 +1096,7 @@ msgid "Weekdays"
msgstr ""
#: project/forms/reference.py:11 project/forms/reference_request.py:16
#: project/templates/_macros.html:489 project/templates/_macros.html:652
#: project/templates/_macros.html:491 project/templates/_macros.html:654
#: project/templates/admin_unit/create.html:28
#: project/templates/admin_unit/update.html:29
#: project/templates/layout.html:242
@ -1106,7 +1124,7 @@ msgstr ""
msgid "Delete request"
msgstr ""
#: project/forms/reference_request.py:28 project/templates/_macros.html:1407
#: project/forms/reference_request.py:28 project/templates/_macros.html:1409
#: project/templates/event_suggestion/review_status.html:18
#: project/templates/reference_request/review_status.html:12
msgid "Review status"
@ -1164,43 +1182,53 @@ msgstr ""
msgid "Deny"
msgstr ""
#: project/forms/user.py:9 project/templates/admin/admin.html:31
#: project/templates/admin/newsletter.html:4
#: project/templates/admin/newsletter.html:93
msgid "Newsletter"
msgstr ""
#: project/forms/user.py:10
msgid "Information about new features and improvements."
msgstr ""
#: project/forms/widgets.py:154
msgid "This field is required."
msgstr ""
#: project/templates/_macros.html:147
#: project/templates/_macros.html:149
msgid "Show on Google Maps"
msgstr ""
#: project/templates/_macros.html:226
#: project/templates/_macros.html:228
msgid "Link"
msgstr ""
#: project/templates/_macros.html:282
#: project/templates/_macros.html:284
msgid "Verified"
msgstr ""
#: project/templates/_macros.html:346
#, python-format
msgid "Created at %(created_at)s by %(created_by)s."
msgstr ""
#: project/templates/_macros.html:348
#, python-format
msgid "Created at %(created_at)s."
msgid "Created at %(created_at)s by %(created_by)s."
msgstr ""
#: project/templates/_macros.html:353
#: project/templates/_macros.html:350
#, python-format
msgid "Last updated at %(updated_at)s by %(updated_by)s."
msgid "Created at %(created_at)s."
msgstr ""
#: project/templates/_macros.html:355
#, python-format
msgid "Last updated at %(updated_at)s by %(updated_by)s."
msgstr ""
#: project/templates/_macros.html:357
#, python-format
msgid "Last updated at %(updated_at)s."
msgstr ""
#: project/templates/_macros.html:385 project/templates/_macros.html:555
#: project/templates/_macros.html:387 project/templates/_macros.html:557
#: project/templates/event/actions.html:25
#: project/templates/event/create.html:230
#: project/templates/event/update.html:122
@ -1208,63 +1236,63 @@ msgstr ""
msgid "Event"
msgstr ""
#: project/templates/_macros.html:391 project/templates/_macros.html:920
#: project/templates/_macros.html:393 project/templates/_macros.html:922
msgid "Date"
msgstr ""
#: project/templates/_macros.html:418 project/templates/_macros.html:577
#: project/templates/_macros.html:1476 project/templates/event/actions.html:51
#: project/templates/_macros.html:420 project/templates/_macros.html:579
#: project/templates/_macros.html:1478 project/templates/event/actions.html:51
msgid "Share"
msgstr ""
#: project/templates/_macros.html:422 project/templates/_macros.html:581
#: project/templates/_macros.html:1506
#: project/templates/_macros.html:424 project/templates/_macros.html:583
#: project/templates/_macros.html:1508
msgid "Add to calendar"
msgstr ""
#: project/templates/_macros.html:430 project/templates/_macros.html:592
#: project/templates/_macros.html:432 project/templates/_macros.html:594
#: project/templates/event/report.html:4
msgid "Report event"
msgstr ""
#: project/templates/_macros.html:457 project/templates/_macros.html:618
#: project/templates/_macros.html:459 project/templates/_macros.html:620
msgid "Show directions"
msgstr ""
#: project/templates/_macros.html:462 project/templates/_macros.html:623
#: project/templates/_macros.html:464 project/templates/_macros.html:625
msgid "The event takes place online."
msgstr ""
#: project/templates/_macros.html:464 project/templates/_macros.html:625
#: project/templates/_macros.html:466 project/templates/_macros.html:627
msgid "The event takes place both offline and online."
msgstr ""
#: project/templates/_macros.html:585 project/templates/layout.html:168
#: project/templates/_macros.html:587 project/templates/layout.html:168
#: project/templates/user/favorite_events.html:4
msgid "Favorite events"
msgstr ""
#: project/templates/_macros.html:679 project/templates/event_date/list.html:5
#: project/templates/_macros.html:681 project/templates/event_date/list.html:5
#: project/templates/event_date/list.html:299
#: project/templates/reference_request/review.html:32
msgid "Event Dates"
msgstr ""
#: project/templates/_macros.html:771
#: project/templates/_macros.html:773
msgid "Search location on Google"
msgstr ""
#: project/templates/_macros.html:837
#: project/templates/_macros.html:839
#, python-format
msgid "%(count)d event dates"
msgstr ""
#: project/templates/_macros.html:860 project/templates/_macros.html:862
#: project/templates/_macros.html:862 project/templates/_macros.html:864
#: project/templates/event_date/list.html:321
msgid "First"
msgstr ""
#: project/templates/_macros.html:865 project/templates/_macros.html:867
#: project/templates/_macros.html:867 project/templates/_macros.html:869
#: project/templates/event_date/list.html:322
#: project/templates/widget/event_suggestion/create.html:193
#: project/templates/widget/event_suggestion/create.html:218
@ -1275,12 +1303,12 @@ msgstr ""
msgid "Previous"
msgstr ""
#: project/templates/_macros.html:869
#: project/templates/_macros.html:871
#, python-format
msgid "Page %(page)d of %(pages)d (%(total)d total)"
msgstr ""
#: project/templates/_macros.html:871 project/templates/_macros.html:873
#: project/templates/_macros.html:873 project/templates/_macros.html:875
#: project/templates/event_date/list.html:324
#: project/templates/widget/event_suggestion/create.html:194
#: project/templates/widget/event_suggestion/create.html:219
@ -1290,88 +1318,88 @@ msgstr ""
msgid "Next"
msgstr ""
#: project/templates/_macros.html:876 project/templates/_macros.html:878
#: project/templates/_macros.html:878 project/templates/_macros.html:880
#: project/templates/event_date/list.html:325
msgid "Last"
msgstr ""
#: project/templates/_macros.html:943
#: project/templates/_macros.html:945
msgid "Radius"
msgstr ""
#: project/templates/_macros.html:1153
#: project/templates/_macros.html:1155
msgid "Edit image"
msgstr ""
#: project/templates/_macros.html:1174
#: project/templates/_macros.html:1176
msgid "Close"
msgstr ""
#: project/templates/_macros.html:1175
#: project/templates/_macros.html:1177
msgid "Okay"
msgstr ""
#: project/templates/_macros.html:1187
#: project/templates/_macros.html:1189
msgid "Choose image file"
msgstr ""
#: project/templates/_macros.html:1223 project/templates/event/actions.html:65
#: project/templates/_macros.html:1225 project/templates/event/actions.html:65
#: project/templates/event/delete.html:12
msgid "Edit event"
msgstr ""
#: project/templates/_macros.html:1226 project/templates/manage/events.html:66
#: project/templates/_macros.html:1228 project/templates/manage/events.html:66
msgid "More"
msgstr ""
#: project/templates/_macros.html:1273
#: project/templates/_macros.html:1275
msgid "Please enter a valid time, between 00:00 and 23:59."
msgstr ""
#: project/templates/_macros.html:1301
#: project/templates/_macros.html:1303
#, python-format
msgid "Just use %(term)s"
msgstr ""
#: project/templates/_macros.html:1367
#: project/templates/_macros.html:1369
msgid "Event suggestion"
msgstr ""
#: project/templates/_macros.html:1485
#: project/templates/_macros.html:1487
msgid "Link copied"
msgstr ""
#: project/templates/_macros.html:1485
#: project/templates/_macros.html:1487
msgid "Copy link"
msgstr ""
#: project/templates/_macros.html:1514
#: project/templates/_macros.html:1516
msgid "Google calendar"
msgstr ""
#: project/templates/_macros.html:1515
#: project/templates/_macros.html:1517
msgid "Apple calendar"
msgstr ""
#: project/templates/_macros.html:1516
#: project/templates/_macros.html:1518
msgid "Yahoo calendar"
msgstr ""
#: project/templates/_macros.html:1517
#: project/templates/_macros.html:1519
msgid "Other calendar"
msgstr ""
#: project/templates/_macros.html:1712
#: project/templates/_macros.html:1714
msgid "Remove event date"
msgstr ""
#: project/templates/_macros.html:1741 project/templates/event/create.html:176
#: project/templates/_macros.html:1743 project/templates/event/create.html:176
#: project/templates/event/update.html:99
#: project/templates/widget/event_suggestion/create.html:129
msgid "Enter organizer"
msgstr ""
#: project/templates/_macros.html:1765
#: project/templates/_macros.html:1767
msgid "Enter list name"
msgstr ""
@ -1415,6 +1443,7 @@ msgstr ""
#: project/templates/admin/admin.html:3 project/templates/admin/admin.html:9
#: project/templates/admin/admin_units.html:10
#: project/templates/admin/email.html:65
#: project/templates/admin/newsletter.html:92
#: project/templates/admin/settings.html:10
#: project/templates/admin/users.html:10 project/templates/layout.html:171
msgid "Admin"
@ -1502,8 +1531,7 @@ msgstr ""
msgid "Organization invitations"
msgstr ""
#: project/templates/admin/admin.html:15 project/templates/admin/email.html:4
#: project/templates/admin/email.html:66
#: project/templates/admin/admin.html:15
#: project/templates/admin/settings.html:4
#: project/templates/admin/settings.html:11
#: project/templates/admin_unit/update.html:6
@ -1529,18 +1557,24 @@ msgid "Switch organization"
msgstr ""
#: project/templates/developer/read.html:4 project/templates/layout.html:310
#: project/templates/profile.html:29
#: project/templates/profile.html:33
msgid "Developer"
msgstr ""
#: project/templates/profile.html:23
#: project/templates/user/notifications.html:4
#: project/templates/user/notifications.html:8
msgid "Notifications"
msgstr ""
#: project/templates/profile.html:27
msgid "Applications"
msgstr ""
#: project/templates/oauth2_client/list.html:4
#: project/templates/oauth2_client/list.html:11
#: project/templates/oauth2_client/read.html:11
#: project/templates/profile.html:33
#: project/templates/profile.html:37
msgid "OAuth2 clients"
msgstr ""
@ -1561,7 +1595,7 @@ msgstr ""
msgid "Edit"
msgstr ""
#: project/templates/admin/email.html:47 project/views/admin.py:119
#: project/templates/admin/email.html:47 project/views/admin.py:122
msgid "Mail sent successfully"
msgstr ""
@ -1573,6 +1607,10 @@ msgstr ""
msgid "Send test mail asynchronously"
msgstr ""
#: project/templates/admin/newsletter.html:59
msgid "Mails sent successfully"
msgstr ""
#: project/templates/admin_unit/create.html:58
#: project/templates/admin_unit/update.html:59
#: project/templates/event/create.html:347
@ -1627,6 +1665,10 @@ msgstr ""
msgid "this is a message from %(site_name)s."
msgstr ""
#: project/templates/email/newsletter.html:7
msgid "Notification settings"
msgstr ""
#: project/templates/email/organization_invitation_accepted_notice.html:4
#, python-format
msgid ""
@ -2036,20 +2078,26 @@ msgstr ""
msgid "Preview"
msgstr ""
#: project/views/admin.py:55
#: project/views/admin.py:58
msgid "Organization successfully updated"
msgstr ""
#: project/views/admin.py:79 project/views/manage.py:361
#: project/views/admin.py:82 project/views/manage.py:361
#: project/views/user.py:27
msgid "Settings successfully updated"
msgstr ""
#: project/views/admin.py:108
#: project/views/admin.py:111
#, python-format
msgid "Test mail from %(site_name)s"
msgstr ""
#: project/views/admin.py:152
#: project/views/admin.py:150
#, python-format
msgid "Newsletter from %(site_name)s"
msgstr ""
#: project/views/admin.py:200
msgid "User successfully updated"
msgstr ""

View File

@ -1,3 +1,4 @@
from celery import group
from flask import flash, redirect, render_template, request, url_for
from flask_babelex import gettext
from flask_security import roles_required
@ -7,6 +8,7 @@ from sqlalchemy.sql import func
from project import app, celery, db
from project.base_tasks import send_mail_task
from project.forms.admin import (
AdminNewsletterForm,
AdminSettingsForm,
AdminTestEmailForm,
UpdateAdminUnitForm,
@ -125,6 +127,51 @@ def admin_email():
return render_template("admin/email.html", form=form)
@app.route("/admin/newsletter", methods=["GET", "POST"])
@roles_required("admin")
def admin_newsletter():
form = AdminNewsletterForm()
if "poll" in request.args: # pragma: no cover
try:
result = celery.GroupResult.restore(request.args["poll"])
ready = result.ready()
return {
"ready": ready,
"count": len(result.children),
"completed": result.completed_count(),
"successful": result.successful() if ready else None,
}
except Exception as e:
return {"ready": True, "successful": False, "error": str(e)}
if form.validate_on_submit():
subject = gettext(
"Newsletter from %(site_name)s",
site_name=app.config["SITE_NAME"],
)
if form.recipient_choice.data == 1: # pragma: no cover
recipients = [form.test_recipient.data]
else:
users = (
User.query.filter(User.email != None)
.filter(User.confirmed_at != None)
.filter(User.newsletter_enabled)
.all()
)
recipients = [u.email for u in users]
result = group(
send_mail_task.s(r, subject, "newsletter", message=form.message.data)
for r in recipients
).delay()
result.save()
return {"result_id": result.id}
return render_template("admin/newsletter.html", form=form)
@app.route("/admin/users")
@roles_required("admin")
def admin_users():

View File

@ -1,9 +1,12 @@
from flask import render_template
from flask_security import auth_required
from flask import flash, redirect, render_template, url_for
from flask_babelex import gettext
from flask_security import auth_required, current_user
from sqlalchemy.exc import SQLAlchemyError
from project import app
from project.models import AdminUnitInvitation
from project.views.utils import get_invitation_access_result
from project import app, db
from project.forms.user import NotificationForm
from project.models import AdminUnitInvitation, User
from project.views.utils import get_invitation_access_result, handleSqlError
@app.route("/profile")
@ -12,6 +15,25 @@ def profile():
return render_template("profile.html")
@app.route("/user/notifications", methods=("GET", "POST"))
@auth_required()
def user_notifications():
user = User.query.get_or_404(current_user.id)
form = NotificationForm(obj=user)
if form.validate_on_submit():
try:
form.populate_obj(user)
db.session.commit()
flash(gettext("Settings successfully updated"), "success")
return redirect(url_for("profile"))
except SQLAlchemyError as e: # pragma: no cover
db.session.rollback()
flash(handleSqlError(e), "danger")
return render_template("user/notifications.html", form=form)
@app.route("/user/organization-invitations/<int:id>")
def user_organization_invitation(id):
invitation = AdminUnitInvitation.query.get_or_404(id)

View File

@ -14,6 +14,7 @@ def pytest_generate_tests(metafunc):
os.environ["DATABASE_URL"] = os.environ.get(
"TEST_DATABASE_URL", "postgresql://postgres@localhost/eventcally_tests"
)
os.environ["REDIS_URL"] = os.environ.get("TEST_REDIS_URL", "redis://")
os.environ["AUTHLIB_INSECURE_TRANSPORT"] = "1"
os.environ[
"JWT_PRIVATE_KEY"

View File

@ -79,6 +79,28 @@ def test_admin_email(client, seeder, utils, app, mocker):
utils.assert_send_mail_called(mail_mock, "test@test.de")
def test_newsletter(app, utils, seeder):
user_id, admin_unit_id = seeder.setup_base(True)
for i in range(10):
seeder.create_user(f"test{i}@test.de")
url = utils.get_url("admin_newsletter")
response = utils.get_ok(url)
response = utils.post_form(
url,
response,
{
"recipient_choice": 2,
"message": "Message",
},
)
utils.assert_response_ok(response)
assert "result_id" in response.json
def test_admin_users(client, seeder, utils, app):
seeder.create_user(admin=True)
user = utils.login()

View File

@ -65,3 +65,26 @@ def test_user_favorite_events(client, seeder, utils):
url = utils.get_url("user_favorite_events")
utils.get_ok(url)
def test_user_notifications(client, seeder, utils, app):
user_id, admin_unit_id = seeder.setup_base()
url = utils.get_url("user_notifications")
response = utils.get_ok(url)
response = utils.post_form(
url,
response,
{
"newsletter_enabled": None,
},
)
utils.assert_response_redirect(response, "profile")
with app.app_context():
from project.models import User
place = User.query.get(user_id)
assert not place.newsletter_enabled