Merge branch 'develop' into 'master'

Prod deploy: Fix Ohlhafv emails

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!52
This commit is contained in:
Aarni Halinen
2022-01-13 20:12:13 +00:00
9 changed files with 421 additions and 367 deletions
+77 -66
View File
@@ -24,28 +24,38 @@ from webapp.utils import send_email
def list_view(request, *args, **kwargs): def list_view(request, *args, **kwargs):
"""Kaehmy application list""" """Kaehmy application list"""
role_filter = request.GET.get('role', None) role_filter = request.GET.get("role", None)
if role_filter is not None and str(role_filter) != '-1': if role_filter is not None and str(role_filter) != "-1":
applications = Application.objects.filter(custom_roles__id=role_filter) | Application.objects.filter(preset_roles__id=role_filter) applications = Application.objects.filter(
custom_roles__id=role_filter
) | Application.objects.filter(preset_roles__id=role_filter)
else: else:
applications = Application.objects.all() applications = Application.objects.all()
applications = applications.order_by('-timestamp') applications = applications.order_by("-timestamp")
filter_options_preset = PresetRole.objects.annotate(form_count=Count('forms')).filter(form_count__gt=0) filter_options_preset = PresetRole.objects.annotate(
filter_options_preset_list = [(r.id, r.name, r.form_count) for r in filter_options_preset] form_count=Count("forms")
filter_options_custom = CustomRole.objects.annotate(form_count=Count('forms')).filter(form_count__gt=0) ).filter(form_count__gt=0)
filter_options_custom_list = [(r.id, r.name, r.form_count) for r in filter_options_custom] filter_options_preset_list = [
(r.id, r.name, r.form_count) for r in filter_options_preset
]
filter_options_custom = CustomRole.objects.annotate(
form_count=Count("forms")
).filter(form_count__gt=0)
filter_options_custom_list = [
(r.id, r.name, r.form_count) for r in filter_options_custom
]
filter_options = filter_options_preset_list + filter_options_custom_list filter_options = filter_options_preset_list + filter_options_custom_list
filter_options.sort(key=lambda f: f[1]) filter_options.sort(key=lambda f: f[1])
context = { context = {
'applications': applications, "applications": applications,
'application_count': len(applications), "application_count": len(applications),
'filter_options': filter_options "filter_options": filter_options,
} }
return render(request, 'kaehmy:list.html', context) return render(request, "kaehmy:list.html", context)
@ensure_csrf_cookie @ensure_csrf_cookie
@@ -56,23 +66,21 @@ def comment(request, *args, **kwargs):
form = CommentForm(request.POST) form = CommentForm(request.POST)
if form.is_valid(): if form.is_valid():
comment = form.save() comment = form.save()
email = comment.parent.email
name = comment.name name = comment.name
subject = 'Kaehmyysi tai kommenttiisi on vastattu!' to_email = comment.parent.email
body = (f'{name.capitalize()} on vastannut kaehmyhakemukseesi tai kommenttiisi kaehmypalvelussa.\r\n\r\n' subject = "Kaehmyysi tai kommenttiisi on vastattu!"
'Käy lukemassa viesti osoitteessa https://{URL}/kaehmy') email_body = (
f"{name.capitalize()} on vastannut kaehmyhakemukseesi tai kommenttiisi kaehmypalvelussa.\r\n\r\n"
"Käy lukemassa viesti osoitteessa https://{URL}/kaehmy"
)
send_email(to=to_email, subject=subject, body=email_body)
logging.debug(f"Sent kaehmy comment email to recipient <{to_email}>")
send_email(email, subject, body) return redirect("/kaehmy")
logging.debug(
f'Sent kaehmy comment email to recipient <{email}>')
return redirect('/kaehmy')
else: else:
context = { context = {"error": form.errors}
'error': form.errors return render(request, "kaehmy:error.html", context)
}
return render(request, 'kaehmy:error.html', context)
@require_http_methods(["GET"]) @require_http_methods(["GET"])
@@ -87,24 +95,24 @@ def statistics_view(request, *args, **kwargs):
for preset in preset_roles: for preset in preset_roles:
people = [form.name for form in preset.forms.all()] people = [form.name for form in preset.forms.all()]
role_list.append((preset.name, len(people), ', '.join(people))) role_list.append((preset.name, len(people), ", ".join(people)))
for custom in custom_roles: for custom in custom_roles:
people = [form.name for form in custom.forms.all()] people = [form.name for form in custom.forms.all()]
role_list.append((custom.name, len(people), ', '.join(people))) role_list.append((custom.name, len(people), ", ".join(people)))
context = { context = {
'applications': applications, "applications": applications,
'application_count': len(applications), "application_count": len(applications),
'role_list': role_list "role_list": role_list,
} }
return render(request, 'kaehmy:statistics.html', context) return render(request, "kaehmy:statistics.html", context)
@require_http_methods(["GET"]) @require_http_methods(["GET"])
def view(request, *args, **kwargs): def view(request, *args, **kwargs):
"""Render Kaehmy form page.""" """Render Kaehmy form page."""
form = ApplicationForm() form = ApplicationForm()
return render(request, 'kaehmy:kaehmy.html', {'form': form}) return render(request, "kaehmy:kaehmy.html", {"form": form})
@ensure_csrf_cookie @ensure_csrf_cookie
@@ -114,56 +122,59 @@ def submit(request, *args, **kwargs):
form = ApplicationForm(request.POST) form = ApplicationForm(request.POST)
if form.is_valid(): if form.is_valid():
application = form.save() application = form.save()
custom_name = form.cleaned_data.get('custom_role_name') custom_name = form.cleaned_data.get("custom_role_name")
custom_is_board = form.cleaned_data.get('custom_role_is_board') custom_is_board = form.cleaned_data.get("custom_role_is_board")
if len(custom_name) > 0: if len(custom_name) > 0:
custom_role = CustomRole( custom_role = CustomRole(name=custom_name, is_board=custom_is_board)
name=custom_name, is_board=custom_is_board)
custom_role.save() custom_role.save()
application.custom_roles.add(custom_role) application.custom_roles.add(custom_role)
url = f'https://{URL}/kaehmy' url = f"https://{URL}/kaehmy"
name = form.cleaned_data.get("name", "Anonymous")
email_body = (
f"Moikka {name}!\r\n\r\nHienoa, että kilta kiinnostaa! Kaehmysi on vastaanotettu.\r\n"
"Mahdollisista kommenteista tulee ilmoitus sähköpostitse.\r\n\r\n"
"Käy katsomassa kaehmytilanne osoitteessa {url}"
)
email = form.cleaned_data.get('email', '') to_email = form.cleaned_data.get("email", "")
name = form.cleaned_data.get('name', 'Anonymous') subject = "Arwokas kirjattu kirje mahdolliselle tulewalle kiltahenkilölle"
subject = 'Arwokas kirjattu kirje mahdolliselle tulewalle kiltahenkilölle'
body = ('Moikka {}!\r\n\r\nHienoa, että kilta kiinnostaa! Kaehmysi on vastaanotettu.\r\n'
'Mahdollisista kommenteista tulee ilmoitus sähköpostitse.\r\n\r\n'
'Käy katsomassa kaehmytilanne osoitteessa {}').format(name, url)
send_email(email, subject, body) send_email(to_email, subject, email_body)
logging.debug('Sent kaehmy email to recipient <{}>'.format(email)) logging.debug(f"Sent kaehmy email to recipient <{to_email}>")
CHAT_IDS = [channel.channel_id for channel in TelegramChannel.objects.all()] CHAT_IDS = [channel.channel_id for channel in TelegramChannel.objects.all()]
for chat_id in CHAT_IDS: for chat_id in CHAT_IDS:
tg_string = 'https://api.telegram.org/bot{}/sendMessage?chat_id={}&text={}'.format( tg_string = (
settings.TELEGRAM_BOT_TOKEN, "https://api.telegram.org/bot{}/sendMessage?chat_id={}&text={}".format(
chat_id, settings.TELEGRAM_BOT_TOKEN,
'Uusi New kaehmy! {} -> {}'.format(name, url) chat_id,
"Uusi New kaehmy! {} -> {}".format(name, url),
)
) )
response = requests.get(tg_string).json() response = requests.get(tg_string).json()
logging.debug('Telegram API response:\n{}'.format(response)) logging.debug("Telegram API response:\n{}".format(response))
logging.debug('Sent kaehmy announcement to {} channels.'.format(len(CHAT_IDS))) logging.debug("Sent kaehmy announcement to {} channels.".format(len(CHAT_IDS)))
else: else:
context = { context = {"error": form.errors}
'error': form.errors return render(request, "kaehmy:error.html", context)
} return HttpResponseRedirect("/kaehmy")
return render(request, 'kaehmy:error.html', context)
return HttpResponseRedirect('/kaehmy')
@require_http_methods(['GET']) @require_http_methods(["GET"])
@login_required(login_url='/admin/login') @login_required(login_url="/admin/login")
def export_view(request, *args, **kwargs): def export_view(request, *args, **kwargs):
def make_table(queryset): def make_table(queryset):
table = ExportTable(queryset, table = ExportTable(
request=request, queryset,
exclude=['id'], request=request,
attrs={'class': 'table table-bordered table-hover'}) exclude=["id"],
attrs={"class": "table table-bordered table-hover"},
)
table.paginate(page=request.GET.get('page', 1), per_page=9999) table.paginate(page=request.GET.get("page", 1), per_page=9999)
table_html = convert_table_to_html(table, request) table_html = convert_table_to_html(table, request)
return table_html return table_html
@@ -172,7 +183,7 @@ def export_view(request, *args, **kwargs):
board = filter(lambda q: q.has_any_board_role(), kaehmys) board = filter(lambda q: q.has_any_board_role(), kaehmys)
context = { context = {
'non_board_table': make_table(non_board), "non_board_table": make_table(non_board),
'board_table': make_table(board), "board_table": make_table(board),
} }
return render(request, 'kaehmy:export.html', context) return render(request, "kaehmy:export.html", context)
Binary file not shown.
+56 -64
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-18 21:36+0200\n" "POT-Creation-Date: 2022-01-13 21:55+0200\n"
"PO-Revision-Date: 2017-11-02 23:09+0200\n" "PO-Revision-Date: 2017-11-02 23:09+0200\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
@@ -112,7 +112,7 @@ msgstr "Preview"
msgid "Delete" msgid "Delete"
msgstr "Delete" msgstr "Delete"
#: infoscreen/templates/tabs/add_remove.html:23 kaehmy/models.py:62 #: infoscreen/templates/tabs/add_remove.html:23 kaehmy/models.py:57
#: kaehmy/templates/list.html:36 webapp/models.py:144 webapp/models.py:173 #: kaehmy/templates/list.html:36 webapp/models.py:144 webapp/models.py:173
msgid "Name" msgid "Name"
msgstr "Name" msgstr "Name"
@@ -189,7 +189,7 @@ msgstr "Phone number (not public)"
msgid "Custom roles" msgid "Custom roles"
msgstr "Custom roles" msgstr "Custom roles"
#: kaehmy/forms.py:49 kaehmy/templates/kaehmy.html:43 #: kaehmy/forms.py:49 kaehmy/templates/kaehmy.html:42
msgid "Preset roles" msgid "Preset roles"
msgstr "Preset roles" msgstr "Preset roles"
@@ -201,153 +201,153 @@ msgstr "Invalid phone number"
msgid "Custom role with the same name already exists." msgid "Custom role with the same name already exists."
msgstr "Custom role with the same name already exists." msgstr "Custom role with the same name already exists."
#: kaehmy/models.py:18 #: kaehmy/models.py:13
msgid "Kaehmy" msgid "Kaehmy"
msgstr "Kaehmy" msgstr "Kaehmy"
#: kaehmy/models.py:25 #: kaehmy/models.py:20
msgid "Corporate affairs" msgid "Corporate affairs"
msgstr "Corporate affairs" msgstr "Corporate affairs"
#: kaehmy/models.py:26 webapp/templates/freshmen.html:10 #: kaehmy/models.py:21 webapp/templates/freshmen.html:10
#: webapp/templates/navigation.html:8 #: webapp/templates/navigation.html:8
msgid "Freshmen" msgid "Freshmen"
msgstr "Freshmen" msgstr "Freshmen"
#: kaehmy/models.py:27 webapp/templates/international.html:10 #: kaehmy/models.py:22 webapp/templates/international.html:10
#: webapp/templates/navigation.html:14 #: webapp/templates/navigation.html:14
msgid "International" msgid "International"
msgstr "International" msgstr "International"
#: kaehmy/models.py:28 #: kaehmy/models.py:23
msgid "External affairs" msgid "External affairs"
msgstr "External affairs" msgstr "External affairs"
#: kaehmy/models.py:29 #: kaehmy/models.py:24
msgid "Media" msgid "Media"
msgstr "" msgstr ""
#: kaehmy/models.py:30 #: kaehmy/models.py:25
msgid "Technology" msgid "Technology"
msgstr "" msgstr ""
#: kaehmy/models.py:31 #: kaehmy/models.py:26
msgid "Wellbeing" msgid "Wellbeing"
msgstr "" msgstr ""
#: kaehmy/models.py:32 #: kaehmy/models.py:27
msgid "Elepaja" msgid "Elepaja"
msgstr "" msgstr ""
#: kaehmy/models.py:33 #: kaehmy/models.py:28
msgid "Ceremonies" msgid "Ceremonies"
msgstr "" msgstr ""
#: kaehmy/models.py:34 #: kaehmy/models.py:29
msgid "Studies" msgid "Studies"
msgstr "" msgstr ""
#: kaehmy/models.py:35 #: kaehmy/models.py:30
msgid "Sössö magazine" msgid "Sössö magazine"
msgstr "Sössö magazine" msgstr "Sössö magazine"
#: kaehmy/models.py:36 #: kaehmy/models.py:31
msgid "Alumni relations" msgid "Alumni relations"
msgstr "Alumni relations" msgstr "Alumni relations"
#: kaehmy/models.py:37 #: kaehmy/models.py:32
msgid "Others" msgid "Others"
msgstr "" msgstr ""
#: kaehmy/models.py:39 #: kaehmy/models.py:34
msgid "Category" msgid "Category"
msgstr "" msgstr ""
#: kaehmy/models.py:45 #: kaehmy/models.py:40
msgid "Description" msgid "Description"
msgstr "Description" msgstr "Description"
#: kaehmy/models.py:48 #: kaehmy/models.py:43
msgid "Preset kaehmy role" msgid "Preset kaehmy role"
msgstr "Preset kaehmy role" msgstr "Preset kaehmy role"
#: kaehmy/models.py:49 #: kaehmy/models.py:44
msgid "Preset kaehmy roles" msgid "Preset kaehmy roles"
msgstr "Preset kaehmy roles" msgstr "Preset kaehmy roles"
#: kaehmy/models.py:56 #: kaehmy/models.py:51
msgid "Custom kaehmy role" msgid "Custom kaehmy role"
msgstr "Custom kaehmy role" msgstr "Custom kaehmy role"
#: kaehmy/models.py:57 #: kaehmy/models.py:52
msgid "Custom kaehmy roles" msgid "Custom kaehmy roles"
msgstr "Custom kaehmy roles" msgstr "Custom kaehmy roles"
#: kaehmy/models.py:63 kaehmy/templates/list.html:40 members/models.py:14 #: kaehmy/models.py:58 kaehmy/templates/list.html:40 members/models.py:14
msgid "Email" msgid "Email"
msgstr "Email" msgstr "Email"
#: kaehmy/models.py:64 #: kaehmy/models.py:59
msgid "Timestamp" msgid "Timestamp"
msgstr "" msgstr ""
#: kaehmy/models.py:78 #: kaehmy/models.py:73
msgid "Kaehmykommentti" msgid "Kaehmykommentti"
msgstr "Kaehmy comment" msgstr "Kaehmy comment"
#: kaehmy/models.py:79 #: kaehmy/models.py:74
msgid "Kaehmykommentit" msgid "Kaehmykommentit"
msgstr "Kaehmy comments" msgstr "Kaehmy comments"
#: kaehmy/models.py:81 ohlhafv/models.py:36 #: kaehmy/models.py:76 ohlhafv/models.py:36
msgid "Message" msgid "Message"
msgstr "" msgstr ""
#: kaehmy/models.py:100 kaehmy/templates/kaehmy.html:12 #: kaehmy/models.py:95 kaehmy/templates/kaehmy.html:12
msgid "Kaehmylomake" msgid "Kaehmylomake"
msgstr "Kaehmy application" msgstr "Kaehmy application"
#: kaehmy/models.py:101 #: kaehmy/models.py:96
msgid "Kaehmylomakkeet" msgid "Kaehmylomakkeet"
msgstr "Kaehmy applications" msgstr "Kaehmy applications"
#: kaehmy/models.py:104 #: kaehmy/models.py:99
msgid "Phone number" msgid "Phone number"
msgstr "" msgstr ""
#: kaehmy/models.py:105 #: kaehmy/models.py:100
msgid "Year" msgid "Year"
msgstr "" msgstr ""
#: kaehmy/models.py:106 #: kaehmy/models.py:101
msgid "Text" msgid "Text"
msgstr "" msgstr ""
#: kaehmy/models.py:108 #: kaehmy/models.py:103
msgid "Custom role name" msgid "Custom role name"
msgstr "" msgstr ""
#: kaehmy/models.py:110 webapp/models.py:174 #: kaehmy/models.py:105 webapp/models.py:174
msgid "Board member" msgid "Board member"
msgstr "Board member" msgstr "Board member"
#: kaehmy/models.py:118 #: kaehmy/models.py:113
msgid "Kaehmy application: {}" msgid "Kaehmy application: {}"
msgstr "Kaehmy application: {}" msgstr "Kaehmy application: {}"
#: kaehmy/models.py:140 #: kaehmy/models.py:135
msgid "Board: {}" msgid "Board: {}"
msgstr "" msgstr ""
#: kaehmy/models.py:146 #: kaehmy/models.py:141
msgid "Official: {}" msgid "Official: {}"
msgstr "" msgstr ""
#: kaehmy/models.py:163 #: kaehmy/models.py:158
msgid "Telegram channel" msgid "Telegram channel"
msgstr "" msgstr ""
#: kaehmy/models.py:164 #: kaehmy/models.py:159
msgid "Telegram channels" msgid "Telegram channels"
msgstr "" msgstr ""
@@ -427,31 +427,27 @@ msgid "Päivämääriä & deadlineja"
msgstr "Dates and deadlines" msgstr "Dates and deadlines"
#: kaehmy/templates/kaehmy.html:31 #: kaehmy/templates/kaehmy.html:31
msgid "Hallitustyrkkypaneeli" msgid "Vaalikokous, osa 1 (puheenjohtajan valinta) ja hallitustyrkkypaneeli"
msgstr "Panel for board applicants" msgstr "Election meeting, part 1 (chairman election)"
#: kaehmy/templates/kaehmy.html:32 #: kaehmy/templates/kaehmy.html:32
msgid "Vaalikokous, osa 1 (puheenjohtajan valinta)" msgid "Vaalikokous, osa 2 (hallituksen valinta)"
msgstr "Election meeting, part 1 (chairman election)" msgstr "Election meeting, part 2 (board election)"
#: kaehmy/templates/kaehmy.html:33 #: kaehmy/templates/kaehmy.html:33
msgid "Toimikunta-appro" msgid "Toimikunta-appro"
msgstr "Guild committee crawl" msgstr "Guild committee crawl"
#: kaehmy/templates/kaehmy.html:34 #: kaehmy/templates/kaehmy.html:34
msgid "Vaalikokous, osa 2 (hallituksen valinta)"
msgstr "Election meeting, part 2 (board election)"
#: kaehmy/templates/kaehmy.html:35
msgid "Vaalikokous, osa 3 (toimarien valinta)" msgid "Vaalikokous, osa 3 (toimarien valinta)"
msgstr "Election meeting, part 3 (non-board election)" msgstr "Election meeting, part 3 (non-board election)"
#: kaehmy/templates/kaehmy.html:78 #: kaehmy/templates/kaehmy.html:77
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
" Hyväksyn <a href=\"https://sik.ayy.fi/files/official/" " Hyväksyn <a href=\"https://static.sahkoinsinoorikilta.fi/"
"Tietosuojaseloste%%20%%E2%%80%%93%%20Toimihenkil%%C3%%B6ksi%%20hakemisen" "GDPR/Tietosuojaseloste%%20%%23U2013%%20Toimihenkil%%23U00f6ksi%%20hakemisen"
"%%20rekisteri.pdf\" target=\"_blank\">tietosuojaselosteen</a> ja tietojeni " "%%20rekisteri.pdf\" target=\"_blank\">tietosuojaselosteen</a> ja tietojeni "
"tallentamisen.\n" "tallentamisen.\n"
" " " "
@@ -463,7 +459,7 @@ msgstr ""
"of personal data.\n" "of personal data.\n"
" " " "
#: kaehmy/templates/kaehmy.html:84 members/templates/settings.html:23 #: kaehmy/templates/kaehmy.html:83 members/templates/settings.html:23
msgid "Submit" msgid "Submit"
msgstr "Submit" msgstr "Submit"
@@ -640,11 +636,11 @@ msgstr "Amazing! Your membership application has been sent."
#: members/templates/application_success.html:9 #: members/templates/application_success.html:9
msgid "" msgid ""
"Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä admin@sahkoinsinoorikilta.fi." "Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä "
"fi jos viestiä ei näy." "admin@sahkoinsinoorikilta.fi jos viestiä ei näy."
msgstr "" msgstr ""
"Confirmation email is sent to given email address. Contact admin@sahkoinsinoorikilta.fi." "Confirmation email is sent to given email address. Contact "
"fi if you didn't receive it." "admin@sahkoinsinoorikilta.fi.fi if you didn't receive it."
#: members/templates/application_success.html:10 #: members/templates/application_success.html:10
msgid "Takaisin Sähköinsinöörikillan web-sivuille" msgid "Takaisin Sähköinsinöörikillan web-sivuille"
@@ -914,11 +910,11 @@ msgstr "Payments in register:"
msgid "Language" msgid "Language"
msgstr "Language" msgstr "Language"
#: members/templates/settings.html:20 sikweb/base.py:217 #: members/templates/settings.html:20 sikweb/base.py:216
msgid "Finnish" msgid "Finnish"
msgstr "Finnish" msgstr "Finnish"
#: members/templates/settings.html:21 sikweb/base.py:218 #: members/templates/settings.html:21 sikweb/base.py:217
msgid "English" msgid "English"
msgstr "English" msgstr "English"
@@ -1099,10 +1095,6 @@ msgstr ""
msgid "Challenge" msgid "Challenge"
msgstr "Challenge" msgstr "Challenge"
#: ohlhafv/views.py:44
msgid "Sinut on haastettu Øhlhäfviin!"
msgstr "You have been challenged at Ohlhafv!"
#: templates/admin/base_site.html:44 #: templates/admin/base_site.html:44
msgid "Go" msgid "Go"
msgstr "Go" msgstr "Go"
@@ -1153,11 +1145,11 @@ msgstr ""
msgid "{}Event: {}" msgid "{}Event: {}"
msgstr "" msgstr ""
#: webapp/models.py:91 #: webapp/models.py:90
msgid "Template question" msgid "Template question"
msgstr "" msgstr ""
#: webapp/models.py:92 #: webapp/models.py:91
msgid "Template questions" msgid "Template questions"
msgstr "" msgstr ""
Binary file not shown.
+57 -65
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-18 21:36+0200\n" "POT-Creation-Date: 2022-01-13 21:55+0200\n"
"PO-Revision-Date: 2017-11-02 23:04+0200\n" "PO-Revision-Date: 2017-11-02 23:04+0200\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
@@ -113,7 +113,7 @@ msgstr "Esikatsele"
msgid "Delete" msgid "Delete"
msgstr "Poista" msgstr "Poista"
#: infoscreen/templates/tabs/add_remove.html:23 kaehmy/models.py:62 #: infoscreen/templates/tabs/add_remove.html:23 kaehmy/models.py:57
#: kaehmy/templates/list.html:36 webapp/models.py:144 webapp/models.py:173 #: kaehmy/templates/list.html:36 webapp/models.py:144 webapp/models.py:173
msgid "Name" msgid "Name"
msgstr "Nimi" msgstr "Nimi"
@@ -190,7 +190,7 @@ msgstr "Puhelinnumero (ei julkinen)"
msgid "Custom roles" msgid "Custom roles"
msgstr "Uudet virat" msgstr "Uudet virat"
#: kaehmy/forms.py:49 kaehmy/templates/kaehmy.html:43 #: kaehmy/forms.py:49 kaehmy/templates/kaehmy.html:42
msgid "Preset roles" msgid "Preset roles"
msgstr "Kaehmyvirat" msgstr "Kaehmyvirat"
@@ -202,153 +202,153 @@ msgstr "Virheellinen puhelinnumero"
msgid "Custom role with the same name already exists." msgid "Custom role with the same name already exists."
msgstr "Samanniminen virka on jo olemassa." msgstr "Samanniminen virka on jo olemassa."
#: kaehmy/models.py:18 #: kaehmy/models.py:13
msgid "Kaehmy" msgid "Kaehmy"
msgstr "Kaehmy" msgstr "Kaehmy"
#: kaehmy/models.py:25 #: kaehmy/models.py:20
msgid "Corporate affairs" msgid "Corporate affairs"
msgstr "Yrityssuhteet" msgstr "Yrityssuhteet"
#: kaehmy/models.py:26 webapp/templates/freshmen.html:10 #: kaehmy/models.py:21 webapp/templates/freshmen.html:10
#: webapp/templates/navigation.html:8 #: webapp/templates/navigation.html:8
msgid "Freshmen" msgid "Freshmen"
msgstr "Fuksit" msgstr "Fuksit"
#: kaehmy/models.py:27 webapp/templates/international.html:10 #: kaehmy/models.py:22 webapp/templates/international.html:10
#: webapp/templates/navigation.html:14 #: webapp/templates/navigation.html:14
msgid "International" msgid "International"
msgstr "International" msgstr "International"
#: kaehmy/models.py:28 #: kaehmy/models.py:23
msgid "External affairs" msgid "External affairs"
msgstr "Ulkosuhteet" msgstr "Ulkosuhteet"
#: kaehmy/models.py:29 #: kaehmy/models.py:24
msgid "Media" msgid "Media"
msgstr "Media" msgstr "Media"
#: kaehmy/models.py:30 #: kaehmy/models.py:25
msgid "Technology" msgid "Technology"
msgstr "Teknologia" msgstr "Teknologia"
#: kaehmy/models.py:31 #: kaehmy/models.py:26
msgid "Wellbeing" msgid "Wellbeing"
msgstr "Hyvinvointi" msgstr "Hyvinvointi"
#: kaehmy/models.py:32 #: kaehmy/models.py:27
msgid "Elepaja" msgid "Elepaja"
msgstr "Elepaja" msgstr "Elepaja"
#: kaehmy/models.py:33 #: kaehmy/models.py:28
msgid "Ceremonies" msgid "Ceremonies"
msgstr "Hupitapahtumat" msgstr "Hupitapahtumat"
#: kaehmy/models.py:34 #: kaehmy/models.py:29
msgid "Studies" msgid "Studies"
msgstr "Opinnot" msgstr "Opinnot"
#: kaehmy/models.py:35 #: kaehmy/models.py:30
msgid "Sössö magazine" msgid "Sössö magazine"
msgstr "Kiltalehti Sössö" msgstr "Kiltalehti Sössö"
#: kaehmy/models.py:36 #: kaehmy/models.py:31
msgid "Alumni relations" msgid "Alumni relations"
msgstr "Alumnisuhteet" msgstr "Alumnisuhteet"
#: kaehmy/models.py:37 #: kaehmy/models.py:32
msgid "Others" msgid "Others"
msgstr "Muut" msgstr "Muut"
#: kaehmy/models.py:39 #: kaehmy/models.py:34
msgid "Category" msgid "Category"
msgstr "Kategoria" msgstr "Kategoria"
#: kaehmy/models.py:45 #: kaehmy/models.py:40
msgid "Description" msgid "Description"
msgstr "Kuvaus" msgstr "Kuvaus"
#: kaehmy/models.py:48 #: kaehmy/models.py:43
msgid "Preset kaehmy role" msgid "Preset kaehmy role"
msgstr "Kaehmyvirka" msgstr "Kaehmyvirka"
#: kaehmy/models.py:49 #: kaehmy/models.py:44
msgid "Preset kaehmy roles" msgid "Preset kaehmy roles"
msgstr "Kaehmyvirat" msgstr "Kaehmyvirat"
#: kaehmy/models.py:56 #: kaehmy/models.py:51
msgid "Custom kaehmy role" msgid "Custom kaehmy role"
msgstr "Uusi virka" msgstr "Uusi virka"
#: kaehmy/models.py:57 #: kaehmy/models.py:52
msgid "Custom kaehmy roles" msgid "Custom kaehmy roles"
msgstr "Uudet kaehmyvirat" msgstr "Uudet kaehmyvirat"
#: kaehmy/models.py:63 kaehmy/templates/list.html:40 members/models.py:14 #: kaehmy/models.py:58 kaehmy/templates/list.html:40 members/models.py:14
msgid "Email" msgid "Email"
msgstr "Sähköposti" msgstr "Sähköposti"
#: kaehmy/models.py:64 #: kaehmy/models.py:59
msgid "Timestamp" msgid "Timestamp"
msgstr "Aikaleima" msgstr "Aikaleima"
#: kaehmy/models.py:78 #: kaehmy/models.py:73
msgid "Kaehmykommentti" msgid "Kaehmykommentti"
msgstr "Kaehmykommentti" msgstr "Kaehmykommentti"
#: kaehmy/models.py:79 #: kaehmy/models.py:74
msgid "Kaehmykommentit" msgid "Kaehmykommentit"
msgstr "Kaehmykommentit" msgstr "Kaehmykommentit"
#: kaehmy/models.py:81 ohlhafv/models.py:36 #: kaehmy/models.py:76 ohlhafv/models.py:36
msgid "Message" msgid "Message"
msgstr "Viesti" msgstr "Viesti"
#: kaehmy/models.py:100 kaehmy/templates/kaehmy.html:12 #: kaehmy/models.py:95 kaehmy/templates/kaehmy.html:12
msgid "Kaehmylomake" msgid "Kaehmylomake"
msgstr "Kaehmylomake" msgstr "Kaehmylomake"
#: kaehmy/models.py:101 #: kaehmy/models.py:96
msgid "Kaehmylomakkeet" msgid "Kaehmylomakkeet"
msgstr "Kaehmylomakkeet" msgstr "Kaehmylomakkeet"
#: kaehmy/models.py:104 #: kaehmy/models.py:99
msgid "Phone number" msgid "Phone number"
msgstr "Puhelinnumero" msgstr "Puhelinnumero"
#: kaehmy/models.py:105 #: kaehmy/models.py:100
msgid "Year" msgid "Year"
msgstr "Vuosi" msgstr "Vuosi"
#: kaehmy/models.py:106 #: kaehmy/models.py:101
msgid "Text" msgid "Text"
msgstr "Teksti" msgstr "Teksti"
#: kaehmy/models.py:108 #: kaehmy/models.py:103
msgid "Custom role name" msgid "Custom role name"
msgstr "Uusi virka" msgstr "Uusi virka"
#: kaehmy/models.py:110 webapp/models.py:174 #: kaehmy/models.py:105 webapp/models.py:174
msgid "Board member" msgid "Board member"
msgstr "Hallituksen jäsen" msgstr "Hallituksen jäsen"
#: kaehmy/models.py:118 #: kaehmy/models.py:113
msgid "Kaehmy application: {}" msgid "Kaehmy application: {}"
msgstr "Kaehmy: {}" msgstr "Kaehmy: {}"
#: kaehmy/models.py:140 #: kaehmy/models.py:135
msgid "Board: {}" msgid "Board: {}"
msgstr "Hallitus: {}" msgstr "Hallitus: {}"
#: kaehmy/models.py:146 #: kaehmy/models.py:141
msgid "Official: {}" msgid "Official: {}"
msgstr "Toimari: {}" msgstr "Toimari: {}"
#: kaehmy/models.py:163 #: kaehmy/models.py:158
msgid "Telegram channel" msgid "Telegram channel"
msgstr "Telegram-kanava" msgstr "Telegram-kanava"
#: kaehmy/models.py:164 #: kaehmy/models.py:159
msgid "Telegram channels" msgid "Telegram channels"
msgstr "Telegram-kanavat" msgstr "Telegram-kanavat"
@@ -404,8 +404,8 @@ msgstr ""
" Koska lista ei ole koskaan täydellinen, voit myös ehdottaa ihan " " Koska lista ei ole koskaan täydellinen, voit myös ehdottaa ihan "
"uutta toimenkuvaa.\n" "uutta toimenkuvaa.\n"
" Jos sinulla on kysyttävää mistä tahansa virasta, kannattaa " " Jos sinulla on kysyttävää mistä tahansa virasta, kannattaa "
"konsultoida <a href=\"https://static.sahkoinsinoorikilta.fi/uus_webi/kahmyopas.pdf" "konsultoida <a href=\"https://static.sahkoinsinoorikilta.fi/uus_webi/"
"\">kaehmyopasta</a> \n" "kahmyopas.pdf\">kaehmyopasta</a> \n"
" tai olla yhteydessä kyseistä virkaa tänä vuonna toimittavaan " " tai olla yhteydessä kyseistä virkaa tänä vuonna toimittavaan "
"henkilöön." "henkilöön."
@@ -430,37 +430,33 @@ msgid "Päivämääriä & deadlineja"
msgstr "Päivämääriä & deadlineja" msgstr "Päivämääriä & deadlineja"
#: kaehmy/templates/kaehmy.html:31 #: kaehmy/templates/kaehmy.html:31
msgid "Hallitustyrkkypaneeli" msgid "Vaalikokous, osa 1 (puheenjohtajan valinta) ja hallitustyrkkypaneeli"
msgstr "" msgstr "Vaalikokous, osa 1 (puheenjohtajan valinta) ja hallitustyrkkypaneeli"
#: kaehmy/templates/kaehmy.html:32 #: kaehmy/templates/kaehmy.html:32
msgid "Vaalikokous, osa 1 (puheenjohtajan valinta)" msgid "Vaalikokous, osa 2 (hallituksen valinta)"
msgstr "Vaalikokous, osa 1 (puheenjohtajan valinta)" msgstr "Vaalikokous, osa 2 (hallituksen valinta)"
#: kaehmy/templates/kaehmy.html:33 #: kaehmy/templates/kaehmy.html:33
msgid "Toimikunta-appro" msgid "Toimikunta-appro"
msgstr "" msgstr ""
#: kaehmy/templates/kaehmy.html:34 #: kaehmy/templates/kaehmy.html:34
msgid "Vaalikokous, osa 2 (hallituksen valinta)"
msgstr "Vaalikokous, osa 2 (hallituksen valinta)"
#: kaehmy/templates/kaehmy.html:35
msgid "Vaalikokous, osa 3 (toimarien valinta)" msgid "Vaalikokous, osa 3 (toimarien valinta)"
msgstr "Vaalikokous, osa 3 (toimarien valinta)" msgstr "Vaalikokous, osa 3 (toimarien valinta)"
#: kaehmy/templates/kaehmy.html:78 #: kaehmy/templates/kaehmy.html:77
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
" Hyväksyn <a href=\"https://static.sahkoinsinoorikilta.fi/GDPR/" " Hyväksyn <a href=\"https://static.sahkoinsinoorikilta.fi/"
"Tietosuojaseloste%20%23U2013%20Toimihenkil%23U00f6ksi%20hakemisen" "GDPR/Tietosuojaseloste%%20%%23U2013%%20Toimihenkil%%23U00f6ksi%%20hakemisen"
"%20rekisteri.pdf\" target=\"_blank\">tietosuojaselosteen</a> ja tietojeni " "%%20rekisteri.pdf\" target=\"_blank\">tietosuojaselosteen</a> ja tietojeni "
"tallentamisen.\n" "tallentamisen.\n"
" " " "
msgstr "" msgstr ""
#: kaehmy/templates/kaehmy.html:84 members/templates/settings.html:23 #: kaehmy/templates/kaehmy.html:83 members/templates/settings.html:23
msgid "Submit" msgid "Submit"
msgstr "Lisää" msgstr "Lisää"
@@ -637,8 +633,8 @@ msgstr "Hienoa! Jäsenhakemuksesi on nyt lähetetty."
#: members/templates/application_success.html:9 #: members/templates/application_success.html:9
msgid "" msgid ""
"Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä admin@sahkoinsinoorikilta.fi." "Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä "
"fi jos viestiä ei näy." "admin@sahkoinsinoorikilta.fi jos viestiä ei näy."
msgstr "" msgstr ""
#: members/templates/application_success.html:10 #: members/templates/application_success.html:10
@@ -905,11 +901,11 @@ msgstr "Maksutapahtumia:"
msgid "Language" msgid "Language"
msgstr "Kieli" msgstr "Kieli"
#: members/templates/settings.html:20 sikweb/base.py:217 #: members/templates/settings.html:20 sikweb/base.py:216
msgid "Finnish" msgid "Finnish"
msgstr "suomi" msgstr "suomi"
#: members/templates/settings.html:21 sikweb/base.py:218 #: members/templates/settings.html:21 sikweb/base.py:217
msgid "English" msgid "English"
msgstr "englanti" msgstr "englanti"
@@ -1088,10 +1084,6 @@ msgstr "Haasta kaverisi mittelöön!"
msgid "Challenge" msgid "Challenge"
msgstr "Haasta" msgstr "Haasta"
#: ohlhafv/views.py:44
msgid "Sinut on haastettu Øhlhäfviin!"
msgstr ""
#: templates/admin/base_site.html:44 #: templates/admin/base_site.html:44
msgid "Go" msgid "Go"
msgstr "Vaihda" msgstr "Vaihda"
@@ -1142,11 +1134,11 @@ msgstr "Tapahtuma"
msgid "{}Event: {}" msgid "{}Event: {}"
msgstr "{}Tapahtuma: {}" msgstr "{}Tapahtuma: {}"
#: webapp/models.py:91 #: webapp/models.py:90
msgid "Template question" msgid "Template question"
msgstr "Vakiokysymys" msgstr "Vakiokysymys"
#: webapp/models.py:92 #: webapp/models.py:91
msgid "Template questions" msgid "Template questions"
msgstr "Vakiokysymykset" msgstr "Vakiokysymykset"
+26 -34
View File
@@ -1,33 +1,26 @@
"""Ohlhafv views.""" """Ohlhafv views."""
from django.db.models import Count import logging
from django.shortcuts import render, redirect from django.shortcuts import render
from django.contrib.auth import login, logout, authenticate
from django.views.decorators.http import require_http_methods from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.csrf import ensure_csrf_cookie
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import permission_required, login_required
from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string from django.template.loader import render_to_string
import logging
import requests
from dealer.git import git
from sikweb.settings import URL
from ohlhafv.models import OhlhafvChallenge from ohlhafv.models import OhlhafvChallenge
from ohlhafv.forms import OhlhafvForm from ohlhafv.forms import OhlhafvForm
from ohlhafv.tables import OhlhafvTable
from webapp.utils import send_email
from kaehmy.tgbot import TelegramBot from kaehmy.tgbot import TelegramBot
from webapp.utils import send_email
from sikweb.settings import URL
@require_http_methods(["GET"]) @require_http_methods(["GET"])
def ohlhafv_view(request, *args, **kwargs): def ohlhafv_view(request, *args, **kwargs):
"""Render Ohlhafv form page.""" """Render Ohlhafv form page."""
form = OhlhafvForm() form = OhlhafvForm()
return render(request, 'ohlhafv:new.html', {'form': form}) return render(request, "ohlhafv:new.html", {"form": form})
@ensure_csrf_cookie @ensure_csrf_cookie
@@ -38,34 +31,33 @@ def ohlhafv_submit(request, *args, **kwargs):
if form.is_valid(): if form.is_valid():
form.save() form.save()
challenge = form.instance challenge = form.instance
email = form.cleaned_data.get('victim_email', '') url = f"https://{URL}/ohlhafv/list"
url = f'https://{URL}/ohlhafv/list' email_body = render_to_string(
subject = _('Sinut on haastettu Øhlhäfviin!') "ohlhafv:email.html",
{
message = render_to_string( "challenge": challenge,
'ohlhafv:email.html', { "url": url,
'challenge': challenge, },
'url': url,
}
) )
send_email(email, subject, message)
to_email = form.cleaned_data.get("victim_email", "")
subject = "Sinut on haastettu Øhlhäfviin!"
send_email(to=to_email, subject=subject, body=email_body)
logging.debug(f"Sent ohlhafv email to recipient <{to_email}>")
try: try:
tg_message = render_to_string( tg_message = render_to_string(
'ohlhafv:tgmsg.tpl', { "ohlhafv:tgmsg.tpl", {"challenge": challenge, "url": url}
'challenge': challenge, )
'url': url})
bot = TelegramBot() bot = TelegramBot()
bot.broadcast(tg_message) bot.broadcast(tg_message)
except Exception: # tg spam is not critical. Ignore on failure except Exception: # tg spam is not critical. Ignore on failure
pass pass
logging.debug(
'Sent ohlhafv email to recipient <{}>'.format(email))
else: else:
pass pass
return HttpResponseRedirect('/ohlhafv/list/') return HttpResponseRedirect("/ohlhafv/list/")
@ensure_csrf_cookie @ensure_csrf_cookie
@@ -73,9 +65,9 @@ def ohlhafv_submit(request, *args, **kwargs):
def ohlhafv_list(request, *args, **kwargs): def ohlhafv_list(request, *args, **kwargs):
"""Present Ohlhafv challenges list.""" """Present Ohlhafv challenges list."""
challenges = OhlhafvChallenge.objects.all() challenges = OhlhafvChallenge.objects.all()
challenges = challenges.order_by('-id') challenges = challenges.order_by("-id")
context = { context = {
'challenges': challenges, "challenges": challenges,
'challenge_count': len(challenges), "challenge_count": len(challenges),
} }
return render(request, 'ohlhafv:list.html', context) return render(request, "ohlhafv:list.html", context)
Generated
+152 -103
View File
@@ -1,16 +1,16 @@
[[package]] [[package]]
name = "attrs" name = "attrs"
version = "21.2.0" version = "21.4.0"
description = "Classes Without Boilerplate" description = "Classes Without Boilerplate"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.extras] [package.extras]
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
[[package]] [[package]]
name = "babel" name = "babel"
@@ -25,7 +25,7 @@ pytz = ">=2015.7"
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2021.5.30" version = "2021.10.8"
description = "Python package for providing Mozilla's CA Bundle." description = "Python package for providing Mozilla's CA Bundle."
category = "main" category = "main"
optional = false optional = false
@@ -33,7 +33,7 @@ python-versions = "*"
[[package]] [[package]]
name = "charset-normalizer" name = "charset-normalizer"
version = "2.0.6" version = "2.0.10"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main" category = "main"
optional = false optional = false
@@ -44,7 +44,7 @@ unicode_backport = ["unicodedata2"]
[[package]] [[package]]
name = "click" name = "click"
version = "8.0.1" version = "8.0.3"
description = "Composable command line interface toolkit" description = "Composable command line interface toolkit"
category = "dev" category = "dev"
optional = false optional = false
@@ -98,7 +98,7 @@ python-versions = ">=2.7"
[[package]] [[package]]
name = "django" name = "django"
version = "2.2.24" version = "2.2.26"
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
category = "main" category = "main"
optional = false optional = false
@@ -162,11 +162,11 @@ python-versions = "*"
[[package]] [[package]]
name = "django-cors-headers" name = "django-cors-headers"
version = "3.9.0" version = "3.11.0"
description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
Django = ">=2.2" Django = ">=2.2"
@@ -267,14 +267,15 @@ tablib = ["tablib"]
[[package]] [[package]]
name = "djangorestframework" name = "djangorestframework"
version = "3.12.4" version = "3.13.1"
description = "Web APIs for Django, made easy." description = "Web APIs for Django, made easy."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.6"
[package.dependencies] [package.dependencies]
django = ">=2.2" django = ">=2.2"
pytz = "*"
[[package]] [[package]]
name = "djangorestframework-jwt" name = "djangorestframework-jwt"
@@ -327,12 +328,28 @@ tornado = ["tornado (>=0.2)"]
[[package]] [[package]]
name = "idna" name = "idna"
version = "3.2" version = "3.3"
description = "Internationalized Domain Names in Applications (IDNA)" description = "Internationalized Domain Names in Applications (IDNA)"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
[[package]]
name = "importlib-metadata"
version = "4.10.0"
description = "Read metadata from Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
[package.dependencies]
zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
perf = ["ipython"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
[[package]] [[package]]
name = "jdcal" name = "jdcal"
version = "1.4.1" version = "1.4.1"
@@ -368,12 +385,15 @@ python-versions = "*"
[[package]] [[package]]
name = "markdown" name = "markdown"
version = "3.3.4" version = "3.3.6"
description = "Python implementation of Markdown." description = "Python implementation of Markdown."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
[package.dependencies]
importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
[package.extras] [package.extras]
testing = ["coverage", "pyyaml"] testing = ["coverage", "pyyaml"]
@@ -410,18 +430,18 @@ jdcal = "*"
[[package]] [[package]]
name = "packaging" name = "packaging"
version = "21.0" version = "21.3"
description = "Core utilities for Python packages" description = "Core utilities for Python packages"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
[package.dependencies] [package.dependencies]
pyparsing = ">=2.0.2" pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
[[package]] [[package]]
name = "phonenumbers" name = "phonenumbers"
version = "8.12.33" version = "8.12.41"
description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
category = "main" category = "main"
optional = false optional = false
@@ -445,11 +465,11 @@ python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
[[package]] [[package]]
name = "pycodestyle" name = "pycodestyle"
version = "2.7.0" version = "2.8.0"
description = "Python style guide checker" description = "Python style guide checker"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]] [[package]]
name = "pyexcel" name = "pyexcel"
@@ -471,7 +491,7 @@ xlsx = ["pyexcel-xlsx (>=0.5.0)"]
[[package]] [[package]]
name = "pyexcel-io" name = "pyexcel-io"
version = "0.6.4" version = "0.6.5"
description = "A python library to read and write structured data in csv, zipped csvformat and to/from databases" description = "A python library to read and write structured data in csv, zipped csvformat and to/from databases"
category = "main" category = "main"
optional = false optional = false
@@ -512,11 +532,14 @@ test = ["pytest (>=4.0.1,<5.0.0)", "pytest-cov (>=2.6.0,<3.0.0)", "pytest-runner
[[package]] [[package]]
name = "pyparsing" name = "pyparsing"
version = "2.4.7" version = "3.0.6"
description = "Python parsing module" description = "Python parsing module"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" python-versions = ">=3.6"
[package.extras]
diagrams = ["jinja2", "railroad-diagrams"]
[[package]] [[package]]
name = "pyrsistent" name = "pyrsistent"
@@ -539,7 +562,7 @@ six = ">=1.5"
[[package]] [[package]]
name = "python-http-client" name = "python-http-client"
version = "3.3.3" version = "3.3.4"
description = "HTTP REST client, simplified for Python" description = "HTTP REST client, simplified for Python"
category = "main" category = "main"
optional = false optional = false
@@ -555,15 +578,15 @@ python-versions = "*"
[[package]] [[package]]
name = "pyyaml" name = "pyyaml"
version = "5.4.1" version = "6.0"
description = "YAML parser and emitter for Python" description = "YAML parser and emitter for Python"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" python-versions = ">=3.6"
[[package]] [[package]]
name = "requests" name = "requests"
version = "2.26.0" version = "2.27.1"
description = "Python HTTP for Humans." description = "Python HTTP for Humans."
category = "main" category = "main"
optional = false optional = false
@@ -595,7 +618,7 @@ requests = "*"
[[package]] [[package]]
name = "sendgrid" name = "sendgrid"
version = "6.8.2" version = "6.9.3"
description = "Twilio SendGrid library for Python" description = "Twilio SendGrid library for Python"
category = "main" category = "main"
optional = false optional = false
@@ -603,11 +626,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.dependencies] [package.dependencies]
python-http-client = ">=3.2.1" python-http-client = ">=3.2.1"
starkbank-ecdsa = ">=1.0.0" starkbank-ecdsa = ">=2.0.1"
[[package]] [[package]]
name = "sentry-sdk" name = "sentry-sdk"
version = "1.4.3" version = "1.5.2"
description = "Python client for Sentry (https://sentry.io)" description = "Python client for Sentry (https://sentry.io)"
category = "main" category = "main"
optional = false optional = false
@@ -629,6 +652,7 @@ flask = ["flask (>=0.11)", "blinker (>=1.1)"]
httpx = ["httpx (>=0.16.0)"] httpx = ["httpx (>=0.16.0)"]
pure_eval = ["pure-eval", "executing", "asttokens"] pure_eval = ["pure-eval", "executing", "asttokens"]
pyspark = ["pyspark (>=2.4.4)"] pyspark = ["pyspark (>=2.4.4)"]
quart = ["quart (>=0.16.1)", "blinker (>=1.1)"]
rq = ["rq (>=0.6)"] rq = ["rq (>=0.6)"]
sanic = ["sanic (>=0.8)"] sanic = ["sanic (>=0.8)"]
sqlalchemy = ["sqlalchemy (>=1.2)"] sqlalchemy = ["sqlalchemy (>=1.2)"]
@@ -652,7 +676,7 @@ python-versions = ">=3.5"
[[package]] [[package]]
name = "starkbank-ecdsa" name = "starkbank-ecdsa"
version = "1.1.1" version = "2.0.3"
description = "A lightweight and fast pure python ECDSA library" description = "A lightweight and fast pure python ECDSA library"
category = "main" category = "main"
optional = false optional = false
@@ -660,7 +684,7 @@ python-versions = "*"
[[package]] [[package]]
name = "tablib" name = "tablib"
version = "3.0.0" version = "3.1.0"
description = "Format agnostic tabular data library (XLS, JSON, YAML, CSV)" description = "Format agnostic tabular data library (XLS, JSON, YAML, CSV)"
category = "main" category = "main"
optional = false optional = false
@@ -694,7 +718,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "1.26.7" version = "1.26.8"
description = "HTTP library with thread-safe connection pooling, file post, and more." description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main" category = "main"
optional = false optional = false
@@ -707,7 +731,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]] [[package]]
name = "uwsgi" name = "uwsgi"
version = "2.0.19.1" version = "2.0.20"
description = "The uWSGI server" description = "The uWSGI server"
category = "main" category = "main"
optional = false optional = false
@@ -724,6 +748,18 @@ python-versions = "*"
[package.extras] [package.extras]
brotli = ["brotli"] brotli = ["brotli"]
[[package]]
name = "zipp"
version = "3.7.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
category = "main"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.9" python-versions = "^3.9"
@@ -731,24 +767,24 @@ content-hash = "755a353d6f70eab1933125429b38d1e7249f57a9a61769507a3ef624f2d3cddb
[metadata.files] [metadata.files]
attrs = [ attrs = [
{file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
{file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
] ]
babel = [ babel = [
{file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"}, {file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"},
{file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"},
] ]
certifi = [ certifi = [
{file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
{file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
] ]
charset-normalizer = [ charset-normalizer = [
{file = "charset-normalizer-2.0.6.tar.gz", hash = "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"}, {file = "charset-normalizer-2.0.10.tar.gz", hash = "sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd"},
{file = "charset_normalizer-2.0.6-py3-none-any.whl", hash = "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6"}, {file = "charset_normalizer-2.0.10-py3-none-any.whl", hash = "sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455"},
] ]
click = [ click = [
{file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"},
{file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"},
] ]
colorama = [ colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
@@ -821,8 +857,8 @@ diff-match-patch = [
{file = "diff_match_patch-20200713-py3-none-any.whl", hash = "sha256:8bf9d9c4e059d917b5c6312bac0c137971a32815ddbda9c682b949f2986b4d34"}, {file = "diff_match_patch-20200713-py3-none-any.whl", hash = "sha256:8bf9d9c4e059d917b5c6312bac0c137971a32815ddbda9c682b949f2986b4d34"},
] ]
django = [ django = [
{file = "Django-2.2.24-py3-none-any.whl", hash = "sha256:f2084ceecff86b1e631c2cd4107d435daf4e12f1efcdf11061a73bf0b5e95f92"}, {file = "Django-2.2.26-py3-none-any.whl", hash = "sha256:85e62019366692f1d5afed946ca32fef34c8693edf342ac9d067d75d64faf0ac"},
{file = "Django-2.2.24.tar.gz", hash = "sha256:3339ff0e03dee13045aef6ae7b523edff75b6d726adf7a7a48f53d5a501f7db7"}, {file = "Django-2.2.26.tar.gz", hash = "sha256:dfa537267d52c6243a62b32855a744ca83c37c70600aacffbfd98bc5d6d8518f"},
] ]
django-app-namespace-template-loader = [ django-app-namespace-template-loader = [
{file = "django-app-namespace-template-loader-0.4.1.tar.gz", hash = "sha256:7a450985479a2e07fe8a1e4e8208fc9e1d8b35503526dd28eba5f8ad4ba31d4e"}, {file = "django-app-namespace-template-loader-0.4.1.tar.gz", hash = "sha256:7a450985479a2e07fe8a1e4e8208fc9e1d8b35503526dd28eba5f8ad4ba31d4e"},
@@ -838,8 +874,8 @@ django-bootstrap3 = [
{file = "django-bootstrap3-11.1.0.tar.gz", hash = "sha256:c417b25328fb8e97cb89e1f07d35632602d702e6eaca863328e833939d0d1743"}, {file = "django-bootstrap3-11.1.0.tar.gz", hash = "sha256:c417b25328fb8e97cb89e1f07d35632602d702e6eaca863328e833939d0d1743"},
] ]
django-cors-headers = [ django-cors-headers = [
{file = "django-cors-headers-3.9.0.tar.gz", hash = "sha256:dc121efc242ebd1acad5df5a3b9907f165beeca3eeb7f839990a71a3771ac4f5"}, {file = "django-cors-headers-3.11.0.tar.gz", hash = "sha256:eb98389bf7a2afc5d374806af4a9149697e3a6955b5a2dc2bf049f7d33647456"},
{file = "django_cors_headers-3.9.0-py3-none-any.whl", hash = "sha256:c28f96b77300efed0ff6b937d9ad2a7e80a7cb3ae5ef14968e793d540600fcd3"}, {file = "django_cors_headers-3.11.0-py3-none-any.whl", hash = "sha256:a22be2befd4069c4fc174f11cf067351df5c061a3a5f94a01650b4e928b0372b"},
] ]
django-filter = [ django-filter = [
{file = "django-filter-2.4.0.tar.gz", hash = "sha256:84e9d5bb93f237e451db814ed422a3a625751cbc9968b484ecc74964a8696b06"}, {file = "django-filter-2.4.0.tar.gz", hash = "sha256:84e9d5bb93f237e451db814ed422a3a625751cbc9968b484ecc74964a8696b06"},
@@ -872,8 +908,8 @@ django-tables2 = [
{file = "django-tables2-1.21.2.tar.gz", hash = "sha256:c5c979201b7a2f7e88f2784dcd478e0c809d3a2053dea576cb71ce51676bbf7a"}, {file = "django-tables2-1.21.2.tar.gz", hash = "sha256:c5c979201b7a2f7e88f2784dcd478e0c809d3a2053dea576cb71ce51676bbf7a"},
] ]
djangorestframework = [ djangorestframework = [
{file = "djangorestframework-3.12.4-py3-none-any.whl", hash = "sha256:6d1d59f623a5ad0509fe0d6bfe93cbdfe17b8116ebc8eda86d45f6e16e819aaf"}, {file = "djangorestframework-3.13.1-py3-none-any.whl", hash = "sha256:24c4bf58ed7e85d1fe4ba250ab2da926d263cd57d64b03e8dcef0ac683f8b1aa"},
{file = "djangorestframework-3.12.4.tar.gz", hash = "sha256:f747949a8ddac876e879190df194b925c177cdeb725a099db1460872f7c0a7f2"}, {file = "djangorestframework-3.13.1.tar.gz", hash = "sha256:0c33407ce23acc68eca2a6e46424b008c9c02eceb8cf18581921d0092bc1f2ee"},
] ]
djangorestframework-jwt = [ djangorestframework-jwt = [
{file = "djangorestframework-jwt-1.11.0.tar.gz", hash = "sha256:5efe33032f3a4518a300dc51a51c92145ad95fb6f4b272e5aa24701db67936a7"}, {file = "djangorestframework-jwt-1.11.0.tar.gz", hash = "sha256:5efe33032f3a4518a300dc51a51c92145ad95fb6f4b272e5aa24701db67936a7"},
@@ -891,8 +927,12 @@ gunicorn = [
{file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"},
] ]
idna = [ idna = [
{file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
{file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
]
importlib-metadata = [
{file = "importlib_metadata-4.10.0-py3-none-any.whl", hash = "sha256:b7cf7d3fef75f1e4c80a96ca660efbd51473d7e8f39b5ab9210febc7809012a4"},
{file = "importlib_metadata-4.10.0.tar.gz", hash = "sha256:92a8b58ce734b2a4494878e0ecf7d79ccd7a128b5fc6014c401e0b61f006f0f6"},
] ]
jdcal = [ jdcal = [
{file = "jdcal-1.4.1-py2.py3-none-any.whl", hash = "sha256:1abf1305fce18b4e8aa248cf8fe0c56ce2032392bc64bbd61b5dff2a19ec8bba"}, {file = "jdcal-1.4.1-py2.py3-none-any.whl", hash = "sha256:1abf1305fce18b4e8aa248cf8fe0c56ce2032392bc64bbd61b5dff2a19ec8bba"},
@@ -907,8 +947,8 @@ lml = [
{file = "lml-0.1.0.tar.gz", hash = "sha256:57a085a29bb7991d70d41c6c3144c560a8e35b4c1030ffb36d85fa058773bcc5"}, {file = "lml-0.1.0.tar.gz", hash = "sha256:57a085a29bb7991d70d41c6c3144c560a8e35b4c1030ffb36d85fa058773bcc5"},
] ]
markdown = [ markdown = [
{file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"}, {file = "Markdown-3.3.6-py3-none-any.whl", hash = "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3"},
{file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"}, {file = "Markdown-3.3.6.tar.gz", hash = "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006"},
] ]
nose = [ nose = [
{file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"},
@@ -922,12 +962,12 @@ openpyxl = [
{file = "openpyxl-2.6.4.tar.gz", hash = "sha256:1d53801678e18d7fe38c116f1ad0c2383a654670c4c8806105b611c92d92f2e3"}, {file = "openpyxl-2.6.4.tar.gz", hash = "sha256:1d53801678e18d7fe38c116f1ad0c2383a654670c4c8806105b611c92d92f2e3"},
] ]
packaging = [ packaging = [
{file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
{file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
] ]
phonenumbers = [ phonenumbers = [
{file = "phonenumbers-8.12.33-py2.py3-none-any.whl", hash = "sha256:758d7f654b1eaec9a637510bf773b64833c6a417e7cf43ba9dccbcc2a16e44e1"}, {file = "phonenumbers-8.12.41-py2.py3-none-any.whl", hash = "sha256:2b8c7a7ffac4fe2be3d8bf20dad316ea1292f27422c9e18b1f3cd16734d4a5ed"},
{file = "phonenumbers-8.12.33.tar.gz", hash = "sha256:de3d5a3cb421c7421f584bb13cb9287e23ee2dd97d832fc35c9b55b96a576a3c"}, {file = "phonenumbers-8.12.41.tar.gz", hash = "sha256:f477da623a51cba084567d6a67b1882a8aaaf3e7beadad655f8613a8f887ac62"},
] ]
pillow = [ pillow = [
{file = "Pillow-8.4.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d"}, {file = "Pillow-8.4.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d"},
@@ -1010,16 +1050,16 @@ psycopg2-binary = [
{file = "psycopg2_binary-2.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6"}, {file = "psycopg2_binary-2.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6"},
] ]
pycodestyle = [ pycodestyle = [
{file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
{file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
] ]
pyexcel = [ pyexcel = [
{file = "pyexcel-0.5.15-py2.py3-none-any.whl", hash = "sha256:7fac067e65567c380933b4d382587a5ce6581d0ad85992f6f0bc7c3f16012184"}, {file = "pyexcel-0.5.15-py2.py3-none-any.whl", hash = "sha256:7fac067e65567c380933b4d382587a5ce6581d0ad85992f6f0bc7c3f16012184"},
{file = "pyexcel-0.5.15.tar.gz", hash = "sha256:f0a7797f3a0de9e6f81151c9581fa90c4e1afce207dc47d2f0ba728dd2e24467"}, {file = "pyexcel-0.5.15.tar.gz", hash = "sha256:f0a7797f3a0de9e6f81151c9581fa90c4e1afce207dc47d2f0ba728dd2e24467"},
] ]
pyexcel-io = [ pyexcel-io = [
{file = "pyexcel-io-0.6.4.tar.gz", hash = "sha256:00f15f4bae2947de49b3206f2600f78780008e044380f7aafe0ce52969cda4ca"}, {file = "pyexcel-io-0.6.5.tar.gz", hash = "sha256:608d8e80da38070d3bb970d132bc47a55dcfd63b4dc03997d93646c5b2ad185b"},
{file = "pyexcel_io-0.6.4-py2.py3-none-any.whl", hash = "sha256:3d7e78ad3344e4755726e1b1fa605b0e95cb76acfc4e6ff0ca0fc2e8303ded38"}, {file = "pyexcel_io-0.6.5-py2.py3-none-any.whl", hash = "sha256:134e27826e44d303b921ab9cdb02a71023e3d61cbe88a37d80f928c2a6910bf5"},
] ]
pyexcel-xlsx = [ pyexcel-xlsx = [
{file = "pyexcel-xlsx-0.5.8.tar.gz", hash = "sha256:ab3913b465d0d645a51e3c896dc006738a398d36ceaad2dad133056132facb92"}, {file = "pyexcel-xlsx-0.5.8.tar.gz", hash = "sha256:ab3913b465d0d645a51e3c896dc006738a398d36ceaad2dad133056132facb92"},
@@ -1030,8 +1070,8 @@ pyjwt = [
{file = "PyJWT-1.7.1.tar.gz", hash = "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"}, {file = "PyJWT-1.7.1.tar.gz", hash = "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"},
] ]
pyparsing = [ pyparsing = [
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
] ]
pyrsistent = [ pyrsistent = [
{file = "pyrsistent-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"}, {file = "pyrsistent-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"},
@@ -1062,58 +1102,63 @@ python-dateutil = [
{file = "python_dateutil-2.6.0-py2.py3-none-any.whl", hash = "sha256:537bf2a8f8ce6f6862ad705cd68f9e405c0b5db014aa40fa29eab4335d4b1716"}, {file = "python_dateutil-2.6.0-py2.py3-none-any.whl", hash = "sha256:537bf2a8f8ce6f6862ad705cd68f9e405c0b5db014aa40fa29eab4335d4b1716"},
] ]
python-http-client = [ python-http-client = [
{file = "python_http_client-3.3.3.tar.gz", hash = "sha256:2aef67b4f49147e623f35f32b82756e30844a8f1b55a8c7c219de694f4818214"}, {file = "python_http_client-3.3.4-py3-none-any.whl", hash = "sha256:742169c42033ee81e22958dcf9e2c6f2b196028d72f87563eecdb28324d82528"},
{file = "python_http_client-3.3.4.tar.gz", hash = "sha256:723d0d6f03d4865cc8d08172aef15837a1eb9d8d8a719a08107e4680d0876e41"},
] ]
pytz = [ pytz = [
{file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
{file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"},
] ]
pyyaml = [ pyyaml = [
{file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
{file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
{file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
{file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
{file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
{file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
{file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
{file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
{file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
{file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
{file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
{file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
{file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
{file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
{file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
{file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
{file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
{file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
{file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
{file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
{file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
{file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
{file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
{file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
{file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
{file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
{file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
{file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
{file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
{file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
{file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
] ]
requests = [ requests = [
{file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
{file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
] ]
safety = [ safety = [
{file = "safety-1.10.3-py2.py3-none-any.whl", hash = "sha256:5f802ad5df5614f9622d8d71fedec2757099705c2356f862847c58c6dfe13e84"}, {file = "safety-1.10.3-py2.py3-none-any.whl", hash = "sha256:5f802ad5df5614f9622d8d71fedec2757099705c2356f862847c58c6dfe13e84"},
{file = "safety-1.10.3.tar.gz", hash = "sha256:30e394d02a20ac49b7f65292d19d38fa927a8f9582cdfd3ad1adbbc66c641ad5"}, {file = "safety-1.10.3.tar.gz", hash = "sha256:30e394d02a20ac49b7f65292d19d38fa927a8f9582cdfd3ad1adbbc66c641ad5"},
] ]
sendgrid = [ sendgrid = [
{file = "sendgrid-6.8.2-py3-none-any.whl", hash = "sha256:bb67bc0c429d1a5d1fcf1c03de179411405270d8ebc07809d0cb8b8c94d673f6"}, {file = "sendgrid-6.9.3-py3-none-any.whl", hash = "sha256:dfe281d60dedcd6386f715662c5c0e95cab539e15fddd17b4909d08b8065fc88"},
{file = "sendgrid-6.8.2.tar.gz", hash = "sha256:ae777ec4a4db32b986b8bfbb9e379c454424a62aa50460fa2d153f46b1549582"}, {file = "sendgrid-6.9.3.tar.gz", hash = "sha256:561bd742728631d194398d856ec8c28ba2a024e7c9e5750561f529202aa1d24a"},
] ]
sentry-sdk = [ sentry-sdk = [
{file = "sentry-sdk-1.4.3.tar.gz", hash = "sha256:b9844751e40710e84a457c5bc29b21c383ccb2b63d76eeaad72f7f1c808c8828"}, {file = "sentry-sdk-1.5.2.tar.gz", hash = "sha256:7bbaa32bba806ec629962f207b597e86831c7ee2c1f287c21ba7de7fea9a9c46"},
{file = "sentry_sdk-1.4.3-py2.py3-none-any.whl", hash = "sha256:c091cc7115ff25fe3a0e410dbecd7a996f81a3f6137d2272daef32d6c3cfa6dc"}, {file = "sentry_sdk-1.5.2-py2.py3-none-any.whl", hash = "sha256:2cec50166bcb67e1965f8073541b2321e3864cd6fd42a526bcde9f0c4e4cc3f8"},
] ]
six = [ six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
@@ -1124,11 +1169,11 @@ sqlparse = [
{file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"},
] ]
starkbank-ecdsa = [ starkbank-ecdsa = [
{file = "starkbank-ecdsa-1.1.1.tar.gz", hash = "sha256:f7b434b4a1e0ba082fb1804b908b79523973fd17b1fde377078857f7cee299d1"}, {file = "starkbank-ecdsa-2.0.3.tar.gz", hash = "sha256:73b62b1b3de54bbaa05dedb1a2d951c033432bb074de899e19d4a96a36b21df6"},
] ]
tablib = [ tablib = [
{file = "tablib-3.0.0-py3-none-any.whl", hash = "sha256:41aa40981cddd7ec4d1fabeae7c38d271601b306386bd05b5c3bcae13e5aeb20"}, {file = "tablib-3.1.0-py3-none-any.whl", hash = "sha256:26141c9cf2d5904a2228d3f5d45f8a46a3f3f2f0fbb4c33b4a1c1ddca9f31348"},
{file = "tablib-3.0.0.tar.gz", hash = "sha256:f83cac08454f225a34a305daa20e2110d5e6335135d505f93bc66583a5f9c10d"}, {file = "tablib-3.1.0.tar.gz", hash = "sha256:d64c9f6712918a3d90ec5d71b44b8bab1083e3609e4844ad2be80eb633e097ed"},
] ]
texttable = [ texttable = [
{file = "texttable-1.6.4-py2.py3-none-any.whl", hash = "sha256:dd2b0eaebb2a9e167d1cefedab4700e5dcbdb076114eed30b58b97ed6b37d6f2"}, {file = "texttable-1.6.4-py2.py3-none-any.whl", hash = "sha256:dd2b0eaebb2a9e167d1cefedab4700e5dcbdb076114eed30b58b97ed6b37d6f2"},
@@ -1139,13 +1184,17 @@ toml = [
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
] ]
urllib3 = [ urllib3 = [
{file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
{file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
] ]
uwsgi = [ uwsgi = [
{file = "uWSGI-2.0.19.1.tar.gz", hash = "sha256:faa85e053c0b1be4d5585b0858d3a511d2cd10201802e8676060fd0a109e5869"}, {file = "uwsgi-2.0.20.tar.gz", hash = "sha256:88ab9867d8973d8ae84719cf233b7dafc54326fcaec89683c3f9f77c002cdff9"},
] ]
whitenoise = [ whitenoise = [
{file = "whitenoise-4.1.4-py2.py3-none-any.whl", hash = "sha256:6dfea214b7c12efd689007abf9afa87a426586e9dbc051873ad2c8e535e2a1ac"}, {file = "whitenoise-4.1.4-py2.py3-none-any.whl", hash = "sha256:6dfea214b7c12efd689007abf9afa87a426586e9dbc051873ad2c8e535e2a1ac"},
{file = "whitenoise-4.1.4.tar.gz", hash = "sha256:22f79cf8f1f509639330f93886acaece8ec5ac5e9600c3b981d33c34e8a42dfd"}, {file = "whitenoise-4.1.4.tar.gz", hash = "sha256:22f79cf8f1f509639330f93886acaece8ec5ac5e9600c3b981d33c34e8a42dfd"},
] ]
zipp = [
{file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"},
{file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"},
]
-6
View File
@@ -23,12 +23,6 @@ sentry_sdk.init(
dsn=SENTRY_DSN, dsn=SENTRY_DSN,
environment=DEPLOY_ENV, environment=DEPLOY_ENV,
integrations=[DjangoIntegration()], integrations=[DjangoIntegration()],
# Set traces_sample_rate to 1.0 to capture 100%
# of transactions for performance monitoring.
# We recommend adjusting this value in production.
traces_sample_rate=0,
# If you wish to associate users to errors (assuming you are using # If you wish to associate users to errors (assuming you are using
# django.contrib.auth) you may enable sending PII data. # django.contrib.auth) you may enable sending PII data.
send_default_pii=True send_default_pii=True
+53 -29
View File
@@ -1,18 +1,30 @@
"""Webapp utils.""" """Webapp utils."""
from django.utils import timezone
import sendgrid
from sendgrid.helpers.mail import *
from datetime import timedelta
import logging import logging
from django.template.loader import render_to_string
from django.core.files.base import ContentFile
import base64 import base64
import uuid import uuid
from sikweb.settings import FRONTEND_URL, EMAIL_API_KEY, DEFAULT_EMAIL_FROM_ADDR, ENABLE_AUTOMATIC_EMAILS
import imghdr import imghdr
import markdown import markdown
import sendgrid
from django.utils import timezone
from sendgrid.helpers.mail import (
Email,
To,
Subject,
Mail,
HtmlContent,
PlainTextContent,
)
from django.template.loader import render_to_string
from django.core.files.base import ContentFile
from sikweb.settings import (
FRONTEND_URL,
EMAIL_API_KEY,
DEFAULT_EMAIL_FROM,
DEFAULT_EMAIL_FROM_ADDR,
ENABLE_AUTOMATIC_EMAILS,
)
from datetime import timedelta
def get_file_extension(file_name, decoded_file): def get_file_extension(file_name, decoded_file):
@@ -25,15 +37,15 @@ def decode_base64_file(data):
# Check if this is a base64 string # Check if this is a base64 string
if isinstance(data, str): if isinstance(data, str):
# Check if the base64 string is in the "data:" format # Check if the base64 string is in the "data:" format
if 'data:' in data and ';base64,' in data: if "data:" in data and ";base64," in data:
# Break out the header from the base64 content # Break out the header from the base64 content
header, data = data.split(';base64,') header, data = data.split(";base64,")
# Try to decode the file. Return validation error if it fails. # Try to decode the file. Return validation error if it fails.
try: try:
decoded_file = base64.b64decode(data) decoded_file = base64.b64decode(data)
except TypeError: except TypeError:
TypeError('invalid_image') TypeError("invalid_image")
# Generate file name: # Generate file name:
file_name = str(uuid.uuid4()) file_name = str(uuid.uuid4())
@@ -41,7 +53,10 @@ def decode_base64_file(data):
# Get the file name extension: # Get the file name extension:
file_extension = get_file_extension(file_name, decoded_file) file_extension = get_file_extension(file_name, decoded_file)
complete_file_name = "%s.%s" % (file_name, file_extension, ) complete_file_name = "%s.%s" % (
file_name,
file_extension,
)
return ContentFile(decoded_file, name=complete_file_name) return ContentFile(decoded_file, name=complete_file_name)
@@ -51,42 +66,51 @@ def month_from_now():
return timezone.now() + timedelta(days=30) return timezone.now() + timedelta(days=30)
def send_email(to, subject, body, html=False): def send_email(to: str, subject: str, body: str, html: bool = False):
if not ENABLE_AUTOMATIC_EMAILS: if ENABLE_AUTOMATIC_EMAILS is False:
logging.debug("Skipping email") logging.debug("Skipping email")
logging.debug(f"to: {to}") logging.debug(f"to: {to}")
logging.debug(f"subject: {subject}") logging.debug(f"subject: {subject}")
logging.debug(f"body: {body}") logging.debug(f"body: {body}")
return return
from_email = Email(DEFAULT_EMAIL_FROM_ADDR) from_email = Email(email=DEFAULT_EMAIL_FROM_ADDR, name=DEFAULT_EMAIL_FROM)
to_email = To(to) to_email = To(email=to)
sub = Subject(subject) sub = Subject(subject=subject)
if (html): html_content = None
content = HtmlContent(body) plain_text_content = None
if html:
html_content = HtmlContent(content=body)
else: else:
content = PlainTextContent(body) plain_text_content = PlainTextContent(content=body)
mail = Mail(from_email, to_email, sub, content) mail = Mail(
from_email=from_email,
to_emails=to_email,
subject=sub,
html_content=html_content,
plain_text_content=plain_text_content,
)
try: try:
sg = sendgrid.SendGridAPIClient(EMAIL_API_KEY) sg = sendgrid.SendGridAPIClient(api_key=EMAIL_API_KEY)
response = sg.client.mail.send.post(request_body=mail.get()) response = sg.send(mail)
if response.status_code != 202: if response.status_code != 202:
raise Exception(f'Failed to send email: {response.body}') raise Exception(f"Failed to send email: {response.body}")
except Exception as ex: except Exception as ex:
logging.exception('Failed to send email.') logging.exception("Failed to send email.")
def send_signup_email(to, subject, id, uuid, content): def send_signup_email(to, subject, id, uuid, content):
message = render_to_string( message = render_to_string(
'webapp:signup_email.html', { "webapp:signup_email.html",
'url': f"https://{FRONTEND_URL}/signup/edit/{id}/{uuid}", {
'content': markdown.markdown(content), "url": f"https://{FRONTEND_URL}/signup/edit/{id}/{uuid}",
} "content": markdown.markdown(content),
},
) )
return send_email(to, subject, message, True) return send_email(to, subject, message, True)