From 5178e7384359756a9d5e109e1aeadd8426f7ba04 Mon Sep 17 00:00:00 2001 From: Daniel Grams Date: Fri, 24 Mar 2023 21:45:34 +0100 Subject: [PATCH] Add admin email test page #388 --- .coveragerc | 1 + README.md | 2 +- deployment/docker-compose/docker-compose.yml | 1 + messages.pot | 108 ++++++++++----- project/__init__.py | 15 ++- project/base_tasks.py | 10 ++ project/celery.py | 18 +-- project/forms/admin.py | 9 +- project/jinja_filters.py | 3 + project/templates/admin/admin.html | 4 + project/templates/admin/email.html | 124 ++++++++++++++++++ project/templates/admin/settings.html | 7 +- project/templates/email/test_email.html | 6 + project/templates/email/test_email.txt | 3 + .../translations/de/LC_MESSAGES/messages.mo | Bin 35013 -> 35509 bytes .../translations/de/LC_MESSAGES/messages.po | 108 ++++++++++----- .../translations/en/LC_MESSAGES/messages.mo | Bin 3565 -> 3565 bytes .../translations/en/LC_MESSAGES/messages.po | 108 ++++++++++----- project/views/admin.py | 57 +++++++- project/views/utils.py | 4 +- requirements.txt | 3 +- tests/views/test_admin.py | 19 +++ tests/views/test_app.py | 2 +- 23 files changed, 472 insertions(+), 140 deletions(-) create mode 100644 project/base_tasks.py create mode 100644 project/templates/admin/email.html create mode 100644 project/templates/email/test_email.html create mode 100644 project/templates/email/test_email.txt diff --git a/.coveragerc b/.coveragerc index 166c774..4a530cf 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,6 +1,7 @@ [run] omit = project/celery.py + project/base_tasks.py project/celery_tasks.py project/cli/test.py project/templates/email/* \ No newline at end of file diff --git a/README.md b/README.md index e72a3b7..090ee8f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Open Event Database +# EventCally - Open event calendar ![Tests](https://github.com/eventcally/eventcally/workflows/Tests/badge.svg) [![codecov](https://codecov.io/gh/eventcally/eventcally/branch/main/graph/badge.svg?token=66CLLWWV7Y)](https://codecov.io/gh/eventcally/eventcally) [![Cypress](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/32g194/main&style=flat&logo=cypress)](https://dashboard.cypress.io/projects/32g194/runs) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Docker Pulls](https://img.shields.io/docker/pulls/eventcally/eventcally)](https://hub.docker.com/r/eventcally/eventcally) diff --git a/deployment/docker-compose/docker-compose.yml b/deployment/docker-compose/docker-compose.yml index ce20ce9..12deda4 100644 --- a/deployment/docker-compose/docker-compose.yml +++ b/deployment/docker-compose/docker-compose.yml @@ -24,6 +24,7 @@ x-web-env: JWT_PRIVATE_KEY: ${JWT_PRIVATE_KEY} JWT_PUBLIC_JWKS: ${JWT_PUBLIC_JWKS} DOCS_URL: ${DOCS_URL} + SITE_NAME: ${SITE_NAME} x-web: &default-web diff --git a/messages.pot b/messages.pot index 982956a..3306229 100644 --- a/messages.pot +++ b/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2023-03-16 19:11+0100\n" +"POT-Creation-Date: 2023-03-24 21:24+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -198,93 +198,101 @@ msgstr "" msgid "You have received an invitation" msgstr "" -#: project/forms/admin.py:10 project/templates/layout.html:294 -#: project/views/root.py:57 +#: project/forms/admin.py:11 project/templates/layout.html:294 +#: project/views/root.py:53 msgid "Terms of service" msgstr "" -#: project/forms/admin.py:11 project/templates/layout.html:298 -#: project/views/root.py:65 +#: project/forms/admin.py:12 project/templates/layout.html:298 +#: project/views/root.py:61 msgid "Legal notice" msgstr "" -#: project/forms/admin.py:12 project/templates/_macros.html:1395 +#: project/forms/admin.py:13 project/templates/_macros.html:1395 #: project/templates/layout.html:302 #: project/templates/widget/event_suggestion/create.html:204 -#: project/views/admin_unit.py:73 project/views/root.py:73 +#: project/views/admin_unit.py:73 project/views/root.py:69 msgid "Contact" msgstr "" -#: project/forms/admin.py:13 project/templates/layout.html:306 -#: project/views/root.py:81 +#: project/forms/admin.py:14 project/templates/layout.html:306 +#: project/views/root.py:77 msgid "Privacy" msgstr "" -#: project/forms/admin.py:14 +#: project/forms/admin.py:15 msgid "Start page" msgstr "" -#: project/forms/admin.py:16 project/forms/oauth2_client.py:24 +#: project/forms/admin.py:17 project/forms/oauth2_client.py:24 msgid "Save" msgstr "" -#: project/forms/admin.py:20 project/forms/admin_unit_member.py:12 +#: project/forms/admin.py:21 project/forms/admin_unit_member.py:12 #: project/forms/admin_unit_member.py:32 msgid "Roles" msgstr "" -#: project/forms/admin.py:21 project/templates/admin/update_user.html:4 +#: project/forms/admin.py:22 project/templates/admin/update_user.html:4 #: project/templates/admin/update_user.html:8 msgid "Update user" msgstr "" -#: project/forms/admin.py:26 +#: project/forms/admin.py:27 msgid "Incoming reference requests allowed" msgstr "" -#: project/forms/admin.py:27 +#: project/forms/admin.py:28 msgid "" "If set, other organizations can ask this organization to reference their " "event." msgstr "" -#: project/forms/admin.py:33 +#: project/forms/admin.py:34 msgid "Suggestions enabled" msgstr "" -#: project/forms/admin.py:34 +#: project/forms/admin.py:35 msgid "If set, the organization can work with suggestions." msgstr "" -#: project/forms/admin.py:38 +#: project/forms/admin.py:39 msgid "Create other organizations" msgstr "" -#: project/forms/admin.py:39 +#: project/forms/admin.py:40 msgid "If set, members of the organization can create other organizations." msgstr "" -#: project/forms/admin.py:45 +#: project/forms/admin.py:46 msgid "Invite other organizations" msgstr "" -#: project/forms/admin.py:46 +#: project/forms/admin.py:47 msgid "If set, members of the organization can invite other organizations." msgstr "" -#: project/forms/admin.py:52 +#: project/forms/admin.py:53 msgid "Verify other organizations" msgstr "" -#: project/forms/admin.py:53 +#: project/forms/admin.py:54 msgid "If set, members of the organization can verify other organizations." msgstr "" -#: project/forms/admin.py:58 project/templates/admin/update_admin_unit.html:4 +#: project/forms/admin.py:59 project/templates/admin/update_admin_unit.html:4 #: project/templates/admin/update_admin_unit.html:8 msgid "Update organization" msgstr "" +#: project/forms/admin.py:63 +msgid "Recipient" +msgstr "" + +#: project/forms/admin.py:65 +msgid "Send test mail synchronously" +msgstr "" + #: project/forms/admin_unit.py:15 project/forms/event_place.py:12 #: project/forms/organizer.py:12 msgid "Street" @@ -348,7 +356,8 @@ msgstr "" #: 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/users.html:19 +#: project/templates/_macros.html:1491 project/templates/admin/admin.html:27 +#: project/templates/admin/users.html:19 msgid "Email" msgstr "" @@ -1365,15 +1374,10 @@ msgstr "" msgid "Enter list name" msgstr "" -#: project/templates/home.html:27 +#: project/templates/home.html:24 msgid "Manage" msgstr "" -#: project/templates/home.html:29 project/templates/security/login_user.html:38 -#: project/views/widget.py:159 -msgid "Register for free" -msgstr "" - #: project/templates/layout.html:152 project/templates/layout.html:200 #: project/templates/manage/events.html:6 #: project/templates/manage/events.html:42 @@ -1409,6 +1413,8 @@ 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/settings.html:10 #: project/templates/admin/users.html:10 project/templates/layout.html:171 msgid "Admin" msgstr "" @@ -1495,9 +1501,10 @@ msgstr "" msgid "Organization invitations" msgstr "" -#: project/templates/admin/admin.html:15 +#: project/templates/admin/admin.html:15 project/templates/admin/email.html:4 +#: project/templates/admin/email.html:66 #: project/templates/admin/settings.html:4 -#: project/templates/admin/settings.html:8 +#: project/templates/admin/settings.html:11 #: project/templates/admin_unit/update.html:6 #: project/templates/admin_unit/update.html:23 #: project/templates/layout.html:253 project/templates/manage/widgets.html:11 @@ -1553,6 +1560,18 @@ msgstr "" msgid "Edit" msgstr "" +#: project/templates/admin/email.html:47 project/views/admin.py:119 +msgid "Mail sent successfully" +msgstr "" + +#: project/templates/admin/email.html:103 +msgid "Test mail" +msgstr "" + +#: project/templates/admin/email.html:111 +msgid "Send test mail asynchronously" +msgstr "" + #: project/templates/admin_unit/create.html:58 #: project/templates/admin_unit/update.html:59 #: project/templates/event/create.html:347 @@ -1665,6 +1684,14 @@ msgstr "" msgid "The review status of your event has been updated." msgstr "" +#: project/templates/email/test_email.html:4 +msgid "This is a test mail" +msgstr "" + +#: project/templates/email/test_email.html:5 +msgid "Click here to open the site" +msgstr "" + #: project/templates/event/actions.html:5 #: project/templates/event/actions.html:22 msgid "Actions for event" @@ -1984,6 +2011,10 @@ msgstr "" msgid "You do not have an account yet? Not a problem!" msgstr "" +#: project/templates/security/login_user.html:38 project/views/widget.py:159 +msgid "Register for free" +msgstr "" + #: project/templates/widget/event_date/list.html:5 msgid "Widget" msgstr "" @@ -2004,15 +2035,20 @@ msgstr "" msgid "Preview" msgstr "" -#: project/views/admin.py:44 +#: project/views/admin.py:55 msgid "Organization successfully updated" msgstr "" -#: project/views/admin.py:68 project/views/manage.py:361 +#: project/views/admin.py:79 project/views/manage.py:361 msgid "Settings successfully updated" msgstr "" -#: project/views/admin.py:103 +#: project/views/admin.py:108 +#, python-format +msgid "Test mail from %(site_name)s" +msgstr "" + +#: project/views/admin.py:152 msgid "User successfully updated" msgstr "" diff --git a/project/__init__.py b/project/__init__.py index 503c8d4..a4ac6de 100644 --- a/project/__init__.py +++ b/project/__init__.py @@ -16,10 +16,18 @@ from flask_wtf.csrf import CSRFProtect from project.custom_session_interface import CustomSessionInterface -def getenv_bool(name: str, default: str = "False"): # pragma: no cover +def getenv_bool(name: str, default: str = "False"): return os.getenv(name, default).lower() in ("true", "1", "t") +def set_env_to_app(app: Flask, key: str, default: str = None): + if key in os.environ and os.environ[key]: # pragma: no cover + app.config[key] = os.environ[key] + + if default: + app.config[key] = default + + # Create app app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DATABASE_URL"] @@ -34,7 +42,6 @@ app.config["SECURITY_RECOVERABLE"] = True app.config["SECURITY_CHANGEABLE"] = True app.config["SECURITY_EMAIL_SENDER"] = os.getenv("MAIL_DEFAULT_SENDER") app.config["LANGUAGES"] = ["en", "de"] -app.config["SITE_NAME"] = os.getenv("SITE_NAME", "eventcally") app.config["SERVER_NAME"] = os.getenv("SERVER_NAME") app.config["DOCS_URL"] = os.getenv("DOCS_URL") app.config["ADMIN_UNIT_CREATE_REQUIRES_ADMIN"] = os.getenv( @@ -42,6 +49,7 @@ app.config["ADMIN_UNIT_CREATE_REQUIRES_ADMIN"] = os.getenv( ) app.config["SEO_SITEMAP_PING_GOOGLE"] = getenv_bool("SEO_SITEMAP_PING_GOOGLE", "False") app.config["GOOGLE_MAPS_API_KEY"] = os.getenv("GOOGLE_MAPS_API_KEY") +set_env_to_app(app, "SITE_NAME", "EventCally") # Proxy handling if os.getenv("PREFERRED_URL_SCHEME"): # pragma: no cover @@ -58,11 +66,8 @@ app.config.update( "broker_url": app.config["REDIS_URL"], "result_backend": app.config["REDIS_URL"], "result_expires": timedelta(hours=1), - "broker_pool_limit": None, - "redis_max_connections": 2, "timezone": "Europe/Berlin", "broker_transport_options": { - "max_connections": 2, "queue_order_strategy": "priority", "priority_steps": list(range(3)), "sep": ":", diff --git a/project/base_tasks.py b/project/base_tasks.py new file mode 100644 index 0000000..f29caf7 --- /dev/null +++ b/project/base_tasks.py @@ -0,0 +1,10 @@ +from project import app, celery +from project.views.utils import send_mail + + +@celery.task( + base=getattr(app, "celery_http_task_cls"), + priority=0, +) +def send_mail_task(recipient, subject, template): + send_mail(recipient, subject, template) diff --git a/project/celery.py b/project/celery.py index 980fa30..e4b6a4a 100644 --- a/project/celery.py +++ b/project/celery.py @@ -2,13 +2,8 @@ from smtplib import SMTPException from urllib.error import URLError from celery import Celery -from celery.signals import ( - after_setup_logger, - after_setup_task_logger, - task_postrun, - worker_ready, -) -from celery_singleton import Singleton, clear_locks +from celery import Task as BaseTask +from celery.signals import after_setup_logger, after_setup_task_logger, task_postrun from requests.exceptions import RequestException @@ -19,7 +14,7 @@ class HttpTaskException(Exception): def create_celery(app): celery = Celery(app.import_name) celery.conf.update(app.config["CELERY_CONFIG"]) - TaskBase = Singleton + TaskBase = BaseTask class ContextTask(TaskBase): abstract = True @@ -71,13 +66,6 @@ def setup_task_logger(logger, *args, **kwargs): init_logger_with_one_line_formatter(logger) -@worker_ready.connect -def unlock_all(**kwargs): - from project import celery - - clear_locks(celery) - - @task_postrun.connect def close_session(*args, **kwargs): from project import app diff --git a/project/forms/admin.py b/project/forms/admin.py index 4898be8..e7251f3 100644 --- a/project/forms/admin.py +++ b/project/forms/admin.py @@ -1,7 +1,8 @@ from flask_babelex import lazy_gettext from flask_wtf import FlaskForm from wtforms import BooleanField, SubmitField, TextAreaField -from wtforms.validators import Optional +from wtforms.fields.html5 import EmailField +from wtforms.validators import DataRequired, Optional from project.forms.widgets import MultiCheckboxField @@ -56,3 +57,9 @@ class UpdateAdminUnitForm(FlaskForm): validators=[Optional()], ) submit = SubmitField(lazy_gettext("Update organization")) + + +class AdminTestEmailForm(FlaskForm): + recipient = EmailField(lazy_gettext("Recipient"), validators=[DataRequired()]) + + submit = SubmitField(lazy_gettext("Send test mail synchronously")) diff --git a/project/jinja_filters.py b/project/jinja_filters.py index 5e61af1..484e70f 100644 --- a/project/jinja_filters.py +++ b/project/jinja_filters.py @@ -26,6 +26,9 @@ def any_dict_value_true(data: dict): def ensure_link_scheme(link: str): + if not link: # pragma: no cover + return link + if link.startswith("http://") or link.startswith("https://"): return link diff --git a/project/templates/admin/admin.html b/project/templates/admin/admin.html index 8e096a5..024b0e1 100644 --- a/project/templates/admin/admin.html +++ b/project/templates/admin/admin.html @@ -23,6 +23,10 @@ {{ _('Users') }} + + {{ _('Email') }} + + {% endblock %} \ No newline at end of file diff --git a/project/templates/admin/email.html b/project/templates/admin/email.html new file mode 100644 index 0000000..88ad55c --- /dev/null +++ b/project/templates/admin/email.html @@ -0,0 +1,124 @@ +{% extends "layout.html" %} +{% from "_macros.html" import render_field, render_field_with_errors %} +{%- block title -%} +{{ _('Settings') }} +{%- endblock -%} +{% block header %} + +{% endblock %} +{% block content %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MAIL_SUPPRESS_SEND{{ config["MAIL_SUPPRESS_SEND"] }}
MAIL_SERVER{{ config["MAIL_SERVER"] }}
MAIL_PORT{{ config["MAIL_PORT"] }}
MAIL_USE_TLS{{ config["MAIL_USE_TLS"] }}
MAIL_USE_SSL{{ config["MAIL_USE_SSL"] }}
MAIL_USERNAME{{ config["MAIL_USERNAME"] }}
MAIL_PASSWORD{{ config["MAIL_PASSWORD"] }}
+ +

{{ _('Test mail')}}

+
+ {{ form.hidden_tag() }} + {{ render_field_with_errors(form.recipient) }} + {{ render_field(form.submit) }} +
+ +

+ +

+
+
+ + +
+

+ + + +{% endblock %} \ No newline at end of file diff --git a/project/templates/admin/settings.html b/project/templates/admin/settings.html index f06f06b..00887e4 100644 --- a/project/templates/admin/settings.html +++ b/project/templates/admin/settings.html @@ -5,7 +5,12 @@ {%- endblock -%} {% block content %} -

{{ _('Settings') }}

+
{{ form.hidden_tag() }} diff --git a/project/templates/email/test_email.html b/project/templates/email/test_email.html new file mode 100644 index 0000000..e8a6850 --- /dev/null +++ b/project/templates/email/test_email.html @@ -0,0 +1,6 @@ +{% extends "email/layout.html" %} +{% from "_macros.html" import render_email_button %} +{% block content %} +

{{ _('This is a test mail') }}

+{{ render_email_button(url_for('home', _external=True), _('Click here to open the site')) }} +{% endblock %} \ No newline at end of file diff --git a/project/templates/email/test_email.txt b/project/templates/email/test_email.txt new file mode 100644 index 0000000..8383563 --- /dev/null +++ b/project/templates/email/test_email.txt @@ -0,0 +1,3 @@ +{{ _('This is a test mail') }} +{{ _('Click the link below to open the site') }} +{{ url_for('home', _external=True) }} diff --git a/project/translations/de/LC_MESSAGES/messages.mo b/project/translations/de/LC_MESSAGES/messages.mo index 790319e7146f51d5ed38b20d43acd66ba3041f68..53cabf652821c752223d85b8ee697f434bbe0c09 100644 GIT binary patch delta 8346 zcmZwM3tZRL{m1bmauXB;K@=5!DhMi|A|=Bsilp;ant98V%MS$+NFe9+YhF-Gt#nao z^>?!@UDFYkmsb9lf7?=&+m@|aYHOK$n6B;h=A3GKJpMg=_&n!)zvuQjpYuiS z=wkt|JRaa(hz@+*@ZYB`jOmQ!k*aThB=_1|EiF`j9156(G1M1Gl%`Ar>ze8zOZ)~I?iYN9j@!C@GMqfpPM zBfm@mziA;WQO_SkZDa>(kEb!5`OTjxw5Q=JYQ;fajbW1}9NS%xiA_vUr;?XVC-a1I7zC2HaaQ2ifHA^u8^Cuz{iccUgc z;9hv!)z6{^{scAfb=1ypqIMRNYL6%i^*kPxw27$a*{Gx&?w(IX9qkm)6$()k%twWC zDQf2{u_e~yowyaX1x+h+GzB+6zXD#XvC7I+ZD@h~cK$6fs#DzqQF`rlCt`v#S35v*S0^g@o>Gb1S| znF`&56{sWFhMM>#?1*Pj16)B3(27-Sp-D)SnS_0C1@g=Mg5NUn0&+?wikI1&`GK<- z6LkL{p`fJOgIdUO!=)hyC3n_3nyt9i%qBjyK-=9Pel!wj(Ip3LvbaR;=_0weuXozcYo_z97O#i9D%+p zYq9f1oIv~KEaJ~QW)Pzc!75C`y{P1CLOs8U^f7&Iw<|A3MWzgO#tV_Jt=WR@a6gX6 zgi5bi`J<6EeZeT0h0=cs|NqmnT!+dfamDC+$%1V^A2 zHU<^JsYp=GOw{;~pdz>z^`3Wtf?hm|TG=u8!tb#;X;6{))EV^yJ3uz7UoL8a`Pd4_ zVSAk7+AB~K*1Gy~RK(U;J@XR^TKVhlg`=o}PdHCuEcLV47B4&hiAmHWa_sZ|sD7hS zNje^Njqi1O&Yz-^`zUtR{cob64%blw1P-(lwL*m`9(|aC9dH!tr(%I~6{`R9xD*>v zk?TtaDk6hW_deh0cdo`T<~KViXhnOl6TXf*>vNcfS5Vg_ez4W&?1AyLr#bI%7NU-1 z87gwCQAe^B73l_4QXfQbD1|E&bjImi0oCtD?cm3#4%<;@_#$dy4X9i>irV?_Pz$_( zdjF#HvU`3FqiGLda4jSj)h}%*@z+XoXpp(6kc~p!`-$$wLRYUs?RW)hz-^d-dz|k$ zFC#bBgb%YvmWx{ObkuF}qaw3#m}kG?8)?wlK95SWH!u-Tq89WyDk3*f0|e#T+=xT< zOG32|Mn!T07UBcg8PA~>dL831cDOzAbdQ2UF$lGzAEH7y6BQ9ZD&*y^eFZAi>rh9s z36-=@pvHL`l}o!($$JpB@V8J4JdN7dg-N1XN8k@_>v{m9Q3a|$(HK%V^)cEJ0n=i)f>&uphKnTD&V(B+M^p`V9cs6UJf z;V#sU-*W9IF^KvV)Y*QCx;@_@H`&DJ+sI5tEqppE5@o1}K7i58Zyutcfu2DPw8Pc+ zU@-N4&eu>K-*ok}uKockDZfBvck4Us#NAOxkc#Se8!B?6Q8_goJ2Ss2rqBl;#BSJt z8Q6r1K+93&0d_@w57s*O;aKW_!hV=B+WwTAjRey?hh6a!l6NNjhc=SqQ1g|cH;lqo z3O;-vl?%5}D~=gsf6S(0GWE?EiU&|3{S^k|Db&vXfXbOms3g3JF&M@w6^TStE~TNy z&lyYn)p5LgVHT=hj!C!-HPKHo9A8Ey*&C=M`vWSuE}(XL4Yk1bWR^CPh?-~s>WIc* z3YK6XZW>4Y!zgT_K_Pw?TVddMJ5U5_hjAE!33xm9zzCd)Yq1>pGl;o{8JIG`{$cYT zRQrRd@5w&YI8CUCp7$sOPzbn_zd*KNSEvcL+{ITAkD)@^ZlW=>Fd2ExtifnpixIdL z6_H)21@CqBSFttqU!r#Wwrl^b(`%xj6~BiHajQu-WU;7$dZI$y7Zuuk)J`U#CalE1 zSc}oP6P3gVk*jacqZZ)1+vY+#>L`XI3-`=S3JOIz>g+e8j${XF!ab-7_oF6y7Yi_y zk47IX!{!KJOX|B&JN-E_w|N=0vEX~`(MF@@>5O5z|LN{Qc5?$ObM-Ga30=7f@$VVwfzsFa_TcwQh$Z17(b0XVtzA%LK>D~Pkh4pE9YmZ z2*pmfI~ja|w6H!T3=;~$IhWcVuWY%Fvd;9j%9TCX2|qwha08VKq4(M&i*UxF#`8G`pmJn9Dya+ZCH@L!H4RFV_1F&U zQD?Lpl>@K2=l_S=`6<+n&!f)zB5I+RusMlm+6~2`-tU9jP!4J%lTh;(%_RO>`63!L zv4GcpF*AGIgG(CP&*DTwBPzD>`pxcm0J^C zeJS>!?ro=_0e+3jg%8n(ZP>mRkb(LRs>iwrs z{hxRBJxD*#9HO9(M{R>S>FV#HI$lI|{2OZLH&7FX6IVs1Jt{Iu*csEX3yyZqL2Y0S z>ZmuM=G)xd?(s(^*RZ3xfe!};^1?n;hl8kv97aua9JQb`u72Km5w)<(7>NHs^}po| z@Y{Z&s0Bo+&itm6dys@d)YDNb?vI)<2Q}evRQ8TRW%CTwgf-X_JygF{sB8BSYT-X| z?LSAozYhtbIgFkr=w4z6=#847501y7sGV%WdfbA#4ZY^@b;G&*R))XB2{>@B{qjAG zcTvB9ld*59eXkCOQ2zp(+siorel*lE$^bloIruls#oqJm0_LN>U<)t-H((0>43)fR zFdsidA7+-@T$qFkbrq_8F(%?R=WFG}Ujx2RLpXko3U%;&oBfff=gFx1orhY;6x6`? zqpsZ&48liI8>mMu@Dys?8>sh#D(r?LQS}&)f+kGB)|i4lFbgwrhI_sVbresaIzEjW zcqeK>FJl;iUeq?pW&T8!?so&rl(6 zLJe>kHQ|@o4O>*%pK?j4jf}AVFcaU$5R9m{k!g>* zUY$@2N<@V`8}-4Nh>Bn(Di>-{U(WTYasCH&YhJ*y_%WtoW({@S|5+5YgO^Zeb`aI^ zP1HcgP%Hi;>Wsf|&u^h}Ah6aRMO%!a9*63mhLMl&!_0aum`NYQ9B%q%8`dq<27P?{9ot0sH3=w+EC0w&R;7`UT6op z4Yi|tFd7R{FV>=VR)@WC8)`vsVLyBiAH>!_;+uh+P(OYTp%(mm)I47~gBIETv5Sbm zBG8itnT2sU)YYe;vb+!#(o$6D?#EbMf?C*P7==4g3qOGAcpQ~eH&ElIEw=CHp>klF zM?pKPLxsA*z0id5)Gwh12wY+pGQc?mwSbYRYc&JMpoi*r92J?rAo*rGEVX}X-hgG) zucF5FrY*Dgbpxtn19rp{s9g99>K3nql4(1U1Hs5_!U+SS$jqjo$H6Ywrna#f*@Zmn}OYGKcya^x`T$j+dy z>j$W#`5JpNze!zT|JTYy)J}Kc8a#%#;hkhwf2_m%@DL8fjw|_pfjAjoz; zMVpN}g6((*p2lGqzuFxcc42jyQqo(ff`VM<@G@vYGK)^ zBgsSMP7!v)WvDFQj_Usos{dJJkLJo+;;#n_*4dpd!C>lj7=jxy3m-=%)iKe`|re|2?9ZF%{k#zWZ`f`Ut{N_o)u;~|5Bvnz^yHU8=v-~0mJ zFQ{HrQ8af!WkqFeb@?JQ$^TzZ|LbAnJ9+gjlE3X~?*6vqD_KxE-2of{OIndQsumy?;*ICw&RXjG}+H_1;o-{M-|kylGfDz-d2 zHKy^*l(n%P$7yx`1tpc`a~AkZi{|>~_}N>rzov28{N2G}Bj;C@9C@x{j(O;DHg^4ispsdN8fJ8J!$N}^lFP9-}U^D7yq9f`IbK)7+X;7DX4FCWD delta 7892 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 bTa8qmIu diff --git a/project/translations/de/LC_MESSAGES/messages.po b/project/translations/de/LC_MESSAGES/messages.po index 298f3e4..045c90c 100644 --- a/project/translations/de/LC_MESSAGES/messages.po +++ b/project/translations/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2023-03-16 19:11+0100\n" +"POT-Creation-Date: 2023-03-24 21:24+0100\n" "PO-Revision-Date: 2020-06-07 18:51+0200\n" "Last-Translator: FULL NAME \n" "Language: de\n" @@ -199,51 +199,51 @@ msgstr "message" msgid "You have received an invitation" msgstr "Du hast eine Einladung erhalten" -#: project/forms/admin.py:10 project/templates/layout.html:294 -#: project/views/root.py:57 +#: project/forms/admin.py:11 project/templates/layout.html:294 +#: project/views/root.py:53 msgid "Terms of service" msgstr "Nutzungsbedingungen" -#: project/forms/admin.py:11 project/templates/layout.html:298 -#: project/views/root.py:65 +#: project/forms/admin.py:12 project/templates/layout.html:298 +#: project/views/root.py:61 msgid "Legal notice" msgstr "Impressum" -#: project/forms/admin.py:12 project/templates/_macros.html:1395 +#: project/forms/admin.py:13 project/templates/_macros.html:1395 #: project/templates/layout.html:302 #: project/templates/widget/event_suggestion/create.html:204 -#: project/views/admin_unit.py:73 project/views/root.py:73 +#: project/views/admin_unit.py:73 project/views/root.py:69 msgid "Contact" msgstr "Kontakt" -#: project/forms/admin.py:13 project/templates/layout.html:306 -#: project/views/root.py:81 +#: project/forms/admin.py:14 project/templates/layout.html:306 +#: project/views/root.py:77 msgid "Privacy" msgstr "Datenschutz" -#: project/forms/admin.py:14 +#: project/forms/admin.py:15 msgid "Start page" msgstr "Startseite" -#: project/forms/admin.py:16 project/forms/oauth2_client.py:24 +#: project/forms/admin.py:17 project/forms/oauth2_client.py:24 msgid "Save" msgstr "Speichern" -#: project/forms/admin.py:20 project/forms/admin_unit_member.py:12 +#: project/forms/admin.py:21 project/forms/admin_unit_member.py:12 #: project/forms/admin_unit_member.py:32 msgid "Roles" msgstr "Rollen" -#: project/forms/admin.py:21 project/templates/admin/update_user.html:4 +#: project/forms/admin.py:22 project/templates/admin/update_user.html:4 #: project/templates/admin/update_user.html:8 msgid "Update user" msgstr "Nutzer aktualisieren" -#: project/forms/admin.py:26 +#: project/forms/admin.py:27 msgid "Incoming reference requests allowed" msgstr "Eingehende Empfehlungsanfragen erlauben" -#: project/forms/admin.py:27 +#: project/forms/admin.py:28 msgid "" "If set, other organizations can ask this organization to reference their " "event." @@ -251,49 +251,57 @@ msgstr "" "Wenn gesetzt, können andere Organisationen diese Organisation bitten, " "deren Veranstaltungen zu empfehlen." -#: project/forms/admin.py:33 +#: project/forms/admin.py:34 msgid "Suggestions enabled" msgstr "Vorschläge aktiv" -#: project/forms/admin.py:34 +#: project/forms/admin.py:35 msgid "If set, the organization can work with suggestions." msgstr "Wenn gesetzt, kann die Organisation mit Vorschlägen arbeiten." -#: project/forms/admin.py:38 +#: project/forms/admin.py:39 msgid "Create other organizations" msgstr "Andere Organisationen erstellen" -#: project/forms/admin.py:39 +#: project/forms/admin.py:40 msgid "If set, members of the organization can create other organizations." msgstr "" "Wenn gesetzt, können Mitglieder der Organisation andere Organisationen " "erstellen." -#: project/forms/admin.py:45 +#: project/forms/admin.py:46 msgid "Invite other organizations" msgstr "Andere Organisationen einladen" -#: project/forms/admin.py:46 +#: project/forms/admin.py:47 msgid "If set, members of the organization can invite other organizations." msgstr "" "Wenn gesetzt, können Mitglieder der Organisation andere Organisationen " "einladen." -#: project/forms/admin.py:52 +#: project/forms/admin.py:53 msgid "Verify other organizations" msgstr "Andere Organisationen verifizieren" -#: project/forms/admin.py:53 +#: project/forms/admin.py:54 msgid "If set, members of the organization can verify other organizations." msgstr "" "Wenn gesetzt, können Mitglieder der Organisation andere Organisationen " "verifizieren." -#: project/forms/admin.py:58 project/templates/admin/update_admin_unit.html:4 +#: project/forms/admin.py:59 project/templates/admin/update_admin_unit.html:4 #: project/templates/admin/update_admin_unit.html:8 msgid "Update organization" msgstr "Organisation aktualisieren" +#: project/forms/admin.py:63 +msgid "Recipient" +msgstr "Empfänger" + +#: project/forms/admin.py:65 +msgid "Send test mail synchronously" +msgstr "Test-Mail synchron senden" + #: project/forms/admin_unit.py:15 project/forms/event_place.py:12 #: project/forms/organizer.py:12 msgid "Street" @@ -360,7 +368,8 @@ msgstr "Link URL" #: 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/users.html:19 +#: project/templates/_macros.html:1491 project/templates/admin/admin.html:27 +#: project/templates/admin/users.html:19 msgid "Email" msgstr "Email" @@ -1415,15 +1424,10 @@ msgstr "Veranstalter eingeben" msgid "Enter list name" msgstr "Listenname eingeben" -#: project/templates/home.html:27 +#: project/templates/home.html:24 msgid "Manage" msgstr "Verwaltung" -#: project/templates/home.html:29 project/templates/security/login_user.html:38 -#: project/views/widget.py:159 -msgid "Register for free" -msgstr "Kostenlos registrieren" - #: project/templates/layout.html:152 project/templates/layout.html:200 #: project/templates/manage/events.html:6 #: project/templates/manage/events.html:42 @@ -1459,6 +1463,8 @@ 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/settings.html:10 #: project/templates/admin/users.html:10 project/templates/layout.html:171 msgid "Admin" msgstr "Administration" @@ -1545,9 +1551,10 @@ msgstr "Beziehungen" msgid "Organization invitations" msgstr "Organisationseinladungen" -#: project/templates/admin/admin.html:15 +#: project/templates/admin/admin.html:15 project/templates/admin/email.html:4 +#: project/templates/admin/email.html:66 #: project/templates/admin/settings.html:4 -#: project/templates/admin/settings.html:8 +#: project/templates/admin/settings.html:11 #: project/templates/admin_unit/update.html:6 #: project/templates/admin_unit/update.html:23 #: project/templates/layout.html:253 project/templates/manage/widgets.html:11 @@ -1603,6 +1610,18 @@ msgstr "Benutzer" msgid "Edit" msgstr "Bearbeiten" +#: project/templates/admin/email.html:47 project/views/admin.py:119 +msgid "Mail sent successfully" +msgstr "Mail erfolgreich gesendet" + +#: project/templates/admin/email.html:103 +msgid "Test mail" +msgstr "Test-Mail" + +#: project/templates/admin/email.html:111 +msgid "Send test mail asynchronously" +msgstr "Test-Mail asynchron senden" + #: project/templates/admin_unit/create.html:58 #: project/templates/admin_unit/update.html:59 #: project/templates/event/create.html:347 @@ -1717,6 +1736,14 @@ msgstr "Klicke hier, um den Vorschlag zu prüfen" msgid "The review status of your event has been updated." msgstr "Der Prüfungsstatus deiner Veranstaltung wurde aktualisiert" +#: project/templates/email/test_email.html:4 +msgid "This is a test mail" +msgstr "Das ist eine Test-Mail" + +#: project/templates/email/test_email.html:5 +msgid "Click here to open the site" +msgstr "Klicke hier, um die Seite zu öffnen" + #: project/templates/event/actions.html:5 #: project/templates/event/actions.html:22 msgid "Actions for event" @@ -2045,6 +2072,10 @@ msgstr "Angemeldet bleiben" msgid "You do not have an account yet? Not a problem!" msgstr "Du hast noch keinen Account? Kein Problem!" +#: project/templates/security/login_user.html:38 project/views/widget.py:159 +msgid "Register for free" +msgstr "Kostenlos registrieren" + #: project/templates/widget/event_date/list.html:5 msgid "Widget" msgstr "Widget" @@ -2065,15 +2096,20 @@ msgstr "Optionale Details" msgid "Preview" msgstr "Vorschau" -#: project/views/admin.py:44 +#: project/views/admin.py:55 msgid "Organization successfully updated" msgstr "Organisation erfolgreich aktualisiert" -#: project/views/admin.py:68 project/views/manage.py:361 +#: project/views/admin.py:79 project/views/manage.py:361 msgid "Settings successfully updated" msgstr "Einstellungen erfolgreich aktualisiert" -#: project/views/admin.py:103 +#: project/views/admin.py:108 +#, python-format +msgid "Test mail from %(site_name)s" +msgstr "Test-Mail from %(site_name)s" + +#: project/views/admin.py:152 msgid "User successfully updated" msgstr "Nutzer erfolgreich aktualisiert" diff --git a/project/translations/en/LC_MESSAGES/messages.mo b/project/translations/en/LC_MESSAGES/messages.mo index 2657414dcc95e8f3a948cc99187218805d3a9e12..f1fcd1de63b22f2729b92260be565e04a7704b17 100644 GIT binary patch delta 21 ccmaDW{Z@LzEKUw169pqfD\n" "Language: en\n" @@ -199,93 +199,101 @@ msgstr "" msgid "You have received an invitation" msgstr "" -#: project/forms/admin.py:10 project/templates/layout.html:294 -#: project/views/root.py:57 +#: project/forms/admin.py:11 project/templates/layout.html:294 +#: project/views/root.py:53 msgid "Terms of service" msgstr "" -#: project/forms/admin.py:11 project/templates/layout.html:298 -#: project/views/root.py:65 +#: project/forms/admin.py:12 project/templates/layout.html:298 +#: project/views/root.py:61 msgid "Legal notice" msgstr "" -#: project/forms/admin.py:12 project/templates/_macros.html:1395 +#: project/forms/admin.py:13 project/templates/_macros.html:1395 #: project/templates/layout.html:302 #: project/templates/widget/event_suggestion/create.html:204 -#: project/views/admin_unit.py:73 project/views/root.py:73 +#: project/views/admin_unit.py:73 project/views/root.py:69 msgid "Contact" msgstr "" -#: project/forms/admin.py:13 project/templates/layout.html:306 -#: project/views/root.py:81 +#: project/forms/admin.py:14 project/templates/layout.html:306 +#: project/views/root.py:77 msgid "Privacy" msgstr "" -#: project/forms/admin.py:14 +#: project/forms/admin.py:15 msgid "Start page" msgstr "" -#: project/forms/admin.py:16 project/forms/oauth2_client.py:24 +#: project/forms/admin.py:17 project/forms/oauth2_client.py:24 msgid "Save" msgstr "" -#: project/forms/admin.py:20 project/forms/admin_unit_member.py:12 +#: project/forms/admin.py:21 project/forms/admin_unit_member.py:12 #: project/forms/admin_unit_member.py:32 msgid "Roles" msgstr "" -#: project/forms/admin.py:21 project/templates/admin/update_user.html:4 +#: project/forms/admin.py:22 project/templates/admin/update_user.html:4 #: project/templates/admin/update_user.html:8 msgid "Update user" msgstr "" -#: project/forms/admin.py:26 +#: project/forms/admin.py:27 msgid "Incoming reference requests allowed" msgstr "" -#: project/forms/admin.py:27 +#: project/forms/admin.py:28 msgid "" "If set, other organizations can ask this organization to reference their " "event." msgstr "" -#: project/forms/admin.py:33 +#: project/forms/admin.py:34 msgid "Suggestions enabled" msgstr "" -#: project/forms/admin.py:34 +#: project/forms/admin.py:35 msgid "If set, the organization can work with suggestions." msgstr "" -#: project/forms/admin.py:38 +#: project/forms/admin.py:39 msgid "Create other organizations" msgstr "" -#: project/forms/admin.py:39 +#: project/forms/admin.py:40 msgid "If set, members of the organization can create other organizations." msgstr "" -#: project/forms/admin.py:45 +#: project/forms/admin.py:46 msgid "Invite other organizations" msgstr "" -#: project/forms/admin.py:46 +#: project/forms/admin.py:47 msgid "If set, members of the organization can invite other organizations." msgstr "" -#: project/forms/admin.py:52 +#: project/forms/admin.py:53 msgid "Verify other organizations" msgstr "" -#: project/forms/admin.py:53 +#: project/forms/admin.py:54 msgid "If set, members of the organization can verify other organizations." msgstr "" -#: project/forms/admin.py:58 project/templates/admin/update_admin_unit.html:4 +#: project/forms/admin.py:59 project/templates/admin/update_admin_unit.html:4 #: project/templates/admin/update_admin_unit.html:8 msgid "Update organization" msgstr "" +#: project/forms/admin.py:63 +msgid "Recipient" +msgstr "" + +#: project/forms/admin.py:65 +msgid "Send test mail synchronously" +msgstr "" + #: project/forms/admin_unit.py:15 project/forms/event_place.py:12 #: project/forms/organizer.py:12 msgid "Street" @@ -349,7 +357,8 @@ msgstr "" #: 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/users.html:19 +#: project/templates/_macros.html:1491 project/templates/admin/admin.html:27 +#: project/templates/admin/users.html:19 msgid "Email" msgstr "" @@ -1366,15 +1375,10 @@ msgstr "" msgid "Enter list name" msgstr "" -#: project/templates/home.html:27 +#: project/templates/home.html:24 msgid "Manage" msgstr "" -#: project/templates/home.html:29 project/templates/security/login_user.html:38 -#: project/views/widget.py:159 -msgid "Register for free" -msgstr "" - #: project/templates/layout.html:152 project/templates/layout.html:200 #: project/templates/manage/events.html:6 #: project/templates/manage/events.html:42 @@ -1410,6 +1414,8 @@ 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/settings.html:10 #: project/templates/admin/users.html:10 project/templates/layout.html:171 msgid "Admin" msgstr "" @@ -1496,9 +1502,10 @@ msgstr "" msgid "Organization invitations" msgstr "" -#: project/templates/admin/admin.html:15 +#: project/templates/admin/admin.html:15 project/templates/admin/email.html:4 +#: project/templates/admin/email.html:66 #: project/templates/admin/settings.html:4 -#: project/templates/admin/settings.html:8 +#: project/templates/admin/settings.html:11 #: project/templates/admin_unit/update.html:6 #: project/templates/admin_unit/update.html:23 #: project/templates/layout.html:253 project/templates/manage/widgets.html:11 @@ -1554,6 +1561,18 @@ msgstr "" msgid "Edit" msgstr "" +#: project/templates/admin/email.html:47 project/views/admin.py:119 +msgid "Mail sent successfully" +msgstr "" + +#: project/templates/admin/email.html:103 +msgid "Test mail" +msgstr "" + +#: project/templates/admin/email.html:111 +msgid "Send test mail asynchronously" +msgstr "" + #: project/templates/admin_unit/create.html:58 #: project/templates/admin_unit/update.html:59 #: project/templates/event/create.html:347 @@ -1666,6 +1685,14 @@ msgstr "" msgid "The review status of your event has been updated." msgstr "" +#: project/templates/email/test_email.html:4 +msgid "This is a test mail" +msgstr "" + +#: project/templates/email/test_email.html:5 +msgid "Click here to open the site" +msgstr "" + #: project/templates/event/actions.html:5 #: project/templates/event/actions.html:22 msgid "Actions for event" @@ -1985,6 +2012,10 @@ msgstr "" msgid "You do not have an account yet? Not a problem!" msgstr "" +#: project/templates/security/login_user.html:38 project/views/widget.py:159 +msgid "Register for free" +msgstr "" + #: project/templates/widget/event_date/list.html:5 msgid "Widget" msgstr "" @@ -2005,15 +2036,20 @@ msgstr "" msgid "Preview" msgstr "" -#: project/views/admin.py:44 +#: project/views/admin.py:55 msgid "Organization successfully updated" msgstr "" -#: project/views/admin.py:68 project/views/manage.py:361 +#: project/views/admin.py:79 project/views/manage.py:361 msgid "Settings successfully updated" msgstr "" -#: project/views/admin.py:103 +#: project/views/admin.py:108 +#, python-format +msgid "Test mail from %(site_name)s" +msgstr "" + +#: project/views/admin.py:152 msgid "User successfully updated" msgstr "" diff --git a/project/views/admin.py b/project/views/admin.py index 5482d0f..b31ba16 100644 --- a/project/views/admin.py +++ b/project/views/admin.py @@ -1,15 +1,26 @@ -from flask import flash, redirect, render_template, url_for +from flask import flash, redirect, render_template, request, url_for from flask_babelex import gettext from flask_security import roles_required from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.sql import func -from project import app, db -from project.forms.admin import AdminSettingsForm, UpdateAdminUnitForm, UpdateUserForm +from project import app, celery, db +from project.base_tasks import send_mail_task +from project.forms.admin import ( + AdminSettingsForm, + AdminTestEmailForm, + UpdateAdminUnitForm, + UpdateUserForm, +) from project.models import AdminUnit, Role, User from project.services.admin import upsert_settings from project.services.user import set_roles_for_user -from project.views.utils import flash_errors, get_pagination_urls, handleSqlError +from project.views.utils import ( + flash_errors, + get_pagination_urls, + handleSqlError, + send_mail, +) @app.route("/admin") @@ -76,6 +87,44 @@ def admin_settings(): return render_template("admin/settings.html", form=form) +@app.route("/admin/email", methods=["GET", "POST"]) +@roles_required("admin") +def admin_email(): + form = AdminTestEmailForm() + + if "poll" in request.args: # pragma: no cover + try: + result = celery.AsyncResult(request.args["poll"]) + ready = result.ready() + return { + "ready": ready, + "successful": result.successful() if ready else None, + "value": result.get() if ready else result.result, + } + except Exception as e: + return {"ready": True, "successful": False, "error": str(e)} + + if form.validate_on_submit(): + subject = gettext( + "Test mail from %(site_name)s", + site_name=app.config["SITE_NAME"], + ) + + if "async" in request.args: # pragma: no cover + result = send_mail_task.delay(form.recipient.data, subject, "test_email") + return {"result_id": result.id} + + try: + send_mail(form.recipient.data, subject, "test_email") + flash(gettext("Mail sent successfully"), "success") + except Exception as e: # pragma: no cover + flash(str(e), "danger") + else: # pragma: no cover + flash_errors(form) + + return render_template("admin/email.html", form=form) + + @app.route("/admin/users") @roles_required("admin") def admin_users(): diff --git a/project/views/utils.py b/project/views/utils.py index a68a33d..746a515 100644 --- a/project/views/utils.py +++ b/project/views/utils.py @@ -27,7 +27,7 @@ def get_current_admin_unit(fallback=True): if admin_unit: return admin_unit - if current_user.is_authenticated: + if current_user and current_user.is_authenticated: admin_unit = get_current_admin_unit_from_cookies() if not admin_unit and fallback: @@ -44,7 +44,7 @@ def get_current_admin_unit(fallback=True): def get_current_admin_unit_from_cookies(): try: - if "manage_admin_unit_id" in request.cookies: + if request and request.cookies and "manage_admin_unit_id" in request.cookies: encoded = request.cookies.get("manage_admin_unit_id") manage_admin_unit_id = int(decode_cookie(encoded)) return get_admin_unit_for_manage(manage_admin_unit_id) diff --git a/requirements.txt b/requirements.txt index c21be42..4fdf330 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,6 @@ black==23.1.0 blinker==1.4 cached-property==1.5.2 celery==5.2.7 -celery-singleton==0.3.1 certifi==2020.12.5 cffi==1.14.4 cfgv==3.2.0 @@ -121,7 +120,7 @@ TatSu==4.4.0 toml==0.10.2 tomli==2.0.1 typed-ast==1.5.4 -typing_extensions==4.5.0 +typing-extensions==4.5.0 urllib3==1.26.5 URLObject==2.4.3 validators==0.18.2 diff --git a/tests/views/test_admin.py b/tests/views/test_admin.py index cbcdf4e..058971d 100644 --- a/tests/views/test_admin.py +++ b/tests/views/test_admin.py @@ -60,6 +60,25 @@ def test_admin_settings(client, seeder, utils, app, mocker, db_error): assert settings.privacy == "Mein Datenschutz" +def test_admin_email(client, seeder, utils, app, mocker): + user_id, admin_unit_id = seeder.setup_base(True) + + url = utils.get_url("admin_email") + response = utils.get_ok(url) + + mail_mock = utils.mock_send_mails(mocker) + response = utils.post_form( + url, + response, + { + "recipient": "test@test.de", + }, + ) + + utils.assert_response_ok(response) + utils.assert_send_mail_called(mail_mock, "test@test.de") + + def test_admin_users(client, seeder, utils, app): seeder.create_user(admin=True) user = utils.login() diff --git a/tests/views/test_app.py b/tests/views/test_app.py index 888f824..0f5fc9e 100644 --- a/tests/views/test_app.py +++ b/tests/views/test_app.py @@ -1,3 +1,3 @@ def test_index(client): response = client.get("/") - assert b"eventcally" in response.data + assert b"EventCally" in response.data