diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8ec2833ac595d3a3e01e7fb8c11736ae8b3bb7dc..bb31f7258498b654f0be082d46a9aef200b9d2a5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,13 +13,16 @@ Added ~~~~~ * Provide an ``ExtensiblePolymorphicModel`` to support the features of extensible models for polymorphic models and vice-versa. +* Implement optional Sentry integration for error and performance tracing. * Option to limit allowed scopes per application, including mixin to enforce that limit on OAuth resource views +* Support trusted OAuth applications that leave out the authorisation screen. Changed ~~~~~~~ * Replace dev.sh helper script with tox environments. * OAuth Grant Flows are now configured system-wide instead of per app. +* Refactor OAuth2 application management views. `2.0`_ - 2021-10-29 ------------------- diff --git a/aleksis/core/forms.py b/aleksis/core/forms.py index a733925cb093312742624f7e3fd68e33a6ba8bc4..dd695cd06ea2c0dbc862be8c9989047d9934c0c3 100644 --- a/aleksis/core/forms.py +++ b/aleksis/core/forms.py @@ -610,4 +610,5 @@ class OAuthApplicationForm(forms.ModelForm): "client_type", "allowed_scopes", "redirect_uris", + "skip_authorization", ) diff --git a/aleksis/core/menus.py b/aleksis/core/menus.py index d9fd84b0f78a1ce141537725d233f57b43a4fbea..99928d34f80b3138700005078c9dbd0ea9b25293 100644 --- a/aleksis/core/menus.py +++ b/aleksis/core/menus.py @@ -214,7 +214,7 @@ MENUS = { }, { "name": _("OAuth2 Applications"), - "url": "oauth_list", + "url": "oauth2_applications", "icon": "touch_app", "validators": [ ( diff --git a/aleksis/core/models.py b/aleksis/core/models.py index 5c590e612a0459127d868991fd8847f9f2b4c0c0..a78bfcc141d5539479983a50bbd257e6b7b7e5b1 100644 --- a/aleksis/core/models.py +++ b/aleksis/core/models.py @@ -983,11 +983,6 @@ class GlobalPermissions(GlobalPermissionModel): ("change_site_preferences", _("Can change site preferences")), ("change_person_preferences", _("Can change person preferences")), ("change_group_preferences", _("Can change group preferences")), - ("add_oauth_applications", _("Can add oauth applications")), - ("list_oauth_applications", _("Can list oauth applications")), - ("view_oauth_applications", _("Can view oauth applications")), - ("update_oauth_applications", _("Can update oauth applications")), - ("delete_oauth_applications", _("Can delete oauth applications")), ("test_pdf", _("Can test PDF generation")), ) diff --git a/aleksis/core/rules.py b/aleksis/core/rules.py index e8e5443e15396554befa1f14c2536c66231c76cf..51a4fb07bf69085b454079aad10aebb0ece9f420 100644 --- a/aleksis/core/rules.py +++ b/aleksis/core/rules.py @@ -319,17 +319,17 @@ can_change_password_predicate = is_site_preference_set(section="auth", pref="all rules.add_perm("core.can_change_password", can_change_password_predicate) # OAuth2 permissions -add_oauth_applications_predicate = has_person & has_global_perm("core.add_oauth_applications") -rules.add_perm("core.add_oauth_applications_rule", add_oauth_applications_predicate) +create_oauthapplication_predicate = has_person & has_global_perm("core.add_oauthapplication") +rules.add_perm("core.create_oauthapplication_rule", create_oauthapplication_predicate) -list_oauth_applications_predicate = has_person & has_global_perm("core.list_oauth_applications") -rules.add_perm("core.list_oauth_applications_rule", list_oauth_applications_predicate) +view_oauth_applications_predicate = has_person & has_global_perm("core.view_oauthapplication") +rules.add_perm("core.view_oauthapplications_rule", view_oauth_applications_predicate) -view_oauth_applications_predicate = has_person & has_global_perm("core.view_oauth_applications") -rules.add_perm("core.view_oauth_applications_rule", view_oauth_applications_predicate) +view_oauth_application_predicate = has_person & has_global_perm("core.view_oauthapplication") +rules.add_perm("core.view_oauthapplication_rule", view_oauth_application_predicate) -update_oauth_applications_predicate = has_person & has_global_perm("core.update_oauth_applications") -rules.add_perm("core.update_oauth_applications_rule", update_oauth_applications_predicate) +edit_oauth_application_predicate = has_person & has_global_perm("core.change_oauthapplication") +rules.add_perm("core.edit_oauthapplication_rule", edit_oauth_application_predicate) delete_oauth_applications_predicate = has_person & has_global_perm("core.delete_oauth_applications") rules.add_perm("core.delete_oauth_applications_rule", delete_oauth_applications_predicate) diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py index 7a733c13983ba1ca7602f9661ef458b64414db8e..9a0a8b5f2e7de5ff23ddd738db1b8974d32430d1 100644 --- a/aleksis/core/settings.py +++ b/aleksis/core/settings.py @@ -486,6 +486,7 @@ YARN_INSTALLED_APPS = [ "paper-css", "jquery-sortablejs", "sortablejs", + "@sentry/tracing", ] merge_app_settings("YARN_INSTALLED_APPS", YARN_INSTALLED_APPS, True) @@ -516,6 +517,7 @@ ANY_JS = { "Roboto500": {"css_url": JS_URL + "/@fontsource/roboto/500.css"}, "Roboto700": {"css_url": JS_URL + "/@fontsource/roboto/700.css"}, "Roboto900": {"css_url": JS_URL + "/@fontsource/roboto/900.css"}, + "Sentry": {"js_url": JS_URL + "/@sentry/tracing/build/bundle.tracing.js"}, } merge_app_settings("ANY_JS", ANY_JS, True) @@ -859,5 +861,31 @@ else: SASS_PROCESSOR_STORAGE = DEFAULT_FILE_STORAGE +SENTRY_ENABLED = _settings.get("health.sentry.enabled", False) +if SENTRY_ENABLED: + import sentry_sdk + from sentry_sdk.integrations.celery import CeleryIntegration + from sentry_sdk.integrations.django import DjangoIntegration + from sentry_sdk.integrations.redis import RedisIntegration + + from aleksis.core import __version__ + + SENTRY_SETTINGS = { + "dsn": _settings.get("health.sentry.dsn"), + "environment": _settings.get("health.sentry.environment"), + "traces_sample_rate": _settings.get("health.sentry.traces_sample_rate", 1.0), + "send_default_pii": _settings.get("health.sentry.send_default_pii", False), + "release": f"aleksis-core@{__version__}", + "in_app_include": "aleksis", + } + sentry_sdk.init( + integrations=[ + DjangoIntegration(transaction_style="function_name"), + RedisIntegration(), + CeleryIntegration(), + ], + **SENTRY_SETTINGS, + ) + # Add django-cleanup after all apps to ensure that it gets all signals as last app INSTALLED_APPS.append("django_cleanup.apps.CleanupConfig") diff --git a/aleksis/core/templates/core/base.html b/aleksis/core/templates/core/base.html index 80e6ee8d7cae0837b1c6b91ce4b258bd2608f22b..0dd75f2c6f237dea1ecac47b010abfac9453000f 100644 --- a/aleksis/core/templates/core/base.html +++ b/aleksis/core/templates/core/base.html @@ -35,6 +35,24 @@ <script src="{% url "calendarweek_i18n_js" %}?first_day=6&locale={{ LANGUAGE_CODE }}" type="text/javascript"></script> + {% if SENTRY_ENABLED %} + {% if SENTRY_TRACE_ID %} + <meta name="sentry-trace" content="{{ SENTRY_TRACE_ID }}" /> + {% endif %} + {% include_js "Sentry" %} + {{ SENTRY_SETTINGS|json_script:"sentry_settings" }} + <script type="text/javascript"> + const sentry_settings = JSON.parse(document.getElementById('sentry_settings').textContent); + + Sentry.init({ + dsn: sentry_settings.dsn, + environment: sentry_settings.environment, + tracesSampleRate: sentry_settings.traces_sample_rate, + integrations: [new Sentry.Integrations.BrowserTracing()] + }); + </script> + {% endif %} + {# Include jQuery early to provide $(document).ready #} {% include_js "jQuery" %} diff --git a/aleksis/core/templates/oauth2_provider/application/create.html b/aleksis/core/templates/oauth2_provider/application/create.html index 38b9a8d02e52b977223cfffdcb8d3c9165c42a71..d81489e922a76de8d7a8e92a7f48686714a3b3a7 100644 --- a/aleksis/core/templates/oauth2_provider/application/create.html +++ b/aleksis/core/templates/oauth2_provider/application/create.html @@ -10,7 +10,7 @@ {% csrf_token %} {% form form=form %}{% endform %} {% include "core/partials/save_button.html" %} - <a class="btn waves-effect red waves-light" href="{% url "oauth_list" %}"> + <a class="btn waves-effect red waves-light" href="{% url "oauth2_applications" %}"> <i class="material-icons left">clear</i> {% trans "Cancel" %} </a> </form> diff --git a/aleksis/core/templates/oauth2_provider/application/detail.html b/aleksis/core/templates/oauth2_provider/application/detail.html new file mode 100644 index 0000000000000000000000000000000000000000..8e55f91122debafbb0a86984a8166768cf879457 --- /dev/null +++ b/aleksis/core/templates/oauth2_provider/application/detail.html @@ -0,0 +1,67 @@ +{% extends "core/base.html" %} + +{% load i18n %} + +{% block browser_title %}{% blocktrans %}OAuth2 Application{% endblocktrans %}{% endblock %} +{% block page_title %} + <a href="{% url "oauth2_applications" %}" + class="btn-flat primary-color-text waves-light waves-effect"> + <i class="material-icons left">chevron_left</i> {% trans "Back" %} + </a> + {{ application.name }} +{% endblock %} + +{% block content %} + <a class="btn orange waves-effect waves-light btn-margin" href="{% url "edit_oauth2_application" application.id %}"> + <i class="material-icons left">edit</i> + {% trans "Edit" %} + </a> + <a class="btn red waves-effect waves-light btn-margin" href="{% url "delete_oauth2_application" application.id %}"> + <i class="material-icons left">delete</i> + {% trans "Delete" %} + </a> + <table class="responsive-table"> + <tbody> + <tr> + <th> + {% trans "Client id" %} + </th> + <td> + <code class="break-word">{{ application.client_id }}</code> + </td> + </tr> + <tr> + <th> + {% trans "Client secret" %} + </th> + <td> + <code class="break-word">{{ application.client_secret }}</code> + </td> + </tr> + <tr> + <th> + {% trans "Client type" %} + </th> + <td> + {{ application.client_type }} + </td> + </tr> + <tr> + <th> + {% trans "Allowed scopes" %} + </th> + <td> + {{ application.allowed_scopes|join:", " }} + </td> + </tr> + <tr> + <th> + {% trans "Redirect URIs" %} + </th> + <td> + {{ application.redirect_uris }} + </td> + </tr> + </tbody> + </table> +{% endblock %} diff --git a/aleksis/core/templates/oauth2_provider/application/edit.html b/aleksis/core/templates/oauth2_provider/application/edit.html index ac2b7d3468c114d7d3739c8fec9729b6d4c7ab54..6755d2420fb6a181f671b825475afb4ec9581521 100644 --- a/aleksis/core/templates/oauth2_provider/application/edit.html +++ b/aleksis/core/templates/oauth2_provider/application/edit.html @@ -10,7 +10,7 @@ {% csrf_token %} {% form form=form %}{% endform %} {% include "core/partials/save_button.html" %} - <a class="btn waves-effect red waves-light" href="{% url "oauth_detail" application.id %}"> + <a class="btn waves-effect red waves-light" href="{% url "oauth2_application" application.id %}"> <i class="material-icons left">clear</i> {% trans "Cancel" %} </a> </form> diff --git a/aleksis/core/templates/oauth2_provider/application_list.html b/aleksis/core/templates/oauth2_provider/application/list.html similarity index 53% rename from aleksis/core/templates/oauth2_provider/application_list.html rename to aleksis/core/templates/oauth2_provider/application/list.html index 894315940ffe8a8faaa1d93e26e06c76e1226fc8..06f1a95c4e05c14dcb5efe69f2416040d184f0bb 100644 --- a/aleksis/core/templates/oauth2_provider/application_list.html +++ b/aleksis/core/templates/oauth2_provider/application/list.html @@ -3,24 +3,22 @@ {% load i18n %} {% block browser_title %}{% blocktrans %}OAuth2 Applications{% endblocktrans %}{% endblock %} +{% block page_title %}{% blocktrans %}OAuth2 Applications{% endblocktrans %}{% endblock %} {% block content %} - <h1>{% blocktrans %}OAuth2 applications{% endblocktrans %}</h1> <a href="{% url "register_oauth_application" %}" class="btn green waves-effect waves-light"> <i class="material-icons left">add</i> {% blocktrans %}Register new application{% endblocktrans %} </a> - <ul class="collection"> - {% for application in applications %} - <li class="collection-item"> - <div> - <a href="{% url "oauth_detail" application.id %}">{{ application.name }}</a> - </div> - </li> - {% empty %} - <li class="collection-item flow-text"> + <div class="collection"> + {% for application in applications %} + <a class="collection-item" href="{% url "oauth2_application" application.id %}"> + {{ application.name }} + </a> + {% empty %} + <div class="collection-item flow-text"> {% blocktrans %}No applications defined.{% endblocktrans %} - </li> - {% endfor %} - </ul> + </div> + {% endfor %} + </div> {% endblock %} diff --git a/aleksis/core/templates/oauth2_provider/application_confirm_delete.html b/aleksis/core/templates/oauth2_provider/application_confirm_delete.html deleted file mode 100644 index f72a5be615700ee32326eda2982964e3e8de3e52..0000000000000000000000000000000000000000 --- a/aleksis/core/templates/oauth2_provider/application_confirm_delete.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends "core/base.html" %} - -{% load i18n %} - -{% block browser_title %}{% trans "Delete application" %}{% endblock %} -{% block page_title %}{% trans "Delete application" %}{% endblock %} - -{% block content %} - <div class="alert info"> - <p> - <i class="material-icons left">warning</i> - {% blocktrans with application_name=application.name %}Are you sure to delete the application {{ application_name }}?{% endblocktrans %} - </p> - </div> - - <form method="post" action="{% url 'oauth2_provider:delete' application.pk %}"> - {% csrf_token %} - <button type="submit" class="btn waves-effect waves-light red"> - <i class="material-icons left">delete</i> - {% trans "Delete" %} - </button> - <a class="btn waves-effect waves-light" href="{% url "oauth2_provider:list" %}"> - <i class="material-icons left">close</i> - {% trans "Cancel" %} - </a> - </form> -{% endblock %} diff --git a/aleksis/core/templates/oauth2_provider/application_detail.html b/aleksis/core/templates/oauth2_provider/application_detail.html deleted file mode 100644 index f7e02ff62ca65cb41692a8155c28906a9900fc2b..0000000000000000000000000000000000000000 --- a/aleksis/core/templates/oauth2_provider/application_detail.html +++ /dev/null @@ -1,71 +0,0 @@ -{% extends "core/base.html" %} - -{% load i18n %} - -{% block browser_title %}{% blocktrans %}OAuth2 Applications{% endblocktrans %}{% endblock %} -{% block page_title %} - <a href="{% url "oauth_list" %}" - class="btn-flat primary-color-text waves-light waves-effect"> - <i class="material-icons left">chevron_left</i> {% trans "Back" %} - </a> - {{ application.name }} -{% endblock %} - -{% block content %} - <a class="btn waves-effect waves-light btn-margin" href="{% url "edit_oauth_application" application.id %}"> - <i class="material-icons left">edit</i> - {% trans "Edit" %} - </a> - <a class="btn red waves-effect waves-light btn-margin" href="{% url "oauth_delete" application.id %}"> - <i class="material-icons left">delete_forever</i> - {% trans "Delete" %} - </a> - <table class="responsive-table"> - <tbody> - <tr> - <th> - {% trans "Client id" %} - </td> - <td> - <code class="break-word">{{ application.client_id }}</code> - </td> - </tr> - <tr> - <th> - {% trans "Client secret"%} - </td> - <td> - <code class="break-word">{{ application.client_secret }}</code> - </td> - </tr> - <tr> - <th> - {% trans "Client type"%} - </td> - <td> - {{ application.client_type }} - </td> - </tr> - <tr> - <th> - {% trans "Allowed scopes"%} - </th> - <td> - <ul> - {% for scope in application.allowed_scopes %} - <li>{{ scope }}</li> - {% endfor %} - </ul> - </td> - </tr> - <tr> - <th> - {% trans "Redirect URIs"%} - </td> - <td> - {{ application.redirect_uris }} - </td> - </tr> - </tbody> - </table> -{% endblock %} diff --git a/aleksis/core/templates/oauth2_provider/authorize.html b/aleksis/core/templates/oauth2_provider/authorize.html index 5eaf3151021c27fd24b8e19e195a4a2e14d5279a..48b996837b8721ef6ba74337d286236e91729f5b 100644 --- a/aleksis/core/templates/oauth2_provider/authorize.html +++ b/aleksis/core/templates/oauth2_provider/authorize.html @@ -32,7 +32,7 @@ <button type="submit" class="btn green waves-effect waves-light btn-margin"> <i class="material-icons left">done_all</i> {% trans "Allow" %} </button> - <a class="btn red waves-effect waves-light btn-margin" href="{% block app-form-back-url %}{% url "oauth_detail" application.id %}{% endblock app-form-back-url %}"> + <a class="btn red waves-effect waves-light btn-margin" href="{% block app-form-back-url %}{% url "oauth2_application" application.id %}{% endblock app-form-back-url %}"> <i class="material-icons left">cancel</i> {% trans "Disallow" %} </a> </form> diff --git a/aleksis/core/templates/oauth2_provider/authorized-token-delete.html b/aleksis/core/templates/oauth2_provider/authorized-token-delete.html index f658822980bda161890060fb9002cec8fb317297..7f6f25920bebcbbaad7bb93fd486db617f25d662 100644 --- a/aleksis/core/templates/oauth2_provider/authorized-token-delete.html +++ b/aleksis/core/templates/oauth2_provider/authorized-token-delete.html @@ -15,11 +15,11 @@ <form method="post"> {% csrf_token %} - <a class="btn waves-effect waves-light red" href="{% url "oauth_list" %}"> + <a class="btn waves-effect waves-light red" href="{% url "oauth2_applications" %}"> <i class="material-icons left">delete</i> {% trans "Revoke" %} </a> - <a class="btn waves-effect waves-light" href="{% url "oauth_list" %}"> + <a class="btn waves-effect waves-light" href="{% url "oauth2_applications" %}"> <i class="material-icons left">cancel</i> {% trans "Cancel" %} </a> diff --git a/aleksis/core/urls.py b/aleksis/core/urls.py index 85f91a2ccd5aa2f0f11f5d905a1d8ed5d5a61a1e..22bbdd344fef8a9082edd2cf4df589627597d3f0 100644 --- a/aleksis/core/urls.py +++ b/aleksis/core/urls.py @@ -102,20 +102,26 @@ urlpatterns = [ ConnectDiscoveryInfoView.as_view(), name="oidc_configuration", ), - path("oauth/applications/", views.OAuth2List.as_view(), name="oauth_list"), + path("oauth2/applications/", views.OAuth2ListView.as_view(), name="oauth2_applications"), path( - "oauth/applications/register/", + "oauth2/applications/register/", views.OAuth2RegisterView.as_view(), name="register_oauth_application", ), - path("oauth/applications/<int:pk>/detail", views.OAuth2Detail.as_view(), name="oauth_detail"), - path("oauth/applications/<int:pk>/delete", views.OAuth2Delete.as_view(), name="oauth_delete"), path( - "oauth/applications/<int:pk>/edit/", + "oauth2/applications/<int:pk>/", views.OAuth2DetailView.as_view(), name="oauth2_application" + ), + path( + "oauth2/applications/<int:pk>/delete/", + views.OAuth2DeleteView.as_view(), + name="delete_oauth2_application", + ), + path( + "oauth2/applications/<int:pk>/edit/", views.OAuth2EditView.as_view(), - name="edit_oauth_application", + name="edit_oauth2_application", ), - path("oauth/", include("oauth2_provider.urls", namespace="oauth2_provider")), + path("oauth2/", include("oauth2_provider.urls", namespace="oauth2_provider")), path("__i18n__/", include("django.conf.urls.i18n")), path( "ckeditor/upload/", diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py index 2c40caf51d41045685a74b67800cc9575d3cf2de..5871fd8dd7f568d463c8f672373fa60b708caddf 100644 --- a/aleksis/core/util/core_helpers.py +++ b/aleksis/core/util/core_helpers.py @@ -208,12 +208,24 @@ def custom_information_processor(request: HttpRequest) -> dict: regrouped_pwa_icons.setdefault(pwa_icon.rel, {}) regrouped_pwa_icons[pwa_icon.rel][pwa_icon.size] = pwa_icon - return { + context = { "FOOTER_MENU": CustomMenu.get_default("footer"), "ADMINS": settings.ADMINS, "PWA_ICONS": regrouped_pwa_icons, + "SENTRY_ENABLED": settings.SENTRY_ENABLED, } + if settings.SENTRY_ENABLED: + context["SENTRY_SETTINGS"] = settings.SENTRY_SETTINGS + + import sentry_sdk + + span = sentry_sdk.Hub.current.scope.span + if span is not None: + context["SENTRY_TRACE_ID"] = span.to_traceparent() + + return context + def now_tomorrow() -> datetime: """Return current time tomorrow.""" diff --git a/aleksis/core/views.py b/aleksis/core/views.py index 1a73deee1773edc55b53f83663931b6006109993..e0135bda5d713c11619de0aeff9528e6234b6aca 100644 --- a/aleksis/core/views.py +++ b/aleksis/core/views.py @@ -1033,44 +1033,44 @@ class EditDashboardView(PermissionRequiredMixin, View): return render(request, "core/edit_dashboard.html", context=context) -class OAuth2List(PermissionRequiredMixin, ListView): +class OAuth2ListView(PermissionRequiredMixin, ListView): """List view for all the applications.""" - permission_required = "core.list_oauth_applications_rule" + permission_required = "core.view_oauthapplications_rule" context_object_name = "applications" - template_name = "oauth2_provider/application_list.html" + template_name = "oauth2_provider/application/list.html" def get_queryset(self): return OAuthApplication.objects.all() -class OAuth2Detail(PermissionRequiredMixin, DetailView): +class OAuth2DetailView(PermissionRequiredMixin, DetailView): """Detail view for an application instance.""" context_object_name = "application" - permission_required = "core.view_oauth_applications_rule" - template_name = "oauth2_provider/application_detail.html" + permission_required = "core.view_oauthapplication_rule" + template_name = "oauth2_provider/application/detail.html" def get_queryset(self): return OAuthApplication.objects.all() -class OAuth2Delete(PermissionRequiredMixin, DeleteView): +class OAuth2DeleteView(PermissionRequiredMixin, AdvancedDeleteView): """View used to delete an application.""" - permission_required = "core.delete_oauth_applications_rule" + permission_required = "core.delete_oauthapplication_rule" context_object_name = "application" - success_url = reverse_lazy("oauth_list") - template_name = "oauth2_provider/application_confirm_delete.html" + success_url = reverse_lazy("oauth2_applications") + template_name = "core/pages/delete.html" def get_queryset(self): return OAuthApplication.objects.all() class OAuth2EditView(PermissionRequiredMixin, AdvancedEditView): - """View used to update an application.""" + """View used to edit an application.""" - permission_required = "core.update_oauth_applications_rule" + permission_required = "core.edit_oauthapplication_rule" context_object_name = "application" template_name = "oauth2_provider/application/edit.html" form_class = OAuthApplicationForm @@ -1082,7 +1082,7 @@ class OAuth2EditView(PermissionRequiredMixin, AdvancedEditView): class OAuth2RegisterView(PermissionRequiredMixin, AdvancedCreateView): """View used to register an application.""" - permission_required = "core.add_oauth_applications_rule" + permission_required = "core.create_oauthapplication_rule" context_object_name = "application" template_name = "oauth2_provider/application/create.html" form_class = OAuthApplicationForm diff --git a/poetry.lock b/poetry.lock index c9d4b0e2db4557925a052ed17ac3f3958a389ee9..5b8035e59280dcc14adefa0cb88178c007ced081 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2269,6 +2269,40 @@ python-versions = "*" [package.dependencies] urllib3 = "*" +[[package]] +name = "sentry-sdk" +version = "1.4.3" +description = "Python client for Sentry (https://sentry.io)" +category = "main" +optional = true +python-versions = "*" + +[package.dependencies] +certifi = "*" +urllib3 = ">=1.10.0" + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +chalice = ["chalice (>=1.16.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +flask = ["flask (>=0.11)", "blinker (>=1.1)"] +httpx = ["httpx (>=0.16.0)"] +pure_eval = ["pure-eval", "executing", "asttokens"] +pyspark = ["pyspark (>=2.4.4)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +tornado = ["tornado (>=5)"] + +[package.source] +type = "legacy" +url = "https://edugit.org/api/v4/projects/461/packages/pypi/simple" +reference = "gitlab" + [[package]] name = "six" version = "1.16.0" @@ -2647,11 +2681,12 @@ pycryptodome = "*" [extras] ldap = ["django-auth-ldap"] s3 = ["boto3", "django-storages"] +sentry = [] [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "9117742426e175d6402dac268ed74f7e72e084fe020e5ebf22e97915ff7acd0d" +content-hash = "d15f5a57e0a3e887cfe411829b19459af4ebfc9aadc6e2a0468b11f4fc03e6b4" [metadata.files] alabaster = [ @@ -3770,6 +3805,10 @@ selenium = [ {file = "selenium-3.141.0-py2.py3-none-any.whl", hash = "sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c"}, {file = "selenium-3.141.0.tar.gz", hash = "sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d"}, ] +sentry-sdk = [ + {file = "sentry-sdk-1.4.3.tar.gz", hash = "sha256:b9844751e40710e84a457c5bc29b21c383ccb2b63d76eeaad72f7f1c808c8828"}, + {file = "sentry_sdk-1.4.3-py2.py3-none-any.whl", hash = "sha256:c091cc7115ff25fe3a0e410dbecd7a996f81a3f6137d2272daef32d6c3cfa6dc"}, +] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, diff --git a/pyproject.toml b/pyproject.toml index 7de56924b6d76c659ab4da8762e25e6815b9f435..044f77bfbf8d6f1c1e45923525274aa81d2a0f0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -113,10 +113,12 @@ Whoosh = "^2.7.4" django-titofisto = "^0.1.0" haystack-redis = "^0.0.1" python-gnupg = "^0.4.7" +sentry-sdk = {version = "^1.4.3", optional = true} [tool.poetry.extras] ldap = ["django-auth-ldap"] s3 = ["boto3", "django-storages"] +sentry = ["sentry"] [tool.poetry.dev-dependencies] aleksis-builddeps = "*"