From 6736caf9f480e8fc55db34eca51d9c9d2766fd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Pi=C3=A9tri?= Date: Tue, 9 Feb 2021 13:01:42 +0100 Subject: [PATCH 1/7] feat: :arrow_up: Support for django 2.2 (#308) Support for django 2.2. Rename django.conf.urlresolvers. Change url to path. Add apps to app folder. Edit migrations for on_delete. Edit models for on_delete. Drop compatibility for django 1.x --- api/apps.py | 11 + api/routers.py | 2 +- api/urls.py | 6 +- cotisations/apps.py | 11 + .../migrations/0004_auto_20210208_1827.py | 49 +++++ .../migrations/0015_auto_20160714_2142.py | 4 +- .../migrations/0016_auto_20160715_0110.py | 2 +- cotisations/models.py | 13 -- cotisations/payment_methods/urls.py | 6 +- cotisations/urls.py | 92 ++++----- ldap_sync/urls.py | 4 +- logs/apps.py | 11 + logs/urls.py | 26 +-- machines/apps.py | 11 + machines/migrations/0001_model_creation.py | 2 +- .../migrations/0003_auto_20210208_1827.py | 108 ++++++++++ .../migrations/0019_auto_20160718_1141.py | 2 +- machines/migrations/0027_alias.py | 2 +- .../migrations/0036_auto_20161224_1204.py | 2 +- machines/migrations/0037_domain_cname.py | 1 + .../migrations/0038_auto_20161224_1721.py | 1 + .../migrations/0039_auto_20161224_1732.py | 2 +- machines/models.py | 29 +-- machines/urls.py | 190 +++++++++--------- multi_op/urls.py | 24 ++- preferences/apps.py | 11 + .../migrations/0003_auto_20210208_1827.py | 65 ++++++ preferences/models.py | 24 --- preferences/urls.py | 103 +++++----- re2o/apps.py | 11 + re2o/context_processors.py | 2 +- re2o/login.py | 4 +- re2o/settings.py | 20 +- re2o/templatetags/acl.py | 4 +- re2o/urls.py | 62 ++---- re2o/views.py | 2 +- search/apps.py | 11 + search/urls.py | 8 +- tickets/urls.py | 22 +- topologie/apps.py | 11 + .../migrations/0002_auto_20160703_1118.py | 4 +- .../migrations/0003_auto_20210208_1827.py | 71 +++++++ topologie/migrations/0013_port_related.py | 2 +- .../migrations/0016_auto_20160706_1531.py | 2 +- .../migrations/0019_auto_20161026_1348.py | 2 +- topologie/models.py | 22 +- topologie/urls.py | 166 +++++++-------- users/apps.py | 11 + users/migrations/0003_auto_20210208_1827.py | 52 +++++ users/models.py | 12 +- users/urls.py | 134 ++++++------ 51 files changed, 909 insertions(+), 540 deletions(-) create mode 100644 api/apps.py create mode 100644 cotisations/apps.py create mode 100644 cotisations/migrations/0004_auto_20210208_1827.py create mode 100644 logs/apps.py create mode 100644 machines/apps.py create mode 100644 machines/migrations/0003_auto_20210208_1827.py create mode 100644 preferences/apps.py create mode 100644 preferences/migrations/0003_auto_20210208_1827.py create mode 100644 re2o/apps.py create mode 100644 search/apps.py create mode 100644 topologie/apps.py create mode 100644 topologie/migrations/0003_auto_20210208_1827.py create mode 100644 users/apps.py create mode 100644 users/migrations/0003_auto_20210208_1827.py diff --git a/api/apps.py b/api/apps.py new file mode 100644 index 00000000..f2bfb744 --- /dev/null +++ b/api/apps.py @@ -0,0 +1,11 @@ +""" +Configuration of api app. +""" + +from django.apps import AppConfig + + +class ApiConfig(AppConfig): + """Configuration of api app.""" + + name = "api" \ No newline at end of file diff --git a/api/routers.py b/api/routers.py index 9703d040..6f672fe2 100644 --- a/api/routers.py +++ b/api/routers.py @@ -26,7 +26,7 @@ from collections import OrderedDict from django.conf.urls import url -from django.core.urlresolvers import NoReverseMatch +from django.urls import NoReverseMatch from rest_framework import views from rest_framework.response import Response from rest_framework.reverse import reverse diff --git a/api/urls.py b/api/urls.py index 5d06dff1..8d57b172 100644 --- a/api/urls.py +++ b/api/urls.py @@ -28,13 +28,15 @@ can also be register. That way a complete API root page presenting all URLs can be generated automatically. """ -from django.conf.urls import url, include +from django.urls import path, include from importlib import import_module from . import views from .routers import AllViewsRouter from django.conf import settings +app_name = "api" + router = AllViewsRouter() urls_viewset = [] @@ -65,4 +67,4 @@ for _url, view, name in urls_functional_view: # TOKEN AUTHENTICATION router.register_view(r"token-auth", views.ObtainExpiringAuthToken) -urlpatterns = [url(r"^", include(router.urls))] +urlpatterns = [path("", include(router.urls))] diff --git a/cotisations/apps.py b/cotisations/apps.py new file mode 100644 index 00000000..1b85f0b3 --- /dev/null +++ b/cotisations/apps.py @@ -0,0 +1,11 @@ +""" +Configuration of cotisations app. +""" + +from django.apps import AppConfig + + +class CotisationsConfig(AppConfig): + """Configuration of cotisations app.""" + + name = "cotisations" \ No newline at end of file diff --git a/cotisations/migrations/0004_auto_20210208_1827.py b/cotisations/migrations/0004_auto_20210208_1827.py new file mode 100644 index 00000000..ed7d5711 --- /dev/null +++ b/cotisations/migrations/0004_auto_20210208_1827.py @@ -0,0 +1,49 @@ +# Generated by Django 2.2.18 on 2021-02-08 17:27 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0003_auto_20210124_1105'), + ] + + operations = [ + migrations.AlterModelOptions( + name='article', + options={'permissions': (('buy_every_article', 'Can buy every article'),), 'verbose_name': 'article', 'verbose_name_plural': 'articles'}, + ), + migrations.AlterModelOptions( + name='banque', + options={'verbose_name': 'bank', 'verbose_name_plural': 'banks'}, + ), + migrations.AlterModelOptions( + name='baseinvoice', + options={}, + ), + migrations.AlterModelOptions( + name='costestimate', + options={}, + ), + migrations.AlterModelOptions( + name='cotisation', + options={'permissions': (('change_all_cotisation', 'Can edit the previous subscriptions'),), 'verbose_name': 'subscription', 'verbose_name_plural': 'subscriptions'}, + ), + migrations.AlterModelOptions( + name='custominvoice', + options={}, + ), + migrations.AlterModelOptions( + name='facture', + options={'permissions': (('change_facture_control', 'Can edit the "controlled" state'), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'invoice', 'verbose_name_plural': 'invoices'}, + ), + migrations.AlterModelOptions( + name='paiement', + options={'permissions': (('use_every_payment', 'Can use every payment method'),), 'verbose_name': 'payment method', 'verbose_name_plural': 'payment methods'}, + ), + migrations.AlterModelOptions( + name='vente', + options={'permissions': (('change_all_vente', 'Can edit all the previous purchases'),), 'verbose_name': 'purchase', 'verbose_name_plural': 'purchases'}, + ), + ] diff --git a/cotisations/migrations/0015_auto_20160714_2142.py b/cotisations/migrations/0015_auto_20160714_2142.py index efb1a733..e8a52839 100644 --- a/cotisations/migrations/0015_auto_20160714_2142.py +++ b/cotisations/migrations/0015_auto_20160714_2142.py @@ -40,12 +40,12 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="cotisation", name="facture", - field=models.OneToOneField(to="cotisations.Facture"), + field=models.OneToOneField(to="cotisations.Facture", on_delete=models.CASCADE), ), migrations.AlterField( model_name="vente", name="facture", - field=models.ForeignKey(to="cotisations.Facture"), + field=models.ForeignKey(to="cotisations.Facture", on_delete=models.CASCADE), ), migrations.AlterField( model_name="vente", diff --git a/cotisations/migrations/0016_auto_20160715_0110.py b/cotisations/migrations/0016_auto_20160715_0110.py index e716960a..ff3701a2 100644 --- a/cotisations/migrations/0016_auto_20160715_0110.py +++ b/cotisations/migrations/0016_auto_20160715_0110.py @@ -41,7 +41,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="cotisation", name="vente", - field=models.OneToOneField(to="cotisations.Vente", null=True), + field=models.OneToOneField(to="cotisations.Vente", null=True, on_delete=models.CASCADE), preserve_default=False, ), ] diff --git a/cotisations/models.py b/cotisations/models.py index 759f5320..c93725a4 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -62,9 +62,6 @@ class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): class Meta: abstract = False - permissions = ( - ("view_baseinvoice", _("Can view an base invoice object")), - ) # TODO : change prix to price def prix(self): @@ -157,7 +154,6 @@ class Facture(BaseInvoice): permissions = ( # TODO : change facture to invoice ("change_facture_control", _('Can edit the "controlled" state')), - ("view_facture", _("Can view an invoice object")), ("change_all_facture", _("Can edit all the previous invoices")), ) verbose_name = _("invoice") @@ -377,8 +373,6 @@ def facture_post_delete(**kwargs): class CustomInvoice(BaseInvoice): - class Meta: - permissions = (("view_custominvoice", _("Can view a custom invoice object")),) recipient = models.CharField(max_length=255, verbose_name=_("recipient")) payment = models.CharField(max_length=255, verbose_name=_("payment type")) @@ -388,8 +382,6 @@ class CustomInvoice(BaseInvoice): class CostEstimate(CustomInvoice): - class Meta: - permissions = (("view_costestimate", _("Can view a cost estimate object")),) validity = models.DurationField( verbose_name=_("period of validity"), help_text="DD HH:MM:SS" @@ -490,7 +482,6 @@ class Vente(RevMixin, AclMixin, models.Model): class Meta: permissions = ( - ("view_vente", _("Can view a purchase object")), ("change_all_vente", _("Can edit all the previous purchases")), ) verbose_name = _("purchase") @@ -750,7 +741,6 @@ class Article(RevMixin, AclMixin, models.Model): class Meta: permissions = ( - ("view_article", _("Can view an article object")), ("buy_every_article", _("Can buy every article")), ) verbose_name = "article" @@ -824,7 +814,6 @@ class Banque(RevMixin, AclMixin, models.Model): name = models.CharField(max_length=255) class Meta: - permissions = (("view_banque", _("Can view a bank object")),) verbose_name = _("bank") verbose_name_plural = _("banks") @@ -856,7 +845,6 @@ class Paiement(RevMixin, AclMixin, models.Model): class Meta: permissions = ( - ("view_paiement", _("Can view a payment method object")), ("use_every_payment", _("Can use every payment method")), ) verbose_name = _("payment method") @@ -980,7 +968,6 @@ class Cotisation(RevMixin, AclMixin, models.Model): class Meta: permissions = ( - ("view_cotisation", _("Can view a subscription object")), ("change_all_cotisation", _("Can edit the previous subscriptions")), ) verbose_name = _("subscription") diff --git a/cotisations/payment_methods/urls.py b/cotisations/payment_methods/urls.py index 9a06f497..c413fac1 100644 --- a/cotisations/payment_methods/urls.py +++ b/cotisations/payment_methods/urls.py @@ -22,7 +22,7 @@ from django.conf.urls import include, url from . import comnpay, cheque, note_kfet urlpatterns = [ - url(r"^comnpay/", include(comnpay.urls, namespace="comnpay")), - url(r"^cheque/", include(cheque.urls, namespace="cheque")), - url(r"^note_kfet/", include(note_kfet.urls, namespace="note_kfet")), + url(r"^comnpay/", include((comnpay.urls, 'comnpay'), namespace="comnpay")), + url(r"^cheque/", include((cheque.urls, 'cheque'), namespace="cheque")), + url(r"^note_kfet/", include((note_kfet.urls, 'note_kfet'), namespace="note_kfet")), ] diff --git a/cotisations/urls.py b/cotisations/urls.py index c78effa6..9967b114 100644 --- a/cotisations/urls.py +++ b/cotisations/urls.py @@ -25,85 +25,87 @@ The defined URLs for the Cotisations app from __future__ import unicode_literals -from django.conf.urls import url +from django.urls import path from . import views, views_autocomplete from . import payment_methods +app_name ="cotisations" + urlpatterns = [ - url(r"^new_facture/(?P[0-9]+)$", views.new_facture, name="new-facture"), - url( - r"^edit_facture/(?P[0-9]+)$", views.edit_facture, name="edit-facture" + path("new_facture/", views.new_facture, name="new-facture"), + path( + "edit_facture/", views.edit_facture, name="edit-facture" ), - url(r"^del_facture/(?P[0-9]+)$", views.del_facture, name="del-facture"), - url(r"^facture_pdf/(?P[0-9]+)$", views.facture_pdf, name="facture-pdf"), - url(r"^voucher_pdf/(?P[0-9]+)$", views.voucher_pdf, name="voucher-pdf"), - url(r"^new_cost_estimate/$", views.new_cost_estimate, name="new-cost-estimate"), - url( - r"^index_cost_estimate/$", views.index_cost_estimate, name="index-cost-estimate" + path("del_facture/", views.del_facture, name="del-facture"), + path("facture_pdf/", views.facture_pdf, name="facture-pdf"), + path("voucher_pdf/", views.voucher_pdf, name="voucher-pdf"), + path("new_cost_estimate", views.new_cost_estimate, name="new-cost-estimate"), + path( + "index_cost_estimate", views.index_cost_estimate, name="index-cost-estimate" ), - url( - r"^cost_estimate_pdf/(?P[0-9]+)$", + path( + "cost_estimate_pdf/", views.cost_estimate_pdf, name="cost-estimate-pdf", ), - url( - r"^index_custom_invoice/$", + path( + "index_custom_invoice", views.index_custom_invoice, name="index-custom-invoice", ), - url( - r"^edit_cost_estimate/(?P[0-9]+)$", + path( + "edit_cost_estimate/", views.edit_cost_estimate, name="edit-cost-estimate", ), - url( - r"^cost_estimate_to_invoice/(?P[0-9]+)$", + path( + "cost_estimate_to_invoice/", views.cost_estimate_to_invoice, name="cost-estimate-to-invoice", ), - url( - r"^del_cost_estimate/(?P[0-9]+)$", + path( + "del_cost_estimate/", views.del_cost_estimate, name="del-cost-estimate", ), - url(r"^new_custom_invoice/$", views.new_custom_invoice, name="new-custom-invoice"), - url( - r"^edit_custom_invoice/(?P[0-9]+)$", + path("new_custom_invoice", views.new_custom_invoice, name="new-custom-invoice"), + path( + "edit_custom_invoice/", views.edit_custom_invoice, name="edit-custom-invoice", ), - url( - r"^custom_invoice_pdf/(?P[0-9]+)$", + path( + "custom_invoice_pdf/", views.custom_invoice_pdf, name="custom-invoice-pdf", ), - url( - r"^del_custom_invoice/(?P[0-9]+)$", + path( + "del_custom_invoice/", views.del_custom_invoice, name="del-custom-invoice", ), - url(r"^credit_solde/(?P[0-9]+)$", views.credit_solde, name="credit-solde"), - url(r"^add_article/$", views.add_article, name="add-article"), - url( - r"^edit_article/(?P[0-9]+)$", views.edit_article, name="edit-article" + path("credit_solde/", views.credit_solde, name="credit-solde"), + path("add_article", views.add_article, name="add-article"), + path( + "edit_article/", views.edit_article, name="edit-article" ), - url(r"^del_article/$", views.del_article, name="del-article"), - url(r"^add_paiement/$", views.add_paiement, name="add-paiement"), - url( - r"^edit_paiement/(?P[0-9]+)$", + path("del_article", views.del_article, name="del-article"), + path("add_paiement", views.add_paiement, name="add-paiement"), + path( + "edit_paiement/", views.edit_paiement, name="edit-paiement", ), - url(r"^del_paiement/$", views.del_paiement, name="del-paiement"), - url(r"^add_banque/$", views.add_banque, name="add-banque"), - url(r"^edit_banque/(?P[0-9]+)$", views.edit_banque, name="edit-banque"), - url(r"^del_banque/$", views.del_banque, name="del-banque"), - url(r"^index_article/$", views.index_article, name="index-article"), - url(r"^index_banque/$", views.index_banque, name="index-banque"), - url(r"^index_paiement/$", views.index_paiement, name="index-paiement"), - url(r"^control/$", views.control, name="control"), - url(r"^$", views.index, name="index"), + path("del_paiement", views.del_paiement, name="del-paiement"), + path("add_banque", views.add_banque, name="add-banque"), + path("edit_banque/", views.edit_banque, name="edit-banque"), + path("del_banque", views.del_banque, name="del-banque"), + path("index_article", views.index_article, name="index-article"), + path("index_banque", views.index_banque, name="index-banque"), + path("index_paiement", views.index_paiement, name="index-paiement"), + path("control", views.control, name="control"), + path("", views.index, name="index"), ### Autocomplete Views - url(r'^banque-autocomplete/$', views_autocomplete.BanqueAutocomplete.as_view(), name='banque-autocomplete',), + path('banque-autocomplete', views_autocomplete.BanqueAutocomplete.as_view(), name='banque-autocomplete',), ] + payment_methods.urls.urlpatterns diff --git a/ldap_sync/urls.py b/ldap_sync/urls.py index 24f25ce8..b9622e85 100644 --- a/ldap_sync/urls.py +++ b/ldap_sync/urls.py @@ -1,4 +1,6 @@ -from django.conf.urls import url +from django.urls import path from .import views +app_name = "ldap_sync" + urlpatterns = [] diff --git a/logs/apps.py b/logs/apps.py new file mode 100644 index 00000000..255ad039 --- /dev/null +++ b/logs/apps.py @@ -0,0 +1,11 @@ +""" +Configuration of logs app. +""" + +from django.apps import AppConfig + + +class LogsConfig(AppConfig): + """Configuration of logs app.""" + + name = "logs" \ No newline at end of file diff --git a/logs/urls.py b/logs/urls.py index deb7ab30..d87a4efc 100644 --- a/logs/urls.py +++ b/logs/urls.py @@ -24,26 +24,28 @@ The defined URLs for the logs app. Included in re2o.urls. """ from __future__ import unicode_literals -from django.conf.urls import url +from django.urls import path from . import views +app_name = "logs" + urlpatterns = [ - url(r"^$", views.index, name="index"), - url(r"^stats_logs$", views.stats_logs, name="stats-logs"), - url( - r"^revert_action/(?P[0-9]+)$", + path("", views.index, name="index"), + path("stats_logs", views.stats_logs, name="stats-logs"), + path( + "revert_action/", views.revert_action, name="revert-action", ), - url( - r"(?P\w+)/(?P\w+)/(?P[0-9]+)$", + path( + "//", views.history, name="history", ), - url(r"^stats_general/$", views.stats_general, name="stats-general"), - url(r"^stats_models/$", views.stats_models, name="stats-models"), - url(r"^stats_users/$", views.stats_users, name="stats-users"), - url(r"^stats_actions/$", views.stats_actions, name="stats-actions"), - url(r"^stats_search_machine/$", views.stats_search_machine_history, name="stats-search-machine"), + path("stats_general", views.stats_general, name="stats-general"), + path("stats_models", views.stats_models, name="stats-models"), + path("stats_users", views.stats_users, name="stats-users"), + path("stats_actions", views.stats_actions, name="stats-actions"), + path("stats_search_machine", views.stats_search_machine_history, name="stats-search-machine"), ] diff --git a/machines/apps.py b/machines/apps.py new file mode 100644 index 00000000..4ba9970c --- /dev/null +++ b/machines/apps.py @@ -0,0 +1,11 @@ +""" +Configuration of machines app. +""" + +from django.apps import AppConfig + + +class MachinesConfig(AppConfig): + """Configuration of machines app.""" + + name = "machines" \ No newline at end of file diff --git a/machines/migrations/0001_model_creation.py b/machines/migrations/0001_model_creation.py index 96c8dffc..c8379981 100644 --- a/machines/migrations/0001_model_creation.py +++ b/machines/migrations/0001_model_creation.py @@ -1098,7 +1098,7 @@ class Migration(migrations.Migration): ( "cname", models.ForeignKey( - "self", null=True, blank=True, related_name="related_domain" + "self", null=True, blank=True, related_name="related_domain", on_delete=models.CASCADE ), ), ( diff --git a/machines/migrations/0003_auto_20210208_1827.py b/machines/migrations/0003_auto_20210208_1827.py new file mode 100644 index 00000000..ad4b8ebc --- /dev/null +++ b/machines/migrations/0003_auto_20210208_1827.py @@ -0,0 +1,108 @@ +# Generated by Django 2.2.18 on 2021-02-08 17:27 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0002_foreign_keys'), + ] + + operations = [ + migrations.AlterModelOptions( + name='dname', + options={'verbose_name': 'DNAME record', 'verbose_name_plural': 'DNAME records'}, + ), + migrations.AlterModelOptions( + name='domain', + options={'permissions': (('change_ttl', 'Can change the TTL of a domain object'),), 'verbose_name': 'domain', 'verbose_name_plural': 'domains'}, + ), + migrations.AlterModelOptions( + name='extension', + options={'permissions': (('use_all_extension', 'Can use all extensions'),), 'verbose_name': 'DNS extension', 'verbose_name_plural': 'DNS extensions'}, + ), + migrations.AlterModelOptions( + name='interface', + options={'permissions': (('change_interface_machine', 'Can change the owner of an interface'),), 'verbose_name': 'interface', 'verbose_name_plural': 'interfaces'}, + ), + migrations.AlterModelOptions( + name='iplist', + options={'verbose_name': 'IPv4 addresses list', 'verbose_name_plural': 'IPv4 addresses lists'}, + ), + migrations.AlterModelOptions( + name='iptype', + options={'permissions': (('use_all_iptype', 'Can use all IP types'),), 'verbose_name': 'IP type', 'verbose_name_plural': 'IP types'}, + ), + migrations.AlterModelOptions( + name='ipv6list', + options={'permissions': (('change_ipv6list_slaac_ip', 'Can change the SLAAC value of an IPv6 addresses list'),), 'verbose_name': 'IPv6 addresses list', 'verbose_name_plural': 'IPv6 addresses lists'}, + ), + migrations.AlterModelOptions( + name='machine', + options={'permissions': (('change_machine_user', 'Can change the user of a machine'),), 'verbose_name': 'machine', 'verbose_name_plural': 'machines'}, + ), + migrations.AlterModelOptions( + name='machinetype', + options={'permissions': (('use_all_machinetype', 'Can use all machine types'),), 'verbose_name': 'machine type', 'verbose_name_plural': 'machine types'}, + ), + migrations.AlterModelOptions( + name='mx', + options={'verbose_name': 'MX record', 'verbose_name_plural': 'MX records'}, + ), + migrations.AlterModelOptions( + name='nas', + options={'verbose_name': 'NAS device', 'verbose_name_plural': 'NAS devices'}, + ), + migrations.AlterModelOptions( + name='ns', + options={'verbose_name': 'NS record', 'verbose_name_plural': 'NS records'}, + ), + migrations.AlterModelOptions( + name='ouvertureportlist', + options={'verbose_name': 'ports opening list', 'verbose_name_plural': 'ports opening lists'}, + ), + migrations.AlterModelOptions( + name='role', + options={'verbose_name': 'server role', 'verbose_name_plural': 'server roles'}, + ), + migrations.AlterModelOptions( + name='service', + options={'verbose_name': 'service to generate (DHCP, DNS, ...)', 'verbose_name_plural': 'services to generate (DHCP, DNS, ...)'}, + ), + migrations.AlterModelOptions( + name='service_link', + options={'verbose_name': 'link between service and server', 'verbose_name_plural': 'links between service and server'}, + ), + migrations.AlterModelOptions( + name='soa', + options={'verbose_name': 'SOA record', 'verbose_name_plural': 'SOA records'}, + ), + migrations.AlterModelOptions( + name='srv', + options={'verbose_name': 'SRV record', 'verbose_name_plural': 'SRV records'}, + ), + migrations.AlterModelOptions( + name='sshfp', + options={'verbose_name': 'SSHFP record', 'verbose_name_plural': 'SSHFP records'}, + ), + migrations.AlterModelOptions( + name='txt', + options={'verbose_name': 'TXT record', 'verbose_name_plural': 'TXT records'}, + ), + migrations.AlterModelOptions( + name='vlan', + options={'verbose_name': 'VLAN', 'verbose_name_plural': 'VLANs'}, + ), + migrations.AlterField( + model_name='domain', + name='cname', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='related_domain', to='machines.Domain'), + ), + migrations.AlterField( + model_name='iptype', + name='ouverture_ports', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.OuverturePortList'), + ), + ] diff --git a/machines/migrations/0019_auto_20160718_1141.py b/machines/migrations/0019_auto_20160718_1141.py index 23f26a00..671ca2b0 100644 --- a/machines/migrations/0019_auto_20160718_1141.py +++ b/machines/migrations/0019_auto_20160718_1141.py @@ -34,6 +34,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="interface", name="machine", - field=models.ForeignKey(to="machines.Machine"), + field=models.ForeignKey(to="machines.Machine", on_delete=models.CASCADE), ) ] diff --git a/machines/migrations/0027_alias.py b/machines/migrations/0027_alias.py index ae63c3f7..e7149481 100644 --- a/machines/migrations/0027_alias.py +++ b/machines/migrations/0027_alias.py @@ -51,7 +51,7 @@ class Migration(migrations.Migration): unique=True, ), ), - ("interface_parent", models.ForeignKey(to="machines.Interface")), + ("interface_parent", models.ForeignKey(to="machines.Interface", on_delete=models.CASCADE)), ], ) ] diff --git a/machines/migrations/0036_auto_20161224_1204.py b/machines/migrations/0036_auto_20161224_1204.py index abc7a67e..c7481ddb 100644 --- a/machines/migrations/0036_auto_20161224_1204.py +++ b/machines/migrations/0036_auto_20161224_1204.py @@ -35,7 +35,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domain", name="interface_parent", - field=models.ForeignKey(to="machines.Interface", null=True, blank=True), + field=models.ForeignKey(to="machines.Interface", null=True, blank=True, on_delete=models.CASCADE), ), migrations.AlterUniqueTogether( name="domain", unique_together=set([("name", "extension")]) diff --git a/machines/migrations/0037_domain_cname.py b/machines/migrations/0037_domain_cname.py index be56b5c7..94c3e9fc 100644 --- a/machines/migrations/0037_domain_cname.py +++ b/machines/migrations/0037_domain_cname.py @@ -39,6 +39,7 @@ class Migration(migrations.Migration): null=True, to="machines.Domain", blank=True, + on_delete=models.CASCADE ), ) ] diff --git a/machines/migrations/0038_auto_20161224_1721.py b/machines/migrations/0038_auto_20161224_1721.py index c8515d79..1666de21 100644 --- a/machines/migrations/0038_auto_20161224_1721.py +++ b/machines/migrations/0038_auto_20161224_1721.py @@ -39,6 +39,7 @@ class Migration(migrations.Migration): to="machines.Domain", related_name="related_domain", blank=True, + on_delete=models.CASCADE, ), ) ] diff --git a/machines/migrations/0039_auto_20161224_1732.py b/machines/migrations/0039_auto_20161224_1732.py index 1ee4fb89..9a5c95c2 100644 --- a/machines/migrations/0039_auto_20161224_1732.py +++ b/machines/migrations/0039_auto_20161224_1732.py @@ -34,6 +34,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domain", name="interface_parent", - field=models.OneToOneField(blank=True, null=True, to="machines.Interface"), + field=models.OneToOneField(blank=True, null=True, to="machines.Interface", on_delete=models.CASCADE), ) ] diff --git a/machines/models.py b/machines/models.py index cc1e64d3..8e4e494f 100644 --- a/machines/models.py +++ b/machines/models.py @@ -80,7 +80,6 @@ class Machine(RevMixin, FieldPermissionModelMixin, AclMixin, models.Model): class Meta: permissions = ( - ("view_machine", _("Can view a machine object")), ("change_machine_user", _("Can change the user of a machine")), ) verbose_name = _("machine") @@ -344,7 +343,6 @@ class MachineType(RevMixin, AclMixin, models.Model): class Meta: permissions = ( - ("view_machinetype", _("Can view a machine type object")), ("use_all_machinetype", _("Can use all machine types")), ) verbose_name = _("machine type") @@ -457,11 +455,10 @@ class IpType(RevMixin, AclMixin, models.Model): default=False, help_text=_("Enable reverse DNS for IPv6.") ) vlan = models.ForeignKey("Vlan", on_delete=models.PROTECT, blank=True, null=True) - ouverture_ports = models.ForeignKey("OuverturePortList", blank=True, null=True) + ouverture_ports = models.ForeignKey("OuverturePortList", blank=True, null=True, on_delete=models.PROTECT) class Meta: permissions = ( - ("view_iptype", _("Can view an IP type object")), ("use_all_iptype", _("Can use all IP types")), ) verbose_name = _("IP type") @@ -729,7 +726,6 @@ class Vlan(RevMixin, AclMixin, models.Model): mld = models.BooleanField(default=False, help_text=_("v6 multicast management.")) class Meta: - permissions = (("view_vlan", _("Can view a VLAN object")),) verbose_name = _("VLAN") verbose_name_plural = _("VLANs") @@ -765,7 +761,6 @@ class Nas(RevMixin, AclMixin, models.Model): autocapture_mac = models.BooleanField(default=False) class Meta: - permissions = (("view_nas", _("Can view a NAS device object")),) verbose_name = _("NAS device") verbose_name_plural = _("NAS devices") @@ -819,7 +814,6 @@ class SOA(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = (("view_soa", _("Can view an SOA record object")),) verbose_name = _("SOA record") verbose_name_plural = _("SOA records") @@ -904,7 +898,6 @@ class Extension(RevMixin, AclMixin, models.Model): class Meta: permissions = ( - ("view_extension", _("Can view an extension object")), ("use_all_extension", _("Can use all extensions")), ) verbose_name = _("DNS extension") @@ -1037,7 +1030,6 @@ class Mx(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = (("view_mx", _("Can view an MX record object")),) verbose_name = _("MX record") verbose_name_plural = _("MX records") @@ -1069,7 +1061,6 @@ class Ns(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = (("view_ns", _("Can view an NS record object")),) verbose_name = _("NS record") verbose_name_plural = _("NS records") @@ -1101,7 +1092,6 @@ class Txt(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = (("view_txt", _("Can view a TXT record object")),) verbose_name = _("TXT record") verbose_name_plural = _("TXT records") @@ -1131,7 +1121,6 @@ class DName(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = (("view_dname", _("Can view a DNAME record object")),) verbose_name = _("DNAME record") verbose_name_plural = _("DNAME records") @@ -1195,7 +1184,6 @@ class Srv(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = (("view_srv", _("Can view an SRV record object")),) verbose_name = _("SRV record") verbose_name_plural = _("SRV records") @@ -1285,7 +1273,6 @@ class SshFp(RevMixin, AclMixin, models.Model): } class Meta: - permissions = (("view_sshfp", _("Can view an SSHFP record object")),) verbose_name = _("SSHFP record") verbose_name_plural = _("SSHFP records") @@ -1350,7 +1337,6 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): class Meta: permissions = ( - ("view_interface", _("Can view an interface object")), ("change_interface_machine", _("Can change the owner of an interface")), ) verbose_name = _("interface") @@ -1741,7 +1727,6 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): class Meta: permissions = ( - ("view_ipv6list", _("Can view an IPv6 addresses list object")), ( "change_ipv6list_slaac_ip", _("Can change the SLAAC value of an IPv6 addresses list"), @@ -1945,7 +1930,7 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ) extension = models.ForeignKey("Extension", on_delete=models.PROTECT) cname = models.ForeignKey( - "self", null=True, blank=True, related_name="related_domain" + "self", null=True, blank=True, related_name="related_domain", on_delete=models.PROTECT ) ttl = models.PositiveIntegerField( verbose_name=_("Time To Live (TTL)"), @@ -1956,7 +1941,6 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): class Meta: unique_together = (("name", "extension"),) permissions = ( - ("view_domain", _("Can view a domain object")), ("change_ttl", _("Can change the TTL of a domain object")), ) verbose_name = _("domain") @@ -2184,7 +2168,6 @@ class IpList(RevMixin, AclMixin, models.Model): ip_type = models.ForeignKey("IpType", on_delete=models.CASCADE) class Meta: - permissions = (("view_iplist", _("Can view an IPv4 addresses list object")),) verbose_name = _("IPv4 addresses list") verbose_name_plural = _("IPv4 addresses lists") @@ -2275,7 +2258,6 @@ class Role(RevMixin, AclMixin, models.Model): specific_role = models.CharField(choices=ROLE, null=True, blank=True, max_length=32) class Meta: - permissions = (("view_role", _("Can view a role object")),) verbose_name = _("server role") verbose_name_plural = _("server roles") @@ -2325,7 +2307,6 @@ class Service(RevMixin, AclMixin, models.Model): servers = models.ManyToManyField("Interface", through="Service_link") class Meta: - permissions = (("view_service", _("Can view a service object")),) verbose_name = _("service to generate (DHCP, DNS, ...)") verbose_name_plural = _("services to generate (DHCP, DNS, ...)") @@ -2383,9 +2364,6 @@ class Service_link(RevMixin, AclMixin, models.Model): asked_regen = models.BooleanField(default=False) class Meta: - permissions = ( - ("view_service_link", _("Can view a service server link object")), - ) verbose_name = _("link between service and server") verbose_name_plural = _("links between service and server") @@ -2438,9 +2416,6 @@ class OuverturePortList(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = ( - ("view_ouvertureportlist", _("Can view a ports opening list" " object")), - ) verbose_name = _("ports opening list") verbose_name_plural = _("ports opening lists") diff --git a/machines/urls.py b/machines/urls.py index 98a6695f..94529a76 100644 --- a/machines/urls.py +++ b/machines/urls.py @@ -26,142 +26,144 @@ The defined URLs for the Machines app from __future__ import unicode_literals -from django.conf.urls import url +from django.urls import path from . import views from . import views_autocomplete +app_name = "machines" + urlpatterns = [ - url(r"^new_machine/(?P[0-9]+)$", views.new_machine, name="new-machine"), - url( - r"^edit_interface/(?P[0-9]+)$", + path("new_machine/", views.new_machine, name="new-machine"), + path( + "edit_interface/", views.edit_interface, name="edit-interface", ), - url(r"^del_machine/(?P[0-9]+)$", views.del_machine, name="del-machine"), - url( - r"^new_interface/(?P[0-9]+)$", + path("del_machine/", views.del_machine, name="del-machine"), + path( + "new_interface/", views.new_interface, name="new-interface", ), - url( - r"^del_interface/(?P[0-9]+)$", + path( + "del_interface/", views.del_interface, name="del-interface", ), - url(r"^add_machinetype/$", views.add_machinetype, name="add-machinetype"), - url( - r"^edit_machinetype/(?P[0-9]+)$", + path("add_machinetype", views.add_machinetype, name="add-machinetype"), + path( + "edit_machinetype/", views.edit_machinetype, name="edit-machinetype", ), - url(r"^del_machinetype/$", views.del_machinetype, name="del-machinetype"), - url(r"^index_machinetype/$", views.index_machinetype, name="index-machinetype"), - url(r"^add_iptype/$", views.add_iptype, name="add-iptype"), - url(r"^edit_iptype/(?P[0-9]+)$", views.edit_iptype, name="edit-iptype"), - url(r"^del_iptype/$", views.del_iptype, name="del-iptype"), - url(r"^index_iptype/$", views.index_iptype, name="index-iptype"), - url(r"^add_extension/$", views.add_extension, name="add-extension"), - url( - r"^edit_extension/(?P[0-9]+)$", + path("del_machinetype", views.del_machinetype, name="del-machinetype"), + path("index_machinetype", views.index_machinetype, name="index-machinetype"), + path("add_iptype", views.add_iptype, name="add-iptype"), + path("edit_iptype/", views.edit_iptype, name="edit-iptype"), + path("del_iptype", views.del_iptype, name="del-iptype"), + path("index_iptype", views.index_iptype, name="index-iptype"), + path("add_extension", views.add_extension, name="add-extension"), + path( + "edit_extension/", views.edit_extension, name="edit-extension", ), - url(r"^del_extension/$", views.del_extension, name="del-extension"), - url(r"^add_soa/$", views.add_soa, name="add-soa"), - url(r"^edit_soa/(?P[0-9]+)$", views.edit_soa, name="edit-soa"), - url(r"^del_soa/$", views.del_soa, name="del-soa"), - url(r"^add_mx/$", views.add_mx, name="add-mx"), - url(r"^edit_mx/(?P[0-9]+)$", views.edit_mx, name="edit-mx"), - url(r"^del_mx/$", views.del_mx, name="del-mx"), - url(r"^add_txt/$", views.add_txt, name="add-txt"), - url(r"^edit_txt/(?P[0-9]+)$", views.edit_txt, name="edit-txt"), - url(r"^del_txt/$", views.del_txt, name="del-txt"), - url(r"^add_dname/$", views.add_dname, name="add-dname"), - url(r"^edit_dname/(?P[0-9]+)$", views.edit_dname, name="edit-dname"), - url(r"^del_dname/$", views.del_dname, name="del-dname"), - url(r"^add_ns/$", views.add_ns, name="add-ns"), - url(r"^edit_ns/(?P[0-9]+)$", views.edit_ns, name="edit-ns"), - url(r"^del_ns/$", views.del_ns, name="del-ns"), - url(r"^add_srv/$", views.add_srv, name="add-srv"), - url(r"^edit_srv/(?P[0-9]+)$", views.edit_srv, name="edit-srv"), - url(r"^del_srv/$", views.del_srv, name="del-srv"), - url(r"^new_sshfp/(?P[0-9]+)$", views.new_sshfp, name="new-sshfp"), - url(r"^edit_sshfp/(?P[0-9]+)$", views.edit_sshfp, name="edit-sshfp"), - url(r"^del_sshfp/(?P[0-9]+)$", views.del_sshfp, name="del-sshfp"), - url(r"^index_sshfp/(?P[0-9]+)$", views.index_sshfp, name="index-sshfp"), - url(r"^index_extension/$", views.index_extension, name="index-extension"), - url(r"^add_alias/(?P[0-9]+)$", views.add_alias, name="add-alias"), - url(r"^edit_alias/(?P[0-9]+)$", views.edit_alias, name="edit-alias"), - url(r"^del_alias/(?P[0-9]+)$", views.del_alias, name="del-alias"), - url( - r"^index_alias/(?P[0-9]+)$", views.index_alias, name="index-alias" + path("del_extension", views.del_extension, name="del-extension"), + path("add_soa", views.add_soa, name="add-soa"), + path("edit_soa/", views.edit_soa, name="edit-soa"), + path("del_soa", views.del_soa, name="del-soa"), + path("add_mx", views.add_mx, name="add-mx"), + path("edit_mx/", views.edit_mx, name="edit-mx"), + path("del_mx", views.del_mx, name="del-mx"), + path("add_txt", views.add_txt, name="add-txt"), + path("edit_txt/", views.edit_txt, name="edit-txt"), + path("del_txt", views.del_txt, name="del-txt"), + path("add_dname", views.add_dname, name="add-dname"), + path("edit_dname/", views.edit_dname, name="edit-dname"), + path("del_dname", views.del_dname, name="del-dname"), + path("add_ns", views.add_ns, name="add-ns"), + path("edit_ns/", views.edit_ns, name="edit-ns"), + path("del_ns", views.del_ns, name="del-ns"), + path("add_srv", views.add_srv, name="add-srv"), + path("edit_srv/", views.edit_srv, name="edit-srv"), + path("del_srv", views.del_srv, name="del-srv"), + path("new_sshfp/", views.new_sshfp, name="new-sshfp"), + path("edit_sshfp/", views.edit_sshfp, name="edit-sshfp"), + path("del_sshfp/", views.del_sshfp, name="del-sshfp"), + path("index_sshfp/", views.index_sshfp, name="index-sshfp"), + path("index_extension", views.index_extension, name="index-extension"), + path("add_alias/", views.add_alias, name="add-alias"), + path("edit_alias/", views.edit_alias, name="edit-alias"), + path("del_alias/", views.del_alias, name="del-alias"), + path( + "index_alias/", views.index_alias, name="index-alias" ), - url( - r"^new_ipv6list/(?P[0-9]+)$", + path( + "new_ipv6list/", views.new_ipv6list, name="new-ipv6list", ), - url( - r"^edit_ipv6list/(?P[0-9]+)$", + path( + "edit_ipv6list/", views.edit_ipv6list, name="edit-ipv6list", ), - url( - r"^del_ipv6list/(?P[0-9]+)$", + path( + "del_ipv6list/", views.del_ipv6list, name="del-ipv6list", ), - url(r"^index_ipv6/(?P[0-9]+)$", views.index_ipv6, name="index-ipv6"), - url(r"^add_service/$", views.add_service, name="add-service"), - url( - r"^edit_service/(?P[0-9]+)$", views.edit_service, name="edit-service" + path("index_ipv6/", views.index_ipv6, name="index-ipv6"), + path("add_service", views.add_service, name="add-service"), + path( + "edit_service/", views.edit_service, name="edit-service" ), - url(r"^del_service/$", views.del_service, name="del-service"), - url( - r"^regen_service/(?P[0-9]+)$", + path("del_service", views.del_service, name="del-service"), + path( + "regen_service/", views.regen_service, name="regen-service", ), - url(r"^index_service/$", views.index_service, name="index-service"), - url(r"^add_role/$", views.add_role, name="add-role"), - url(r"^edit_role/(?P[0-9]+)$", views.edit_role, name="edit-role"), - url(r"^del_role/$", views.del_role, name="del-role"), - url(r"^index_role/$", views.index_role, name="index-role"), - url(r"^add_vlan/$", views.add_vlan, name="add-vlan"), - url(r"^edit_vlan/(?P[0-9]+)$", views.edit_vlan, name="edit-vlan"), - url(r"^del_vlan/$", views.del_vlan, name="del-vlan"), - url(r"^index_vlan/$", views.index_vlan, name="index-vlan"), - url(r"^add_nas/$", views.add_nas, name="add-nas"), - url(r"^edit_nas/(?P[0-9]+)$", views.edit_nas, name="edit-nas"), - url(r"^del_nas/$", views.del_nas, name="del-nas"), - url(r"^index_nas/$", views.index_nas, name="index-nas"), - url(r"^$", views.index, name="index"), - url(r"index_portlist/$", views.index_portlist, name="index-portlist"), - url( - r"^edit_portlist/(?P[0-9]+)$", + path("index_service", views.index_service, name="index-service"), + path("add_role", views.add_role, name="add-role"), + path("edit_role/", views.edit_role, name="edit-role"), + path("del_role", views.del_role, name="del-role"), + path("index_role", views.index_role, name="index-role"), + path("add_vlan", views.add_vlan, name="add-vlan"), + path("edit_vlan/", views.edit_vlan, name="edit-vlan"), + path("del_vlan", views.del_vlan, name="del-vlan"), + path("index_vlan", views.index_vlan, name="index-vlan"), + path("add_nas", views.add_nas, name="add-nas"), + path("edit_nas/", views.edit_nas, name="edit-nas"), + path("del_nas", views.del_nas, name="del-nas"), + path("index_nas", views.index_nas, name="index-nas"), + path("", views.index, name="index"), + path("index_portlist", views.index_portlist, name="index-portlist"), + path( + "edit_portlist/", views.edit_portlist, name="edit-portlist", ), - url( - r"^del_portlist/(?P[0-9]+)$", + path( + "del_portlist/", views.del_portlist, name="del-portlist", ), - url(r"^add_portlist/$", views.add_portlist, name="add-portlist"), - url( - r"^port_config/(?P[0-9]+)$", + path("add_portlist", views.add_portlist, name="add-portlist"), + path( + "port_config/", views.configure_ports, name="port-config", ), ### Autocomplete Views - url(r'^vlan-autocomplete/$', views_autocomplete.VlanAutocomplete.as_view(), name='vlan-autocomplete',), - url(r'^interface-autocomplete/$', views_autocomplete.InterfaceAutocomplete.as_view(), name='interface-autocomplete',), - url(r'^machine-autocomplete/$', views_autocomplete.MachineAutocomplete.as_view(), name='machine-autocomplete',), - url(r'^machinetype-autocomplete/$', views_autocomplete.MachineTypeAutocomplete.as_view(), name='machinetype-autocomplete',), - url(r'^iptype-autocomplete/$', views_autocomplete.IpTypeAutocomplete.as_view(), name='iptype-autocomplete',), - url(r'^extension-autocomplete/$', views_autocomplete.ExtensionAutocomplete.as_view(), name='extension-autocomplete',), - url(r'^domain-autocomplete/$', views_autocomplete.DomainAutocomplete.as_view(), name='domain-autocomplete',), - url(r'^ouvertureportlist-autocomplete/$', views_autocomplete.OuverturePortListAutocomplete.as_view(), name='ouvertureportlist-autocomplete',), - url(r'^iplist-autocomplete/$', views_autocomplete.IpListAutocomplete.as_view(), name='iplist-autocomplete',), + path('vlan-autocomplete', views_autocomplete.VlanAutocomplete.as_view(), name='vlan-autocomplete',), + path('interface-autocomplete', views_autocomplete.InterfaceAutocomplete.as_view(), name='interface-autocomplete',), + path('machine-autocomplete', views_autocomplete.MachineAutocomplete.as_view(), name='machine-autocomplete',), + path('machinetype-autocomplete', views_autocomplete.MachineTypeAutocomplete.as_view(), name='machinetype-autocomplete',), + path('iptype-autocomplete', views_autocomplete.IpTypeAutocomplete.as_view(), name='iptype-autocomplete',), + path('extension-autocomplete', views_autocomplete.ExtensionAutocomplete.as_view(), name='extension-autocomplete',), + path('domain-autocomplete', views_autocomplete.DomainAutocomplete.as_view(), name='domain-autocomplete',), + path('ouvertureportlist-autocomplete', views_autocomplete.OuverturePortListAutocomplete.as_view(), name='ouvertureportlist-autocomplete',), + path('iplist-autocomplete', views_autocomplete.IpListAutocomplete.as_view(), name='iplist-autocomplete',), ] diff --git a/multi_op/urls.py b/multi_op/urls.py index 3e10c882..4cae707e 100644 --- a/multi_op/urls.py +++ b/multi_op/urls.py @@ -25,35 +25,37 @@ For further details on each of those models, see the documentation details for each. """ -from django.conf.urls import url +from django.urls import path, re_path from . import views from .preferences.views import edit_options +app_name = "multi_op" + urlpatterns = [ - url(r"^$", views.aff_state_global, name="aff-state-global"), - url( - r"^(?P[0-9]+)$", + path("", views.aff_state_global, name="aff-state-global"), + path( + "", views.aff_state_dormitory, name="aff-state-dormitory", ), - url( + re_path( r"^edit_options/(?P
MultiopOption)$", edit_options, name="edit-options", ), - url( - r"^pending-connection$", + path( + "pending-connection", views.aff_pending_connection, name="aff-pending-connection", ), - url( - r"^pending-disconnection$", + path( + "pending-disconnection", views.aff_pending_disconnection, name="aff-pending-disconnection", ), - url( - r"^disconnect-room/(?P[0-9]+)$", + path( + "disconnect-room/", views.disconnect_room, name="disconnect-room", ), diff --git a/preferences/apps.py b/preferences/apps.py new file mode 100644 index 00000000..2db4b4b1 --- /dev/null +++ b/preferences/apps.py @@ -0,0 +1,11 @@ +""" +Configuration of preferences app. +""" + +from django.apps import AppConfig + + +class PreferencesConfig(AppConfig): + """Configuration of preferences app.""" + + name = "preferences" \ No newline at end of file diff --git a/preferences/migrations/0003_auto_20210208_1827.py b/preferences/migrations/0003_auto_20210208_1827.py new file mode 100644 index 00000000..207cdc56 --- /dev/null +++ b/preferences/migrations/0003_auto_20210208_1827.py @@ -0,0 +1,65 @@ +# Generated by Django 2.2.18 on 2021-02-08 17:27 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0002_foreign_keys'), + ] + + operations = [ + migrations.AlterModelOptions( + name='assooption', + options={'verbose_name': 'organisation preferences'}, + ), + migrations.AlterModelOptions( + name='generaloption', + options={'verbose_name': 'general preferences'}, + ), + migrations.AlterModelOptions( + name='homeoption', + options={'verbose_name': 'homepage preferences'}, + ), + migrations.AlterModelOptions( + name='mailcontact', + options={'verbose_name': 'contact email address', 'verbose_name_plural': 'contact email addresses'}, + ), + migrations.AlterModelOptions( + name='mailmessageoption', + options={'verbose_name': 'email message preferences'}, + ), + migrations.AlterModelOptions( + name='mandate', + options={'verbose_name': 'mandate', 'verbose_name_plural': 'mandates'}, + ), + migrations.AlterModelOptions( + name='optionalmachine', + options={'verbose_name': 'machine preferences'}, + ), + migrations.AlterModelOptions( + name='optionaltopologie', + options={'verbose_name': 'topology preferences'}, + ), + migrations.AlterModelOptions( + name='optionaluser', + options={'verbose_name': 'user preferences'}, + ), + migrations.AlterModelOptions( + name='radiuskey', + options={'verbose_name': 'RADIUS key', 'verbose_name_plural': 'RADIUS keys'}, + ), + migrations.AlterModelOptions( + name='reminder', + options={'verbose_name': 'reminder', 'verbose_name_plural': 'reminders'}, + ), + migrations.AlterModelOptions( + name='service', + options={'verbose_name': 'service', 'verbose_name_plural': 'services'}, + ), + migrations.AlterModelOptions( + name='switchmanagementcred', + options={'verbose_name': 'switch management credentials'}, + ), + ] diff --git a/preferences/models.py b/preferences/models.py index 4c196527..b35acac3 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -185,7 +185,6 @@ class OptionalUser(AclMixin, PreferencesModel): ) class Meta: - permissions = (("view_optionaluser", _("Can view the user preferences")),) verbose_name = _("user preferences") def clean(self): @@ -241,7 +240,6 @@ class OptionalMachine(AclMixin, PreferencesModel): return not self.get_cached_value("ipv6_mode") == "DISABLED" class Meta: - permissions = (("view_optionalmachine", _("Can view the machine preferences")),) verbose_name = _("machine preferences") @@ -421,9 +419,6 @@ class OptionalTopologie(AclMixin, PreferencesModel): ) class Meta: - permissions = ( - ("view_optionaltopologie", _("Can view the topology preferences")), - ) verbose_name = _("topology preferences") @@ -453,7 +448,6 @@ class RadiusKey(AclMixin, models.Model): ) class Meta: - permissions = (("view_radiuskey", _("Can view a RADIUS key object")),) verbose_name = _("RADIUS key") verbose_name_plural = _("RADIUS keys") @@ -483,12 +477,6 @@ class SwitchManagementCred(AclMixin, models.Model): ) class Meta: - permissions = ( - ( - "view_switchmanagementcred", - _("Can view a switch management credentials object"), - ), - ) verbose_name = _("switch management credentials") def __str__(self): @@ -518,7 +506,6 @@ class Reminder(AclMixin, models.Model): ) class Meta: - permissions = (("view_reminder", _("Can view a reminder object")),) verbose_name = _("reminder") verbose_name_plural = _("reminders") @@ -582,7 +569,6 @@ class GeneralOption(AclMixin, PreferencesModel): GTU = models.FileField(upload_to="", default="", null=True, blank=True) class Meta: - permissions = (("view_generaloption", _("Can view the general preferences")),) verbose_name = _("general preferences") @@ -609,7 +595,6 @@ class Service(AclMixin, models.Model): image = models.ImageField(upload_to="logo", blank=True) class Meta: - permissions = (("view_service", _("Can view the service preferences")),) verbose_name = _("service") verbose_name_plural = _("services") @@ -641,9 +626,6 @@ class MailContact(AclMixin, models.Model): return self.address.split("@")[0] class Meta: - permissions = ( - ("view_mailcontact", _("Can view a contact email address object")), - ) verbose_name = _("contact email address") verbose_name_plural = _("contact email addresses") @@ -664,7 +646,6 @@ class Mandate(RevMixin, AclMixin, models.Model): class Meta: verbose_name = _("mandate") verbose_name_plural = _("mandates") - permissions = (("view_mandate", _("Can view a mandate object")),) president = models.ForeignKey( "users.User", @@ -740,7 +721,6 @@ class AssoOption(AclMixin, PreferencesModel): description = models.TextField(null=True, blank=True) class Meta: - permissions = (("view_assooption", _("Can view the organisation preferences")),) verbose_name = _("organisation preferences") @@ -766,7 +746,6 @@ class HomeOption(AclMixin, PreferencesModel): twitter_account_name = models.CharField(max_length=32, null=True, blank=True) class Meta: - permissions = (("view_homeoption", _("Can view the homepage preferences")),) verbose_name = _("homepage preferences") @@ -793,9 +772,6 @@ class MailMessageOption(AclMixin, models.Model): ) class Meta: - permissions = ( - ("view_mailmessageoption", _("Can view the email message preferences")), - ) verbose_name = _("email message preferences") diff --git a/preferences/urls.py b/preferences/urls.py index c919a84c..b5b72599 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -25,139 +25,140 @@ Urls de l'application preferences, pointant vers les fonctions de views from __future__ import unicode_literals -from django.conf.urls import url +from django.urls import path, re_path from . import views from .views import edit_options +app_name = "preferences" urlpatterns = [ - url( + re_path( r"^edit_options/(?P
OptionalUser)$", edit_options, name="edit-options", ), - url( + re_path( r"^edit_options/(?P
OptionalMachine)$", edit_options, name="edit-options", ), - url( + re_path( r"^edit_options/(?P
OptionalTopologie)$", edit_options, name="edit-options", ), - url( + re_path( r"^edit_options/(?P
GeneralOption)$", edit_options, name="edit-options", ), - url( + re_path( r"^edit_options/(?P
AssoOption)$", edit_options, name="edit-options", ), - url( + re_path( r"^edit_options/(?P
HomeOption)$", edit_options, name="edit-options", ), - url( + re_path( r"^edit_options/(?P
MailMessageOption)$", edit_options, name="edit-options", ), - url( + re_path( r"^edit_options/(?P
RadiusOption)$", edit_options, name="edit-options", ), - url( + re_path( r"^edit_options/(?P
CotisationsOption)$", edit_options, name="edit-options", ), - url(r"^add_service/$", views.add_service, name="add-service"), - url( - r"^edit_service/(?P[0-9]+)$", views.edit_service, name="edit-service" + path("add_service", views.add_service, name="add-service"), + path( + "edit_service/", views.edit_service, name="edit-service" ), - url(r"^del_service/(?P[0-9]+)$", views.del_service, name="del-service"), - url(r"^add_mailcontact/$", views.add_mailcontact, name="add-mailcontact"), - url( - r"^edit_mailcontact/(?P[0-9]+)$", + path("del_service/", views.del_service, name="del-service"), + path("add_mailcontact", views.add_mailcontact, name="add-mailcontact"), + path( + "edit_mailcontact/", views.edit_mailcontact, name="edit-mailcontact", ), - url(r"^del_mailcontact/$", views.del_mailcontact, name="del-mailcontact"), - url(r"^add_reminder/$", views.add_reminder, name="add-reminder"), - url( - r"^edit_reminder/(?P[0-9]+)$", + path("del_mailcontact", views.del_mailcontact, name="del-mailcontact"), + path("add_reminder", views.add_reminder, name="add-reminder"), + path( + "edit_reminder/", views.edit_reminder, name="edit-reminder", ), - url( - r"^del_reminder/(?P[0-9]+)$", + path( + "del_reminder/", views.del_reminder, name="del-reminder", ), - url(r"^add_radiuskey/$", views.add_radiuskey, name="add-radiuskey"), - url( - r"^edit_radiuskey/(?P[0-9]+)$", + path("add_radiuskey", views.add_radiuskey, name="add-radiuskey"), + path( + "edit_radiuskey/", views.edit_radiuskey, name="edit-radiuskey", ), - url( - r"^del_radiuskey/(?P[0-9]+)$", + path( + "del_radiuskey/", views.del_radiuskey, name="del-radiuskey", ), - url( - r"^add_switchmanagementcred/$", + path( + "add_switchmanagementcred", views.add_switchmanagementcred, name="add-switchmanagementcred", ), - url( - r"^edit_switchmanagementcred/(?P[0-9]+)$", + path( + "edit_switchmanagementcred/", views.edit_switchmanagementcred, name="edit-switchmanagementcred", ), - url( - r"^del_switchmanagementcred/(?P[0-9]+)$", + path( + "del_switchmanagementcred/", views.del_switchmanagementcred, name="del-switchmanagementcred", ), - url( - r"^add_document_template/$", + path( + "add_document_template", views.add_document_template, name="add-document-template", ), - url( - r"^edit_document_template/(?P[0-9]+)$", + path( + "edit_document_template/", views.edit_document_template, name="edit-document-template", ), - url( - r"^del_document_template/$", + path( + "del_document_template", views.del_document_template, name="del-document-template", ), - url(r"^add_mandate/$", views.add_mandate, name="add-mandate"), - url( - r"^edit_mandate/(?P[0-9]+)$", views.edit_mandate, name="edit-mandate" + path("add_mandate", views.add_mandate, name="add-mandate"), + path( + "edit_mandate/", views.edit_mandate, name="edit-mandate" ), - url(r"^del_mandate/(?P[0-9]+)$", views.del_mandate, name="del-mandate"), - url( - r"^add_radiusattribute/$", views.add_radiusattribute, name="add-radiusattribute" + path("del_mandate/", views.del_mandate, name="del-mandate"), + path( + "add_radiusattribute", views.add_radiusattribute, name="add-radiusattribute" ), - url( - r"^edit_radiusattribute/(?P[0-9]+)$", + path( + "edit_radiusattribute/", views.edit_radiusattribute, name="edit-radiusattribute", ), - url( - r"^del_radiusattribute/(?P[0-9]+)$", + path( + "del_radiusattribute/", views.del_radiusattribute, name="del-radiusattribute", ), - url(r"^$", views.display_options, name="display-options"), + path("", views.display_options, name="display-options"), ] diff --git a/re2o/apps.py b/re2o/apps.py new file mode 100644 index 00000000..e19abee2 --- /dev/null +++ b/re2o/apps.py @@ -0,0 +1,11 @@ +""" +Configuration of re2o app. +""" + +from django.apps import AppConfig + + +class Re2oConfig(AppConfig): + """Configuration of re2o app.""" + + name = "re2o" \ No newline at end of file diff --git a/re2o/context_processors.py b/re2o/context_processors.py index 07ee1c68..0fca6037 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -53,7 +53,7 @@ def context_user(request): else: if global_message not in [msg.message for msg in get_messages(request._request)]: messages.warning(request._request, global_message) - if user.is_authenticated(): + if user.is_authenticated: interfaces = user.user_interfaces() else: interfaces = None diff --git a/re2o/login.py b/re2o/login.py index a997074b..0df5bf6d 100644 --- a/re2o/login.py +++ b/re2o/login.py @@ -283,9 +283,9 @@ class RecryptBackend(ModelBackend): """ - def authenticate(self, username=None, password=None): + def authenticate(self, request, username=None, password=None, **kwargs): # we obtain from the classical auth backend the user - user = super(RecryptBackend, self).authenticate(None, username, password) + user = super(RecryptBackend, self).authenticate(request, username, password, **kwargs) if user: if not (user.pwd_ntlm): # if we dont have NT hash, we create it diff --git a/re2o/settings.py b/re2o/settings.py index 612741fb..66219032 100644 --- a/re2o/settings.py +++ b/re2o/settings.py @@ -84,16 +84,15 @@ LOCAL_APPS = ( INSTALLED_APPS = ( EARLY_EXTERNAL_CONTRIB_APPS + DJANGO_CONTRIB_APPS + EXTERNAL_CONTRIB_APPS + LOCAL_APPS + OPTIONNAL_APPS ) -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( + "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.locale.LocaleMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.auth.middleware.SessionAuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - "django.middleware.security.SecurityMiddleware", "reversion.middleware.RevisionMiddleware", ) @@ -195,6 +194,21 @@ GRAPH_MODELS = {"all_applications": True, "group_models": True} # Timeout when sending emails through Django (in seconds) EMAIL_TIMEOUT = 10 +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + # Activate API if "api" in INSTALLED_APPS: from api.settings import * diff --git a/re2o/templatetags/acl.py b/re2o/templatetags/acl.py index 4c88b207..d8bdc310 100644 --- a/re2o/templatetags/acl.py +++ b/re2o/templatetags/acl.py @@ -382,7 +382,7 @@ class AclNode(Node): def render(self, context): resolved_args = [arg.resolve(context) for arg in self.args] - if context["user"].is_anonymous(): + if context["user"].is_anonymous: can = False else: can, _, _ = self.callback(context["user"], *(resolved_args)) @@ -407,7 +407,7 @@ class AclInstanceNode(Node): def render(self, context): callback = get_callback(self.tag_name, self.instance.resolve(context)) resolved_args = [arg.resolve(context) for arg in self.args] - if context["user"].is_anonymous(): + if context["user"].is_anonymous: can = False else: can, _, _ = callback(context["user"], *(resolved_args)) diff --git a/re2o/urls.py b/re2o/urls.py index 0942ad48..ece23894 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -21,67 +21,47 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -"""re2o URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.8/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home) - 3. Optional: Add a custom name for this URL: - url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view()) - 3. Optional: Add a custom name for this URL: - url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) - 2. Optional: Add a custom namespace for all URL using this urlpatterns: - url(r'^blog/', include('blog.urls'), namespace='blog') -""" from __future__ import unicode_literals from django.conf import settings -from django.conf.urls import include, url +from django.urls import include, path from django.contrib import admin from django.utils.translation import ugettext_lazy as _ from django.views.generic import RedirectView from .settings_local import OPTIONNAL_APPS_RE2O -from .views import index, about_page, contact_page +from .views import index, about_page, contact_page, handler404, handler500 # Admin site configuration admin.site.index_title = _("Homepage") admin.site.index_template = "admin/custom_index.html" -handler500 = "re2o.views.handler500" -handler404 = "re2o.views.handler404" +handler500 = handler500 +handler404 = handler404 urlpatterns = [ - url(r"^$", index, name="index"), - url(r"^about/$", about_page, name="about"), - url(r"^contact/$", contact_page, name="contact"), - url(r"^i18n/", include("django.conf.urls.i18n")), - url(r"^users/", include("users.urls", namespace="users")), - url(r"^search/", include("search.urls", namespace="search")), - url(r"^cotisations/", include("cotisations.urls", namespace="cotisations")), - url(r"^machines/", include("machines.urls", namespace="machines")), - url(r"^topologie/", include("topologie.urls", namespace="topologie")), - url(r"^logs/", include("logs.urls", namespace="logs")), - url(r"^preferences/", include("preferences.urls", namespace="preferences")), + path("", index, name="index"), + path("about", about_page, name="about"), + path("contact", contact_page, name="contact"), + path("i18n/", include("django.conf.urls.i18n")), + path("users/", include("users.urls", namespace="users")), + path("search/", include("search.urls", namespace="search")), + path("cotisations/", include("cotisations.urls", namespace="cotisations")), + path("machines/", include("machines.urls", namespace="machines")), + path("topologie/", include("topologie.urls", namespace="topologie")), + path("logs/", include("logs.urls", namespace="logs")), + path("preferences/", include("preferences.urls", namespace="preferences")), # Include contrib auth and contrib admin # manage/login/ is redirected to the non-admin login page - url(r"^", include("django.contrib.auth.urls")), - url(r"^admin/login/$", RedirectView.as_view(pattern_name="login")), - url(r"^admin/", include(admin.site.urls)), + path("", include("django.contrib.auth.urls")), + path("admin/login/", RedirectView.as_view(pattern_name="login")), + path("admin/", admin.site.urls), ] urlpatterns += [ - url(r"^{}/".format(app), include("{}.urls".format(app), namespace=app)) + path("{}/".format(app), include("{}.urls".format(app), namespace=app)) for app in OPTIONNAL_APPS_RE2O ] @@ -89,6 +69,6 @@ urlpatterns += [ if "debug_toolbar" in settings.INSTALLED_APPS: import debug_toolbar - urlpatterns += [url(r"^__debug__/", include(debug_toolbar.urls))] + urlpatterns += [path("__debug__/", include(debug_toolbar.urls))] if "api" in settings.INSTALLED_APPS: - urlpatterns += [url(r"^api/", include("api.urls", namespace="api"))] + urlpatterns += [path("api/", include("api.urls", namespace="api"))] diff --git a/re2o/views.py b/re2o/views.py index bf08009a..f9bcb322 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -168,7 +168,7 @@ def handler500(request): return render(request, "errors/500.html", status=500) -def handler404(request): +def handler404(request, exception): """The handler view for a 404 error""" return render(request, "errors/404.html", status=404) diff --git a/search/apps.py b/search/apps.py new file mode 100644 index 00000000..1dad5588 --- /dev/null +++ b/search/apps.py @@ -0,0 +1,11 @@ +""" +Configuration of search app. +""" + +from django.apps import AppConfig + + +class SearchConfig(AppConfig): + """Configuration of search app.""" + + name = "search" \ No newline at end of file diff --git a/search/urls.py b/search/urls.py index 72778cfd..c39c00cc 100644 --- a/search/urls.py +++ b/search/urls.py @@ -24,11 +24,13 @@ from __future__ import unicode_literals -from django.conf.urls import url +from django.urls import path from . import views +app_name = "search" + urlpatterns = [ - url(r"^$", views.search, name="search"), - url(r"^advanced/$", views.searchp, name="searchp"), + path("", views.search, name="search"), + path("advanced", views.searchp, name="searchp"), ] diff --git a/tickets/urls.py b/tickets/urls.py index 1fcab4c5..c853fcfc 100644 --- a/tickets/urls.py +++ b/tickets/urls.py @@ -23,23 +23,25 @@ Tickets url """ -from django.conf.urls import url +from django.urls import path, re_path from . import views from .preferences.views import edit_options +app_name = "tickets" + urlpatterns = [ - url(r"^$", views.aff_tickets, name="aff-tickets"), - url(r"^(?P[0-9]+)$", views.aff_ticket, name="aff-ticket"), - url(r"^change_ticket_status/(?P[0-9]+)$", views.change_ticket_status, name="change-ticket-status"), - url(r"^edit_ticket/(?P[0-9]+)$", views.edit_ticket, name="edit-ticket"), - url( + path("", views.aff_tickets, name="aff-tickets"), + path("", views.aff_ticket, name="aff-ticket"), + path("change_ticket_status/", views.change_ticket_status, name="change-ticket-status"), + path("edit_ticket/", views.edit_ticket, name="edit-ticket"), + re_path( r"^edit_options/(?P
TicketOption)$", edit_options, name="edit-options", ), - url(r"^new_ticket/$", views.new_ticket, name="new-ticket"), - url(r"^add_comment/(?P[0-9]+)$", views.add_comment, name="add-comment"), - url(r"^edit_comment/(?P[0-9]+)$", views.edit_comment, name="edit-comment"), - url(r"^del_comment/(?P[0-9]+)$", views.del_comment, name="del-comment"), + path("new_ticket", views.new_ticket, name="new-ticket"), + path("add_comment/", views.add_comment, name="add-comment"), + path("edit_comment/", views.edit_comment, name="edit-comment"), + path("del_comment/", views.del_comment, name="del-comment"), ] diff --git a/topologie/apps.py b/topologie/apps.py new file mode 100644 index 00000000..df131bc0 --- /dev/null +++ b/topologie/apps.py @@ -0,0 +1,11 @@ +""" +Configuration of topologie app. +""" + +from django.apps import AppConfig + + +class TopologieConfig(AppConfig): + """Configuration of topologie app.""" + + name = "topologie" \ No newline at end of file diff --git a/topologie/migrations/0002_auto_20160703_1118.py b/topologie/migrations/0002_auto_20160703_1118.py index 8f5bf6a0..580d184a 100644 --- a/topologie/migrations/0002_auto_20160703_1118.py +++ b/topologie/migrations/0002_auto_20160703_1118.py @@ -52,12 +52,12 @@ class Migration(migrations.Migration): ( "_content_type", models.ForeignKey( - null=True, blank=True, to="contenttypes.ContentType" + null=True, blank=True, to="contenttypes.ContentType", on_delete=models.CASCADE ), ), ( "switch", - models.ForeignKey(related_name="ports", to="topologie.Switch"), + models.ForeignKey(related_name="ports", to="topologie.Switch", on_delete=models.CASCADE), ), ], ), diff --git a/topologie/migrations/0003_auto_20210208_1827.py b/topologie/migrations/0003_auto_20210208_1827.py new file mode 100644 index 00000000..3f4c4b6a --- /dev/null +++ b/topologie/migrations/0003_auto_20210208_1827.py @@ -0,0 +1,71 @@ +# Generated by Django 2.2.18 on 2021-02-08 17:27 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('topologie', '0002_foreign_keys'), + ] + + operations = [ + migrations.AlterModelOptions( + name='accesspoint', + options={'verbose_name': 'access point', 'verbose_name_plural': 'access points'}, + ), + migrations.AlterModelOptions( + name='building', + options={'verbose_name': 'building', 'verbose_name_plural': 'buildings'}, + ), + migrations.AlterModelOptions( + name='constructorswitch', + options={'verbose_name': 'switch constructor', 'verbose_name_plural': 'switch constructors'}, + ), + migrations.AlterModelOptions( + name='dormitory', + options={'verbose_name': 'dormitory', 'verbose_name_plural': 'dormitories'}, + ), + migrations.AlterModelOptions( + name='modelswitch', + options={'verbose_name': 'switch model', 'verbose_name_plural': 'switch models'}, + ), + migrations.AlterModelOptions( + name='moduleonswitch', + options={'verbose_name': 'link between switch and module', 'verbose_name_plural': 'links between switch and module'}, + ), + migrations.AlterModelOptions( + name='moduleswitch', + options={'verbose_name': 'switch module', 'verbose_name_plural': 'switch modules'}, + ), + migrations.AlterModelOptions( + name='port', + options={'verbose_name': 'port', 'verbose_name_plural': 'ports'}, + ), + migrations.AlterModelOptions( + name='portprofile', + options={'verbose_name': 'port profile', 'verbose_name_plural': 'port profiles'}, + ), + migrations.AlterModelOptions( + name='room', + options={'ordering': ['building__name'], 'verbose_name': 'room', 'verbose_name_plural': 'rooms'}, + ), + migrations.AlterModelOptions( + name='stack', + options={'verbose_name': 'switches stack', 'verbose_name_plural': 'switches stacks'}, + ), + migrations.AlterModelOptions( + name='switch', + options={'verbose_name': 'switch', 'verbose_name_plural': 'switches'}, + ), + migrations.AlterModelOptions( + name='switchbay', + options={'verbose_name': 'switch bay', 'verbose_name_plural': 'switch bays'}, + ), + migrations.AlterField( + model_name='port', + name='related', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='related_port', to='topologie.Port'), + ), + ] diff --git a/topologie/migrations/0013_port_related.py b/topologie/migrations/0013_port_related.py index decbeca9..08b0643d 100644 --- a/topologie/migrations/0013_port_related.py +++ b/topologie/migrations/0013_port_related.py @@ -35,7 +35,7 @@ class Migration(migrations.Migration): model_name="port", name="related", field=models.OneToOneField( - null=True, to="topologie.Port", blank=True, related_name="related_port" + null=True, to="topologie.Port", blank=True, related_name="related_port", on_delete=models.CASCADE ), ) ] diff --git a/topologie/migrations/0016_auto_20160706_1531.py b/topologie/migrations/0016_auto_20160706_1531.py index 3298e753..fa69dd68 100644 --- a/topologie/migrations/0016_auto_20160706_1531.py +++ b/topologie/migrations/0016_auto_20160706_1531.py @@ -36,7 +36,7 @@ class Migration(migrations.Migration): model_name="port", name="related", field=models.OneToOneField( - blank=True, to="topologie.Port", related_name="related_port", null=True + blank=True, to="topologie.Port", related_name="related_port", null=True, on_delete=models.CASCADE ), ), ] diff --git a/topologie/migrations/0019_auto_20161026_1348.py b/topologie/migrations/0019_auto_20161026_1348.py index 310629fc..8bcdae8d 100644 --- a/topologie/migrations/0019_auto_20161026_1348.py +++ b/topologie/migrations/0019_auto_20161026_1348.py @@ -43,7 +43,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="switch", name="switch_interface", - field=models.OneToOneField(default=1, to="machines.Interface"), + field=models.OneToOneField(default=1, to="machines.Interface", on_delete=models.CASCADE), preserve_default=False, ), migrations.AlterUniqueTogether(name="switch", unique_together=set([])), diff --git a/topologie/models.py b/topologie/models.py index faecf380..b0d78249 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -70,7 +70,6 @@ class Stack(AclMixin, RevMixin, models.Model): member_id_max = models.PositiveIntegerField() class Meta: - permissions = (("view_stack", _("Can view a stack object")),) verbose_name = _("switches stack") verbose_name_plural = _("switches stacks") @@ -106,7 +105,6 @@ class AccessPoint(Machine): ) class Meta: - permissions = (("view_accesspoint", _("Can view an access point object")),) verbose_name = _("access point") verbose_name_plural = _("access points") @@ -282,7 +280,6 @@ class Switch(Machine): class Meta: unique_together = ("stack", "stack_member_id") - permissions = (("view_switch", _("Can view a switch object")),) verbose_name = _("switch") verbose_name_plural = _("switches") @@ -590,7 +587,6 @@ class ModelSwitch(AclMixin, RevMixin, models.Model): ) class Meta: - permissions = (("view_modelswitch", _("Can view a switch model object")),) verbose_name = _("switch model") verbose_name_plural = _("switch models") @@ -623,7 +619,6 @@ class ModuleSwitch(AclMixin, RevMixin, models.Model): ) class Meta: - permissions = (("view_moduleswitch", _("Can view a switch module object")),) verbose_name = _("switch module") verbose_name_plural = _("switch modules") @@ -647,12 +642,6 @@ class ModuleOnSwitch(AclMixin, RevMixin, models.Model): ) class Meta: - permissions = ( - ( - "view_moduleonswitch", - _("Can view a link between switch and module object"), - ), - ) verbose_name = _("link between switch and module") verbose_name_plural = _("links between switch and module") unique_together = ["slot", "switch"] @@ -673,9 +662,6 @@ class ConstructorSwitch(AclMixin, RevMixin, models.Model): name = models.CharField(max_length=255) class Meta: - permissions = ( - ("view_constructorswitch", _("Can view a switch constructor object")), - ) verbose_name = _("switch constructor") verbose_name_plural = _("switch constructors") @@ -697,7 +683,6 @@ class SwitchBay(AclMixin, RevMixin, models.Model): info = models.CharField(max_length=255, blank=True, null=True) class Meta: - permissions = (("view_switchbay", _("Can view a switch bay object")),) verbose_name = _("switch bay") verbose_name_plural = _("switch bays") @@ -715,7 +700,6 @@ class Dormitory(AclMixin, RevMixin, models.Model): name = models.CharField(max_length=255) class Meta: - permissions = (("view_dormitory", _("Can view a dormitory object")),) verbose_name = _("dormitory") verbose_name_plural = _("dormitories") @@ -764,7 +748,6 @@ class Building(AclMixin, RevMixin, models.Model): dormitory = models.ForeignKey("Dormitory", on_delete=models.PROTECT) class Meta: - permissions = (("view_building", _("Can view a building object")),) verbose_name = _("building") verbose_name_plural = _("buildings") @@ -837,7 +820,7 @@ class Port(AclMixin, RevMixin, models.Model): "machines.Interface", on_delete=models.SET_NULL, blank=True, null=True ) related = models.OneToOneField( - "self", null=True, blank=True, related_name="related_port" + "self", null=True, blank=True, related_name="related_port", on_delete=models.SET_NULL ) custom_profile = models.ForeignKey( "PortProfile", on_delete=models.PROTECT, blank=True, null=True @@ -851,7 +834,6 @@ class Port(AclMixin, RevMixin, models.Model): class Meta: unique_together = ("switch", "port") - permissions = (("view_port", _("Can view a port object")),) verbose_name = _("port") verbose_name_plural = _("ports") @@ -971,7 +953,6 @@ class Room(AclMixin, RevMixin, models.Model): class Meta: ordering = ["building__name"] - permissions = (("view_room", _("Can view a room object")),) verbose_name = _("room") verbose_name_plural = _("rooms") unique_together = ("name", "building") @@ -1121,7 +1102,6 @@ class PortProfile(AclMixin, RevMixin, models.Model): ) class Meta: - permissions = (("view_portprofile", _("Can view a port profile object")),) verbose_name = _("port profile") verbose_name_plural = _("port profiles") unique_together = ["on_dormitory", "profil_default"] diff --git a/topologie/urls.py b/topologie/urls.py index 05688fd3..6e5640ee 100644 --- a/topologie/urls.py +++ b/topologie/urls.py @@ -25,157 +25,159 @@ The defined URLs for topologie app. Included in re2o.urls. from __future__ import unicode_literals -from django.conf.urls import url +from django.urls import path from . import views from . import views_autocomplete +app_name = "topologie" + urlpatterns = [ - url(r"^$", views.index, name="index"), - url(r"^index_ap/$", views.index_ap, name="index-ap"), - url(r"^new_ap/$", views.new_ap, name="new-ap"), - url(r"^edit_ap/(?P[0-9]+)$", views.edit_ap, name="edit-ap"), - url( - r"^create_ports/(?P[0-9]+)$", views.create_ports, name="create-ports" + path("", views.index, name="index"), + path("index_ap", views.index_ap, name="index-ap"), + path("new_ap", views.new_ap, name="new-ap"), + path("edit_ap/", views.edit_ap, name="edit-ap"), + path( + "create_ports/", views.create_ports, name="create-ports" ), - url(r"^index_room/$", views.index_room, name="index-room"), - url(r"^new_room/$", views.new_room, name="new-room"), - url(r"^edit_room/(?P[0-9]+)$", views.edit_room, name="edit-room"), - url(r"^del_room/(?P[0-9]+)$", views.del_room, name="del-room"), - url(r"^new_switch/$", views.new_switch, name="new-switch"), - url(r"^switch/(?P[0-9]+)$", views.index_port, name="index-port"), - url(r"^edit_port/(?P[0-9]+)$", views.edit_port, name="edit-port"), - url(r"^new_port/(?P[0-9]+)$", views.new_port, name="new-port"), - url(r"^del_port/(?P[0-9]+)$", views.del_port, name="del-port"), - url(r"^edit_switch/(?P[0-9]+)$", views.edit_switch, name="edit-switch"), - url(r"^new_stack/$", views.new_stack, name="new-stack"), - url( - r"^index_stack/$", + path("index_room", views.index_room, name="index-room"), + path("new_room", views.new_room, name="new-room"), + path("edit_room/", views.edit_room, name="edit-room"), + path("del_room/", views.del_room, name="del-room"), + path("new_switch", views.new_switch, name="new-switch"), + path("switch/", views.index_port, name="index-port"), + path("edit_port/", views.edit_port, name="edit-port"), + path("new_port/", views.new_port, name="new-port"), + path("del_port/", views.del_port, name="del-port"), + path("edit_switch/", views.edit_switch, name="edit-switch"), + path("new_stack", views.new_stack, name="new-stack"), + path( + "index_stack", views.index_stack, name="index-stack", ), - url( - r"^index_switch_bay/$", + path( + "index_switch_bay", views.index_switch_bay, name="index-switch-bay", ), - url( - r"^index_building/$", + path( + "index_building", views.index_building, name="index-building", ), - url( - r"^index_dormitory/$", + path( + "index_dormitory", views.index_dormitory, name="index-dormitory", ), - url(r"^edit_stack/(?P[0-9]+)$", views.edit_stack, name="edit-stack"), - url(r"^del_stack/(?P[0-9]+)$", views.del_stack, name="del-stack"), - url(r"^index_model_switch/$", views.index_model_switch, name="index-model-switch"), - url(r"^index_model_switch/$", views.index_model_switch, name="index-model-switch"), - url(r"^new_model_switch/$", views.new_model_switch, name="new-model-switch"), - url( - r"^edit_model_switch/(?P[0-9]+)$", + path("edit_stack/", views.edit_stack, name="edit-stack"), + path("del_stack/", views.del_stack, name="del-stack"), + path("index_model_switch", views.index_model_switch, name="index-model-switch"), + path("index_model_switch", views.index_model_switch, name="index-model-switch"), + path("new_model_switch", views.new_model_switch, name="new-model-switch"), + path( + "edit_model_switch/", views.edit_model_switch, name="edit-model-switch", ), - url( - r"^del_model_switch/(?P[0-9]+)$", + path( + "del_model_switch/", views.del_model_switch, name="del-model-switch", ), - url( - r"^new_constructor_switch/$", + path( + "new_constructor_switch", views.new_constructor_switch, name="new-constructor-switch", ), - url( - r"^edit_constructor_switch/(?P[0-9]+)$", + path( + "edit_constructor_switch/", views.edit_constructor_switch, name="edit-constructor-switch", ), - url( - r"^del_constructor_switch/(?P[0-9]+)$", + path( + "del_constructor_switch/", views.del_constructor_switch, name="del-constructor-switch", ), - url(r"^new_switch_bay/$", views.new_switch_bay, name="new-switch-bay"), - url( - r"^edit_switch_bay/(?P[0-9]+)$", + path("new_switch_bay", views.new_switch_bay, name="new-switch-bay"), + path( + "edit_switch_bay/", views.edit_switch_bay, name="edit-switch-bay", ), - url( - r"^del_switch_bay/(?P[0-9]+)$", + path( + "del_switch_bay/", views.del_switch_bay, name="del-switch-bay", ), - url(r"^new_building/$", views.new_building, name="new-building"), - url( - r"^edit_building/(?P[0-9]+)$", + path("new_building", views.new_building, name="new-building"), + path( + "edit_building/", views.edit_building, name="edit-building", ), - url( - r"^del_building/(?P[0-9]+)$", + path( + "del_building/", views.del_building, name="del-building", ), - url(r"^new_dormitory/$", views.new_dormitory, name="new-dormitory"), - url( - r"^edit_dormitory/(?P[0-9]+)$", + path("new_dormitory", views.new_dormitory, name="new-dormitory"), + path( + "edit_dormitory/", views.edit_dormitory, name="edit-dormitory", ), - url( - r"^del_dormitory/(?P[0-9]+)$", + path( + "del_dormitory/", views.del_dormitory, name="del-dormitory", ), - url(r"^index_port_profile/$", views.index_port_profile, name="index-port-profile"), - url(r"^new_port_profile/$", views.new_port_profile, name="new-port-profile"), - url( - r"^edit_port_profile/(?P[0-9]+)$", + path("index_port_profile", views.index_port_profile, name="index-port-profile"), + path("new_port_profile", views.new_port_profile, name="new-port-profile"), + path( + "edit_port_profile/", views.edit_port_profile, name="edit-port-profile", ), - url( - r"^del_port_profile/(?P[0-9]+)$", + path( + "del_port_profile/", views.del_port_profile, name="del-port-profile", ), - url( - r"^edit_vlanoptions/(?P[0-9]+)$", + path( + "edit_vlanoptions/", views.edit_vlanoptions, name="edit-vlanoptions", ), - url(r"^add_module/$", views.add_module, name="add-module"), - url( - r"^edit_module/(?P[0-9]+)$", + path("add_module", views.add_module, name="add-module"), + path( + "edit_module/", views.edit_module, name="edit-module", ), - url( - r"^del_module/(?P[0-9]+)$", views.del_module, name="del-module" + path( + "del_module/", views.del_module, name="del-module" ), - url(r"^index_module/$", views.index_module, name="index-module"), - url(r"^add_module_on/$", views.add_module_on, name="add-module-on"), - url( - r"^edit_module_on/(?P[0-9]+)$", + path("index_module", views.index_module, name="index-module"), + path("add_module_on", views.add_module_on, name="add-module-on"), + path( + "edit_module_on/", views.edit_module_on, name="edit-module-on", ), - url( - r"^del_module_on/(?P[0-9]+)$", + path( + "del_module_on/", views.del_module_on, name="del-module-on", ), ### Autocomplete Views - url(r'^room-autocomplete/$', views_autocomplete.RoomAutocomplete.as_view(), name='room-autocomplete',), - url(r'^building-autocomplete/$', views_autocomplete.BuildingAutocomplete.as_view(), name='building-autocomplete',), - url(r'^dormitory-autocomplete/$', views_autocomplete.DormitoryAutocomplete.as_view(), name='dormitory-autocomplete',), - url(r'^switch-autocomplete/$', views_autocomplete.SwitchAutocomplete.as_view(), name='switch-autocomplete',), - url(r'^port-autocomplete/$', views_autocomplete.PortAutocomplete.as_view(), name='profile-autocomplete',), - url(r'^portprofile-autocomplete/$', views_autocomplete.PortProfileAutocomplete.as_view(), name='portprofile-autocomplete',), - url(r'^switchbay-autocomplete/$', views_autocomplete.SwitchBayAutocomplete.as_view(), name='switchbay-autocomplete',), + path('room-autocomplete', views_autocomplete.RoomAutocomplete.as_view(), name='room-autocomplete',), + path('building-autocomplete', views_autocomplete.BuildingAutocomplete.as_view(), name='building-autocomplete',), + path('dormitory-autocomplete', views_autocomplete.DormitoryAutocomplete.as_view(), name='dormitory-autocomplete',), + path('switch-autocomplete', views_autocomplete.SwitchAutocomplete.as_view(), name='switch-autocomplete',), + path('port-autocomplete', views_autocomplete.PortAutocomplete.as_view(), name='profile-autocomplete',), + path('portprofile-autocomplete', views_autocomplete.PortProfileAutocomplete.as_view(), name='portprofile-autocomplete',), + path('switchbay-autocomplete', views_autocomplete.SwitchBayAutocomplete.as_view(), name='switchbay-autocomplete',), ] diff --git a/users/apps.py b/users/apps.py new file mode 100644 index 00000000..626c66e5 --- /dev/null +++ b/users/apps.py @@ -0,0 +1,11 @@ +""" +Configuration of users app. +""" + +from django.apps import AppConfig + + +class CoreConfig(AppConfig): + """Configuration of users app.""" + + name = "users" \ No newline at end of file diff --git a/users/migrations/0003_auto_20210208_1827.py b/users/migrations/0003_auto_20210208_1827.py new file mode 100644 index 00000000..ba04ab0b --- /dev/null +++ b/users/migrations/0003_auto_20210208_1827.py @@ -0,0 +1,52 @@ +# Generated by Django 2.2.18 on 2021-02-08 17:27 + +import django.contrib.auth.models +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0002_foreign_keys'), + ] + + operations = [ + migrations.AlterModelOptions( + name='ban', + options={'verbose_name': 'ban', 'verbose_name_plural': 'bans'}, + ), + migrations.AlterModelOptions( + name='emailaddress', + options={'verbose_name': 'local email account', 'verbose_name_plural': 'local email accounts'}, + ), + migrations.AlterModelOptions( + name='listright', + options={'verbose_name': 'group of rights', 'verbose_name_plural': 'groups of rights'}, + ), + migrations.AlterModelOptions( + name='listshell', + options={'verbose_name': 'shell', 'verbose_name_plural': 'shells'}, + ), + migrations.AlterModelOptions( + name='school', + options={'verbose_name': 'school', 'verbose_name_plural': 'schools'}, + ), + migrations.AlterModelOptions( + name='serviceuser', + options={'verbose_name': 'service user', 'verbose_name_plural': 'service users'}, + ), + migrations.AlterModelOptions( + name='user', + options={'permissions': (('change_user_password', 'Can change the password of a user'), ('change_user_state', 'Can edit the state of a user'), ('change_user_force', 'Can force the move'), ('change_user_shell', 'Can edit the shell of a user'), ('change_user_pseudo', 'Can edit the pseudo of a user'), ('change_user_groups', 'Can edit the groups of rights of a user (critical permission)'), ('change_all_users', 'Can edit all users, including those with rights')), 'verbose_name': 'user (member or club)', 'verbose_name_plural': 'users (members or clubs)'}, + ), + migrations.AlterModelOptions( + name='whitelist', + options={'verbose_name': 'whitelist (free of charge access)', 'verbose_name_plural': 'whitelists (free of charge access)'}, + ), + migrations.AlterModelManagers( + name='listright', + managers=[ + ('objects', django.contrib.auth.models.GroupManager()), + ], + ), + ] diff --git a/users/models.py b/users/models.py index befcd8bc..5256d7c5 100755 --- a/users/models.py +++ b/users/models.py @@ -57,7 +57,7 @@ from django.db.models.signals import post_save, post_delete, m2m_changed from django.dispatch import receiver from django.utils.functional import cached_property from django.template import loader -from django.core.urlresolvers import reverse +from django.urls import reverse from django.db import transaction from django.utils import timezone from datetime import timedelta @@ -319,7 +319,6 @@ class User( _("Can edit the groups of rights of a user (critical permission)"), ), ("change_all_users", _("Can edit all users, including those with rights")), - ("view_user", _("Can view a user object")), ) verbose_name = _("user (member or club)") verbose_name_plural = _("users (members or clubs)") @@ -2161,7 +2160,6 @@ class ServiceUser(RevMixin, AclMixin, AbstractBaseUser): objects = UserManager() class Meta: - permissions = (("view_serviceuser", _("Can view a service user object")),) verbose_name = _("service user") verbose_name_plural = _("service users") @@ -2218,7 +2216,6 @@ class School(RevMixin, AclMixin, models.Model): name = models.CharField(max_length=255) class Meta: - permissions = (("view_school", _("Can view a school object")),) verbose_name = _("school") verbose_name_plural = _("schools") @@ -2272,7 +2269,6 @@ class ListRight(RevMixin, AclMixin, Group): details = models.CharField(help_text=_("Description."), max_length=255, blank=True) class Meta: - permissions = (("view_listright", _("Can view a group of rights object")),) verbose_name = _("group of rights") verbose_name_plural = _("groups of rights") @@ -2312,7 +2308,6 @@ class ListShell(RevMixin, AclMixin, models.Model): shell = models.CharField(max_length=255, unique=True) class Meta: - permissions = (("view_listshell", _("Can view a shell object")),) verbose_name = _("shell") verbose_name_plural = _("shells") @@ -2378,7 +2373,6 @@ class Ban(RevMixin, AclMixin, models.Model): request = None class Meta: - permissions = (("view_ban", _("Can view a ban object")),) verbose_name = _("ban") verbose_name_plural = _("bans") @@ -2495,7 +2489,6 @@ class Whitelist(RevMixin, AclMixin, models.Model): date_end = models.DateTimeField() class Meta: - permissions = (("view_whitelist", _("Can view a whitelist object")),) verbose_name = _("whitelist (free of charge access)") verbose_name_plural = _("whitelists (free of charge access)") @@ -2617,9 +2610,6 @@ class EMailAddress(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = ( - ("view_emailaddress", _("Can view a local email account object")), - ) verbose_name = _("local email account") verbose_name_plural = _("local email accounts") diff --git a/users/urls.py b/users/urls.py index b7d52ddc..3dc1d5d8 100644 --- a/users/urls.py +++ b/users/urls.py @@ -28,111 +28,113 @@ The defined URLs for the Users app from __future__ import unicode_literals -from django.conf.urls import url +from django.urls import path, re_path from . import views from . import views_autocomplete +app_name = "users" + urlpatterns = [ - url(r"^new_user/$", views.new_user, name="new-user"), - url(r"^new_club/$", views.new_club, name="new-club"), - url(r"^edit_info/(?P[0-9]+)$", views.edit_info, name="edit-info"), - url( - r"^edit_club_admin_members/(?P[0-9]+)$", + path("new_user", views.new_user, name="new-user"), + path("new_club", views.new_club, name="new-club"), + path("edit_info/", views.edit_info, name="edit-info"), + path( + "edit_club_admin_members/", views.edit_club_admin_members, name="edit-club-admin-members", ), - url(r"^state/(?P[0-9]+)$", views.state, name="state"), - url(r"^groups/(?P[0-9]+)$", views.groups, name="groups"), - url(r"^password/(?P[0-9]+)$", views.password, name="password"), - url(r"^confirm_email/(?P[0-9]+)$", views.resend_confirmation_email, name="resend-confirmation-email"), - url( - r"^del_group/(?P[0-9]+)/(?P[0-9]+)$", + path("state/", views.state, name="state"), + path("groups/", views.groups, name="groups"), + path("password/", views.password, name="password"), + path("confirm_email/", views.resend_confirmation_email, name="resend-confirmation-email"), + path( + "del_group//", views.del_group, name="del-group", ), - url( - r"^del_superuser/(?P[0-9]+)$", views.del_superuser, name="del-superuser" + path( + "del_superuser/", views.del_superuser, name="del-superuser" ), - url(r"^new_serviceuser/$", views.new_serviceuser, name="new-serviceuser"), - url( - r"^edit_serviceuser/(?P[0-9]+)$", + path("new_serviceuser", views.new_serviceuser, name="new-serviceuser"), + path( + "edit_serviceuser/", views.edit_serviceuser, name="edit-serviceuser", ), - url( - r"^del_serviceuser/(?P[0-9]+)$", + path( + "del_serviceuser/", views.del_serviceuser, name="del-serviceuser", ), - url(r"^add_ban/(?P[0-9]+)$", views.add_ban, name="add-ban"), - url(r"^edit_ban/(?P[0-9]+)$", views.edit_ban, name="edit-ban"), - url(r"^del-ban/(?P[0-9]+)$", views.del_ban, name="del-ban"), - url( - r"^add_whitelist/(?P[0-9]+)$", views.add_whitelist, name="add-whitelist" + path("add_ban/", views.add_ban, name="add-ban"), + path("edit_ban/", views.edit_ban, name="edit-ban"), + path("del-ban/", views.del_ban, name="del-ban"), + path( + "add_whitelist/", views.add_whitelist, name="add-whitelist" ), - url( - r"^edit_whitelist/(?P[0-9]+)$", + path( + "edit_whitelist/", views.edit_whitelist, name="edit-whitelist", ), - url( - r"^del_whitelist/(?P[0-9]+)$", + path( + "del_whitelist/", views.del_whitelist, name="del-whitelist", ), - url( - r"^add_emailaddress/(?P[0-9]+)$", + path( + "add_emailaddress/", views.add_emailaddress, name="add-emailaddress", ), - url( - r"^edit_emailaddress/(?P[0-9]+)$", + path( + "edit_emailaddress/", views.edit_emailaddress, name="edit-emailaddress", ), - url( - r"^del_emailaddress/(?P[0-9]+)$", + path( + "del_emailaddress/", views.del_emailaddress, name="del-emailaddress", ), - url( - r"^edit_email_settings/(?P[0-9]+)$", + path( + "edit_email_settings/", views.edit_email_settings, name="edit-email-settings", ), - url(r"^add_school/$", views.add_school, name="add-school"), - url(r"^edit_school/(?P[0-9]+)$", views.edit_school, name="edit-school"), - url(r"^del_school/$", views.del_school, name="del-school"), - url(r"^add_listright/$", views.add_listright, name="add-listright"), - url( - r"^edit_listright/(?P[0-9]+)$", + path("add_school", views.add_school, name="add-school"), + path("edit_school/", views.edit_school, name="edit-school"), + path("del_school", views.del_school, name="del-school"), + path("add_listright", views.add_listright, name="add-listright"), + path( + "edit_listright/", views.edit_listright, name="edit-listright", ), - url(r"^del_listright/$", views.del_listright, name="del-listright"), - url(r"^add_shell/$", views.add_shell, name="add-shell"), - url(r"^edit_shell/(?P[0-9]+)$", views.edit_shell, name="edit-shell"), - url(r"^del_shell/(?P[0-9]+)$", views.del_shell, name="del-shell"), - url(r"^profil/(?P[0-9]+)$", views.profil, name="profil"), - url(r"^index_ban/$", views.index_ban, name="index-ban"), - url(r"^index_white/$", views.index_white, name="index-white"), - url(r"^index_school/$", views.index_school, name="index-school"), - url(r"^index_shell/$", views.index_shell, name="index-shell"), - url(r"^index_listright/$", views.index_listright, name="index-listright"), - url(r"^index_serviceusers/$", views.index_serviceusers, name="index-serviceusers"), - url(r"^mon_profil/$", views.mon_profil, name="mon-profil"), - url(r"^process/(?P[a-z0-9]{32})/$", views.process, name="process"), - url(r"^reset_password/$", views.reset_password, name="reset-password"), - url(r"^mass_archive/$", views.mass_archive, name="mass-archive"), - url(r"^$", views.index, name="index"), - url(r"^index_clubs/$", views.index_clubs, name="index-clubs"), - url(r"^initial_register/$", views.initial_register, name="initial-register"), - url(r"^edit_theme/(?P[0-9]+)$", views.edit_theme, name="edit-theme"), + path("del_listright", views.del_listright, name="del-listright"), + path("add_shell", views.add_shell, name="add-shell"), + path("edit_shell/", views.edit_shell, name="edit-shell"), + path("del_shell/", views.del_shell, name="del-shell"), + path("profil/", views.profil, name="profil"), + path("index_ban", views.index_ban, name="index-ban"), + path("index_white", views.index_white, name="index-white"), + path("index_school", views.index_school, name="index-school"), + path("index_shell", views.index_shell, name="index-shell"), + path("index_listright", views.index_listright, name="index-listright"), + path("index_serviceusers", views.index_serviceusers, name="index-serviceusers"), + path("mon_profil", views.mon_profil, name="mon-profil"), + re_path(r"^process/(?P[a-z0-9]{32})/$", views.process, name="process"), + path("reset_password", views.reset_password, name="reset-password"), + path("mass_archive", views.mass_archive, name="mass-archive"), + path("", views.index, name="index"), + path("index_clubs", views.index_clubs, name="index-clubs"), + path("initial_register", views.initial_register, name="initial-register"), + path("edit_theme/", views.edit_theme, name="edit-theme"), ### Autocomplete Views - url(r'^user-autocomplete/$', views_autocomplete.UserAutocomplete.as_view(), name='user-autocomplete',), - url(r'^adherent-autocomplete/$', views_autocomplete.AdherentAutocomplete.as_view(), name='adherent-autocomplete',), - url(r'^club-autocomplete/$', views_autocomplete.ClubAutocomplete.as_view(), name='club-autocomplete',), - url(r'^school-autocomplete/$', views_autocomplete.SchoolAutocomplete.as_view(), name='school-autocomplete',), - url(r'^shell-autocomplete/$', views_autocomplete.ShellAutocomplete.as_view(), name='shell-autocomplete',), + path('user-autocomplete', views_autocomplete.UserAutocomplete.as_view(), name='user-autocomplete',), + path('adherent-autocomplete', views_autocomplete.AdherentAutocomplete.as_view(), name='adherent-autocomplete',), + path('club-autocomplete', views_autocomplete.ClubAutocomplete.as_view(), name='club-autocomplete',), + path('school-autocomplete', views_autocomplete.SchoolAutocomplete.as_view(), name='school-autocomplete',), + path('shell-autocomplete', views_autocomplete.ShellAutocomplete.as_view(), name='shell-autocomplete',), ] From ec2b4afd4113b5a1d45c9c984f2f9617e7d46c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Pi=C3=A9tri?= Date: Wed, 10 Feb 2021 11:06:09 +0100 Subject: [PATCH 2/7] style: :art: Apply black and isort --- api/apps.py | 2 +- api/authentication.py | 6 +- api/permissions.py | 3 +- api/serializers.py | 5 - api/urls.py | 5 +- api/views.py | 5 +- cotisations/admin.py | 4 +- cotisations/api/serializers.py | 45 ++-- cotisations/api/urls.py | 5 +- cotisations/api/views.py | 32 +-- cotisations/apps.py | 2 +- cotisations/forms.py | 19 +- cotisations/models.py | 70 ++++-- cotisations/payment_methods/__init__.py | 2 +- cotisations/payment_methods/balance/models.py | 3 +- cotisations/payment_methods/cheque/forms.py | 2 +- cotisations/payment_methods/cheque/urls.py | 1 + cotisations/payment_methods/cheque/views.py | 8 +- .../payment_methods/comnpay/comnpay.py | 8 +- cotisations/payment_methods/comnpay/models.py | 8 +- cotisations/payment_methods/comnpay/urls.py | 1 + cotisations/payment_methods/comnpay/views.py | 16 +- cotisations/payment_methods/forms.py | 3 +- cotisations/payment_methods/free/models.py | 6 +- .../payment_methods/note_kfet/models.py | 6 +- cotisations/payment_methods/note_kfet/note.py | 2 +- cotisations/payment_methods/note_kfet/urls.py | 1 + .../payment_methods/note_kfet/views.py | 17 +- cotisations/payment_methods/urls.py | 9 +- cotisations/test_models.py | 48 ++-- cotisations/test_views.py | 11 +- cotisations/tex.py | 13 +- cotisations/urls.py | 23 +- cotisations/utils.py | 18 +- cotisations/views.py | 93 +++----- cotisations/views_autocomplete.py | 13 +- freeradius_utils/auth.py | 26 +- ldap_sync/admin.py | 10 +- ldap_sync/apps.py | 2 +- ldap_sync/management/commands/ldap_rebuild.py | 7 +- ldap_sync/management/commands/ldap_sync.py | 2 +- ldap_sync/models.py | 43 ++-- ldap_sync/urls.py | 3 +- logs/apps.py | 2 +- logs/forms.py | 9 +- logs/models.py | 87 +++---- logs/urls.py | 6 +- logs/views.py | 98 +++----- machines/admin.py | 22 +- machines/api/serializers.py | 78 +++--- machines/api/urls.py | 6 +- machines/api/views.py | 75 +++--- machines/apps.py | 2 +- machines/forms.py | 42 +--- machines/models.py | 164 ++++++------- machines/urls.py | 65 +++-- machines/views.py | 154 +++++------- machines/views_autocomplete.py | 17 +- multi_op/forms.py | 10 +- multi_op/models.py | 15 +- multi_op/preferences/__init__.py | 2 +- multi_op/preferences/forms.py | 3 +- multi_op/preferences/models.py | 2 +- multi_op/preferences/views.py | 14 +- multi_op/views.py | 46 ++-- preferences/admin.py | 19 +- preferences/api/serializers.py | 33 +-- preferences/api/urls.py | 8 +- preferences/api/views.py | 34 +-- preferences/apps.py | 2 +- preferences/forms.py | 59 ++--- preferences/models.py | 27 +-- preferences/urls.py | 12 +- preferences/views.py | 64 ++--- re2o/acl.py | 2 +- re2o/aes_field.py | 14 +- re2o/apps.py | 2 +- re2o/base.py | 13 +- re2o/context_processors.py | 19 +- re2o/contributors.py | 82 +++---- re2o/field_permissions.py | 4 +- re2o/login.py | 22 +- re2o/mail_utils.py | 16 +- re2o/management/commands/gen_contrib.py | 1 + re2o/mixins.py | 3 +- re2o/script_utils.py | 26 +- re2o/settings.py | 24 +- re2o/settings_default.py | 24 +- re2o/settings_local.example.py | 24 +- re2o/templatetags/acl.py | 5 +- re2o/templatetags/pagination_extra.py | 10 +- re2o/templatetags/self_adhesion.py | 2 +- re2o/urls.py | 5 +- re2o/utils.py | 93 +++++--- re2o/views.py | 35 ++- re2o/widgets.py | 8 +- re2o/wsgi.py | 3 +- search/apps.py | 2 +- search/engine.py | 13 +- search/forms.py | 1 + search/views.py | 31 +-- test_utils/runner.py | 7 +- tickets/admin.py | 7 +- tickets/forms.py | 18 +- tickets/models.py | 51 ++-- tickets/preferences/__init__.py | 2 +- tickets/preferences/forms.py | 3 +- tickets/preferences/models.py | 2 +- tickets/preferences/views.py | 13 +- tickets/urls.py | 6 +- tickets/views.py | 63 +++-- topologie/admin.py | 16 +- topologie/api/serializers.py | 51 ++-- topologie/api/urls.py | 3 +- topologie/api/views.py | 47 ++-- topologie/apps.py | 2 +- topologie/forms.py | 28 +-- topologie/models.py | 53 ++--- topologie/urls.py | 53 +++-- topologie/views.py | 83 +++---- topologie/views_autocomplete.py | 15 +- users/admin.py | 55 +++-- users/api/serializers.py | 42 ++-- users/api/urls.py | 5 +- users/api/views.py | 51 ++-- users/apps.py | 2 +- users/forms.py | 103 ++++---- users/management/commands/anonymise.py | 23 +- users/management/commands/chgpass.py | 7 +- users/management/commands/chsh.py | 6 +- .../management/commands/clean_notyetactive.py | 12 +- .../management/commands/derniere_connexion.py | 2 +- .../commands/disable_emailnotyetconfirmed.py | 10 +- users/models.py | 225 +++++++++--------- users/signals.py | 12 +- users/test_models.py | 6 +- users/tests.py | 8 +- users/urls.py | 47 ++-- users/views.py | 190 ++++++++------- users/views_autocomplete.py | 10 +- users/widgets.py | 21 +- 141 files changed, 1687 insertions(+), 1942 deletions(-) diff --git a/api/apps.py b/api/apps.py index f2bfb744..f7cbb3b9 100644 --- a/api/apps.py +++ b/api/apps.py @@ -8,4 +8,4 @@ from django.apps import AppConfig class ApiConfig(AppConfig): """Configuration of api app.""" - name = "api" \ No newline at end of file + name = "api" diff --git a/api/authentication.py b/api/authentication.py index 1fa381e0..af9afa69 100644 --- a/api/authentication.py +++ b/api/authentication.py @@ -31,12 +31,10 @@ from rest_framework.authentication import TokenAuthentication class ExpiringTokenAuthentication(TokenAuthentication): - """Authenticate a user if the provided token is valid and not expired. - """ + """Authenticate a user if the provided token is valid and not expired.""" def authenticate_credentials(self, key): - """See base class. Add the verification the token is not expired. - """ + """See base class. Add the verification the token is not expired.""" base = super(ExpiringTokenAuthentication, self) user, token = base.authenticate_credentials(key) diff --git a/api/permissions.py b/api/permissions.py index 7ab96f1e..8e3bd2d4 100644 --- a/api/permissions.py +++ b/api/permissions.py @@ -22,8 +22,9 @@ """Defines the permission classes used in the API. """ -from rest_framework import permissions, exceptions from django.http import Http404 +from rest_framework import exceptions, permissions + from . import acl diff --git a/api/serializers.py b/api/serializers.py index de57e26a..cbbfafdb 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -24,7 +24,6 @@ from rest_framework import serializers - # The namespace used for the API. It must match the namespace used in the # urlpatterns to include the API URLs. API_NAMESPACE = "api" @@ -59,7 +58,3 @@ class NamespacedHMSerializer(serializers.HyperlinkedModelSerializer): serializer_related_field = NamespacedHRField serializer_url_field = NamespacedHIField - - - - diff --git a/api/urls.py b/api/urls.py index 8d57b172..be7b197c 100644 --- a/api/urls.py +++ b/api/urls.py @@ -28,12 +28,13 @@ can also be register. That way a complete API root page presenting all URLs can be generated automatically. """ -from django.urls import path, include from importlib import import_module +from django.conf import settings +from django.urls import include, path + from . import views from .routers import AllViewsRouter -from django.conf import settings app_name = "api" diff --git a/api/views.py b/api/views.py index 70ff33bf..5a4a902f 100644 --- a/api/views.py +++ b/api/views.py @@ -29,9 +29,9 @@ the response (JSON or other), the CSRF exempting, ... import datetime from django.conf import settings -from django.db.models import Q from django.contrib.auth.models import Group -from rest_framework import viewsets, generics, views +from django.db.models import Q +from rest_framework import generics, views, viewsets from rest_framework.authtoken.models import Token from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.response import Response @@ -41,7 +41,6 @@ from .pagination import PageSizedPagination from .permissions import ACLPermission - class ObtainExpiringAuthToken(ObtainAuthToken): """Exposes a view to obtain a authentication token. diff --git a/cotisations/admin.py b/cotisations/admin.py index ea280fca..5ea24e32 100644 --- a/cotisations/admin.py +++ b/cotisations/admin.py @@ -29,8 +29,8 @@ from __future__ import unicode_literals from django.contrib import admin from reversion.admin import VersionAdmin -from .models import Facture, Article, Banque, Paiement, Cotisation, Vente -from .models import CustomInvoice, CostEstimate +from .models import (Article, Banque, CostEstimate, Cotisation, CustomInvoice, + Facture, Paiement, Vente) class FactureAdmin(VersionAdmin): diff --git a/cotisations/api/serializers.py b/cotisations/api/serializers.py index f7279ea9..bfc785c7 100644 --- a/cotisations/api/serializers.py +++ b/cotisations/api/serializers.py @@ -23,13 +23,13 @@ from rest_framework import serializers import cotisations.models as cotisations import preferences.models as preferences -from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer +from api.serializers import (NamespacedHIField, NamespacedHMSerializer, + NamespacedHRField) from users.api.serializers import UserSerializer class FactureSerializer(NamespacedHMSerializer): - """Serialize `cotisations.models.Facture` objects. - """ + """Serialize `cotisations.models.Facture` objects.""" class Meta: model = cotisations.Facture @@ -54,8 +54,7 @@ class BaseInvoiceSerializer(NamespacedHMSerializer): class VenteSerializer(NamespacedHMSerializer): - """Serialize `cotisations.models.Vente` objects. - """ + """Serialize `cotisations.models.Vente` objects.""" class Meta: model = cotisations.Vente @@ -74,17 +73,24 @@ class VenteSerializer(NamespacedHMSerializer): class ArticleSerializer(NamespacedHMSerializer): - """Serialize `cotisations.models.Article` objects. - """ + """Serialize `cotisations.models.Article` objects.""" class Meta: model = cotisations.Article - fields = ("name", "prix", "duration_membership", "duration_days_membership", "duration_connection", "duration_days_connection", "type_user", "api_url") + fields = ( + "name", + "prix", + "duration_membership", + "duration_days_membership", + "duration_connection", + "duration_days_connection", + "type_user", + "api_url", + ) class BanqueSerializer(NamespacedHMSerializer): - """Serialize `cotisations.models.Banque` objects. - """ + """Serialize `cotisations.models.Banque` objects.""" class Meta: model = cotisations.Banque @@ -92,8 +98,7 @@ class BanqueSerializer(NamespacedHMSerializer): class PaiementSerializer(NamespacedHMSerializer): - """Serialize `cotisations.models.Paiement` objects. - """ + """Serialize `cotisations.models.Paiement` objects.""" class Meta: model = cotisations.Paiement @@ -101,17 +106,23 @@ class PaiementSerializer(NamespacedHMSerializer): class CotisationSerializer(NamespacedHMSerializer): - """Serialize `cotisations.models.Cotisation` objects. - """ + """Serialize `cotisations.models.Cotisation` objects.""" class Meta: model = cotisations.Cotisation - fields = ("vente", "type_cotisation", "date_start_con", "date_end_con", "date_start_memb", "date_end_memb", "api_url") + fields = ( + "vente", + "type_cotisation", + "date_start_con", + "date_end_con", + "date_start_memb", + "date_end_memb", + "api_url", + ) class ReminderUsersSerializer(UserSerializer): - """Serialize the data about a mailing member. - """ + """Serialize the data about a mailing member.""" class Meta(UserSerializer.Meta): fields = ("get_full_name", "get_mail") diff --git a/cotisations/api/urls.py b/cotisations/api/urls.py index 85e60c72..69af4105 100644 --- a/cotisations/api/urls.py +++ b/cotisations/api/urls.py @@ -27,12 +27,11 @@ urls_viewset = [ (r"cotisations/article", views.ArticleViewSet, None), (r"cotisations/banque", views.BanqueViewSet, None), (r"cotisations/paiement", views.PaiementViewSet, None), - (r"cotisations/cotisation", views.CotisationViewSet, None) + (r"cotisations/cotisation", views.CotisationViewSet, None), ] urls_view = [ (r"cotisations/reminder-get-users", views.ReminderView), - # Deprecated (r"reminder/get-users", views.ReminderView), -] \ No newline at end of file +] diff --git a/cotisations/api/views.py b/cotisations/api/views.py index 2995e721..bdc7504d 100644 --- a/cotisations/api/views.py +++ b/cotisations/api/views.py @@ -19,71 +19,65 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -from rest_framework import viewsets, generics +from rest_framework import generics, viewsets -from . import serializers import cotisations.models as cotisations import preferences.models as preferences +from . import serializers + + class FactureViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `cotisations.models.Facture` objects. - """ + """Exposes list and details of `cotisations.models.Facture` objects.""" queryset = cotisations.Facture.objects.all() serializer_class = serializers.FactureSerializer class FactureViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `cotisations.models.Facture` objects. - """ + """Exposes list and details of `cotisations.models.Facture` objects.""" queryset = cotisations.BaseInvoice.objects.all() serializer_class = serializers.BaseInvoiceSerializer class VenteViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `cotisations.models.Vente` objects. - """ + """Exposes list and details of `cotisations.models.Vente` objects.""" queryset = cotisations.Vente.objects.all() serializer_class = serializers.VenteSerializer class ArticleViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `cotisations.models.Article` objects. - """ + """Exposes list and details of `cotisations.models.Article` objects.""" queryset = cotisations.Article.objects.all() serializer_class = serializers.ArticleSerializer class BanqueViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `cotisations.models.Banque` objects. - """ + """Exposes list and details of `cotisations.models.Banque` objects.""" queryset = cotisations.Banque.objects.all() serializer_class = serializers.BanqueSerializer class PaiementViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `cotisations.models.Paiement` objects. - """ + """Exposes list and details of `cotisations.models.Paiement` objects.""" queryset = cotisations.Paiement.objects.all() serializer_class = serializers.PaiementSerializer class CotisationViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `cotisations.models.Cotisation` objects. - """ + """Exposes list and details of `cotisations.models.Cotisation` objects.""" queryset = cotisations.Cotisation.objects.all() serializer_class = serializers.CotisationSerializer class ReminderView(generics.ListAPIView): - """Output for users to remind an end of their subscription. - """ + """Output for users to remind an end of their subscription.""" queryset = preferences.Reminder.objects.all() - serializer_class = serializers.ReminderSerializer \ No newline at end of file + serializer_class = serializers.ReminderSerializer diff --git a/cotisations/apps.py b/cotisations/apps.py index 1b85f0b3..16bf8250 100644 --- a/cotisations/apps.py +++ b/cotisations/apps.py @@ -8,4 +8,4 @@ from django.apps import AppConfig class CotisationsConfig(AppConfig): """Configuration of cotisations app.""" - name = "cotisations" \ No newline at end of file + name = "cotisations" diff --git a/cotisations/forms.py b/cotisations/forms.py index f9e44686..fcbe66f6 100644 --- a/cotisations/forms.py +++ b/cotisations/forms.py @@ -37,25 +37,18 @@ of each of the method. from __future__ import unicode_literals from django import forms -from django.db.models import Q -from django.forms import ModelForm, Form from django.core.validators import MinValueValidator - -from django.utils.translation import ugettext_lazy as _ +from django.db.models import Q +from django.forms import Form, ModelForm from django.shortcuts import get_object_or_404 +from django.utils.translation import ugettext_lazy as _ from re2o.field_permissions import FieldPermissionFormMixin from re2o.mixins import FormRevMixin from re2o.widgets import AutocompleteModelWidget -from .models import ( - Article, - Paiement, - Facture, - Banque, - CustomInvoice, - Vente, - CostEstimate, -) + +from .models import (Article, Banque, CostEstimate, CustomInvoice, Facture, + Paiement, Vente) from .payment_methods import balance diff --git a/cotisations/models.py b/cotisations/models.py index c93725a4..556e13f5 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -32,29 +32,29 @@ each. """ from __future__ import unicode_literals -from dateutil.relativedelta import relativedelta +from dateutil.relativedelta import relativedelta +from django.contrib import messages +from django.core.validators import MinValueValidator from django.db import models -from django.db.models import Q, Max -from django.db.models.signals import post_save, post_delete +from django.db.models import Max, Q +from django.db.models.signals import post_delete, post_save from django.dispatch import receiver from django.forms import ValidationError -from django.core.validators import MinValueValidator +from django.shortcuts import redirect +from django.urls import reverse from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from django.urls import reverse -from django.shortcuts import redirect -from django.contrib import messages -from preferences.models import CotisationsOption +import users.models +import users.signals +from cotisations.utils import (find_payment_method, send_mail_invoice, + send_mail_voucher) +from cotisations.validators import check_no_balance from machines.models import regen +from preferences.models import CotisationsOption from re2o.field_permissions import FieldPermissionModelMixin from re2o.mixins import AclMixin, RevMixin -import users.signals -import users.models - -from cotisations.utils import find_payment_method, send_mail_invoice, send_mail_voucher -from cotisations.validators import check_no_balance class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): @@ -360,7 +360,13 @@ def facture_post_save(**kwargs): if facture.valid: user = facture.user user.set_active() - users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=True, mac_refresh=False) + users.signals.synchronise.send( + sender=users.models.User, + instance=user, + base=False, + access_refresh=True, + mac_refresh=False, + ) @receiver(post_delete, sender=Facture) @@ -369,7 +375,13 @@ def facture_post_delete(**kwargs): Synchronise the LDAP user after an invoice has been deleted. """ user = kwargs["instance"].user - users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=True, mac_refresh=False) + users.signals.synchronise.send( + sender=users.models.User, + instance=user, + base=False, + access_refresh=True, + mac_refresh=False, + ) class CustomInvoice(BaseInvoice): @@ -481,9 +493,7 @@ class Vente(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = ( - ("change_all_vente", _("Can edit all the previous purchases")), - ) + permissions = (("change_all_vente", _("Can edit all the previous purchases")),) verbose_name = _("purchase") verbose_name_plural = _("purchases") @@ -660,7 +670,13 @@ def vente_post_save(**kwargs): purchase.cotisation.save() user = purchase.facture.facture.user user.set_active() - users.signals.synchronise.send(sender=users.models.User, instance=user, base=True, access_refresh=True, mac_refresh=False) + users.signals.synchronise.send( + sender=users.models.User, + instance=user, + base=True, + access_refresh=True, + mac_refresh=False, + ) # TODO : change vente to purchase @@ -676,7 +692,13 @@ def vente_post_delete(**kwargs): return if purchase.type_cotisation: user = invoice.user - users.signals.synchronise.send(sender=users.models.User, instance=user, base=True, access_refresh=True, mac_refresh=False) + users.signals.synchronise.send( + sender=users.models.User, + instance=user, + base=True, + access_refresh=True, + mac_refresh=False, + ) class Article(RevMixin, AclMixin, models.Model): @@ -740,9 +762,7 @@ class Article(RevMixin, AclMixin, models.Model): unique_together = ("name", "type_user") class Meta: - permissions = ( - ("buy_every_article", _("Can buy every article")), - ) + permissions = (("buy_every_article", _("Can buy every article")),) verbose_name = "article" verbose_name_plural = "articles" @@ -844,9 +864,7 @@ class Paiement(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = ( - ("use_every_payment", _("Can use every payment method")), - ) + permissions = (("use_every_payment", _("Can use every payment method")),) verbose_name = _("payment method") verbose_name_plural = _("payment methods") diff --git a/cotisations/payment_methods/__init__.py b/cotisations/payment_methods/__init__.py index 1170bd92..bd4bf525 100644 --- a/cotisations/payment_methods/__init__.py +++ b/cotisations/payment_methods/__init__.py @@ -127,6 +127,6 @@ method to your model, where `form` is an instance of """ -from . import comnpay, cheque, balance, note_kfet, free, urls +from . import balance, cheque, comnpay, free, note_kfet, urls PAYMENT_METHODS = [comnpay, cheque, balance, note_kfet, free] diff --git a/cotisations/payment_methods/balance/models.py b/cotisations/payment_methods/balance/models.py index 9f07f930..206e3cf8 100644 --- a/cotisations/payment_methods/balance/models.py +++ b/cotisations/payment_methods/balance/models.py @@ -18,12 +18,11 @@ # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +from django.contrib import messages from django.db import models from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import ugettext_lazy as _ -from django.contrib import messages - from cotisations.models import Paiement from cotisations.payment_methods.mixins import PaymentMethodMixin diff --git a/cotisations/payment_methods/cheque/forms.py b/cotisations/payment_methods/cheque/forms.py index f83cc8b3..d367771a 100644 --- a/cotisations/payment_methods/cheque/forms.py +++ b/cotisations/payment_methods/cheque/forms.py @@ -20,8 +20,8 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from django import forms -from re2o.mixins import FormRevMixin from cotisations.models import Facture as Invoice +from re2o.mixins import FormRevMixin class InvoiceForm(FormRevMixin, forms.ModelForm): diff --git a/cotisations/payment_methods/cheque/urls.py b/cotisations/payment_methods/cheque/urls.py index 0187ae53..72a2f913 100644 --- a/cotisations/payment_methods/cheque/urls.py +++ b/cotisations/payment_methods/cheque/urls.py @@ -19,6 +19,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from django.conf.urls import url + from . import views urlpatterns = [url(r"^validate/(?P[0-9]+)$", views.cheque, name="validate")] diff --git a/cotisations/payment_methods/cheque/views.py b/cotisations/payment_methods/cheque/views.py index 191e4159..c2df1165 100644 --- a/cotisations/payment_methods/cheque/views.py +++ b/cotisations/payment_methods/cheque/views.py @@ -23,17 +23,17 @@ Here are defined some views dedicated to cheque payement. """ -from django.urls import reverse -from django.shortcuts import redirect, render, get_object_or_404 -from django.contrib.auth.decorators import login_required from django.contrib import messages +from django.contrib.auth.decorators import login_required +from django.shortcuts import get_object_or_404, redirect, render +from django.urls import reverse from django.utils.translation import ugettext as _ from cotisations.models import Facture as Invoice from cotisations.utils import find_payment_method -from .models import ChequePayment from .forms import InvoiceForm +from .models import ChequePayment @login_required diff --git a/cotisations/payment_methods/comnpay/comnpay.py b/cotisations/payment_methods/comnpay/comnpay.py index b03239a4..993eed7e 100644 --- a/cotisations/payment_methods/comnpay/comnpay.py +++ b/cotisations/payment_methods/comnpay/comnpay.py @@ -3,15 +3,15 @@ The module in charge of handling the negociation with Comnpay for online payment """ -import time -from random import randrange import base64 import hashlib +import time from collections import OrderedDict +from random import randrange class Transaction: - """ The class representing a transaction with all the functions + """The class representing a transaction with all the functions used during the negociation """ @@ -35,7 +35,7 @@ class Transaction: self.idTransaction = "" def buildSecretHTML(self, produit="Produit", montant="0.00", idTransaction=""): - """ Build an HTML hidden form with the different parameters for the + """Build an HTML hidden form with the different parameters for the transaction """ if idTransaction == "": diff --git a/cotisations/payment_methods/comnpay/models.py b/cotisations/payment_methods/comnpay/models.py index ef0c6cf5..8aa52bbb 100644 --- a/cotisations/payment_methods/comnpay/models.py +++ b/cotisations/payment_methods/comnpay/models.py @@ -25,8 +25,8 @@ from django.utils.translation import ugettext_lazy as _ from cotisations.models import Paiement from cotisations.payment_methods.mixins import PaymentMethodMixin - from re2o.aes_field import AESEncryptedField + from .comnpay import Transaction @@ -53,8 +53,7 @@ class ComnpayPayment(PaymentMethodMixin, models.Model): minimum_payment = models.DecimalField( verbose_name=_("minimum payment"), help_text=_( - "The minimal amount of money you have to use when paying with" - " ComNpay." + "The minimal amount of money you have to use when paying with" " ComNpay." ), max_digits=5, decimal_places=2, @@ -107,8 +106,7 @@ class ComnpayPayment(PaymentMethodMixin, models.Model): return render(request, "cotisations/payment.html", r) def check_price(self, price, *args, **kwargs): - """Checks that the price meets the requirement to be paid with ComNpay. - """ + """Checks that the price meets the requirement to be paid with ComNpay.""" return ( (price >= self.minimum_payment), _( diff --git a/cotisations/payment_methods/comnpay/urls.py b/cotisations/payment_methods/comnpay/urls.py index babf2448..a90ca0fd 100644 --- a/cotisations/payment_methods/comnpay/urls.py +++ b/cotisations/payment_methods/comnpay/urls.py @@ -19,6 +19,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from django.conf.urls import url + from . import views urlpatterns = [ diff --git a/cotisations/payment_methods/comnpay/views.py b/cotisations/payment_methods/comnpay/views.py index 38bcbf96..e7055b6b 100644 --- a/cotisations/payment_methods/comnpay/views.py +++ b/cotisations/payment_methods/comnpay/views.py @@ -25,16 +25,17 @@ Here are the views needed by comnpay from collections import OrderedDict -from django.urls import reverse -from django.shortcuts import redirect, get_object_or_404 -from django.contrib.auth.decorators import login_required from django.contrib import messages -from django.views.decorators.csrf import csrf_exempt +from django.contrib.auth.decorators import login_required +from django.http import HttpResponse, HttpResponseBadRequest +from django.shortcuts import get_object_or_404, redirect +from django.urls import reverse from django.utils.datastructures import MultiValueDictKeyError from django.utils.translation import ugettext as _ -from django.http import HttpResponse, HttpResponseBadRequest +from django.views.decorators.csrf import csrf_exempt from cotisations.models import Facture + from .comnpay import Transaction from .models import ComnpayPayment @@ -55,7 +56,10 @@ def accept_payment(request, factureid): ) # In case a cotisation was bought, inform the user, the # cotisation time has been extended too - if any(purchase.test_membership_or_connection() for purchase in invoice.vente_set.all()): + if any( + purchase.test_membership_or_connection() + for purchase in invoice.vente_set.all() + ): messages.success( request, _( diff --git a/cotisations/payment_methods/forms.py b/cotisations/payment_methods/forms.py index 447fa38f..3b2b1f34 100644 --- a/cotisations/payment_methods/forms.py +++ b/cotisations/payment_methods/forms.py @@ -21,9 +21,10 @@ from django import forms from django.utils.translation import ugettext_lazy as _ -from . import PAYMENT_METHODS from cotisations.utils import find_payment_method +from . import PAYMENT_METHODS + def payment_method_factory(payment, *args, creation=True, **kwargs): """This function finds the right payment method form for a given payment. diff --git a/cotisations/payment_methods/free/models.py b/cotisations/payment_methods/free/models.py index a4c24459..bcecab35 100644 --- a/cotisations/payment_methods/free/models.py +++ b/cotisations/payment_methods/free/models.py @@ -18,10 +18,9 @@ # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +from django.contrib import messages from django.db import models from django.utils.translation import ugettext_lazy as _ -from django.contrib import messages - from cotisations.models import Paiement from cotisations.payment_methods.mixins import PaymentMethodMixin @@ -43,8 +42,7 @@ class FreePayment(PaymentMethodMixin, models.Model): ) def end_payment(self, invoice, request): - """Ends the payment normally. - """ + """Ends the payment normally.""" return invoice.paiement.end_payment(invoice, request, use_payment_method=False) def check_price(self, price, user, *args, **kwargs): diff --git a/cotisations/payment_methods/note_kfet/models.py b/cotisations/payment_methods/note_kfet/models.py index 4f1a8152..a71b79f8 100644 --- a/cotisations/payment_methods/note_kfet/models.py +++ b/cotisations/payment_methods/note_kfet/models.py @@ -19,17 +19,15 @@ # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +from django.contrib import messages from django.db import models -from django.shortcuts import render +from django.shortcuts import redirect, render from django.urls import reverse from django.utils.translation import ugettext_lazy as _ -from django.contrib import messages from cotisations.models import Paiement from cotisations.payment_methods.mixins import PaymentMethodMixin -from django.shortcuts import render, redirect - class NotePayment(PaymentMethodMixin, models.Model): """ diff --git a/cotisations/payment_methods/note_kfet/note.py b/cotisations/payment_methods/note_kfet/note.py index 40811913..8bac3158 100755 --- a/cotisations/payment_methods/note_kfet/note.py +++ b/cotisations/payment_methods/note_kfet/note.py @@ -5,8 +5,8 @@ """ Module pour dialoguer avec la NoteKfet2015 """ -import socket import json +import socket import ssl import traceback diff --git a/cotisations/payment_methods/note_kfet/urls.py b/cotisations/payment_methods/note_kfet/urls.py index a7fe3046..3fb20df8 100644 --- a/cotisations/payment_methods/note_kfet/urls.py +++ b/cotisations/payment_methods/note_kfet/urls.py @@ -19,6 +19,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from django.conf.urls import url + from . import views urlpatterns = [ diff --git a/cotisations/payment_methods/note_kfet/views.py b/cotisations/payment_methods/note_kfet/views.py index a3fb54b3..c0af4c8b 100644 --- a/cotisations/payment_methods/note_kfet/views.py +++ b/cotisations/payment_methods/note_kfet/views.py @@ -26,22 +26,23 @@ Here are the views needed by comnpay from collections import OrderedDict -from django.urls import reverse -from django.shortcuts import redirect, get_object_or_404 -from django.contrib.auth.decorators import login_required from django.contrib import messages -from django.views.decorators.csrf import csrf_exempt +from django.contrib.auth.decorators import login_required +from django.http import HttpResponse, HttpResponseBadRequest +from django.shortcuts import get_object_or_404, redirect +from django.urls import reverse from django.utils.datastructures import MultiValueDictKeyError from django.utils.translation import ugettext as _ -from django.http import HttpResponse, HttpResponseBadRequest +from django.views.decorators.csrf import csrf_exempt from cotisations.models import Facture from cotisations.utils import find_payment_method -from .models import NotePayment -from re2o.views import form from re2o.acl import can_create, can_edit -from .note import login, don +from re2o.views import form + from .forms import NoteCredentialForm +from .models import NotePayment +from .note import don, login @login_required diff --git a/cotisations/payment_methods/urls.py b/cotisations/payment_methods/urls.py index c413fac1..6ebcb6fa 100644 --- a/cotisations/payment_methods/urls.py +++ b/cotisations/payment_methods/urls.py @@ -19,10 +19,11 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from django.conf.urls import include, url -from . import comnpay, cheque, note_kfet + +from . import cheque, comnpay, note_kfet urlpatterns = [ - url(r"^comnpay/", include((comnpay.urls, 'comnpay'), namespace="comnpay")), - url(r"^cheque/", include((cheque.urls, 'cheque'), namespace="cheque")), - url(r"^note_kfet/", include((note_kfet.urls, 'note_kfet'), namespace="note_kfet")), + url(r"^comnpay/", include((comnpay.urls, "comnpay"), namespace="comnpay")), + url(r"^cheque/", include((cheque.urls, "cheque"), namespace="cheque")), + url(r"^note_kfet/", include((note_kfet.urls, "note_kfet"), namespace="note_kfet")), ] diff --git a/cotisations/test_models.py b/cotisations/test_models.py index 08c4a3b8..ea19725b 100644 --- a/cotisations/test_models.py +++ b/cotisations/test_models.py @@ -1,11 +1,12 @@ -from django.test import TestCase - import datetime -from django.utils import timezone + from dateutil.relativedelta import relativedelta +from django.test import TestCase +from django.utils import timezone from users.models import User -from .models import Vente, Facture, Cotisation, Paiement + +from .models import Cotisation, Facture, Paiement, Vente class VenteModelTests(TestCase): @@ -74,7 +75,7 @@ class VenteModelTests(TestCase): def test_one_month_and_one_week_cotisation(self): """ It should be possible to have one day membership. - Add one mounth and one week of membership and one mounth + Add one mounth and one week of membership and one mounth and one week of connection """ date = timezone.now() @@ -111,12 +112,21 @@ class VenteModelTests(TestCase): duration_days_connection=1, duration_membership=0, duration_deys_membership=1, - prix=0 + prix=0, + ) + v.create_cotis( + date_start_con=timezone.make_aware(datetime.datetime(1998, 10, 16)), + date_start_memb=timezone.make_aware(datetime.datetime(1998, 10, 16)), ) - v.create_cotis(date_start_con=timezone.make_aware(datetime.datetime(1998, 10, 16)), date_start_memb=timezone.make_aware(datetime.datetime(1998, 10, 16))) v.save() - self.assertEqual(v.cotisation.date_end_con, timezone.make_aware(datetime.datetime(1998, 10, 17))) - self.assertEqual(v.cotisation.date_end_memb, timezone.make_aware(datetime.datetime(1998, 10, 17))) + self.assertEqual( + v.cotisation.date_end_con, + timezone.make_aware(datetime.datetime(1998, 10, 17)), + ) + self.assertEqual( + v.cotisation.date_end_memb, + timezone.make_aware(datetime.datetime(1998, 10, 17)), + ) def test_one_day_cotisation_membership_only(self): """ @@ -207,12 +217,21 @@ class VenteModelTests(TestCase): duration_days_connection=0, duration_membership=0, duration_days_membership=1, - prix=0 + prix=0, + ) + v.create_cotis( + date_start_con=timezone.make_aware(datetime.datetime(1998, 10, 16)), + date_start_memb=timezone.make_aware(datetime.datetime(1998, 10, 16)), ) - v.create_cotis(date_start_con=timezone.make_aware(datetime.datetime(1998, 10, 16)), date_start_memb=timezone.make_aware(datetime.datetime(1998, 10, 16))) v.save() - self.assertEqual(v.cotisation.date_end_con, timezone.make_aware(datetime.datetime(1998, 10, 17))) - self.assertEqual(v.cotisation.date_end_memb, timezone.make_aware(datetime.datetime(1998, 10, 16))) + self.assertEqual( + v.cotisation.date_end_con, + timezone.make_aware(datetime.datetime(1998, 10, 17)), + ) + self.assertEqual( + v.cotisation.date_end_memb, + timezone.make_aware(datetime.datetime(1998, 10, 16)), + ) def test_cotisation_membership_diff_connection(self): """ @@ -252,9 +271,11 @@ class FactureModelTests(TestCase): def setUp(self): self.user = User.objects.create(pseudo="testUserPlop", email="test@example.org") self.paiement = Paiement.objects.create(moyen="test payment") + def tearDown(self): self.user.delete() self.paiement.delete() + def test_cotisations_prolongation(self): """When user already have one valid cotisation, the new one should be added at the end of the existing one.""" @@ -300,4 +321,3 @@ class FactureModelTests(TestCase): raise e invoice1.delete() invoice2.delete() - diff --git a/cotisations/test_views.py b/cotisations/test_views.py index c15848cb..9f9b80c7 100644 --- a/cotisations/test_views.py +++ b/cotisations/test_views.py @@ -1,13 +1,14 @@ +import datetime + +from dateutil.relativedelta import relativedelta +from django.contrib.auth.models import Permission from django.test import TestCase from django.urls import reverse -from django.contrib.auth.models import Permission - -import datetime -from dateutil.relativedelta import relativedelta from django.utils import timezone from users.models import Adherent -from .models import Vente, Facture, Cotisation, Paiement, Article + +from .models import Article, Cotisation, Facture, Paiement, Vente class NewFactureTests(TestCase): diff --git a/cotisations/tex.py b/cotisations/tex.py index fd6b6cc4..49697699 100644 --- a/cotisations/tex.py +++ b/cotisations/tex.py @@ -26,20 +26,19 @@ Used to generated PDF invoice. """ -import tempfile -from subprocess import Popen, PIPE import os +import tempfile from datetime import datetime +from subprocess import PIPE, Popen -from django.db import models -from django.template.loader import get_template -from django.http import HttpResponse from django.conf import settings +from django.db import models +from django.http import HttpResponse +from django.template.loader import get_template from django.utils.text import slugify -from re2o.mixins import AclMixin, RevMixin from preferences.models import CotisationsOption - +from re2o.mixins import AclMixin, RevMixin TEMP_PREFIX = getattr(settings, "TEX_TEMP_PREFIX", "render_tex-") CACHE_PREFIX = getattr(settings, "TEX_CACHE_PREFIX", "render-tex") diff --git a/cotisations/urls.py b/cotisations/urls.py index 9967b114..70a8fa92 100644 --- a/cotisations/urls.py +++ b/cotisations/urls.py @@ -27,23 +27,18 @@ from __future__ import unicode_literals from django.urls import path -from . import views, views_autocomplete -from . import payment_methods +from . import payment_methods, views, views_autocomplete -app_name ="cotisations" +app_name = "cotisations" urlpatterns = [ path("new_facture/", views.new_facture, name="new-facture"), - path( - "edit_facture/", views.edit_facture, name="edit-facture" - ), + path("edit_facture/", views.edit_facture, name="edit-facture"), path("del_facture/", views.del_facture, name="del-facture"), path("facture_pdf/", views.facture_pdf, name="facture-pdf"), path("voucher_pdf/", views.voucher_pdf, name="voucher-pdf"), path("new_cost_estimate", views.new_cost_estimate, name="new-cost-estimate"), - path( - "index_cost_estimate", views.index_cost_estimate, name="index-cost-estimate" - ), + path("index_cost_estimate", views.index_cost_estimate, name="index-cost-estimate"), path( "cost_estimate_pdf/", views.cost_estimate_pdf, @@ -87,9 +82,7 @@ urlpatterns = [ ), path("credit_solde/", views.credit_solde, name="credit-solde"), path("add_article", views.add_article, name="add-article"), - path( - "edit_article/", views.edit_article, name="edit-article" - ), + path("edit_article/", views.edit_article, name="edit-article"), path("del_article", views.del_article, name="del-article"), path("add_paiement", views.add_paiement, name="add-paiement"), path( @@ -107,5 +100,9 @@ urlpatterns = [ path("control", views.control, name="control"), path("", views.index, name="index"), ### Autocomplete Views - path('banque-autocomplete', views_autocomplete.BanqueAutocomplete.as_view(), name='banque-autocomplete',), + path( + "banque-autocomplete", + views_autocomplete.BanqueAutocomplete.as_view(), + name="banque-autocomplete", + ), ] + payment_methods.urls.urlpatterns diff --git a/cotisations/utils.py b/cotisations/utils.py index f484546a..b287f78d 100644 --- a/cotisations/utils.py +++ b/cotisations/utils.py @@ -21,14 +21,16 @@ import os -from django.template.loader import get_template from django.core.mail import EmailMessage +from django.template.loader import get_template + +from preferences.models import (AssoOption, CotisationsOption, GeneralOption, + Mandate) +from re2o import settings from re2o.mail_utils import send_mail_object +from re2o.settings import LOGO_PATH from .tex import create_pdf -from preferences.models import AssoOption, GeneralOption, CotisationsOption, Mandate -from re2o.settings import LOGO_PATH -from re2o import settings def find_payment_method(payment): @@ -74,7 +76,9 @@ def send_mail_invoice(invoice, request=None): "tpl_path": os.path.join(settings.BASE_DIR, LOGO_PATH), } - template = CotisationsOption.get_cached_value("invoice_template").template.name.split("/")[-1] + template = CotisationsOption.get_cached_value( + "invoice_template" + ).template.name.split("/")[-1] pdf = create_pdf(template, ctx) template = get_template("cotisations/email_invoice") @@ -106,7 +110,9 @@ def send_mail_voucher(invoice, request=None): "email": invoice.user.email, "phone": invoice.user.telephone, "date_end": invoice.get_subscription().latest("date_end_memb").date_end_memb, - "date_begin": invoice.get_subscription().earliest("date_start_memb").date_start_memb, + "date_begin": invoice.get_subscription() + .earliest("date_start_memb") + .date_start_memb, } templatename = CotisationsOption.get_cached_value( "voucher_template" diff --git a/cotisations/views.py b/cotisations/views.py index e114b569..d6fda3f5 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -29,62 +29,38 @@ The different views used in the Cotisations module """ from __future__ import unicode_literals + import os -from django.urls import reverse -from django.shortcuts import render, redirect, get_object_or_404 -from django.template.loader import render_to_string -from django.contrib.auth.decorators import login_required from django.contrib import messages -from django.db.models import ProtectedError -from django.db.models import Q -from django.forms import modelformset_factory, formset_factory +from django.contrib.auth.decorators import login_required +from django.db.models import ProtectedError, Q +from django.forms import formset_factory, modelformset_factory +from django.shortcuts import get_object_or_404, redirect, render +from django.template.loader import render_to_string +from django.urls import reverse from django.utils import timezone from django.utils.translation import ugettext as _ - # Import des models, forms et fonctions re2o from reversion import revisions as reversion -from users.models import User -from re2o.settings import LOGO_PATH -from re2o import settings -from re2o.views import form -from re2o.base import SortTable, re2o_paginator -from re2o.acl import ( - can_create, - can_edit, - can_delete, - can_view, - can_view_all, - can_delete_set, - can_change, -) + from preferences.models import AssoOption, GeneralOption, Mandate -from .models import ( - Facture, - Article, - Vente, - Paiement, - Banque, - CustomInvoice, - BaseInvoice, - CostEstimate, -) -from .forms import ( - FactureForm, - ArticleForm, - DelArticleForm, - PaiementForm, - DelPaiementForm, - BanqueForm, - DelBanqueForm, - SelectArticleForm, - RechargeForm, - CustomInvoiceForm, - DiscountForm, - CostEstimateForm, -) -from .tex import render_invoice, render_voucher, escape_chars +from re2o import settings +from re2o.acl import (can_change, can_create, can_delete, can_delete_set, + can_edit, can_view, can_view_all) +from re2o.base import SortTable, re2o_paginator +from re2o.settings import LOGO_PATH +from re2o.views import form +from users.models import User + +from .forms import (ArticleForm, BanqueForm, CostEstimateForm, + CustomInvoiceForm, DelArticleForm, DelBanqueForm, + DelPaiementForm, DiscountForm, FactureForm, PaiementForm, + RechargeForm, SelectArticleForm) +from .models import (Article, Banque, BaseInvoice, CostEstimate, CustomInvoice, + Facture, Paiement, Vente) from .payment_methods.forms import payment_method_factory +from .tex import escape_chars, render_invoice, render_voucher from .utils import find_payment_method @@ -136,7 +112,7 @@ def new_facture(request, user, userid): duration_membership=article.duration_membership, duration_days_membership=article.duration_days_membership, number=quantity, - ) + ) purchases.append(new_purchase) p = find_payment_method(new_invoice_instance.paiement) if hasattr(p, "check_price"): @@ -1057,12 +1033,15 @@ def voucher_pdf(request, invoice, **_kwargs): "lastname": invoice.user.surname, "email": invoice.user.email, "phone": invoice.user.telephone, - "date_end": invoice.get_subscription().latest("date_end_memb").date_end_memb, + "date_end": invoice.get_subscription() + .latest("date_end_memb") + .date_end_memb, "date_begin": invoice.date, }, ) -def aff_profil(request,user): + +def aff_profil(request, user): """View used to display the cotisations on a user's profil.""" factures = Facture.objects.filter(user=user) @@ -1071,16 +1050,16 @@ def aff_profil(request,user): request.GET.get("col"), request.GET.get("order"), SortTable.COTISATIONS_INDEX, - ) - + ) + pagination_large_number = GeneralOption.get_cached_value("pagination_large_number") - factures = re2o_paginator(request, factures,pagination_large_number) + factures = re2o_paginator(request, factures, pagination_large_number) context = { - "users":user, + "users": user, "facture_list": factures, - } + } return render_to_string( - "cotisations/aff_profil.html",context=context,request=request,using=None - ) + "cotisations/aff_profil.html", context=context, request=request, using=None + ) diff --git a/cotisations/views_autocomplete.py b/cotisations/views_autocomplete.py index 1e634813..bb89ace5 100644 --- a/cotisations/views_autocomplete.py +++ b/cotisations/views_autocomplete.py @@ -31,20 +31,13 @@ Here are defined the autocomplete class based view. """ from __future__ import unicode_literals -from django.db.models import Q, Value, CharField - -from .models import ( - Banque -) +from django.db.models import CharField, Q, Value +from re2o.acl import can_view_all from re2o.views import AutocompleteViewMixin -from re2o.acl import ( - can_view_all, -) +from .models import Banque class BanqueAutocomplete(AutocompleteViewMixin): obj_type = Banque - - diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index f4201f44..00c3e774 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -34,12 +34,12 @@ https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_pyth Inspired by Daniel Stan in Crans """ +import logging import os import sys -import logging import traceback -import radiusd # Magic module freeradius (radiusd.py is dummy) +import radiusd # Magic module freeradius (radiusd.py is dummy) from django.core.wsgi import get_wsgi_application from django.db.models import Q @@ -54,11 +54,10 @@ os.chdir(proj_path) # This is so models get loaded. application = get_wsgi_application() -from machines.models import Interface, IpList, Nas, Domain +from machines.models import Domain, Interface, IpList, Nas +from preferences.models import RadiusOption from topologie.models import Port, Switch from users.models import User -from preferences.models import RadiusOption - # Logging @@ -76,7 +75,7 @@ class RadiusdHandler(logging.Handler): radiusd.radlog(rad_sig, str(record.msg)) -# Init for logging +# Init for logging logger = logging.getLogger("auth.py") logger.setLevel(logging.DEBUG) formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s") @@ -132,10 +131,10 @@ def authorize(data): - If the nas is known, we apply the 802.1X if enabled, - It the nas is known AND nas auth is enabled with mac address, returns accept here""" - # For proxified request, split + # For proxified request, split nas = data.get("NAS-IP-Address", data.get("NAS-Identifier", None)) nas_instance = find_nas_from_request(nas) - # For none proxified requests + # For none proxified requests nas_type = None if nas_instance: nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first() @@ -162,12 +161,11 @@ def authorize(data): @radius_event def post_auth(data): - """ Function called after the user is authenticated - """ + """Function called after the user is authenticated""" nas = data.get("NAS-IP-Address", data.get("NAS-Identifier", None)) nas_instance = find_nas_from_request(nas) - # All non proxified requests + # All non proxified requests if not nas_instance: logger.info("Proxified request, nas unknown") return radiusd.RLM_MODULE_OK @@ -309,7 +307,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address): - no room : Decision set in Re2o RadiusOption, - no user in this room : Reject, - user of this room is banned or disable : Reject, - - user of this room non-contributor and not whitelisted: + - user of this room non-contributor and not whitelisted: Decision set in Re2o RadiusOption - mode common : - mac-address already registered: @@ -336,7 +334,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address): } # Get port from switch and port number extra_log = "" - # If NAS is unknown, go to default vlan + # If NAS is unknown, go to default vlan if not nas_machine: return ( "?", @@ -366,7 +364,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address): RadiusOption.get_cached_value("unknown_port") != RadiusOption.REJECT, RadiusOption.get_attributes("unknown_port_attributes", attributes_kwargs), ) - + # Retrieve port profile port_profile = port.get_port_profile diff --git a/ldap_sync/admin.py b/ldap_sync/admin.py index 0cba55da..ef859188 100644 --- a/ldap_sync/admin.py +++ b/ldap_sync/admin.py @@ -1,11 +1,8 @@ from django.contrib import admin -from .models import ( - LdapUser, - LdapServiceUser, - LdapServiceUserGroup, - LdapUserGroup, -) +from .models import (LdapServiceUser, LdapServiceUserGroup, LdapUser, + LdapUserGroup) + class LdapUserAdmin(admin.ModelAdmin): """LdapUser Admin view. Can't change password, manage @@ -15,6 +12,7 @@ class LdapUserAdmin(admin.ModelAdmin): Django ModelAdmin: Apply on django ModelAdmin """ + list_display = ("name", "uidNumber", "login_shell") exclude = ("user_password", "sambat_nt_password") search_fields = ("name",) diff --git a/ldap_sync/apps.py b/ldap_sync/apps.py index b96c34d1..ed06ca2a 100644 --- a/ldap_sync/apps.py +++ b/ldap_sync/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class LdapSyncConfig(AppConfig): - name = 'ldap_sync' + name = "ldap_sync" diff --git a/ldap_sync/management/commands/ldap_rebuild.py b/ldap_sync/management/commands/ldap_rebuild.py index 1fc3c969..dbe171eb 100644 --- a/ldap_sync/management/commands/ldap_rebuild.py +++ b/ldap_sync/management/commands/ldap_rebuild.py @@ -18,11 +18,12 @@ import subprocess from base64 import decodebytes -from django.core.management.base import BaseCommand, CommandError from django.conf import settings +from django.core.management.base import BaseCommand, CommandError -from users.models import User, ListRight -from ldap_sync.models import synchronise_user, synchronise_serviceuser, synchronise_usergroup +from ldap_sync.models import (synchronise_serviceuser, synchronise_user, + synchronise_usergroup) +from users.models import ListRight, User def split_lines(lines): diff --git a/ldap_sync/management/commands/ldap_sync.py b/ldap_sync/management/commands/ldap_sync.py index 984f3fd7..75af7738 100644 --- a/ldap_sync/management/commands/ldap_sync.py +++ b/ldap_sync/management/commands/ldap_sync.py @@ -19,8 +19,8 @@ # from django.core.management.base import BaseCommand, CommandError -from users.models import User from ldap_sync.models import synchronise_user +from users.models import User class Command(BaseCommand): diff --git a/ldap_sync/models.py b/ldap_sync/models.py index b360e7c1..ac3e69a7 100644 --- a/ldap_sync/models.py +++ b/ldap_sync/models.py @@ -1,18 +1,16 @@ import sys -from django.db import models -from django.conf import settings -from django.dispatch import receiver - -from django.contrib.auth.models import Group - import ldapdb.models import ldapdb.models.fields - -import users.signals -import users.models +from django.conf import settings +from django.contrib.auth.models import Group +from django.db import models +from django.dispatch import receiver import machines.models +import users.models +import users.signals + class LdapUser(ldapdb.models.Model): """A class representing a LdapUser in LDAP, its LDAP conterpart. @@ -110,13 +108,13 @@ def synchronise_user(sender, **kwargs): * mac_refresh : Default `True`. When True, synchronise the list of mac addresses. * group_refresh: Default `False`. When `True` synchronise the groups of the instance. """ - base=kwargs.get('base', True) - access_refresh=kwargs.get('access_refresh', True) - mac_refresh=kwargs.get('mac_refresh', True ) - group_refresh=kwargs.get('group_refresh', False) + base = kwargs.get("base", True) + access_refresh = kwargs.get("access_refresh", True) + mac_refresh = kwargs.get("mac_refresh", True) + group_refresh = kwargs.get("group_refresh", False) + + user = kwargs["instance"] - user=kwargs["instance"] - if sys.version_info[0] >= 3 and ( user.state == user.STATE_ACTIVE or user.state == user.STATE_ARCHIVE @@ -136,9 +134,7 @@ def synchronise_user(sender, **kwargs): user_ldap.dialupAccess = str(user.has_access()) user_ldap.home_directory = user.home_directory user_ldap.mail = user.get_mail - user_ldap.given_name = ( - user.surname.lower() + "_" + user.name.lower()[:3] - ) + user_ldap.given_name = user.surname.lower() + "_" + user.name.lower()[:3] user_ldap.gid = settings.LDAP["user_gid"] if "{SSHA}" in user.password or "{SMD5}" in user.password: # We remove the extra $ added at import from ldap @@ -169,9 +165,12 @@ def synchronise_user(sender, **kwargs): # be part of the updated group (case of group removal) for group in Group.objects.all(): if hasattr(group, "listright"): - synchronise_usergroup(users.models.ListRight, instance=group.listright) + synchronise_usergroup( + users.models.ListRight, instance=group.listright + ) user_ldap.save() + @receiver(users.signals.remove, sender=users.models.User) def remove_user(sender, **kwargs): user = kwargs["instance"] @@ -181,6 +180,7 @@ def remove_user(sender, **kwargs): except LdapUser.DoesNotExist: pass + @receiver(users.signals.remove_mass, sender=users.models.User) def remove_users(sender, **kwargs): queryset_users = kwargs["queryset"] @@ -217,6 +217,7 @@ class LdapUserGroup(ldapdb.models.Model): def __str__(self): return self.name + @receiver(users.signals.synchronise, sender=users.models.ListRight) def synchronise_usergroup(sender, **kwargs): group = kwargs["instance"] @@ -228,6 +229,7 @@ def synchronise_usergroup(sender, **kwargs): group_ldap.members = [user.pseudo for user in group.user_set.all()] group_ldap.save() + @receiver(users.signals.remove, sender=users.models.ListRight) def remove_usergroup(sender, **kwargs): group = kwargs["instance"] @@ -238,7 +240,6 @@ def remove_usergroup(sender, **kwargs): pass - class LdapServiceUser(ldapdb.models.Model): """A class representing a ServiceUser in LDAP, its LDAP conterpart. Synced from ServiceUser, with a copy of its attributes/fields into LDAP, @@ -296,6 +297,7 @@ def synchronise_serviceuser(sender, **kwargs): user_ldap.save() synchronise_serviceuser_group(user) + @receiver(users.signals.remove, sender=users.models.ServiceUser) def remove_serviceuser(sender, **kwargs): user = kwargs["instance"] @@ -331,4 +333,3 @@ class LdapServiceUserGroup(ldapdb.models.Model): def __str__(self): return self.name - diff --git a/ldap_sync/urls.py b/ldap_sync/urls.py index b9622e85..6af84065 100644 --- a/ldap_sync/urls.py +++ b/ldap_sync/urls.py @@ -1,5 +1,6 @@ from django.urls import path -from .import views + +from . import views app_name = "ldap_sync" diff --git a/logs/apps.py b/logs/apps.py index 255ad039..0badfaae 100644 --- a/logs/apps.py +++ b/logs/apps.py @@ -8,4 +8,4 @@ from django.apps import AppConfig class LogsConfig(AppConfig): """Configuration of logs app.""" - name = "logs" \ No newline at end of file + name = "logs" diff --git a/logs/forms.py b/logs/forms.py index 0a2ca09c..989d5e7e 100644 --- a/logs/forms.py +++ b/logs/forms.py @@ -21,13 +21,11 @@ """The forms used by the machine search view""" +import inspect + from django import forms from django.forms import Form from django.utils.translation import ugettext_lazy as _ -from re2o.base import get_input_formats_help_text -from re2o.widgets import AutocompleteModelWidget - -import inspect # Import all models in which there are classes to be filtered on import cotisations.models @@ -35,7 +33,8 @@ import machines.models import preferences.models import topologie.models import users.models - +from re2o.base import get_input_formats_help_text +from re2o.widgets import AutocompleteModelWidget CHOICES_ACTION_TYPE = ( ("users", _("Users")), diff --git a/logs/models.py b/logs/models.py index 51b250f3..97b4201d 100644 --- a/logs/models.py +++ b/logs/models.py @@ -21,23 +21,17 @@ """logs.models The models definitions for the logs app """ -from reversion.models import Version, Revision -from django.utils.translation import ugettext_lazy as _ +from django.apps import apps from django.contrib.auth.models import Group from django.db.models import Q -from django.apps import apps -from netaddr import EUI +from django.utils.translation import ugettext_lazy as _ from macaddress.fields import default_dialect +from netaddr import EUI +from reversion.models import Revision, Version -from machines.models import IpList -from machines.models import Interface -from machines.models import Machine -from machines.models import MachineType -from users.models import User -from users.models import Adherent -from users.models import Club -from topologie.models import Room -from topologie.models import Port +from machines.models import Interface, IpList, Machine, MachineType +from topologie.models import Port, Room +from users.models import Adherent, Club, User from .forms import classes_for_action_type @@ -53,13 +47,12 @@ def make_version_filter(key, value): # The lookup is done in a json string, so it has to be formated # based on the value's type (to add " or not) if type(value) is str: - formatted_value = "\"{}\"".format(value) + formatted_value = '"{}"'.format(value) else: formatted_value = str(value) - return ( - Q(serialized_data__contains='\"{}\": {},'.format(key, formatted_value)) - | Q(serialized_data__contains='\"{}\": {}}}'.format(key, formatted_value)) + return Q(serialized_data__contains='"{}": {},'.format(key, formatted_value)) | Q( + serialized_data__contains='"{}": {}}}'.format(key, formatted_value) ) @@ -67,6 +60,7 @@ def make_version_filter(key, value): # Machine history search # ############################ + class MachineHistorySearchEvent: def __init__(self, user, machine, interface, start=None, end=None): """Initialise an instance of MachineHistorySearchEvent. @@ -113,7 +107,7 @@ class MachineHistorySearchEvent: self.ipv4, self.start_date, self.end_date, - self.comment or "No comment" + self.comment or "No comment", ) @@ -300,6 +294,7 @@ class MachineHistorySearch: # Generic history classes # ############################ + class RelatedHistory: def __init__(self, version): """Initialise an instance of RelatedHistory. @@ -317,10 +312,7 @@ class RelatedHistory: self.name = "{}: {}".format(self.model_name.title(), self.name) def __eq__(self, other): - return ( - self.model_name == other.model_name - and self.object_id == other.object_id - ) + return self.model_name == other.model_name and self.object_id == other.object_id def __hash__(self): return hash((self.model_name, self.object_id)) @@ -382,15 +374,11 @@ class HistoryEvent: # Take into account keys that may exist in only one dict if field in self.previous_version.field_dict: old_value = self._repr( - field, - self.previous_version.field_dict[field] + field, self.previous_version.field_dict[field] ) if field in self.version.field_dict: - new_value = self._repr( - field, - self.version.field_dict[field] - ) + new_value = self._repr(field, self.version.field_dict[field]) edits.append((field, old_value, new_value)) @@ -487,6 +475,7 @@ class History: # Revision history # ############################ + class VersionAction(HistoryEvent): def __init__(self, version): self.version = version @@ -533,15 +522,14 @@ class VersionAction(HistoryEvent): """ model = self.object_type() try: - query = ( - make_version_filter("pk", self.object_id()) - & Q( - revision__date_created__lt=self.version.revision.date_created - ) + query = make_version_filter("pk", self.object_id()) & Q( + revision__date_created__lt=self.version.revision.date_created + ) + return ( + Version.objects.get_for_model(model) + .filter(query) + .order_by("-revision__date_created")[0] ) - return (Version.objects.get_for_model(model) - .filter(query) - .order_by("-revision__date_created")[0]) except Exception: return None @@ -648,6 +636,7 @@ class ActionsSearch: # Class-specific history # ############################ + class UserHistoryEvent(HistoryEvent): def _repr(self, name, value): """Get the appropriate representation of the given field. @@ -733,13 +722,15 @@ class UserHistoryEvent(HistoryEvent): ) def __hash__(self): - return hash((frozenset(self.edited_fields), self.date, self.performed_by, self.comment)) + return hash( + (frozenset(self.edited_fields), self.date, self.performed_by, self.comment) + ) def __repr__(self): return "{} edited fields {} ({})".format( self.performed_by, self.edited_fields or "nothing", - self.comment or "No comment" + self.comment or "No comment", ) @@ -762,9 +753,8 @@ class UserHistory(History): # Try to find an Adherent object # If it exists, its id will be the same as the user's - adherents = ( - Version.objects.get_for_model(Adherent) - .filter(make_version_filter("pk", user_id)) + adherents = Version.objects.get_for_model(Adherent).filter( + make_version_filter("pk", user_id) ) try: obj = adherents[0] @@ -774,9 +764,8 @@ class UserHistory(History): # Fallback on a Club if obj is None: - clubs = ( - Version.objects.get_for_model(Club) - .filter(make_version_filter("pk", user_id)) + clubs = Version.objects.get_for_model(Club).filter( + make_version_filter("pk", user_id) ) try: @@ -826,11 +815,7 @@ class UserHistory(History): # Remove duplicates and sort self.events = list(dict.fromkeys(self.events)) - return sorted( - self.events, - key=lambda e: e.date, - reverse=True - ) + return sorted(self.events, key=lambda e: e.date, reverse=True) def _add_revision(self, version): """Add a new revision to the chronological order. @@ -843,7 +828,7 @@ class UserHistory(History): diff = self._compute_diff( version, self._last_version, - ignoring=["last_login", "pwd_ntlm", "email_change_date"] + ignoring=["last_login", "pwd_ntlm", "email_change_date"], ) # Ignore "empty" events like login @@ -973,7 +958,7 @@ HISTORY_CLASS_MAPPING = { User: UserHistory, Machine: MachineHistory, Interface: InterfaceHistory, - "default": History + "default": History, } diff --git a/logs/urls.py b/logs/urls.py index d87a4efc..880d7486 100644 --- a/logs/urls.py +++ b/logs/urls.py @@ -47,5 +47,9 @@ urlpatterns = [ path("stats_models", views.stats_models, name="stats-models"), path("stats_users", views.stats_users, name="stats-users"), path("stats_actions", views.stats_actions, name="stats-actions"), - path("stats_search_machine", views.stats_search_machine_history, name="stats-search-machine"), + path( + "stats_search_machine", + views.stats_search_machine_history, + name="stats-search-machine", + ), ] diff --git a/logs/views.py b/logs/views.py index 7b01c4a5..66d1a99d 100644 --- a/logs/views.py +++ b/logs/views.py @@ -38,84 +38,38 @@ objects for per model, number of actions per user etc. from __future__ import unicode_literals -from django.urls import reverse -from django.shortcuts import render, redirect +from django.apps import apps from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.http import Http404 from django.db.models import Count -from django.apps import apps +from django.http import Http404 +from django.shortcuts import redirect, render +from django.urls import reverse from django.utils.translation import ugettext as _ +from reversion.models import ContentType, Revision, Version -from reversion.models import Revision -from reversion.models import Version, ContentType - -from users.models import ( - User, - ServiceUser, - School, - ListRight, - ListShell, - Ban, - Whitelist, - Adherent, - Club, -) -from cotisations.models import Facture, Vente, Article, Banque, Paiement, Cotisation -from machines.models import ( - Machine, - MachineType, - IpType, - Extension, - Interface, - Domain, - IpList, - OuverturePortList, - Service, - Vlan, - Nas, - SOA, - Mx, - Ns, -) -from topologie.models import ( - Switch, - Port, - Room, - Stack, - ModelSwitch, - ConstructorSwitch, - AccessPoint, -) +from cotisations.models import (Article, Banque, Cotisation, Facture, Paiement, + Vente) +from machines.models import (SOA, Domain, Extension, Interface, IpList, IpType, + Machine, MachineType, Mx, Nas, Ns, + OuverturePortList, Service, Vlan) from preferences.models import GeneralOption +from re2o.acl import (acl_error_message, can_edit_history, can_view, + can_view_all, can_view_app) +from re2o.base import SortTable, re2o_paginator +from re2o.utils import (all_active_assigned_interfaces_count, + all_active_interfaces_count, all_adherent, all_baned, + all_has_access, all_whitelisted) from re2o.views import form -from re2o.utils import ( - all_whitelisted, - all_baned, - all_has_access, - all_adherent, - all_active_assigned_interfaces_count, - all_active_interfaces_count, -) -from re2o.base import re2o_paginator, SortTable -from re2o.acl import ( - can_view_all, - can_view_app, - can_edit_history, - can_view, - acl_error_message, -) - -from .models import ( - ActionsSearch, - RevisionAction, - MachineHistorySearch, - get_history_class, -) - -from .forms import ActionsSearchForm, MachineHistorySearchForm +from topologie.models import (AccessPoint, ConstructorSwitch, ModelSwitch, + Port, Room, Stack, Switch) +from users.models import (Adherent, Ban, Club, ListRight, ListShell, School, + ServiceUser, User, Whitelist) from .acl import can_view as can_view_logs +from .forms import ActionsSearchForm, MachineHistorySearchForm +from .models import (ActionsSearch, MachineHistorySearch, RevisionAction, + get_history_class) @login_required @@ -528,7 +482,11 @@ def stats_search_machine_history(request): max_result = GeneralOption.get_cached_value("pagination_number") events = re2o_paginator(request, events, max_result) - return render(request, "logs/machine_history.html", {"events": events},) + return render( + request, + "logs/machine_history.html", + {"events": events}, + ) return render( request, "logs/search_machine_history.html", {"history_form": history_form} ) diff --git a/machines/admin.py b/machines/admin.py index dc2817f0..6306e00f 100644 --- a/machines/admin.py +++ b/machines/admin.py @@ -29,24 +29,10 @@ from __future__ import unicode_literals from django.contrib import admin from reversion.admin import VersionAdmin -from .models import ( - Extension, - SOA, - Mx, - Ns, - Vlan, - Txt, - DName, - Srv, - SshFp, - Nas, - Service, - Role, - OuverturePort, - Ipv6List, - OuverturePortList, -) -from .models import IpType, Machine, MachineType, Domain, IpList, Interface +from .models import (SOA, DName, Domain, Extension, Interface, IpList, IpType, + Ipv6List, Machine, MachineType, Mx, Nas, Ns, + OuverturePort, OuverturePortList, Role, Service, Srv, + SshFp, Txt, Vlan) class MachineAdmin(VersionAdmin): diff --git a/machines/api/serializers.py b/machines/api/serializers.py index 0c8b7ffe..bfbed72e 100644 --- a/machines/api/serializers.py +++ b/machines/api/serializers.py @@ -22,12 +22,12 @@ from rest_framework import serializers import machines.models as machines -from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer +from api.serializers import (NamespacedHIField, NamespacedHMSerializer, + NamespacedHRField) class MachineSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Machine` objects. - """ + """Serialize `machines.models.Machine` objects.""" class Meta: model = machines.Machine @@ -35,8 +35,7 @@ class MachineSerializer(NamespacedHMSerializer): class MachineTypeSerializer(NamespacedHMSerializer): - """Serialize `machines.models.MachineType` objects. - """ + """Serialize `machines.models.MachineType` objects.""" class Meta: model = machines.MachineType @@ -44,8 +43,7 @@ class MachineTypeSerializer(NamespacedHMSerializer): class IpTypeSerializer(NamespacedHMSerializer): - """Serialize `machines.models.IpType` objects. - """ + """Serialize `machines.models.IpType` objects.""" class Meta: model = machines.IpType @@ -63,8 +61,7 @@ class IpTypeSerializer(NamespacedHMSerializer): class VlanSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Vlan` objects. - """ + """Serialize `machines.models.Vlan` objects.""" class Meta: model = machines.Vlan @@ -82,8 +79,7 @@ class VlanSerializer(NamespacedHMSerializer): class NasSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Nas` objects. - """ + """Serialize `machines.models.Nas` objects.""" class Meta: model = machines.Nas @@ -98,8 +94,7 @@ class NasSerializer(NamespacedHMSerializer): class SOASerializer(NamespacedHMSerializer): - """Serialize `machines.models.SOA` objects. - """ + """Serialize `machines.models.SOA` objects.""" class Meta: model = machines.SOA @@ -107,8 +102,7 @@ class SOASerializer(NamespacedHMSerializer): class ExtensionSerializer(NamespacedHMSerializer): - """Serialize machines.models.Extension objects. - """ + """Serialize machines.models.Extension objects.""" class Meta: model = machines.Extension @@ -116,8 +110,7 @@ class ExtensionSerializer(NamespacedHMSerializer): class MxSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Mx` objects. - """ + """Serialize `machines.models.Mx` objects.""" class Meta: model = machines.Mx @@ -125,8 +118,7 @@ class MxSerializer(NamespacedHMSerializer): class DNameSerializer(NamespacedHMSerializer): - """Serialize `machines.models.DName` objects. - """ + """Serialize `machines.models.DName` objects.""" class Meta: model = machines.DName @@ -134,8 +126,7 @@ class DNameSerializer(NamespacedHMSerializer): class NsSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Ns` objects. - """ + """Serialize `machines.models.Ns` objects.""" class Meta: model = machines.Ns @@ -143,8 +134,7 @@ class NsSerializer(NamespacedHMSerializer): class TxtSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Txt` objects. - """ + """Serialize `machines.models.Txt` objects.""" class Meta: model = machines.Txt @@ -152,8 +142,7 @@ class TxtSerializer(NamespacedHMSerializer): class SrvSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Srv` objects. - """ + """Serialize `machines.models.Srv` objects.""" class Meta: model = machines.Srv @@ -171,8 +160,7 @@ class SrvSerializer(NamespacedHMSerializer): class SshFpSerializer(NamespacedHMSerializer): - """Serialize `machines.models.SSHFP` objects. - """ + """Serialize `machines.models.SSHFP` objects.""" class Meta: model = machines.SshFp @@ -180,8 +168,7 @@ class SshFpSerializer(NamespacedHMSerializer): class InterfaceSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Interface` objects. - """ + """Serialize `machines.models.Interface` objects.""" mac_address = serializers.CharField() active = serializers.BooleanField(source="is_active") @@ -201,8 +188,7 @@ class InterfaceSerializer(NamespacedHMSerializer): class Ipv6ListSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Ipv6List` objects. - """ + """Serialize `machines.models.Ipv6List` objects.""" class Meta: model = machines.Ipv6List @@ -210,8 +196,7 @@ class Ipv6ListSerializer(NamespacedHMSerializer): class DomainSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Domain` objects. - """ + """Serialize `machines.models.Domain` objects.""" class Meta: model = machines.Domain @@ -219,8 +204,7 @@ class DomainSerializer(NamespacedHMSerializer): class IpListSerializer(NamespacedHMSerializer): - """Serialize `machines.models.IpList` objects. - """ + """Serialize `machines.models.IpList` objects.""" class Meta: model = machines.IpList @@ -228,8 +212,7 @@ class IpListSerializer(NamespacedHMSerializer): class ServiceSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Service` objects. - """ + """Serialize `machines.models.Service` objects.""" class Meta: model = machines.Service @@ -243,8 +226,7 @@ class ServiceSerializer(NamespacedHMSerializer): class ServiceLinkSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Service_link` objects. - """ + """Serialize `machines.models.Service_link` objects.""" class Meta: model = machines.Service_link @@ -260,8 +242,7 @@ class ServiceLinkSerializer(NamespacedHMSerializer): class OuverturePortListSerializer(NamespacedHMSerializer): - """Serialize `machines.models.OuverturePortList` objects. - """ + """Serialize `machines.models.OuverturePortList` objects.""" tcp_ports_in = NamespacedHRField( view_name="ouvertureport-detail", many=True, read_only=True @@ -289,8 +270,7 @@ class OuverturePortListSerializer(NamespacedHMSerializer): class OuverturePortSerializer(NamespacedHMSerializer): - """Serialize `machines.models.OuverturePort` objects. - """ + """Serialize `machines.models.OuverturePort` objects.""" class Meta: model = machines.OuverturePort @@ -298,8 +278,7 @@ class OuverturePortSerializer(NamespacedHMSerializer): class RoleSerializer(NamespacedHMSerializer): - """Serialize `machines.models.OuverturePort` objects. - """ + """Serialize `machines.models.OuverturePort` objects.""" servers = InterfaceSerializer(read_only=True, many=True) @@ -309,8 +288,7 @@ class RoleSerializer(NamespacedHMSerializer): class ServiceRegenSerializer(NamespacedHMSerializer): - """Serialize the data about the services to regen. - """ + """Serialize the data about the services to regen.""" hostname = serializers.CharField(source="server.domain.name", read_only=True) service_name = serializers.CharField(source="service.service_type", read_only=True) @@ -517,8 +495,7 @@ class DNAMERecordSerializer(serializers.ModelSerializer): class DNSZonesSerializer(serializers.ModelSerializer): - """Serialize the data about DNS Zones. - """ + """Serialize the data about DNS Zones.""" soa = SOARecordSerializer() ns_records = NSRecordSerializer(many=True, source="ns_set") @@ -559,8 +536,7 @@ class DNSZonesSerializer(serializers.ModelSerializer): class DNSReverseZonesSerializer(serializers.ModelSerializer): - """Serialize the data about DNS Zones. - """ + """Serialize the data about DNS Zones.""" soa = SOARecordSerializer(source="extension.soa") extension = serializers.CharField(source="extension.name", read_only=True) diff --git a/machines/api/urls.py b/machines/api/urls.py index 3542e28c..d76187f1 100644 --- a/machines/api/urls.py +++ b/machines/api/urls.py @@ -45,9 +45,8 @@ urls_viewset = [ (r"machines/ouvertureport", views.OuverturePortViewSet, None), (r"machines/role", views.RoleViewSet, None), (r"machines/services-regen", views.ServiceRegenViewSet, "serviceregen"), - # Deprecated - (r"services/regen", views.ServiceRegenViewSet, "serviceregen") + (r"services/regen", views.ServiceRegenViewSet, "serviceregen"), ] urls_view = [ @@ -56,11 +55,10 @@ urls_view = [ (r"machines/firewall-interface-ports", views.InterfacePortsOpenView), (r"machines/dns-zones", views.DNSZonesView), (r"machines/dns-reverse-zones", views.DNSReverseZonesView), - # Deprecated (r"dhcp/hostmacip", views.HostMacIpView), (r"firewall/subnet-ports", views.SubnetPortsOpenView), (r"firewall/interface-ports", views.InterfacePortsOpenView), (r"dns/zones", views.DNSZonesView), (r"dns/reverse-zones", views.DNSReverseZonesView), -] \ No newline at end of file +] diff --git a/machines/api/views.py b/machines/api/views.py index 4fa23d8e..8d30bf53 100644 --- a/machines/api/views.py +++ b/machines/api/views.py @@ -19,159 +19,142 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -from rest_framework import viewsets, generics +from rest_framework import generics, viewsets -from . import serializers import machines.models as machines from re2o.utils import all_active_interfaces +from . import serializers + + class MachineViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Machine` objects. - """ + """Exposes list and details of `machines.models.Machine` objects.""" queryset = machines.Machine.objects.all() serializer_class = serializers.MachineSerializer class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.MachineType` objects. - """ + """Exposes list and details of `machines.models.MachineType` objects.""" queryset = machines.MachineType.objects.all() serializer_class = serializers.MachineTypeSerializer class IpTypeViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.IpType` objects. - """ + """Exposes list and details of `machines.models.IpType` objects.""" queryset = machines.IpType.objects.all() serializer_class = serializers.IpTypeSerializer class VlanViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Vlan` objects. - """ + """Exposes list and details of `machines.models.Vlan` objects.""" queryset = machines.Vlan.objects.all() serializer_class = serializers.VlanSerializer class NasViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Nas` objects. - """ + """Exposes list and details of `machines.models.Nas` objects.""" queryset = machines.Nas.objects.all() serializer_class = serializers.NasSerializer class SOAViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.SOA` objects. - """ + """Exposes list and details of `machines.models.SOA` objects.""" queryset = machines.SOA.objects.all() serializer_class = serializers.SOASerializer class ExtensionViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Extension` objects. - """ + """Exposes list and details of `machines.models.Extension` objects.""" queryset = machines.Extension.objects.all() serializer_class = serializers.ExtensionSerializer class MxViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Mx` objects. - """ + """Exposes list and details of `machines.models.Mx` objects.""" queryset = machines.Mx.objects.all() serializer_class = serializers.MxSerializer class NsViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Ns` objects. - """ + """Exposes list and details of `machines.models.Ns` objects.""" queryset = machines.Ns.objects.all() serializer_class = serializers.NsSerializer class TxtViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Txt` objects. - """ + """Exposes list and details of `machines.models.Txt` objects.""" queryset = machines.Txt.objects.all() serializer_class = serializers.TxtSerializer class DNameViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.DName` objects. - """ + """Exposes list and details of `machines.models.DName` objects.""" queryset = machines.DName.objects.all() serializer_class = serializers.DNameSerializer class SrvViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Srv` objects. - """ + """Exposes list and details of `machines.models.Srv` objects.""" queryset = machines.Srv.objects.all() serializer_class = serializers.SrvSerializer class SshFpViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.SshFp` objects. - """ + """Exposes list and details of `machines.models.SshFp` objects.""" queryset = machines.SshFp.objects.all() serializer_class = serializers.SshFpSerializer class InterfaceViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Interface` objects. - """ + """Exposes list and details of `machines.models.Interface` objects.""" queryset = machines.Interface.objects.all() serializer_class = serializers.InterfaceSerializer class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Ipv6List` objects. - """ + """Exposes list and details of `machines.models.Ipv6List` objects.""" queryset = machines.Ipv6List.objects.all() serializer_class = serializers.Ipv6ListSerializer class DomainViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Domain` objects. - """ + """Exposes list and details of `machines.models.Domain` objects.""" queryset = machines.Domain.objects.all() serializer_class = serializers.DomainSerializer class IpListViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.IpList` objects. - """ + """Exposes list and details of `machines.models.IpList` objects.""" queryset = machines.IpList.objects.all() serializer_class = serializers.IpListSerializer class ServiceViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Service` objects. - """ + """Exposes list and details of `machines.models.Service` objects.""" queryset = machines.Service.objects.all() serializer_class = serializers.ServiceSerializer class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Service_link` objects. - """ + """Exposes list and details of `machines.models.Service_link` objects.""" queryset = machines.Service_link.objects.all() serializer_class = serializers.ServiceLinkSerializer @@ -187,24 +170,21 @@ class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet): class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.OuverturePort` objects. - """ + """Exposes list and details of `machines.models.OuverturePort` objects.""" queryset = machines.OuverturePort.objects.all() serializer_class = serializers.OuverturePortSerializer class RoleViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `machines.models.Machine` objects. - """ + """Exposes list and details of `machines.models.Machine` objects.""" queryset = machines.Role.objects.all() serializer_class = serializers.RoleSerializer class ServiceRegenViewSet(viewsets.ModelViewSet): - """Exposes list and details of the services to regen - """ + """Exposes list and details of the services to regen""" serializer_class = serializers.ServiceRegenSerializer @@ -238,6 +218,7 @@ class InterfacePortsOpenView(generics.ListAPIView): queryset = machines.Interface.objects.filter(port_lists__isnull=False).distinct() serializer_class = serializers.InterfacePortsOpenSerializer + class DNSZonesView(generics.ListAPIView): """Exposes the detailed information about each extension (hostnames, IPs, DNS records, etc.) in order to build the DNS zone files. @@ -264,4 +245,4 @@ class DNSReverseZonesView(generics.ListAPIView): """ queryset = machines.IpType.objects.all() - serializer_class = serializers.DNSReverseZonesSerializer \ No newline at end of file + serializer_class = serializers.DNSReverseZonesSerializer diff --git a/machines/apps.py b/machines/apps.py index 4ba9970c..f7f96755 100644 --- a/machines/apps.py +++ b/machines/apps.py @@ -8,4 +8,4 @@ from django.apps import AppConfig class MachinesConfig(AppConfig): """Configuration of machines app.""" - name = "machines" \ No newline at end of file + name = "machines" diff --git a/machines/forms.py b/machines/forms.py index ed5975e3..e2d3e1b1 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -36,37 +36,17 @@ Forms to create, edit and delete: from __future__ import unicode_literals from django import forms -from django.forms import ModelForm, Form +from django.forms import Form, ModelForm from django.utils.translation import ugettext_lazy as _ from re2o.field_permissions import FieldPermissionFormMixin from re2o.mixins import FormRevMixin -from re2o.widgets import ( - AutocompleteModelWidget, - AutocompleteMultipleModelWidget, -) -from .models import ( - Domain, - Machine, - Interface, - IpList, - MachineType, - Extension, - SOA, - Mx, - Txt, - DName, - Ns, - Role, - Service, - Vlan, - Srv, - SshFp, - Nas, - IpType, - OuverturePortList, - Ipv6List, -) +from re2o.widgets import (AutocompleteModelWidget, + AutocompleteMultipleModelWidget) + +from .models import (SOA, DName, Domain, Extension, Interface, IpList, IpType, + Ipv6List, Machine, MachineType, Mx, Nas, Ns, + OuverturePortList, Role, Service, Srv, SshFp, Txt, Vlan) class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): @@ -248,7 +228,9 @@ class IpTypeForm(FormRevMixin, ModelForm): fields = "__all__" widgets = { "vlan": AutocompleteModelWidget(url="/machines/vlan-autocomplete"), - "extension": AutocompleteModelWidget(url="/machines/extension-autocomplete"), + "extension": AutocompleteModelWidget( + url="/machines/extension-autocomplete" + ), "ouverture_ports": AutocompleteModelWidget( url="/machines/ouvertureportlist-autocomplete" ), @@ -525,7 +507,9 @@ class SrvForm(FormRevMixin, ModelForm): model = Srv fields = "__all__" widgets = { - "extension": AutocompleteModelWidget(url="/machines/extension-autocomplete"), + "extension": AutocompleteModelWidget( + url="/machines/extension-autocomplete" + ), "target": AutocompleteModelWidget(url="/machines/domain-autocomplete"), } diff --git a/machines/models.py b/machines/models.py index 8e4e494f..302d6bd3 100644 --- a/machines/models.py +++ b/machines/models.py @@ -35,26 +35,18 @@ from ipaddress import IPv6Address from itertools import chain from django.core.validators import MaxValueValidator, MinValueValidator -from django.db import models +from django.db import models, transaction from django.db.models import Q -from django.db.models.signals import post_save, post_delete +from django.db.models.signals import post_delete, post_save from django.dispatch import receiver from django.forms import ValidationError from django.utils import timezone -from django.db import transaction -from reversion import revisions as reversion from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from macaddress.fields import MACAddressField, default_dialect -from netaddr import ( - mac_bare, - EUI, - NotRegisteredError, - IPSet, - IPRange, - IPNetwork, - IPAddress, -) +from netaddr import (EUI, IPAddress, IPNetwork, IPRange, IPSet, + NotRegisteredError, mac_bare) +from reversion import revisions as reversion import preferences.models import users.models @@ -79,9 +71,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, AclMixin, models.Model): active = models.BooleanField(default=True) class Meta: - permissions = ( - ("change_machine_user", _("Can change the user of a machine")), - ) + permissions = (("change_machine_user", _("Can change the user of a machine")),) verbose_name = _("machine") verbose_name_plural = _("machines") @@ -342,9 +332,7 @@ class MachineType(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = ( - ("use_all_machinetype", _("Can use all machine types")), - ) + permissions = (("use_all_machinetype", _("Can use all machine types")),) verbose_name = _("machine type") verbose_name_plural = _("machine types") @@ -356,7 +344,9 @@ class MachineType(RevMixin, AclMixin, models.Model): """Update domains extension with the extension of interface_parent. Called after update of an ip_type or a machine_type object. Exceptions are handled in the views. (Calling domain.clear() for all domains could take several minutes) """ - Domain.objects.filter(interface_parent__machine_type=self).update(extension=self.ip_type.extension) + Domain.objects.filter(interface_parent__machine_type=self).update( + extension=self.ip_type.extension + ) @staticmethod def can_use_all(user_request, *_args, **_kwargs): @@ -379,7 +369,7 @@ class MachineType(RevMixin, AclMixin, models.Model): @classmethod def can_list(cls, user_request, *_args, **_kwargs): - """All users can list unprivileged machinetypes + """All users can list unprivileged machinetypes Only members of privileged groups can list all. :param user_request: The user who wants to view the list. @@ -389,20 +379,13 @@ class MachineType(RevMixin, AclMixin, models.Model): """ can, _message, _group = cls.can_use_all(user_request) if can: - return ( - True, - None, - None, - cls.objects.all() - ) + return (True, None, None, cls.objects.all()) else: return ( True, _("You don't have the right to use all machine types."), ("machines.use_all_machinetype",), - cls.objects.filter( - ip_type__in=IpType.objects.filter(need_infra=False) - ), + cls.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False)), ) def __str__(self): @@ -455,12 +438,12 @@ class IpType(RevMixin, AclMixin, models.Model): default=False, help_text=_("Enable reverse DNS for IPv6.") ) vlan = models.ForeignKey("Vlan", on_delete=models.PROTECT, blank=True, null=True) - ouverture_ports = models.ForeignKey("OuverturePortList", blank=True, null=True, on_delete=models.PROTECT) + ouverture_ports = models.ForeignKey( + "OuverturePortList", blank=True, null=True, on_delete=models.PROTECT + ) class Meta: - permissions = ( - ("use_all_iptype", _("Can use all IP types")), - ) + permissions = (("use_all_iptype", _("Can use all IP types")),) verbose_name = _("IP type") verbose_name_plural = _("IP types") @@ -897,9 +880,7 @@ class Extension(RevMixin, AclMixin, models.Model): ) class Meta: - permissions = ( - ("use_all_extension", _("Can use all extensions")), - ) + permissions = (("use_all_extension", _("Can use all extensions")),) verbose_name = _("DNS extension") verbose_name_plural = _("DNS extensions") @@ -977,7 +958,7 @@ class Extension(RevMixin, AclMixin, models.Model): @classmethod def can_list(cls, user_request, *_args, **_kwargs): - """All users can list unprivileged extensions + """All users can list unprivileged extensions Only members of privileged groups can list all. :param user_request: The user who wants to view the list. @@ -987,12 +968,7 @@ class Extension(RevMixin, AclMixin, models.Model): """ can, _message, _group = cls.can_use_all(user_request) if can: - return ( - True, - None, - None, - cls.objects.all() - ) + return (True, None, None, cls.objects.all()) else: return ( True, @@ -1035,8 +1011,7 @@ class Mx(RevMixin, AclMixin, models.Model): @cached_property def dns_entry(self): - """Get the complete DNS entry of the MX record, to put in zone files. - """ + """Get the complete DNS entry of the MX record, to put in zone files.""" return "@ IN MX {prior} {name}".format( prior=str(self.priority).ljust(3), name=str(self.name) ) @@ -1066,8 +1041,7 @@ class Ns(RevMixin, AclMixin, models.Model): @cached_property def dns_entry(self): - """Get the complete DNS entry of the NS record, to put in zone files. - """ + """Get the complete DNS entry of the NS record, to put in zone files.""" return "@ IN NS " + str(self.ns) def __str__(self): @@ -1100,8 +1074,7 @@ class Txt(RevMixin, AclMixin, models.Model): @cached_property def dns_entry(self): - """Get the complete DNS entry of the TXT record, to put in zone files. - """ + """Get the complete DNS entry of the TXT record, to put in zone files.""" return str(self.field1).ljust(15) + " IN TXT " + str(self.field2) @@ -1129,8 +1102,7 @@ class DName(RevMixin, AclMixin, models.Model): @cached_property def dns_entry(self): - """Get the complete DNS entry of the TXT record, to put in zone files. - """ + """Get the complete DNS entry of the TXT record, to put in zone files.""" return str(self.alias).ljust(15) + " IN DNAME " + str(self.zone) @@ -1204,8 +1176,7 @@ class Srv(RevMixin, AclMixin, models.Model): @cached_property def dns_entry(self): - """Get the complete DNS entry of the SRV record, to put in zone files. - """ + """Get the complete DNS entry of the SRV record, to put in zone files.""" return ( str(self.service) + "._" @@ -1387,8 +1358,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): return vendor def sync_ipv6_dhcpv6(self): - """Assign an IPv6 address by DHCPv6, computed from the interface's ID. - """ + """Assign an IPv6 address by DHCPv6, computed from the interface's ID.""" ipv6_dhcpv6 = self.gen_ipv6_dhcpv6 if not ipv6_dhcpv6: return @@ -1414,8 +1384,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ipv6_object.save() def sync_ipv6(self): - """Create and update the IPv6 addresses according to the IPv6 mode set. - """ + """Create and update the IPv6 addresses according to the IPv6 mode set.""" if preferences.models.OptionalMachine.get_cached_value("ipv6_mode") == "SLAAC": self.sync_ipv6_slaac() elif ( @@ -1581,8 +1550,10 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): _("You don't have the right to add a machine."), ("machines.add_interface",), ) - max_lambdauser_interfaces = preferences.models.OptionalMachine.get_cached_value( - "max_lambdauser_interfaces" + max_lambdauser_interfaces = ( + preferences.models.OptionalMachine.get_cached_value( + "max_lambdauser_interfaces" + ) ) if machine.user != user_request: return ( @@ -1721,8 +1692,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ) slaac_ip = models.BooleanField(default=False) active = models.BooleanField( - default=True, - help_text=_("If false,the DNS will not provide this ip.") + default=True, help_text=_("If false,the DNS will not provide this ip.") ) class Meta: @@ -1856,8 +1826,9 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def check_and_replace_prefix(self, prefix=None): """Check if the IPv6 prefix is correct and update it if not.""" - prefix_v6 = prefix or self.interface.machine_type.ip_type.prefix_v6.encode().decode( - "utf-8" + prefix_v6 = ( + prefix + or self.interface.machine_type.ip_type.prefix_v6.encode().decode("utf-8") ) if not prefix_v6: return @@ -1930,7 +1901,11 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ) extension = models.ForeignKey("Extension", on_delete=models.PROTECT) cname = models.ForeignKey( - "self", null=True, blank=True, related_name="related_domain", on_delete=models.PROTECT + "self", + null=True, + blank=True, + related_name="related_domain", + on_delete=models.PROTECT, ) ttl = models.PositiveIntegerField( verbose_name=_("Time To Live (TTL)"), @@ -1940,9 +1915,7 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): class Meta: unique_together = (("name", "extension"),) - permissions = ( - ("change_ttl", _("Can change the TTL of a domain object")), - ) + permissions = (("change_ttl", _("Can change the TTL of a domain object")),) verbose_name = _("domain") verbose_name_plural = _("domains") @@ -2037,8 +2010,10 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): except Interface.DoesNotExist: return False, _("Nonexistent interface."), None if not user_request.has_perm("machines.add_domain"): - max_lambdauser_aliases = preferences.models.OptionalMachine.get_cached_value( - "max_lambdauser_aliases" + max_lambdauser_aliases = ( + preferences.models.OptionalMachine.get_cached_value( + "max_lambdauser_aliases" + ) ) if interface.machine.user != user_request: return ( @@ -2173,8 +2148,7 @@ class IpList(RevMixin, AclMixin, models.Model): @cached_property def need_infra(self): - """Check if the 'infra' right is required to assign this IP address. - """ + """Check if the 'infra' right is required to assign this IP address.""" return self.ip_type.need_infra def clean(self): @@ -2206,20 +2180,13 @@ class IpList(RevMixin, AclMixin, models.Model): """ can, _message, _group = IpType.can_use_all(user_request) if can: - return ( - True, - None, - None, - cls.objects.all() - ) + return (True, None, None, cls.objects.all()) else: return ( True, _("You don't have the right to use all machine types."), ("machines.use_all_machinetype",), - cls.objects.filter( - ip_type__in=IpType.objects.filter(need_infra=False) - ), + cls.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False)), ) def __str__(self): @@ -2517,7 +2484,13 @@ class OuverturePort(RevMixin, AclMixin, models.Model): def machine_post_save(**kwargs): """Synchronise LDAP and regen firewall/DHCP after a machine is edited.""" user = kwargs["instance"].user - users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=False, mac_refresh=True) + users.signals.synchronise.send( + sender=users.models.User, + instance=user, + base=False, + access_refresh=False, + mac_refresh=True, + ) regen("dhcp") regen("mac_ip_list") @@ -2527,7 +2500,13 @@ def machine_post_delete(**kwargs): """Synchronise LDAP and regen firewall/DHCP after a machine is deleted.""" machine = kwargs["instance"] user = machine.user - users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=False, mac_refresh=True) + users.signals.synchronise.send( + sender=users.models.User, + instance=user, + base=False, + access_refresh=False, + mac_refresh=True, + ) regen("dhcp") regen("mac_ip_list") @@ -2540,7 +2519,13 @@ def interface_post_save(**kwargs): interface = kwargs["instance"] interface.sync_ipv6() user = interface.machine.user - users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=False, mac_refresh=True) + users.signals.synchronise.send( + sender=users.models.User, + instance=user, + base=False, + access_refresh=False, + mac_refresh=True, + ) # Regen services regen("dhcp") regen("mac_ip_list") @@ -2552,11 +2537,16 @@ def interface_post_save(**kwargs): @receiver(post_delete, sender=Interface) def interface_post_delete(**kwargs): - """Synchronise LDAP and regen firewall/DHCP after an interface is deleted. - """ + """Synchronise LDAP and regen firewall/DHCP after an interface is deleted.""" interface = kwargs["instance"] user = interface.machine.user - users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=False, mac_refresh=True) + users.signals.synchronise.send( + sender=users.models.User, + instance=user, + base=False, + access_refresh=False, + mac_refresh=True, + ) @receiver(post_save, sender=IpType) diff --git a/machines/urls.py b/machines/urls.py index 94529a76..b8ed184c 100644 --- a/machines/urls.py +++ b/machines/urls.py @@ -28,8 +28,7 @@ from __future__ import unicode_literals from django.urls import path -from . import views -from . import views_autocomplete +from . import views, views_autocomplete app_name = "machines" @@ -96,9 +95,7 @@ urlpatterns = [ path("add_alias/", views.add_alias, name="add-alias"), path("edit_alias/", views.edit_alias, name="edit-alias"), path("del_alias/", views.del_alias, name="del-alias"), - path( - "index_alias/", views.index_alias, name="index-alias" - ), + path("index_alias/", views.index_alias, name="index-alias"), path( "new_ipv6list/", views.new_ipv6list, @@ -116,9 +113,7 @@ urlpatterns = [ ), path("index_ipv6/", views.index_ipv6, name="index-ipv6"), path("add_service", views.add_service, name="add-service"), - path( - "edit_service/", views.edit_service, name="edit-service" - ), + path("edit_service/", views.edit_service, name="edit-service"), path("del_service", views.del_service, name="del-service"), path( "regen_service/", @@ -157,13 +152,49 @@ urlpatterns = [ name="port-config", ), ### Autocomplete Views - path('vlan-autocomplete', views_autocomplete.VlanAutocomplete.as_view(), name='vlan-autocomplete',), - path('interface-autocomplete', views_autocomplete.InterfaceAutocomplete.as_view(), name='interface-autocomplete',), - path('machine-autocomplete', views_autocomplete.MachineAutocomplete.as_view(), name='machine-autocomplete',), - path('machinetype-autocomplete', views_autocomplete.MachineTypeAutocomplete.as_view(), name='machinetype-autocomplete',), - path('iptype-autocomplete', views_autocomplete.IpTypeAutocomplete.as_view(), name='iptype-autocomplete',), - path('extension-autocomplete', views_autocomplete.ExtensionAutocomplete.as_view(), name='extension-autocomplete',), - path('domain-autocomplete', views_autocomplete.DomainAutocomplete.as_view(), name='domain-autocomplete',), - path('ouvertureportlist-autocomplete', views_autocomplete.OuverturePortListAutocomplete.as_view(), name='ouvertureportlist-autocomplete',), - path('iplist-autocomplete', views_autocomplete.IpListAutocomplete.as_view(), name='iplist-autocomplete',), + path( + "vlan-autocomplete", + views_autocomplete.VlanAutocomplete.as_view(), + name="vlan-autocomplete", + ), + path( + "interface-autocomplete", + views_autocomplete.InterfaceAutocomplete.as_view(), + name="interface-autocomplete", + ), + path( + "machine-autocomplete", + views_autocomplete.MachineAutocomplete.as_view(), + name="machine-autocomplete", + ), + path( + "machinetype-autocomplete", + views_autocomplete.MachineTypeAutocomplete.as_view(), + name="machinetype-autocomplete", + ), + path( + "iptype-autocomplete", + views_autocomplete.IpTypeAutocomplete.as_view(), + name="iptype-autocomplete", + ), + path( + "extension-autocomplete", + views_autocomplete.ExtensionAutocomplete.as_view(), + name="extension-autocomplete", + ), + path( + "domain-autocomplete", + views_autocomplete.DomainAutocomplete.as_view(), + name="domain-autocomplete", + ), + path( + "ouvertureportlist-autocomplete", + views_autocomplete.OuverturePortListAutocomplete.as_view(), + name="ouvertureportlist-autocomplete", + ), + path( + "iplist-autocomplete", + views_autocomplete.IpListAutocomplete.as_view(), + name="iplist-autocomplete", + ), ] diff --git a/machines/views.py b/machines/views.py index 04b8a3a8..461862cf 100644 --- a/machines/views.py +++ b/machines/views.py @@ -34,11 +34,11 @@ from __future__ import unicode_literals from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required -from django.db.models import ProtectedError, F from django.db import IntegrityError +from django.db.models import F, ProtectedError from django.forms import modelformset_factory from django.http import HttpResponse -from django.shortcuts import render, redirect +from django.shortcuts import redirect, render from django.template.loader import render_to_string from django.urls import reverse from django.utils.translation import ugettext as _ @@ -46,82 +46,28 @@ from django.views.decorators.csrf import csrf_exempt from rest_framework.renderers import JSONRenderer from preferences.models import GeneralOption -from re2o.acl import ( - can_create, - can_edit, - can_view, - can_delete, - can_view_all, - can_delete_set, -) -from re2o.utils import all_active_assigned_interfaces, filter_active_interfaces +from re2o.acl import (can_create, can_delete, can_delete_set, can_edit, + can_view, can_view_all) from re2o.base import SortTable, re2o_paginator +from re2o.utils import all_active_assigned_interfaces, filter_active_interfaces from re2o.views import form from users.models import User -from .forms import ( - NewMachineForm, - EditMachineForm, - EditInterfaceForm, - AddInterfaceForm, - MachineTypeForm, - DelMachineTypeForm, - ExtensionForm, - DelExtensionForm, - EditIpTypeForm, - IpTypeForm, - DelIpTypeForm, - DomainForm, - AliasForm, - DelAliasForm, - SOAForm, - DelSOAForm, - NsForm, - DelNsForm, - TxtForm, - DelTxtForm, - DNameForm, - DelDNameForm, - MxForm, - DelMxForm, - VlanForm, - DelVlanForm, - RoleForm, - DelRoleForm, - ServiceForm, - DelServiceForm, - SshFpForm, - NasForm, - DelNasForm, - SrvForm, - DelSrvForm, - Ipv6ListForm, - EditOuverturePortListForm, - EditOuverturePortConfigForm, -) -from .models import ( - IpType, - Machine, - Interface, - MachineType, - Extension, - SOA, - Mx, - Ns, - Domain, - Role, - Service, - Service_link, - regen, - Vlan, - Nas, - Txt, - DName, - Srv, - SshFp, - OuverturePortList, - OuverturePort, - Ipv6List, -) + +from .forms import (AddInterfaceForm, AliasForm, DelAliasForm, DelDNameForm, + DelExtensionForm, DelIpTypeForm, DelMachineTypeForm, + DelMxForm, DelNasForm, DelNsForm, DelRoleForm, + DelServiceForm, DelSOAForm, DelSrvForm, DelTxtForm, + DelVlanForm, DNameForm, DomainForm, EditInterfaceForm, + EditIpTypeForm, EditMachineForm, + EditOuverturePortConfigForm, EditOuverturePortListForm, + ExtensionForm, IpTypeForm, Ipv6ListForm, MachineTypeForm, + MxForm, NasForm, NewMachineForm, NsForm, RoleForm, + ServiceForm, SOAForm, SrvForm, SshFpForm, TxtForm, + VlanForm) +from .models import (SOA, DName, Domain, Extension, Interface, IpType, + Ipv6List, Machine, MachineType, Mx, Nas, Ns, + OuverturePort, OuverturePortList, Role, Service, + Service_link, Srv, SshFp, Txt, Vlan, regen) @login_required @@ -135,7 +81,9 @@ def new_machine(request, user, **_kwargs): """ machine = NewMachineForm(request.POST or None, user=request.user) interface = AddInterfaceForm(request.POST or None, user=request.user) - domain = DomainForm(request.POST or None, user=user, initial={'name': user.get_next_domain_name()}) + domain = DomainForm( + request.POST or None, user=user, initial={"name": user.get_next_domain_name()} + ) if machine.is_valid() and interface.is_valid(): new_machine_obj = machine.save(commit=False) new_machine_obj.user = user @@ -229,7 +177,11 @@ def new_interface(request, machine, **_kwargs): machine. """ interface_form = AddInterfaceForm(request.POST or None, user=request.user) - domain_form = DomainForm(request.POST or None, user=request.user, initial={'name': machine.user.get_next_domain_name()}) + domain_form = DomainForm( + request.POST or None, + user=request.user, + initial={"name": machine.user.get_next_domain_name()}, + ) if interface_form.is_valid(): new_interface_obj = interface_form.save(commit=False) domain_form.instance.interface_parent = new_interface_obj @@ -268,7 +220,9 @@ def del_interface(request, interface, **_kwargs): reverse("users:profil", kwargs={"userid": str(request.user.id)}) ) return form( - {"objet": interface, "objet_name": _("interface")}, "machines/delete.html", request + {"objet": interface, "objet_name": _("interface")}, + "machines/delete.html", + request, ) @@ -328,7 +282,9 @@ def del_ipv6list(request, ipv6list, **_kwargs): reverse("machines:index-ipv6", kwargs={"interfaceid": str(interfaceid)}) ) return form( - {"objet": ipv6list, "objet_name": _("IPv6 addresses list")}, "machines/delete.html", request + {"objet": ipv6list, "objet_name": _("IPv6 addresses list")}, + "machines/delete.html", + request, ) @@ -384,7 +340,9 @@ def del_sshfp(request, sshfp, **_kwargs): reverse("machines:index-sshfp", kwargs={"machineid": str(machineid)}) ) return form( - {"objet": sshfp, "objet_name": _("SSHFP record")}, "machines/delete.html", request + {"objet": sshfp, "objet_name": _("SSHFP record")}, + "machines/delete.html", + request, ) @@ -421,7 +379,9 @@ def edit_iptype(request, iptype_instance, **_kwargs): iptype.save() messages.success(request, _("The IP type was edited.")) except IntegrityError as e: - messages.success(request, _("This IP type change would create duplicated domains")) + messages.success( + request, _("This IP type change would create duplicated domains") + ) return redirect(reverse("machines:index-iptype")) return form( {"iptypeform": iptype, "action_name": _("Edit")}, @@ -490,7 +450,10 @@ def edit_machinetype(request, machinetype_instance, **_kwargs): machinetype.save() messages.success(request, _("The machine type was edited.")) except IntegrityError as e: - messages.error(request, _("This machine type change would create duplicated domains")) + messages.error( + request, + _("This machine type change would create duplicated domains"), + ) return redirect(reverse("machines:index-machinetype")) return form( {"machinetypeform": machinetype, "action_name": _("Edit")}, @@ -580,10 +543,16 @@ def del_extension(request, instances): _( "The extension %s is assigned to following %s : %s" ", you can't delete it." - ) % ( + ) + % ( extension_del, str(e.protected_objects.model._meta.verbose_name_plural), - ",".join(map(lambda x: str(x['name']), e.protected_objects.values('name').iterator())) + ",".join( + map( + lambda x: str(x["name"]), + e.protected_objects.values("name").iterator(), + ) + ), ) ), ) @@ -1221,17 +1190,18 @@ def index(request): machines_list = re2o_paginator(request, machines_list, pagination_large_number) return render(request, "machines/index.html", {"machines_list": machines_list}) + # Canonic view for displaying machines in users's profil def aff_profil(request, user): """View used to display the machines on a user's profile.""" machines = ( - Machine.objects.filter(user=user) + Machine.objects.filter(user=user) .select_related("user") .prefetch_related("interface_set__domain__extension") .prefetch_related("interface_set__ipv4__ip_type__extension") .prefetch_related("interface_set__machine_type") .prefetch_related("interface_set__domain__related_domain__extension") - ) + ) machines = SortTable.sort( machines, request.GET.get("col"), @@ -1243,19 +1213,16 @@ def aff_profil(request, user): machines = re2o_paginator(request, machines, pagination_large_number) context = { - "users":user, - "machines_list": machines, - "nb_machines":nb_machines, + "users": user, + "machines_list": machines, + "nb_machines": nb_machines, } return render_to_string( - "machines/aff_profil.html",context=context,request=request,using=None + "machines/aff_profil.html", context=context, request=request, using=None ) - - - @login_required @can_view_all(IpType) def index_iptype(request): @@ -1531,4 +1498,3 @@ def configure_ports(request, interface_instance, **_kwargs): "machines/machine.html", request, ) - diff --git a/machines/views_autocomplete.py b/machines/views_autocomplete.py index 94b55a59..51010f9a 100644 --- a/machines/views_autocomplete.py +++ b/machines/views_autocomplete.py @@ -31,23 +31,14 @@ Here are defined the autocomplete class based view. """ from __future__ import unicode_literals -from django.db.models import Q, Value, CharField +from django.db.models import CharField, Q, Value from django.db.models.functions import Concat -from .models import ( - Interface, - Machine, - Vlan, - MachineType, - IpType, - Extension, - Domain, - OuverturePortList, - IpList, -) - from re2o.views import AutocompleteViewMixin +from .models import (Domain, Extension, Interface, IpList, IpType, Machine, + MachineType, OuverturePortList, Vlan) + class VlanAutocomplete(AutocompleteViewMixin): obj_type = Vlan diff --git a/multi_op/forms.py b/multi_op/forms.py index f4c839de..a953679f 100644 --- a/multi_op/forms.py +++ b/multi_op/forms.py @@ -27,11 +27,11 @@ Select a dorm from django import forms -from django.forms import ModelForm, Form -from re2o.field_permissions import FieldPermissionFormMixin -from re2o.mixins import FormRevMixin +from django.forms import Form, ModelForm from django.utils.translation import ugettext_lazy as _ +from re2o.field_permissions import FieldPermissionFormMixin +from re2o.mixins import FormRevMixin from topologie.models import Dormitory from .preferences.models import MultiopOption @@ -49,4 +49,6 @@ class DormitoryForm(FormRevMixin, Form): def __init__(self, *args, **kwargs): super(DormitoryForm, self).__init__(*args, **kwargs) - self.fields["dormitory"].queryset = MultiopOption.get_cached_value("enabled_dorm").all() + self.fields["dormitory"].queryset = MultiopOption.get_cached_value( + "enabled_dorm" + ).all() diff --git a/multi_op/models.py b/multi_op/models.py index 4b74df49..e9fdca24 100644 --- a/multi_op/models.py +++ b/multi_op/models.py @@ -25,21 +25,18 @@ Multi_op model from __future__ import absolute_import +from django.core.mail import EmailMessage from django.db import models -from django.utils.translation import ugettext_lazy as _ -from django.template import loader from django.db.models.signals import post_save from django.dispatch import receiver +from django.template import loader from django.utils.functional import cached_property - +from django.utils.translation import ugettext_lazy as _ from reversion.models import Version -from re2o.mixins import AclMixin -from re2o.mail_utils import send_mail_object -from django.core.mail import EmailMessage - -from preferences.models import GeneralOption - import users.models +from preferences.models import GeneralOption +from re2o.mail_utils import send_mail_object +from re2o.mixins import AclMixin from .preferences.models import MultiopOption diff --git a/multi_op/preferences/__init__.py b/multi_op/preferences/__init__.py index 737e0f26..bbe53822 100644 --- a/multi_op/preferences/__init__.py +++ b/multi_op/preferences/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2020 Gabriel Détraz -# Copyright © 2019 Arthur Grisel-Davy +# Copyright © 2019 Arthur Grisel-Davy # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/multi_op/preferences/forms.py b/multi_op/preferences/forms.py index 45941007..d53a212c 100644 --- a/multi_op/preferences/forms.py +++ b/multi_op/preferences/forms.py @@ -27,8 +27,9 @@ each. from django import forms -from django.forms import ModelForm, Form +from django.forms import Form, ModelForm from django.utils.translation import ugettext_lazy as _ + from re2o.widgets import AutocompleteMultipleModelWidget from .models import MultiopOption diff --git a/multi_op/preferences/models.py b/multi_op/preferences/models.py index d4228e8e..2a9c9e40 100644 --- a/multi_op/preferences/models.py +++ b/multi_op/preferences/models.py @@ -27,8 +27,8 @@ with multiple operators. from django.db import models from django.utils.translation import ugettext_lazy as _ -from re2o.mixins import AclMixin, RevMixin from preferences.models import PreferencesModel +from re2o.mixins import AclMixin, RevMixin class MultiopOption(AclMixin, PreferencesModel): diff --git a/multi_op/preferences/views.py b/multi_op/preferences/views.py index 87e34e6d..1fd3f962 100644 --- a/multi_op/preferences/views.py +++ b/multi_op/preferences/views.py @@ -26,20 +26,16 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.shortcuts import render, redirect +from django.shortcuts import redirect, render from django.template.loader import render_to_string -from django.utils.translation import ugettext as _ from django.urls import reverse - -from re2o.base import re2o_paginator - -from re2o.acl import can_view, can_view_all, can_edit, can_create +from django.utils.translation import ugettext as _ from preferences.views import edit_options_template_function +from re2o.acl import can_create, can_edit, can_view, can_view_all +from re2o.base import re2o_paginator -from . import forms -from . import models - +from . import forms, models def aff_preferences(request): diff --git a/multi_op/views.py b/multi_op/views.py index b4a559f4..e4650d92 100644 --- a/multi_op/views.py +++ b/multi_op/views.py @@ -27,28 +27,24 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.shortcuts import render, redirect -from django.template.loader import render_to_string -from django.views.decorators.cache import cache_page -from django.utils.translation import ugettext as _ -from django.urls import reverse -from django.forms import modelformset_factory from django.db.models import Q +from django.forms import modelformset_factory +from django.shortcuts import redirect, render +from django.template.loader import render_to_string +from django.urls import reverse +from django.utils.translation import ugettext as _ +from django.views.decorators.cache import cache_page + +from preferences.models import AssoOption, GeneralOption +from re2o.acl import can_create, can_edit, can_view, can_view_all +from re2o.base import SortTable, re2o_paginator +from re2o.utils import all_adherent, all_has_access from re2o.views import form -from re2o.utils import all_has_access, all_adherent - -from re2o.base import re2o_paginator, SortTable - -from re2o.acl import can_view, can_view_all, can_edit, can_create - -from preferences.models import GeneralOption, AssoOption +from topologie.models import Dormitory, Room from .forms import DormitoryForm - from .preferences.models import MultiopOption -from topologie.models import Room, Dormitory - def display_rooms_connection(request, dormitory=None): """View used to display an overview of the rooms' connection state. @@ -58,9 +54,13 @@ def display_rooms_connection(request, dormitory=None): dormitory: Dormitory, the dormitory used to filter rooms. If no dormitory is given, all rooms are displayed (default: None). """ - room_list = Room.objects.select_related("building__dormitory").filter( - building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all() - ).order_by("building_dormitory", "port") + room_list = ( + Room.objects.select_related("building__dormitory") + .filter( + building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all() + ) + .order_by("building_dormitory", "port") + ) if dormitory: room_list = room_list.filter(building__dormitory=dormitory) room_list = SortTable.sort( @@ -113,7 +113,9 @@ def aff_pending_connection(request): Room.objects.select_related("building__dormitory") .filter(port__isnull=True) .filter(adherent__in=all_has_access()) - .filter(building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all()) + .filter( + building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all() + ) .order_by("building_dormitory", "port") ) dormitory_form = DormitoryForm(request.POST or None) @@ -151,7 +153,9 @@ def aff_pending_disconnection(request): Room.objects.select_related("building__dormitory") .filter(port__isnull=False) .exclude(Q(adherent__in=all_has_access()) | Q(adherent__in=all_adherent())) - .filter(building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all()) + .filter( + building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all() + ) .order_by("building_dormitory", "port") ) dormitory_form = DormitoryForm(request.POST or None) diff --git a/preferences/admin.py b/preferences/admin.py index fc55d93d..c88016cc 100644 --- a/preferences/admin.py +++ b/preferences/admin.py @@ -28,21 +28,10 @@ from __future__ import unicode_literals from django.contrib import admin from reversion.admin import VersionAdmin -from .models import ( - OptionalUser, - OptionalMachine, - OptionalTopologie, - GeneralOption, - Service, - MailContact, - AssoOption, - MailMessageOption, - HomeOption, - RadiusKey, - SwitchManagementCred, - Reminder, - DocumentTemplate, -) +from .models import (AssoOption, DocumentTemplate, GeneralOption, HomeOption, + MailContact, MailMessageOption, OptionalMachine, + OptionalTopologie, OptionalUser, RadiusKey, Reminder, + Service, SwitchManagementCred) class OptionalUserAdmin(VersionAdmin): diff --git a/preferences/api/serializers.py b/preferences/api/serializers.py index 47a4a07a..a0b757c3 100644 --- a/preferences/api/serializers.py +++ b/preferences/api/serializers.py @@ -22,11 +22,12 @@ from rest_framework import serializers import preferences.models as preferences -from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer +from api.serializers import (NamespacedHIField, NamespacedHMSerializer, + NamespacedHRField) + class OptionalUserSerializer(NamespacedHMSerializer): - """Serialize `preferences.models.OptionalUser` objects. - """ + """Serialize `preferences.models.OptionalUser` objects.""" tel_mandatory = serializers.BooleanField(source="is_tel_mandatory") shell_default = serializers.StringRelatedField() @@ -47,8 +48,7 @@ class OptionalUserSerializer(NamespacedHMSerializer): class OptionalMachineSerializer(NamespacedHMSerializer): - """Serialize `preferences.models.OptionalMachine` objects. - """ + """Serialize `preferences.models.OptionalMachine` objects.""" class Meta: model = preferences.OptionalMachine @@ -59,13 +59,12 @@ class OptionalMachineSerializer(NamespacedHMSerializer): "ipv6_mode", "create_machine", "ipv6", - "default_dns_ttl" + "default_dns_ttl", ) class OptionalTopologieSerializer(NamespacedHMSerializer): - """Serialize `preferences.models.OptionalTopologie` objects. - """ + """Serialize `preferences.models.OptionalTopologie` objects.""" switchs_management_interface_ip = serializers.CharField() @@ -85,8 +84,7 @@ class OptionalTopologieSerializer(NamespacedHMSerializer): class RadiusOptionSerializer(NamespacedHMSerializer): - """Serialize `preferences.models.RadiusOption` objects - """ + """Serialize `preferences.models.RadiusOption` objects""" class Meta: model = preferences.RadiusOption @@ -107,8 +105,7 @@ class RadiusOptionSerializer(NamespacedHMSerializer): class GeneralOptionSerializer(NamespacedHMSerializer): - """Serialize `preferences.models.GeneralOption` objects. - """ + """Serialize `preferences.models.GeneralOption` objects.""" class Meta: model = preferences.GeneralOption @@ -128,8 +125,7 @@ class GeneralOptionSerializer(NamespacedHMSerializer): class HomeServiceSerializer(NamespacedHMSerializer): - """Serialize `preferences.models.Service` objects. - """ + """Serialize `preferences.models.Service` objects.""" class Meta: model = preferences.Service @@ -138,8 +134,7 @@ class HomeServiceSerializer(NamespacedHMSerializer): class AssoOptionSerializer(NamespacedHMSerializer): - """Serialize `preferences.models.AssoOption` objects. - """ + """Serialize `preferences.models.AssoOption` objects.""" class Meta: model = preferences.AssoOption @@ -157,8 +152,7 @@ class AssoOptionSerializer(NamespacedHMSerializer): class HomeOptionSerializer(NamespacedHMSerializer): - """Serialize `preferences.models.HomeOption` objects. - """ + """Serialize `preferences.models.HomeOption` objects.""" class Meta: model = preferences.HomeOption @@ -166,8 +160,7 @@ class HomeOptionSerializer(NamespacedHMSerializer): class MailMessageOptionSerializer(NamespacedHMSerializer): - """Serialize `preferences.models.MailMessageOption` objects. - """ + """Serialize `preferences.models.MailMessageOption` objects.""" class Meta: model = preferences.MailMessageOption diff --git a/preferences/api/urls.py b/preferences/api/urls.py index df0a210c..87ffa74e 100644 --- a/preferences/api/urls.py +++ b/preferences/api/urls.py @@ -21,9 +21,7 @@ from . import views -urls_viewset = [ - (r"preferences/service", views.HomeServiceViewSet, "homeservice") -] +urls_viewset = [(r"preferences/service", views.HomeServiceViewSet, "homeservice")] urls_view = [ (r"preferences/optionaluser", views.OptionalUserView), @@ -33,5 +31,5 @@ urls_view = [ (r"preferences/generaloption", views.GeneralOptionView), (r"preferences/assooption", views.AssoOptionView), (r"preferences/homeoption", views.HomeOptionView), - (r"preferences/mailmessageoption", views.MailMessageOptionView) -] \ No newline at end of file + (r"preferences/mailmessageoption", views.MailMessageOptionView), +] diff --git a/preferences/api/views.py b/preferences/api/views.py index e52766f1..821a7ea2 100644 --- a/preferences/api/views.py +++ b/preferences/api/views.py @@ -19,16 +19,16 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -from rest_framework import viewsets, generics +from rest_framework import generics, viewsets -from . import serializers import preferences.models as preferences from api.permissions import ACLPermission +from . import serializers + class OptionalUserView(generics.RetrieveAPIView): - """Exposes details of `preferences.models.` settings. - """ + """Exposes details of `preferences.models.` settings.""" permission_classes = (ACLPermission,) perms_map = {"GET": [preferences.OptionalUser.can_view_all]} @@ -39,8 +39,7 @@ class OptionalUserView(generics.RetrieveAPIView): class OptionalMachineView(generics.RetrieveAPIView): - """Exposes details of `preferences.models.OptionalMachine` settings. - """ + """Exposes details of `preferences.models.OptionalMachine` settings.""" permission_classes = (ACLPermission,) perms_map = {"GET": [preferences.OptionalMachine.can_view_all]} @@ -51,8 +50,7 @@ class OptionalMachineView(generics.RetrieveAPIView): class OptionalTopologieView(generics.RetrieveAPIView): - """Exposes details of `preferences.models.OptionalTopologie` settings. - """ + """Exposes details of `preferences.models.OptionalTopologie` settings.""" permission_classes = (ACLPermission,) perms_map = {"GET": [preferences.OptionalTopologie.can_view_all]} @@ -63,8 +61,7 @@ class OptionalTopologieView(generics.RetrieveAPIView): class RadiusOptionView(generics.RetrieveAPIView): - """Exposes details of `preferences.models.OptionalTopologie` settings. - """ + """Exposes details of `preferences.models.OptionalTopologie` settings.""" permission_classes = (ACLPermission,) perms_map = {"GET": [preferences.RadiusOption.can_view_all]} @@ -75,8 +72,7 @@ class RadiusOptionView(generics.RetrieveAPIView): class GeneralOptionView(generics.RetrieveAPIView): - """Exposes details of `preferences.models.GeneralOption` settings. - """ + """Exposes details of `preferences.models.GeneralOption` settings.""" permission_classes = (ACLPermission,) perms_map = {"GET": [preferences.GeneralOption.can_view_all]} @@ -87,16 +83,14 @@ class GeneralOptionView(generics.RetrieveAPIView): class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `preferences.models.Service` objects. - """ + """Exposes list and details of `preferences.models.Service` objects.""" queryset = preferences.Service.objects.all() serializer_class = serializers.HomeServiceSerializer class AssoOptionView(generics.RetrieveAPIView): - """Exposes details of `preferences.models.AssoOption` settings. - """ + """Exposes details of `preferences.models.AssoOption` settings.""" permission_classes = (ACLPermission,) perms_map = {"GET": [preferences.AssoOption.can_view_all]} @@ -107,8 +101,7 @@ class AssoOptionView(generics.RetrieveAPIView): class HomeOptionView(generics.RetrieveAPIView): - """Exposes details of `preferences.models.HomeOption` settings. - """ + """Exposes details of `preferences.models.HomeOption` settings.""" permission_classes = (ACLPermission,) perms_map = {"GET": [preferences.HomeOption.can_view_all]} @@ -119,12 +112,11 @@ class HomeOptionView(generics.RetrieveAPIView): class MailMessageOptionView(generics.RetrieveAPIView): - """Exposes details of `preferences.models.MailMessageOption` settings. - """ + """Exposes details of `preferences.models.MailMessageOption` settings.""" permission_classes = (ACLPermission,) perms_map = {"GET": [preferences.MailMessageOption.can_view_all]} serializer_class = serializers.MailMessageOptionSerializer def get_object(self): - return preferences.MailMessageOption.objects.first() \ No newline at end of file + return preferences.MailMessageOption.objects.first() diff --git a/preferences/apps.py b/preferences/apps.py index 2db4b4b1..729da0af 100644 --- a/preferences/apps.py +++ b/preferences/apps.py @@ -8,4 +8,4 @@ from django.apps import AppConfig class PreferencesConfig(AppConfig): """Configuration of preferences app.""" - name = "preferences" \ No newline at end of file + name = "preferences" diff --git a/preferences/forms.py b/preferences/forms.py index e19737c1..032290e4 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -25,36 +25,22 @@ Forms to edit preferences: users, machines, topology, organisation etc. from __future__ import unicode_literals -from django.forms import ModelForm, Form -from django.db.models import Q from django import forms +from django.db.models import Q +from django.forms import Form, ModelForm from django.utils.translation import ugettext_lazy as _ + from re2o.mixins import FormRevMixin -from re2o.widgets import ( - AutocompleteModelWidget, - AutocompleteMultipleModelWidget -) -from .models import ( - OptionalUser, - OptionalMachine, - OptionalTopologie, - GeneralOption, - AssoOption, - MailMessageOption, - HomeOption, - Service, - MailContact, - Reminder, - RadiusKey, - SwitchManagementCred, - RadiusOption, - CotisationsOption, - DocumentTemplate, - RadiusAttribute, - Mandate, -) +from re2o.widgets import (AutocompleteModelWidget, + AutocompleteMultipleModelWidget) from topologie.models import Switch +from .models import (AssoOption, CotisationsOption, DocumentTemplate, + GeneralOption, HomeOption, MailContact, MailMessageOption, + Mandate, OptionalMachine, OptionalTopologie, OptionalUser, + RadiusAttribute, RadiusKey, RadiusOption, Reminder, + Service, SwitchManagementCred) + class EditOptionalUserForm(ModelForm): """Form used to edit user preferences.""" @@ -74,14 +60,22 @@ class EditOptionalUserForm(ModelForm): self.fields["self_change_shell"].label = _("Self change shell") self.fields["self_change_pseudo"].label = _("Self change pseudo") self.fields["self_room_policy"].label = _("Self room policy") - self.fields["local_email_accounts_enabled"].label = _("Local email accounts enabled") + self.fields["local_email_accounts_enabled"].label = _( + "Local email accounts enabled" + ) self.fields["local_email_domain"].label = _("Local email domain") self.fields["max_email_address"].label = _("Max local email address") self.fields["delete_notyetactive"].label = _("Delete not yet active users") - self.fields["disable_emailnotyetconfirmed"].label = _("Disabled email not yet confirmed") + self.fields["disable_emailnotyetconfirmed"].label = _( + "Disabled email not yet confirmed" + ) self.fields["self_adhesion"].label = _("Self registration") - self.fields["all_users_active"].label = _("All users are state active by default") - self.fields["allow_set_password_during_user_creation"].label = _("Allow set password during user creation") + self.fields["all_users_active"].label = _( + "All users are state active by default" + ) + self.fields["allow_set_password_during_user_creation"].label = _( + "Allow set password during user creation" + ) self.fields["allow_archived_connexion"].label = _("Allow archived connexion") @@ -211,9 +205,7 @@ class EditMailMessageOptionForm(ModelForm): def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditMailMessageOptionForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields["welcome_mail_fr"].label = _( - "Message for the French welcome email" - ) + self.fields["welcome_mail_fr"].label = _("Message for the French welcome email") self.fields["welcome_mail_en"].label = _( "Message for the English welcome email" ) @@ -355,8 +347,7 @@ class ServiceForm(ModelForm): class DelServiceForm(Form): - """Form used to delete one or several services displayed on the home page. - """ + """Form used to delete one or several services displayed on the home page.""" services = forms.ModelMultipleChoiceField( queryset=Service.objects.none(), diff --git a/preferences/models.py b/preferences/models.py index b35acac3..799fd006 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -25,23 +25,22 @@ Models defining the preferences for users, machines, emails, general settings etc. """ from __future__ import unicode_literals -import os -from django.utils.functional import cached_property -from django.utils import timezone +import os +from datetime import timedelta + +from django.core.cache import cache from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver -from django.core.cache import cache from django.forms import ValidationError +from django.utils import timezone +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ import machines.models - -from re2o.mixins import AclMixin, RevMixin from re2o.aes_field import AESEncryptedField - -from datetime import timedelta +from re2o.mixins import AclMixin, RevMixin class PreferencesModel(models.Model): @@ -328,7 +327,7 @@ class OptionalTopologie(AclMixin, PreferencesModel): configuration. """ if self.switchs_ip_type: - from machines.models import Role, Interface + from machines.models import Interface, Role return ( Interface.objects.filter( @@ -364,14 +363,14 @@ class OptionalTopologie(AclMixin, PreferencesModel): """Get the dictionary of IP addresses for the configuration of switches. """ - from machines.models import Role, Ipv6List, Interface + from machines.models import Interface, Ipv6List, Role def return_ips_dict(interfaces): return { "ipv4": [str(interface.ipv4) for interface in interfaces], - "ipv6": Ipv6List.objects.filter(interface__in=interfaces).filter(active=True).values_list( - "ipv6", flat=True - ), + "ipv6": Ipv6List.objects.filter(interface__in=interfaces) + .filter(active=True) + .values_list("ipv6", flat=True), } ntp_servers = Role.all_interfaces_for_roletype("ntp-server").filter( @@ -660,7 +659,7 @@ class Mandate(RevMixin, AclMixin, models.Model): @classmethod def get_mandate(cls, date=timezone.now): - """"Get the mandate taking place at the given date. + """ "Get the mandate taking place at the given date. Args: date: the date used to find the mandate (default: timezone.now). diff --git a/preferences/urls.py b/preferences/urls.py index b5b72599..96a9b231 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -79,9 +79,7 @@ urlpatterns = [ name="edit-options", ), path("add_service", views.add_service, name="add-service"), - path( - "edit_service/", views.edit_service, name="edit-service" - ), + path("edit_service/", views.edit_service, name="edit-service"), path("del_service/", views.del_service, name="del-service"), path("add_mailcontact", views.add_mailcontact, name="add-mailcontact"), path( @@ -143,13 +141,9 @@ urlpatterns = [ name="del-document-template", ), path("add_mandate", views.add_mandate, name="add-mandate"), - path( - "edit_mandate/", views.edit_mandate, name="edit-mandate" - ), + path("edit_mandate/", views.edit_mandate, name="edit-mandate"), path("del_mandate/", views.del_mandate, name="del-mandate"), - path( - "add_radiusattribute", views.add_radiusattribute, name="add-radiusattribute" - ), + path("add_radiusattribute", views.add_radiusattribute, name="add-radiusattribute"), path( "edit_radiusattribute/", views.edit_radiusattribute, diff --git a/preferences/views.py b/preferences/views.py index 5eab39f4..36b8a5f5 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -30,61 +30,33 @@ services etc.) from __future__ import unicode_literals -from django.urls import reverse -from django.shortcuts import redirect +from importlib import import_module + from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.db.models import ProtectedError from django.db import transaction +from django.db.models import ProtectedError +from django.shortcuts import redirect +from django.urls import reverse from django.utils.translation import ugettext as _ - from reversion import revisions as reversion -from importlib import import_module +from re2o.acl import (acl_error_message, can_create, can_delete, + can_delete_set, can_edit, can_view_all) from re2o.settings_local import OPTIONNAL_APPS_RE2O from re2o.views import form -from re2o.acl import ( - can_create, - can_edit, - can_delete_set, - can_view_all, - can_delete, - acl_error_message, -) -from .forms import MailContactForm, DelMailContactForm -from .forms import ( - ServiceForm, - ReminderForm, - RadiusKeyForm, - SwitchManagementCredForm, - DocumentTemplateForm, - DelDocumentTemplateForm, - RadiusAttributeForm, - DelRadiusAttributeForm, - MandateForm, -) -from .models import ( - Service, - MailContact, - OptionalUser, - OptionalMachine, - AssoOption, - MailMessageOption, - GeneralOption, - OptionalTopologie, - HomeOption, - Reminder, - RadiusKey, - SwitchManagementCred, - RadiusOption, - CotisationsOption, - DocumentTemplate, - RadiusAttribute, - Mandate, -) -from . import models -from . import forms +from . import forms, models +from .forms import (DelDocumentTemplateForm, DelMailContactForm, + DelRadiusAttributeForm, DocumentTemplateForm, + MailContactForm, MandateForm, RadiusAttributeForm, + RadiusKeyForm, ReminderForm, ServiceForm, + SwitchManagementCredForm) +from .models import (AssoOption, CotisationsOption, DocumentTemplate, + GeneralOption, HomeOption, MailContact, MailMessageOption, + Mandate, OptionalMachine, OptionalTopologie, OptionalUser, + RadiusAttribute, RadiusKey, RadiusOption, Reminder, + Service, SwitchManagementCred) def edit_options_template_function(request, section, forms, models): diff --git a/re2o/acl.py b/re2o/acl.py index 692df905..d1d2c3a9 100644 --- a/re2o/acl.py +++ b/re2o/acl.py @@ -30,8 +30,8 @@ from __future__ import unicode_literals import sys from itertools import chain -from django.db.models import Model from django.contrib import messages +from django.db.models import Model from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import ugettext as _ diff --git a/re2o/aes_field.py b/re2o/aes_field.py index 156531f7..3c847c69 100644 --- a/re2o/aes_field.py +++ b/re2o/aes_field.py @@ -28,22 +28,22 @@ Module defining a AESEncryptedField object that can be used in forms to handle the use of properly encrypting and decrypting AES keys """ -import string import binascii +import string from random import choice -from Crypto.Cipher import AES -from django.db import models +from Crypto.Cipher import AES from django import forms from django.conf import settings +from django.db import models EOD_asbyte = b"`%EofD%`" # This should be something that will not occur in strings EOD = EOD_asbyte.decode("utf-8") def genstring(length=16, chars=string.printable): - """ Generate a random string of length `length` and composed of - the characters in `chars` """ + """Generate a random string of length `length` and composed of + the characters in `chars`""" return "".join([choice(chars) for i in range(length)]) @@ -71,8 +71,8 @@ class AESEncryptedFormField(forms.CharField): class AESEncryptedField(models.CharField): - """ A Field that can be used in forms for adding the support - of AES ecnrypted fields """ + """A Field that can be used in forms for adding the support + of AES ecnrypted fields""" def save_form_data(self, instance, data): setattr( diff --git a/re2o/apps.py b/re2o/apps.py index e19abee2..abcecb77 100644 --- a/re2o/apps.py +++ b/re2o/apps.py @@ -8,4 +8,4 @@ from django.apps import AppConfig class Re2oConfig(AppConfig): """Configuration of re2o app.""" - name = "re2o" \ No newline at end of file + name = "re2o" diff --git a/re2o/base.py b/re2o/base.py index 80f033d8..5c3ac781 100644 --- a/re2o/base.py +++ b/re2o/base.py @@ -26,12 +26,11 @@ Global independant usefull functions import smtplib +from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator from django.utils.translation import ugettext_lazy as _ -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from re2o.settings import EMAIL_HOST - # Mapping of srtftime format for better understanding # https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior datetime_mapping = { @@ -64,7 +63,7 @@ datetime_mapping = { def smtp_check(local_part): """Return True if the local_part is already taken - False if available""" + False if available""" try: srv = smtplib.SMTP(EMAIL_HOST) srv.putcmd("vrfy", local_part) @@ -108,9 +107,9 @@ def get_input_formats_help_text(input_formats): class SortTable: - """ Class gathering uselful stuff to sort the colums of a table, according + """Class gathering uselful stuff to sort the colums of a table, according to the column and order requested. It's used with a dict of possible - values and associated model_fields """ + values and associated model_fields""" # All the possible possible values # The naming convention is based on the URL or the views function @@ -228,8 +227,8 @@ class SortTable: @staticmethod def sort(request, col, order, values): - """ Check if the given values are possible and add .order_by() and - a .reverse() as specified according to those values """ + """Check if the given values are possible and add .order_by() and + a .reverse() as specified according to those values""" fields = values.get(col, None) if not fields: fields = values.get("default", []) diff --git a/re2o/context_processors.py b/re2o/context_processors.py index 0fca6037..88471819 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -24,21 +24,22 @@ from __future__ import unicode_literals import datetime +from importlib import import_module from django.contrib import messages from django.contrib.messages import get_messages from django.http import HttpRequest -from preferences.models import GeneralOption, OptionalMachine from django.utils.translation import get_language -from importlib import import_module + +from preferences.models import GeneralOption, OptionalMachine from re2o.settings_local import OPTIONNAL_APPS_RE2O def context_user(request): """Global Context function - Returns: - dict:Containing user's interfaces and himself if logged, else None + Returns: + dict:Containing user's interfaces and himself if logged, else None """ user = request.user @@ -51,7 +52,9 @@ def context_user(request): if global_message not in [msg.message for msg in get_messages(request)]: messages.warning(request, global_message) else: - if global_message not in [msg.message for msg in get_messages(request._request)]: + if global_message not in [ + msg.message for msg in get_messages(request._request) + ]: messages.warning(request._request, global_message) if user.is_authenticated: interfaces = user.user_interfaces() @@ -70,9 +73,9 @@ def context_user(request): def context_optionnal_apps(request): """Context functions. Called to add optionnal apps buttons in navbari - Returns: - dict:Containing optionnal template list of functions for navbar found - in optional apps + Returns: + dict:Containing optionnal template list of functions for navbar found + in optional apps """ optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] diff --git a/re2o/contributors.py b/re2o/contributors.py index cbca94f0..61e16e2b 100644 --- a/re2o/contributors.py +++ b/re2o/contributors.py @@ -4,44 +4,44 @@ A list of the proud contributors to Re2o """ CONTRIBUTORS = [ - 'Gabriel Detraz', - 'Hugo Levy-falk', - 'Maël Kervella', - 'Jean-romain Garnier', - 'Arthur Grisel-davy', - 'Laouen Fernet', - 'Augustin Lemesle', - 'Lara Kermarec', - 'Root `root` Root', - 'Alexandre Iooss', - 'Yoann Piétri', - 'Charlie Jacomme', - 'Corentin Canebier', - 'Bombar Maxime', - 'Guillaume Goessel', - 'Matthieu Michelet', - 'Edpibu', - 'Fardale', - 'Jean-marie Mineau', - 'David Sinquin', - 'Gabriel Le Bouder', - 'Simon Brélivet', - '~anonymised~', - 'Benjamin Graillot', - 'Leïla Bekaddour', - 'Éloi Alain', - 'Pierre Cadart', - 'Antoine Vintache', - 'Thibault De Boutray', - 'Delphine Salvy', - 'Joanne Steiner', - 'Krokmou', - 'B', - 'Daniel Stan', - 'Gwenael Le Hir', - 'Hugo Hervieux', - 'Mikachu', - 'Nymous', - 'Pierre-antoine Comby', - 'Vincent Le Gallic', -] \ No newline at end of file + "Gabriel Detraz", + "Hugo Levy-falk", + "Maël Kervella", + "Jean-romain Garnier", + "Arthur Grisel-davy", + "Laouen Fernet", + "Augustin Lemesle", + "Lara Kermarec", + "Root `root` Root", + "Alexandre Iooss", + "Yoann Piétri", + "Charlie Jacomme", + "Corentin Canebier", + "Bombar Maxime", + "Guillaume Goessel", + "Matthieu Michelet", + "Edpibu", + "Fardale", + "Jean-marie Mineau", + "David Sinquin", + "Gabriel Le Bouder", + "Simon Brélivet", + "~anonymised~", + "Benjamin Graillot", + "Leïla Bekaddour", + "Éloi Alain", + "Pierre Cadart", + "Antoine Vintache", + "Thibault De Boutray", + "Delphine Salvy", + "Joanne Steiner", + "Krokmou", + "B", + "Daniel Stan", + "Gwenael Le Hir", + "Hugo Hervieux", + "Mikachu", + "Nymous", + "Pierre-antoine Comby", + "Vincent Le Gallic", +] diff --git a/re2o/field_permissions.py b/re2o/field_permissions.py index a35d206d..9a06cf80 100644 --- a/re2o/field_permissions.py +++ b/re2o/field_permissions.py @@ -40,8 +40,8 @@ class FieldPermissionModelMixin: FIELD_PERMISSION_MISSING_DEFAULT = True def has_field_perm(self, user, field): - """ Checks if a `user` has the right to edit the `field` - of this model """ + """Checks if a `user` has the right to edit the `field` + of this model""" if field in self.field_permissions: checks = self.field_permissions[field] if not isinstance(checks, (list, tuple)): diff --git a/re2o/login.py b/re2o/login.py index 0df5bf6d..c8248ae3 100644 --- a/re2o/login.py +++ b/re2o/login.py @@ -32,12 +32,12 @@ import binascii import crypt import hashlib import os -from base64 import encodestring, decodestring, b64encode, b64decode +from base64 import b64decode, b64encode, decodestring, encodestring from collections import OrderedDict -from django.contrib.auth import hashers -from django.contrib.auth.backends import ModelBackend from hmac import compare_digest as constant_time_compare +from django.contrib.auth import hashers +from django.contrib.auth.backends import ModelBackend ALGO_NAME = "{SSHA}" ALGO_LEN = len(ALGO_NAME + "$") @@ -45,7 +45,7 @@ DIGEST_LEN = 20 def makeSecret(password): - """ Build a hashed and salted version of the password with SSHA + """Build a hashed and salted version of the password with SSHA Parameters: password (string): Password to hash @@ -60,7 +60,7 @@ def makeSecret(password): def hashNT(password): - """ Build a md4 hash of the password to use as the NT-password + """Build a md4 hash of the password to use as the NT-password Parameters: password (string): Password to hash @@ -78,7 +78,7 @@ def checkPassword(challenge_password, password): Parameters: challenge_password (string): Password to verify with hash - password (string): Hashed password to verify + password (string): Hashed password to verify Returns: boolean: True if challenge_password and password match @@ -93,7 +93,7 @@ def checkPassword(challenge_password, password): def hash_password_salt(hashed_password): - """ Extract the salt from a given hashed password + """Extract the salt from a given hashed password Parameters: hashed_password (string): Hashed password to extract salt @@ -277,15 +277,17 @@ class SSHAPasswordHasher(hashers.BasePasswordHasher): class RecryptBackend(ModelBackend): """Function for legacy users. During auth, if their hash password is different from SSHA or ntlm password is empty, rehash in SSHA or NTLM - + Returns: model user instance: Instance of the user logged - + """ def authenticate(self, request, username=None, password=None, **kwargs): # we obtain from the classical auth backend the user - user = super(RecryptBackend, self).authenticate(request, username, password, **kwargs) + user = super(RecryptBackend, self).authenticate( + request, username, password, **kwargs + ) if user: if not (user.pwd_ntlm): # if we dont have NT hash, we create it diff --git a/re2o/mail_utils.py b/re2o/mail_utils.py index c80f2cfb..ec0b5d8c 100644 --- a/re2o/mail_utils.py +++ b/re2o/mail_utils.py @@ -25,11 +25,13 @@ All functions linked with emails here. Non model or app dependant """ -from django.utils.translation import ugettext_lazy as _ -from django.core.mail import send_mail as django_send_mail -from django.contrib import messages from smtplib import SMTPException -from socket import herror, gaierror +from socket import gaierror, herror + +from django.contrib import messages +from django.core.mail import send_mail as django_send_mail +from django.utils.translation import ugettext_lazy as _ + def send_mail(request, *args, **kwargs): """Wrapper for Django's send_mail which handles errors""" @@ -39,7 +41,8 @@ def send_mail(request, *args, **kwargs): except (SMTPException, ConnectionError, herror, gaierror) as e: messages.error( request, - _("Failed to send email: %(error)s.") % { + _("Failed to send email: %(error)s.") + % { "error": e, }, ) @@ -53,7 +56,8 @@ def send_mail_object(mail, request): if request: messages.error( request, - _("Failed to send email: %(error)s.") % { + _("Failed to send email: %(error)s.") + % { "error": e, }, ) diff --git a/re2o/management/commands/gen_contrib.py b/re2o/management/commands/gen_contrib.py index c5d693be..a4e810af 100644 --- a/re2o/management/commands/gen_contrib.py +++ b/re2o/management/commands/gen_contrib.py @@ -25,6 +25,7 @@ commits. This list is extracted from the current gitlab repository. """ import os + from django.core.management.base import BaseCommand diff --git a/re2o/mixins.py b/re2o/mixins.py index 22933e67..ddc827b6 100644 --- a/re2o/mixins.py +++ b/re2o/mixins.py @@ -23,9 +23,9 @@ A set of mixins used all over the project to avoid duplicating code """ -from reversion import revisions as reversion from django.db import transaction from django.utils.translation import ugettext as _ +from reversion import revisions as reversion class RevMixin(object): @@ -252,4 +252,3 @@ class AclMixin(object): else None, (permission,), ) - diff --git a/re2o/script_utils.py b/re2o/script_utils.py index 12464594..b82604ec 100644 --- a/re2o/script_utils.py +++ b/re2o/script_utils.py @@ -24,17 +24,16 @@ with Re2o throught the CLI """ import os -from os.path import dirname -import sys import pwd - +import sys from getpass import getpass -from reversion import revisions as reversion +from os.path import dirname -from django.core.wsgi import get_wsgi_application from django.core.management.base import CommandError +from django.core.wsgi import get_wsgi_application from django.db import transaction from django.utils.html import strip_tags +from reversion import revisions as reversion from users.models import User @@ -48,27 +47,24 @@ application = get_wsgi_application() def get_user(pseudo): """Find a user from its pseudo - + Parameters: pseudo (string): pseudo of this user Returns: user instance:Instance of user - + """ user = User.objects.filter(pseudo=pseudo) if len(user) == 0: raise CommandError("Invalid user.") if len(user) > 1: - raise CommandError( - "Several users match this username. This SHOULD NOT happen." - ) + raise CommandError("Several users match this username. This SHOULD NOT happen.") return user[0] def get_system_user(): - """Find the system user login who used the command - """ + """Find the system user login who used the command""" return pwd.getpwuid(int(os.getenv("SUDO_UID") or os.getuid())).pw_name @@ -80,7 +76,7 @@ def form_cli(Form, user, action, *args, **kwargs): Form : a django class form to fill-in user : a re2o user doign the modification action: the action done with that form, for logs purpose - + """ data = {} dumb_form = Form(user=user, *args, **kwargs) @@ -105,6 +101,4 @@ def form_cli(Form, user, action, *args, **kwargs): reversion.set_user(user) reversion.set_comment(action) - sys.stdout.write( - "%s: done. The edit may take several minutes to apply.\n" % action - ) + sys.stdout.write("%s: done. The edit may take several minutes to apply.\n" % action) diff --git a/re2o/settings.py b/re2o/settings.py index 66219032..158a278b 100644 --- a/re2o/settings.py +++ b/re2o/settings.py @@ -36,7 +36,9 @@ https://docs.djangoproject.com/en/1.8/ref/settings/ from __future__ import unicode_literals import os + from .settings_default import * + try: from .settings_local import * except ImportError: @@ -60,7 +62,11 @@ LOGIN_REDIRECT_URL = "/" # The URL for redirecting after login # Application definition # dal_legacy_static only needed for Django < 2.0 (https://django-autocomplete-light.readthedocs.io/en/master/install.html#django-versions-earlier-than-2-0) -EARLY_EXTERNAL_CONTRIB_APPS = ("dal", "dal_select2", "dal_legacy_static") # Need to be added before django.contrib.admin (https://django-autocomplete-light.readthedocs.io/en/master/install.html#configuration) +EARLY_EXTERNAL_CONTRIB_APPS = ( + "dal", + "dal_select2", + "dal_legacy_static", +) # Need to be added before django.contrib.admin (https://django-autocomplete-light.readthedocs.io/en/master/install.html#configuration) DJANGO_CONTRIB_APPS = ( "django.contrib.admin", "django.contrib.auth", @@ -82,7 +88,11 @@ LOCAL_APPS = ( "logs", ) INSTALLED_APPS = ( - EARLY_EXTERNAL_CONTRIB_APPS + DJANGO_CONTRIB_APPS + EXTERNAL_CONTRIB_APPS + LOCAL_APPS + OPTIONNAL_APPS + EARLY_EXTERNAL_CONTRIB_APPS + + DJANGO_CONTRIB_APPS + + EXTERNAL_CONTRIB_APPS + + LOCAL_APPS + + OPTIONNAL_APPS ) MIDDLEWARE = ( "django.middleware.security.SecurityMiddleware", @@ -196,18 +206,18 @@ EMAIL_TIMEOUT = 10 AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, -] +] # Activate API if "api" in INSTALLED_APPS: diff --git a/re2o/settings_default.py b/re2o/settings_default.py index d5ceb431..8f552c2b 100644 --- a/re2o/settings_default.py +++ b/re2o/settings_default.py @@ -56,7 +56,7 @@ GID_RANGES = {"posix": [501, 600]} # If you want to add a database routers, please fill in above and add your databse. # Then, add a file "local_routers.py" in folder app re2o, and add your router path in -# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers. +# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers. LOCAL_ROUTERS = [] # Some optionnal Re2o Apps @@ -65,24 +65,24 @@ OPTIONNAL_APPS_RE2O = () # Some Django apps you want to add in you local project OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + () -#Set auth password validator +# Set auth password validator AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - 'OPTIONS': { - 'user_attributes': ['surname', 'pseudo', 'name', 'email'], - } + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + "OPTIONS": { + "user_attributes": ["surname", "pseudo", "name", "email"], + }, }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - 'OPTIONS': { - 'min_length': 8, - } + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + "OPTIONS": { + "min_length": 8, + }, }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] diff --git a/re2o/settings_local.example.py b/re2o/settings_local.example.py index d557d7eb..fc3cd8fc 100644 --- a/re2o/settings_local.example.py +++ b/re2o/settings_local.example.py @@ -105,7 +105,7 @@ GID_RANGES = {"posix": [501, 600]} # If you want to add a database routers, please fill in above and add your databse. # Then, add a file "local_routers.py" in folder app re2o, and add your router path in -# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers. +# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers. LOCAL_ROUTERS = [] # Some optionnal Re2o Apps @@ -114,24 +114,24 @@ OPTIONNAL_APPS_RE2O = () # Some Django apps you want to add in you local project OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + () -#Set auth password validator +# Set auth password validator AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - 'OPTIONS': { - 'user_attributes': ['surname', 'pseudo', 'name', 'email'], - } + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + "OPTIONS": { + "user_attributes": ["surname", "pseudo", "name", "email"], + }, }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - 'OPTIONS': { - 'min_length': 8, - } + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + "OPTIONS": { + "min_length": 8, + }, }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] diff --git a/re2o/templatetags/acl.py b/re2o/templatetags/acl.py index d8bdc310..0079c00e 100644 --- a/re2o/templatetags/acl.py +++ b/re2o/templatetags/acl.py @@ -73,9 +73,8 @@ an instance of a model (either Model.can_xxx or instance.can_xxx) import sys from django import template -from django.template.base import Node, NodeList from django.contrib.contenttypes.models import ContentType - +from django.template.base import Node, NodeList register = template.Library() @@ -202,7 +201,7 @@ def acl_fct(callback, reverse): @register.tag("cannot_edit_history") def acl_history_filter(parser, token): """Templatetag for acl checking on history.""" - tag_name, = token.split_contents() + (tag_name,) = token.split_contents() callback = get_callback(tag_name) oknodes = parser.parse(("acl_else", "acl_end")) diff --git a/re2o/templatetags/pagination_extra.py b/re2o/templatetags/pagination_extra.py index eb50a90d..405a4aef 100644 --- a/re2o/templatetags/pagination_extra.py +++ b/re2o/templatetags/pagination_extra.py @@ -20,10 +20,12 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from django import template + from .url_insert_param import url_insert_param register = template.Library() + @register.simple_tag def pagination_insert_page_and_id(url, page=1, id=None, **kwargs): """ @@ -77,10 +79,14 @@ def pagination_insert_page_and_id(url, page=1, id=None, **kwargs): """ page_arg = "page" - if "page_arg" in kwargs and kwargs["page_arg"] is not None and len(kwargs["page_arg"]) > 0: + if ( + "page_arg" in kwargs + and kwargs["page_arg"] is not None + and len(kwargs["page_arg"]) > 0 + ): page_arg = kwargs["page_arg"] - args = { "url": url, page_arg: page} + args = {"url": url, page_arg: page} new_url = url_insert_param(**args) if id != None: diff --git a/re2o/templatetags/self_adhesion.py b/re2o/templatetags/self_adhesion.py index 31f8ccc9..2e446106 100644 --- a/re2o/templatetags/self_adhesion.py +++ b/re2o/templatetags/self_adhesion.py @@ -26,8 +26,8 @@ which indicated if a user can creates an account by himself """ from django import template -from preferences.models import OptionalUser +from preferences.models import OptionalUser register = template.Library() diff --git a/re2o/urls.py b/re2o/urls.py index ece23894..82ecb855 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -24,14 +24,13 @@ from __future__ import unicode_literals from django.conf import settings -from django.urls import include, path from django.contrib import admin +from django.urls import include, path from django.utils.translation import ugettext_lazy as _ from django.views.generic import RedirectView from .settings_local import OPTIONNAL_APPS_RE2O - -from .views import index, about_page, contact_page, handler404, handler500 +from .views import about_page, contact_page, handler404, handler500, index # Admin site configuration admin.site.index_title = _("Homepage") diff --git a/re2o/utils.py b/re2o/utils.py index b7a0cd23..9fff653c 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -36,14 +36,14 @@ Functions: from __future__ import unicode_literals -from django.utils import timezone +from django.contrib.auth.models import Group, Permission from django.db.models import Q -from django.contrib.auth.models import Permission, Group +from django.utils import timezone from cotisations.models import Cotisation, Facture, Vente from machines.models import Interface, Machine -from users.models import Adherent, User, Ban, Whitelist from preferences.models import AssoOption +from users.models import Adherent, Ban, User, Whitelist def get_group_having_permission(*permission_name): @@ -83,7 +83,9 @@ def filter_results(query_filter, dormitory, user_type): - on user_type (adherent or club) is specified Returns the filter""" if dormitory: - query_filter &= (Q(adherent__room__building__dormitory=dormitory) | Q(club__room__building__dormitory=dormitory)) + query_filter &= Q(adherent__room__building__dormitory=dormitory) | Q( + club__room__building__dormitory=dormitory + ) if user_type == "adherent": query_filter &= Q(adherent__isnull=False) if user_type == "club": @@ -91,18 +93,20 @@ def filter_results(query_filter, dormitory, user_type): return query_filter -def all_adherent(search_time=None, including_asso=True, dormitory=None, user_type="all"): +def all_adherent( + search_time=None, including_asso=True, dormitory=None, user_type="all" +): """Return all people who have a valid membership at org. Optimised to make only one sql query. Build a filter and then apply it to User. Check for each user if a valid membership is registered at the desired search_time. - + Parameters: search_time (django datetime): Datetime to perform this search, if not provided, search_time will be set à timezone.now() including_asso (boolean): Decide if org itself is included in results Returns: - django queryset: Django queryset containing all users with valid membership + django queryset: Django queryset containing all users with valid membership """ if search_time is None: @@ -110,9 +114,9 @@ def all_adherent(search_time=None, including_asso=True, dormitory=None, user_typ filter_user = Q( facture__in=Facture.objects.filter( vente__cotisation__in=Cotisation.objects.filter( - Q(vente__facture__facture__valid=True) & - Q(date_start_memb__lt=search_time) & - Q(date_end_memb__gt=search_time) + Q(vente__facture__facture__valid=True) + & Q(date_start_memb__lt=search_time) + & Q(date_end_memb__gt=search_time) ) ) ) @@ -126,15 +130,15 @@ def all_adherent(search_time=None, including_asso=True, dormitory=None, user_typ def all_baned(search_time=None, dormitory=None, user_type="all"): """Return all people who are banned at org. Optimised to make only one - sql query. Build a filter and then apply it to User. Check for each user + sql query. Build a filter and then apply it to User. Check for each user banned at the desired search_time. - + Parameters: search_time (django datetime): Datetime to perform this search, if not provided, search_time will be set à timezone.now() Returns: - django queryset: Django queryset containing all users banned + django queryset: Django queryset containing all users banned """ if search_time is None: @@ -152,13 +156,13 @@ def all_whitelisted(search_time=None, dormitory=None, user_type="all"): """Return all people who have a free access at org. Optimised to make only one sql query. Build a filter and then apply it to User. Check for each user with a whitelisted free access at the desired search_time. - + Parameters: search_time (django datetime): Datetime to perform this search, if not provided, search_time will be set à timezone.now() Returns: - django queryset: Django queryset containing all users whitelisted + django queryset: Django queryset containing all users whitelisted """ if search_time is None: @@ -191,9 +195,9 @@ def all_conn(search_time=None, including_asso=True, dormitory=None, user_type="a filter_user = Q( facture__in=Facture.objects.filter( vente__cotisation__in=Cotisation.objects.filter( - Q(vente__facture__facture__valid=True) & - Q(date_start_con__lt=search_time) & - Q(date_end_con__gt=search_time) + Q(vente__facture__facture__valid=True) + & Q(date_start_con__lt=search_time) + & Q(date_end_con__gt=search_time) ) ) ) @@ -205,9 +209,11 @@ def all_conn(search_time=None, including_asso=True, dormitory=None, user_type="a return User.objects.filter(filter_user).distinct() -def all_has_access(search_time=None, including_asso=True, dormitory=None, user_type="all"): +def all_has_access( + search_time=None, including_asso=True, dormitory=None, user_type="all" +): """Return all people who have an valid internet access at org. Call previously buid filters. - Can't do that in one sql query unfortunatly. Apply each filters, and return users + Can't do that in one sql query unfortunatly. Apply each filters, and return users with a whitelist, or a valid paid access, except banned users. Parameters: @@ -216,14 +222,13 @@ def all_has_access(search_time=None, including_asso=True, dormitory=None, user_t including_asso (boolean): Decide if org itself is included in results Returns: - django queryset: Django queryset containing all valid connection users + django queryset: Django queryset containing all valid connection users """ if search_time is None: search_time = timezone.now() - filter_user = ( - Q(state=User.STATE_ACTIVE) - & ~Q(email_state=User.EMAIL_STATE_UNVERIFIED) + filter_user = Q(state=User.STATE_ACTIVE) & ~Q( + email_state=User.EMAIL_STATE_UNVERIFIED ) if including_asso: asso_user = AssoOption.get_cached_value("utilisateur_asso") @@ -231,18 +236,36 @@ def all_has_access(search_time=None, including_asso=True, dormitory=None, user_t filter_user |= Q(id=asso_user.id) filter_user = filter_results(filter_user, dormitory, user_type) return User.objects.filter( - Q(filter_user) & ( + Q(filter_user) + & ( Q( - id__in=all_whitelisted(search_time=search_time, dormitory=dormitory, user_type=user_type) - ) | ( - Q( - id__in=all_adherent(search_time=search_time, including_asso=including_asso, dormitory=dormitory, user_type=user_type) - ) & Q( - id__in=all_conn(search_time=search_time, including_asso=including_asso, dormitory=dormitory, user_type=user_type) + id__in=all_whitelisted( + search_time=search_time, dormitory=dormitory, user_type=user_type ) ) - ) & ~Q( - id__in=all_baned(search_time=search_time, dormitory=dormitory, user_type=user_type) + | ( + Q( + id__in=all_adherent( + search_time=search_time, + including_asso=including_asso, + dormitory=dormitory, + user_type=user_type, + ) + ) + & Q( + id__in=all_conn( + search_time=search_time, + including_asso=including_asso, + dormitory=dormitory, + user_type=user_type, + ) + ) + ) + ) + & ~Q( + id__in=all_baned( + search_time=search_time, dormitory=dormitory, user_type=user_type + ) ) ).distinct() @@ -257,7 +280,7 @@ def filter_active_interfaces(interface_set): interface_set (django queryset): A queryset of interfaces to perform filter Returns: - django filter: Django filter to apply to an interfaces queryset, + django filter: Django filter to apply to an interfaces queryset, will return when applied all active interfaces, related with a user with valid membership @@ -289,7 +312,7 @@ def filter_complete_interfaces(interface_set): interface_set (django queryset): A queryset of interfaces to perform filter Returns: - django filter: Django filter to apply to an interfaces queryset, + django filter: Django filter to apply to an interfaces queryset, will return when applied all active interfaces, related with a user with valid membership diff --git a/re2o/views.py b/re2o/views.py index f9bcb322..07f55253 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -26,34 +26,28 @@ Welcom main page view, and several template widely used in re2o views from __future__ import unicode_literals -import git +from importlib import import_module +import git +from dal import autocomplete +from django.conf import settings +from django.contrib.auth.mixins import LoginRequiredMixin from django.shortcuts import render from django.template.context_processors import csrf -from django.conf import settings -from django.utils.translation import ugettext as _ -from django.contrib.auth.mixins import LoginRequiredMixin from django.utils.decorators import method_decorator -from dal import autocomplete +from django.utils.translation import ugettext as _ -from preferences.models import ( - Service, - MailContact, - AssoOption, - HomeOption, - GeneralOption, - Mandate, -) +from preferences.models import (AssoOption, GeneralOption, HomeOption, + MailContact, Mandate, Service) +from re2o.settings_local import OPTIONNAL_APPS_RE2O from .contributors import CONTRIBUTORS -from importlib import import_module -from re2o.settings_local import OPTIONNAL_APPS_RE2O def form(ctx, template, request): """Global template function, used in all re2o views, for building a render with context, template and request. Adding csrf. - + Parameters: ctx (dict): Dict of values to transfer to template template (django template): The django template of this view @@ -70,8 +64,8 @@ def form(ctx, template, request): def index(request): """Display all services provided on main page - Returns: a form with all services linked and description, and social media - link if provided. + Returns: a form with all services linked and description, and social media + link if provided. """ services = [[], [], []] @@ -95,9 +89,9 @@ def index(request): def about_page(request): - """ The view for the about page. + """The view for the about page. Fetch some info about the configuration of the project. If it can't - get the info from the Git repository, fallback to default string """ + get the info from the Git repository, fallback to default string""" option = AssoOption.objects.get() general = GeneralOption.objects.get() git_info_contributors = CONTRIBUTORS @@ -197,4 +191,3 @@ class AutocompleteLoggedOutViewMixin(autocomplete.Select2QuerySetView): class AutocompleteViewMixin(LoginRequiredMixin, AutocompleteLoggedOutViewMixin): pass - diff --git a/re2o/widgets.py b/re2o/widgets.py index 935806fe..32b49724 100644 --- a/re2o/widgets.py +++ b/re2o/widgets.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2021 Gabriel Détraz -# Copyright © 2021 Jean-Romain Garnier +# Copyright © 2021 Jean-Romain Garnier # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,12 +25,12 @@ Re2o Forms and ModelForms Widgets. Used in others forms for using autocomplete engine. """ -from django.utils.translation import ugettext as _ from dal import autocomplete +from django.utils.translation import ugettext as _ class AutocompleteModelWidget(autocomplete.ModelSelect2): - """ A mixin subclassing django-autocomplete-light's Select2 model to pass default options + """A mixin subclassing django-autocomplete-light's Select2 model to pass default options See https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#passing-options-to-select2 """ @@ -54,7 +54,7 @@ class AutocompleteModelWidget(autocomplete.ModelSelect2): class AutocompleteMultipleModelWidget(autocomplete.ModelSelect2Multiple): - """ A mixin subclassing django-autocomplete-light's Select2 model to pass default options + """A mixin subclassing django-autocomplete-light's Select2 model to pass default options See https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#passing-options-to-select2 """ diff --git a/re2o/wsgi.py b/re2o/wsgi.py index 4f8d2196..2f67a767 100644 --- a/re2o/wsgi.py +++ b/re2o/wsgi.py @@ -32,12 +32,11 @@ https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/ from __future__ import unicode_literals import os -from os.path import dirname import sys +from os.path import dirname from django.core.wsgi import get_wsgi_application - sys.path.append(dirname(dirname(__file__))) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings") diff --git a/search/apps.py b/search/apps.py index 1dad5588..b7754062 100644 --- a/search/apps.py +++ b/search/apps.py @@ -8,4 +8,4 @@ from django.apps import AppConfig class SearchConfig(AppConfig): """Configuration of search app.""" - name = "search" \ No newline at end of file + name = "search" diff --git a/search/engine.py b/search/engine.py index a724cd8c..4202df1f 100644 --- a/search/engine.py +++ b/search/engine.py @@ -28,19 +28,16 @@ Gplv2""" from __future__ import unicode_literals +from django.db.models import Q, Value +from django.db.models.functions import Concat from netaddr import EUI, AddrFormatError -from django.db.models import Q -from django.db.models import Value -from django.db.models.functions import Concat - -from users.models import User, Adherent, Club, Ban, Whitelist -from machines.models import Machine -from topologie.models import Port, Switch, Room from cotisations.models import Facture +from machines.models import Machine from preferences.models import GeneralOption from re2o.base import SortTable, re2o_paginator - +from topologie.models import Port, Room, Switch +from users.models import Adherent, Ban, Club, User, Whitelist # List of fields the search applies to FILTER_FIELDS = [ diff --git a/search/forms.py b/search/forms.py index 35151a3a..266eaaab 100644 --- a/search/forms.py +++ b/search/forms.py @@ -27,6 +27,7 @@ from __future__ import unicode_literals from django import forms from django.forms import Form from django.utils.translation import ugettext_lazy as _ + from re2o.base import get_input_formats_help_text CHOICES_USER = ( diff --git a/search/views.py b/search/views.py index afb6065e..20206858 100644 --- a/search/views.py +++ b/search/views.py @@ -28,24 +28,18 @@ Gplv2""" from __future__ import unicode_literals -from django.shortcuts import render from django.contrib.auth.decorators import login_required +from django.shortcuts import render -from users.models import User from cotisations.models import Cotisation from machines.models import Machine -from search.forms import ( - SearchForm, - SearchFormPlus, - CHOICES_USER, - CHOICES_EMAILS, - CHOICES_AFF, - initial_choices, -) from re2o.acl import can_view_all +from search.forms import (CHOICES_AFF, CHOICES_EMAILS, CHOICES_USER, + SearchForm, SearchFormPlus, initial_choices) +from users.models import User -from .engine import empty_filters, create_queries, search_single_query -from .engine import apply_filters, finish_results +from .engine import (apply_filters, create_queries, empty_filters, + finish_results, search_single_query) def get_results(query, request, params): @@ -70,10 +64,7 @@ def get_results(query, request, params): results = apply_filters(filters, request.user, aff) results = finish_results( - request, - results, - request.GET.get("col"), - request.GET.get("order") + request, results, request.GET.get("col"), request.GET.get("order") ) results.update({"search_term": query}) @@ -90,9 +81,7 @@ def search(request): request, "search/index.html", get_results( - search_form.cleaned_data.get("q", ""), - request, - search_form.cleaned_data + search_form.cleaned_data.get("q", ""), request, search_form.cleaned_data ), ) return render(request, "search/search.html", {"search_form": search_form}) @@ -108,9 +97,7 @@ def searchp(request): request, "search/index.html", get_results( - search_form.cleaned_data.get("q", ""), - request, - search_form.cleaned_data + search_form.cleaned_data.get("q", ""), request, search_form.cleaned_data ), ) return render(request, "search/search.html", {"search_form": search_form}) diff --git a/test_utils/runner.py b/test_utils/runner.py index 888e8a02..219b6a2c 100644 --- a/test_utils/runner.py +++ b/test_utils/runner.py @@ -23,13 +23,14 @@ """Defines the custom runners for Re2o. """ -import volatildap import os.path -from django.test.runner import DiscoverRunner +import volatildap from django.conf import settings +from django.test.runner import DiscoverRunner -from users.models import LdapUser, LdapUserGroup, LdapServiceUser, LdapServiceUserGroup +from users.models import (LdapServiceUser, LdapServiceUserGroup, LdapUser, + LdapUserGroup) # The path of this file __here = os.path.dirname(os.path.realpath(__file__)) diff --git a/tickets/admin.py b/tickets/admin.py index 620fc998..6d34281f 100644 --- a/tickets/admin.py +++ b/tickets/admin.py @@ -25,15 +25,18 @@ Ticket preferences model from django.contrib import admin -from .models import Ticket, CommentTicket - from reversion.admin import VersionAdmin +from .models import CommentTicket, Ticket + + class TicketAdmin(VersionAdmin): pass + class CommentTicketAdmin(VersionAdmin): pass + admin.site.register(Ticket, TicketAdmin) admin.site.register(CommentTicket, CommentTicketAdmin) diff --git a/tickets/forms.py b/tickets/forms.py index aad78837..d4a1d5fb 100644 --- a/tickets/forms.py +++ b/tickets/forms.py @@ -25,14 +25,15 @@ Ticket form from django import forms +from django.forms import Form, ModelForm from django.template.loader import render_to_string -from django.forms import ModelForm, Form +from django.utils.translation import ugettext_lazy as _ + from re2o.field_permissions import FieldPermissionFormMixin from re2o.mixins import FormRevMixin from re2o.widgets import AutocompleteModelWidget -from django.utils.translation import ugettext_lazy as _ -from .models import Ticket, CommentTicket +from .models import CommentTicket, Ticket class NewTicketForm(FormRevMixin, ModelForm): @@ -46,10 +47,12 @@ class NewTicketForm(FormRevMixin, ModelForm): request = kwargs.pop("request", None) super(NewTicketForm, self).__init__(*args, **kwargs) if request.user.is_authenticated: - self.fields.pop('email') + self.fields.pop("email") self.instance.user = request.user - self.fields['description'].help_text = render_to_string('tickets/help_text.html') - self.instance.language = getattr(request, "LANGUAGE_CODE", "en") + self.fields["description"].help_text = render_to_string( + "tickets/help_text.html" + ) + self.instance.language = getattr(request, "LANGUAGE_CODE", "en") self.instance.request = request @@ -67,7 +70,7 @@ class EditTicketForm(FormRevMixin, ModelForm): def __init__(self, *args, **kwargs): super(EditTicketForm, self).__init__(*args, **kwargs) - self.fields['email'].required = False + self.fields["email"].required = False class CommentTicketForm(FormRevMixin, ModelForm): @@ -83,4 +86,3 @@ class CommentTicketForm(FormRevMixin, ModelForm): super(CommentTicketForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["comment"].label = _("comment") self.instance.request = request - diff --git a/tickets/models.py b/tickets/models.py index 3bae040a..bc62e22b 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -25,22 +25,19 @@ Ticket model from __future__ import absolute_import +from django.core.mail import EmailMessage from django.db import models -from django.utils.translation import ugettext_lazy as _ -from django.template import loader from django.db.models.signals import post_save from django.dispatch import receiver +from django.template import loader from django.utils.functional import cached_property - +from django.utils.translation import ugettext_lazy as _ from reversion.models import Version -from re2o.mixins import AclMixin -from re2o.mail_utils import send_mail_object -from django.core.mail import EmailMessage - -from preferences.models import GeneralOption - import users.models +from preferences.models import GeneralOption +from re2o.mail_utils import send_mail_object +from re2o.mixins import AclMixin from .preferences.models import TicketOption @@ -85,7 +82,7 @@ class Ticket(AclMixin, models.Model): ) solved = models.BooleanField(default=False) language = models.CharField( - max_length=16, help_text=_("Language of the ticket."), default="en" + max_length=16, help_text=_("Language of the ticket."), default="en" ) request = None @@ -96,7 +93,9 @@ class Ticket(AclMixin, models.Model): def __str__(self): if self.user: - return _("Ticket from {name}. Date: {date}.").format(name=self.user.get_full_name(),date=self.date) + return _("Ticket from {name}. Date: {date}.").format( + name=self.user.get_full_name(), date=self.date + ) else: return _("Anonymous ticket. Date: %s.") % (self.date) @@ -106,12 +105,12 @@ class Ticket(AclMixin, models.Model): if self.user: return self.user.get_full_name() else: - return _("Anonymous user") + return _("Anonymous user") @cached_property def get_mail(self): """Get the email address of the user who opened the ticket.""" - return self.email or self.user.get_mail + return self.email or self.user.get_mail def publish_mail(self): """Send an email for a newly opened ticket to the address set in the @@ -137,7 +136,6 @@ class Ticket(AclMixin, models.Model): ) send_mail_object(mail_to_send, self.request) - def can_view(self, user_request, *_args, **_kwargs): """Check that the user has the right to view the ticket or that it is the author.""" @@ -189,9 +187,7 @@ class CommentTicket(AclMixin, models.Model): blank=False, null=False, ) - parent_ticket = models.ForeignKey( - "Ticket", on_delete=models.CASCADE - ) + parent_ticket = models.ForeignKey("Ticket", on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) created_by = models.ForeignKey( "users.User", @@ -207,7 +203,12 @@ class CommentTicket(AclMixin, models.Model): @cached_property def comment_id(self): - return CommentTicket.objects.filter(parent_ticket=self.parent_ticket, pk__lt=self.pk).count() + 1 + return ( + CommentTicket.objects.filter( + parent_ticket=self.parent_ticket, pk__lt=self.pk + ).count() + + 1 + ) def can_view(self, user_request, *_args, **_kwargs): """Check that the user has the right to view the ticket comment @@ -218,7 +219,9 @@ class CommentTicket(AclMixin, models.Model): ): return ( False, - _("You don't have the right to view other tickets comments than yours."), + _( + "You don't have the right to view other tickets comments than yours." + ), ("tickets.view_commentticket",), ) else: @@ -227,13 +230,15 @@ class CommentTicket(AclMixin, models.Model): def can_edit(self, user_request, *_args, **_kwargs): """Check that the user has the right to edit the ticket comment or that it is the author.""" - if ( - not user_request.has_perm("tickets.change_commentticket") - and (self.parent_ticket.user != user_request or self.parent_ticket.user != self.created_by) + if not user_request.has_perm("tickets.change_commentticket") and ( + self.parent_ticket.user != user_request + or self.parent_ticket.user != self.created_by ): return ( False, - _("You don't have the right to edit other tickets comments than yours."), + _( + "You don't have the right to edit other tickets comments than yours." + ), ("tickets.change_commentticket",), ) else: diff --git a/tickets/preferences/__init__.py b/tickets/preferences/__init__.py index 2147642b..441f485d 100644 --- a/tickets/preferences/__init__.py +++ b/tickets/preferences/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2020 Gabriel Détraz -# Copyright © 2019 Arthur Grisel-Davy +# Copyright © 2019 Arthur Grisel-Davy # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/tickets/preferences/forms.py b/tickets/preferences/forms.py index ff76f1d9..b043c517 100644 --- a/tickets/preferences/forms.py +++ b/tickets/preferences/forms.py @@ -24,10 +24,11 @@ Ticket preferences form """ from django import forms -from django.forms import ModelForm, Form +from django.forms import Form, ModelForm from django.utils.translation import ugettext_lazy as _ from re2o.mixins import FormRevMixin + from .models import TicketOption diff --git a/tickets/preferences/models.py b/tickets/preferences/models.py index 67f8435a..92d8e8c5 100644 --- a/tickets/preferences/models.py +++ b/tickets/preferences/models.py @@ -27,8 +27,8 @@ Ticket preferences model from django.db import models from django.utils.translation import ugettext_lazy as _ -from re2o.mixins import AclMixin, RevMixin from preferences.models import PreferencesModel +from re2o.mixins import AclMixin, RevMixin class TicketOption(AclMixin, PreferencesModel): diff --git a/tickets/preferences/views.py b/tickets/preferences/views.py index e1549fd2..a59b4db2 100644 --- a/tickets/preferences/views.py +++ b/tickets/preferences/views.py @@ -26,19 +26,16 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.shortcuts import render, redirect +from django.shortcuts import redirect, render from django.template.loader import render_to_string -from django.utils.translation import ugettext as _ from django.urls import reverse - -from re2o.base import re2o_paginator - -from re2o.acl import can_view, can_view_all, can_edit, can_create +from django.utils.translation import ugettext as _ from preferences.views import edit_options_template_function +from re2o.acl import can_create, can_edit, can_view, can_view_all +from re2o.base import re2o_paginator -from . import forms -from . import models +from . import forms, models def aff_preferences(request): diff --git a/tickets/urls.py b/tickets/urls.py index c853fcfc..a31cbb35 100644 --- a/tickets/urls.py +++ b/tickets/urls.py @@ -33,7 +33,11 @@ app_name = "tickets" urlpatterns = [ path("", views.aff_tickets, name="aff-tickets"), path("", views.aff_ticket, name="aff-ticket"), - path("change_ticket_status/", views.change_ticket_status, name="change-ticket-status"), + path( + "change_ticket_status/", + views.change_ticket_status, + name="change-ticket-status", + ), path("edit_ticket/", views.edit_ticket, name="edit-ticket"), re_path( r"^edit_options/(?P
TicketOption)$", diff --git a/tickets/views.py b/tickets/views.py index f0736265..d1a4d433 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -22,29 +22,20 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.shortcuts import render, redirect -from django.template.loader import render_to_string -from django.views.decorators.cache import cache_page -from django.utils.translation import ugettext as _ -from django.urls import reverse from django.forms import modelformset_factory -from re2o.views import form - -from re2o.base import re2o_paginator - -from re2o.acl import ( - can_view, - can_view_all, - can_edit, - can_create, - can_delete -) +from django.shortcuts import redirect, render +from django.template.loader import render_to_string +from django.urls import reverse +from django.utils.translation import ugettext as _ +from django.views.decorators.cache import cache_page from preferences.models import GeneralOption +from re2o.acl import can_create, can_delete, can_edit, can_view, can_view_all +from re2o.base import re2o_paginator +from re2o.views import form -from .models import Ticket, CommentTicket - -from .forms import NewTicketForm, EditTicketForm, CommentTicketForm +from .forms import CommentTicketForm, EditTicketForm, NewTicketForm +from .models import CommentTicket, Ticket def new_ticket(request): @@ -62,10 +53,12 @@ def new_ticket(request): return redirect(reverse("index")) else: return redirect( - reverse("users:profil", kwargs={"userid": str(request.user.id)}) + reverse("users:profil", kwargs={"userid": str(request.user.id)}) ) return form( - {"ticketform": ticketform, 'action_name': ("Create a ticket")}, "tickets/edit.html", request + {"ticketform": ticketform, "action_name": ("Create a ticket")}, + "tickets/edit.html", + request, ) @@ -87,9 +80,7 @@ def change_ticket_status(request, ticket, ticketid): """View used to change a ticket's status.""" ticket.solved = not ticket.solved ticket.save() - return redirect( - reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)}) - ) + return redirect(reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)})) @login_required @@ -101,15 +92,15 @@ def edit_ticket(request, ticket, ticketid): ticketform.save() messages.success( request, - _( - "Ticket has been updated successfully" - ), + _("Ticket has been updated successfully"), ) return redirect( reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)}) ) return form( - {"ticketform": ticketform, 'action_name': ("Edit this ticket")}, "tickets/edit.html", request + {"ticketform": ticketform, "action_name": ("Edit this ticket")}, + "tickets/edit.html", + request, ) @@ -128,7 +119,9 @@ def add_comment(request, ticket, ticketid): reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)}) ) return form( - {"ticketform": commentticket, "action_name": _("Add a comment")}, "tickets/edit.html", request + {"ticketform": commentticket, "action_name": _("Add a comment")}, + "tickets/edit.html", + request, ) @@ -136,7 +129,9 @@ def add_comment(request, ticket, ticketid): @can_edit(CommentTicket) def edit_comment(request, commentticket_instance, **_kwargs): """View used to edit a comment of a ticket.""" - commentticket = CommentTicketForm(request.POST or None, instance=commentticket_instance) + commentticket = CommentTicketForm( + request.POST or None, instance=commentticket_instance + ) if commentticket.is_valid(): ticketid = commentticket_instance.parent_ticket.id if commentticket.changed_data: @@ -146,7 +141,9 @@ def edit_comment(request, commentticket_instance, **_kwargs): reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)}) ) return form( - {"ticketform": commentticket, "action_name": _("Edit")}, "tickets/edit.html", request, + {"ticketform": commentticket, "action_name": _("Edit")}, + "tickets/edit.html", + request, ) @@ -162,7 +159,9 @@ def del_comment(request, commentticket, **_kwargs): reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)}) ) return form( - {"objet": commentticket, "objet_name": _("Ticket Comment")}, "tickets/delete.html", request + {"objet": commentticket, "objet_name": _("Ticket Comment")}, + "tickets/delete.html", + request, ) diff --git a/topologie/admin.py b/topologie/admin.py index 514af42d..33441ddd 100644 --- a/topologie/admin.py +++ b/topologie/admin.py @@ -29,19 +29,9 @@ from __future__ import unicode_literals from django.contrib import admin from reversion.admin import VersionAdmin -from .models import ( - Port, - Room, - Switch, - Stack, - ModelSwitch, - ConstructorSwitch, - AccessPoint, - SwitchBay, - Building, - Dormitory, - PortProfile, -) +from .models import (AccessPoint, Building, ConstructorSwitch, Dormitory, + ModelSwitch, Port, PortProfile, Room, Stack, Switch, + SwitchBay) class StackAdmin(VersionAdmin): diff --git a/topologie/api/serializers.py b/topologie/api/serializers.py index 0dd9f599..e6f3dbb2 100644 --- a/topologie/api/serializers.py +++ b/topologie/api/serializers.py @@ -21,15 +21,15 @@ from rest_framework import serializers -import topologie.models as topologie import machines.models as machines -from machines.api.serializers import VlanSerializer, Ipv6ListSerializer -from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer +import topologie.models as topologie +from api.serializers import (NamespacedHIField, NamespacedHMSerializer, + NamespacedHRField) +from machines.api.serializers import Ipv6ListSerializer, VlanSerializer class StackSerializer(NamespacedHMSerializer): - """Serialize `topologie.models.Stack` objects - """ + """Serialize `topologie.models.Stack` objects""" class Meta: model = topologie.Stack @@ -44,8 +44,7 @@ class StackSerializer(NamespacedHMSerializer): class AccessPointSerializer(NamespacedHMSerializer): - """Serialize `topologie.models.AccessPoint` objects - """ + """Serialize `topologie.models.AccessPoint` objects""" class Meta: model = topologie.AccessPoint @@ -53,8 +52,7 @@ class AccessPointSerializer(NamespacedHMSerializer): class SwitchSerializer(NamespacedHMSerializer): - """Serialize `topologie.models.Switch` objects - """ + """Serialize `topologie.models.Switch` objects""" port_amount = serializers.IntegerField(source="number") @@ -74,8 +72,7 @@ class SwitchSerializer(NamespacedHMSerializer): class ServerSerializer(NamespacedHMSerializer): - """Serialize `topologie.models.Server` objects - """ + """Serialize `topologie.models.Server` objects""" class Meta: model = topologie.Server @@ -83,8 +80,7 @@ class ServerSerializer(NamespacedHMSerializer): class ModelSwitchSerializer(NamespacedHMSerializer): - """Serialize `topologie.models.ModelSwitch` objects - """ + """Serialize `topologie.models.ModelSwitch` objects""" class Meta: model = topologie.ModelSwitch @@ -92,8 +88,7 @@ class ModelSwitchSerializer(NamespacedHMSerializer): class ConstructorSwitchSerializer(NamespacedHMSerializer): - """Serialize `topologie.models.ConstructorSwitch` objects - """ + """Serialize `topologie.models.ConstructorSwitch` objects""" class Meta: model = topologie.ConstructorSwitch @@ -101,8 +96,7 @@ class ConstructorSwitchSerializer(NamespacedHMSerializer): class SwitchBaySerializer(NamespacedHMSerializer): - """Serialize `topologie.models.SwitchBay` objects - """ + """Serialize `topologie.models.SwitchBay` objects""" class Meta: model = topologie.SwitchBay @@ -110,23 +104,23 @@ class SwitchBaySerializer(NamespacedHMSerializer): class BuildingSerializer(NamespacedHMSerializer): - """Serialize `topologie.models.Building` objects - """ + """Serialize `topologie.models.Building` objects""" class Meta: model = topologie.Building fields = ("name", "dormitory", "api_url") + class DormitorySerializer(NamespacedHMSerializer): - """Serialize `topologie.models.Dormitory` objects - """ + """Serialize `topologie.models.Dormitory` objects""" + class Meta: model = topologie.Dormitory fields = ("name", "api_url") + class PortProfileSerializer(NamespacedHMSerializer): - """Serialize `topologie.models.Room` objects - """ + """Serialize `topologie.models.Room` objects""" class Meta: model = topologie.PortProfile @@ -151,8 +145,7 @@ class PortProfileSerializer(NamespacedHMSerializer): class RoomSerializer(NamespacedHMSerializer): - """Serialize `topologie.models.Room` objects - """ + """Serialize `topologie.models.Room` objects""" class Meta: model = topologie.Room @@ -208,8 +201,7 @@ class InterfaceRoleSerializer(NamespacedHMSerializer): class RoleSerializer(NamespacedHMSerializer): - """Serialize `machines.models.OuverturePort` objects. - """ + """Serialize `machines.models.OuverturePort` objects.""" servers = InterfaceRoleSerializer(read_only=True, many=True) @@ -265,8 +257,7 @@ class SwitchBaySerializer(NamespacedHMSerializer): class PortsSerializer(NamespacedHMSerializer): - """Serialize `machines.models.Ipv6List` objects. - """ + """Serialize `machines.models.Ipv6List` objects.""" get_port_profile = ProfilSerializer(read_only=True) @@ -301,5 +292,3 @@ class SwitchPortSerializer(serializers.ModelSerializer): "get_radius_servers", "list_modules", ) - - diff --git a/topologie/api/urls.py b/topologie/api/urls.py index 4c5e859a..c5539418 100644 --- a/topologie/api/urls.py +++ b/topologie/api/urls.py @@ -33,13 +33,12 @@ urls_viewset = [ (r"topologie/dormitory", views.DormitoryViewSet, None), (r"topologie/switchport", views.SwitchPortViewSet, "switchport"), (r"topologie/portprofile", views.PortProfileViewSet, "portprofile"), - (r"topologie/room", views.RoomViewSet, None) + (r"topologie/room", views.RoomViewSet, None), ] urls_view = [ (r"topologie/switchs-ports-config", views.SwitchPortView), (r"topologie/switchs-role", views.RoleView), - # Deprecated (r"switchs/ports-config", views.SwitchPortView), (r"switchs/role", views.RoleView), diff --git a/topologie/api/views.py b/topologie/api/views.py index a84eda5f..41315fcc 100644 --- a/topologie/api/views.py +++ b/topologie/api/views.py @@ -19,48 +19,44 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -from rest_framework import viewsets, generics +from rest_framework import generics, viewsets + +import machines.models as machines +import topologie.models as topologie from . import serializers -import topologie.models as topologie -import machines.models as machines class StackViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.Stack` objects. - """ + """Exposes list and details of `topologie.models.Stack` objects.""" queryset = topologie.Stack.objects.all() serializer_class = serializers.StackSerializer class AccessPointViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.AccessPoint` objects. - """ + """Exposes list and details of `topologie.models.AccessPoint` objects.""" queryset = topologie.AccessPoint.objects.all() serializer_class = serializers.AccessPointSerializer class SwitchViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.Switch` objects. - """ + """Exposes list and details of `topologie.models.Switch` objects.""" queryset = topologie.Switch.objects.all() serializer_class = serializers.SwitchSerializer class ServerViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.Server` objects. - """ + """Exposes list and details of `topologie.models.Server` objects.""" queryset = topologie.Server.objects.all() serializer_class = serializers.ServerSerializer class ModelSwitchViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.ModelSwitch` objects. - """ + """Exposes list and details of `topologie.models.ModelSwitch` objects.""" queryset = topologie.ModelSwitch.objects.all() serializer_class = serializers.ModelSwitchSerializer @@ -76,55 +72,51 @@ class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet): class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.SwitchBay` objects. - """ + """Exposes list and details of `topologie.models.SwitchBay` objects.""" queryset = topologie.SwitchBay.objects.all() serializer_class = serializers.SwitchBaySerializer class BuildingViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.Building` objects. - """ + """Exposes list and details of `topologie.models.Building` objects.""" queryset = topologie.Building.objects.all() serializer_class = serializers.BuildingSerializer class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.Port` objects. - """ + """Exposes list and details of `topologie.models.Port` objects.""" queryset = topologie.Port.objects.all() serializer_class = serializers.SwitchPortSerializer class PortProfileViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.PortProfile` objects. - """ + """Exposes list and details of `topologie.models.PortProfile` objects.""" queryset = topologie.PortProfile.objects.all() serializer_class = serializers.PortProfileSerializer class RoomViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.Room` objects. - """ + """Exposes list and details of `topologie.models.Room` objects.""" queryset = topologie.Room.objects.all() serializer_class = serializers.RoomSerializer + class DormitoryViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.Dormitory` - objects. + objects. """ queryset = topologie.Dormitory.objects.all() serializer_class = serializers.DormitorySerializer + class PortProfileViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `topologie.models.PortProfile` objects. - """ + """Exposes list and details of `topologie.models.PortProfile` objects.""" queryset = topologie.PortProfile.objects.all() serializer_class = serializers.PortProfileSerializer @@ -149,8 +141,7 @@ class SwitchPortView(generics.ListAPIView): class RoleView(generics.ListAPIView): - """Output of roles for each server - """ + """Output of roles for each server""" queryset = machines.Role.objects.all().prefetch_related("servers") serializer_class = serializers.RoleSerializer diff --git a/topologie/apps.py b/topologie/apps.py index df131bc0..342857a0 100644 --- a/topologie/apps.py +++ b/topologie/apps.py @@ -8,4 +8,4 @@ from django.apps import AppConfig class TopologieConfig(AppConfig): """Configuration of topologie app.""" - name = "topologie" \ No newline at end of file + name = "topologie" diff --git a/topologie/forms.py b/topologie/forms.py index 0cbe1a5e..717cee2c 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -31,33 +31,19 @@ The forms are used to: from __future__ import unicode_literals from django import forms -from django.forms import ModelForm from django.db.models import Prefetch +from django.forms import ModelForm from django.utils.translation import ugettext_lazy as _ -from machines.models import Interface from machines.forms import EditMachineForm, NewMachineForm +from machines.models import Interface from re2o.mixins import FormRevMixin -from re2o.widgets import ( - AutocompleteModelWidget, - AutocompleteMultipleModelWidget, -) +from re2o.widgets import (AutocompleteModelWidget, + AutocompleteMultipleModelWidget) -from .models import ( - Port, - Switch, - Room, - Stack, - ModelSwitch, - ConstructorSwitch, - AccessPoint, - SwitchBay, - Building, - Dormitory, - PortProfile, - ModuleSwitch, - ModuleOnSwitch, -) +from .models import (AccessPoint, Building, ConstructorSwitch, Dormitory, + ModelSwitch, ModuleOnSwitch, ModuleSwitch, Port, + PortProfile, Room, Stack, Switch, SwitchBay) class PortForm(FormRevMixin, ModelForm): diff --git a/topologie/models.py b/topologie/models.py index b0d78249..9b2f22e7 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -36,19 +36,18 @@ from __future__ import unicode_literals import itertools -from django.db import models -from django.db.models.signals import post_save, post_delete -from django.utils.functional import cached_property from django.core.cache import cache -from django.dispatch import receiver from django.core.exceptions import ValidationError -from django.db import IntegrityError -from django.db import transaction +from django.db import IntegrityError, models, transaction +from django.db.models.signals import post_delete, post_save +from django.dispatch import receiver +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from reversion import revisions as reversion -from preferences.models import OptionalTopologie, RadiusKey, SwitchManagementCred -from machines.models import Machine, regen, Role, MachineType, Ipv6List +from machines.models import Ipv6List, Machine, MachineType, Role, regen +from preferences.models import (OptionalTopologie, RadiusKey, + SwitchManagementCred) from re2o.mixins import AclMixin, RevMixin @@ -364,7 +363,7 @@ class Switch(Machine): @cached_property def get_radius_servers_objects(self): """Return radius servers objects for Switchs provisioning, via REST API. - + Returns : Interfaces objects query_set for the Role type radius-server """ @@ -378,16 +377,17 @@ class Switch(Machine): def get_radius_servers(self): """Return radius servers string, ipv4 and ipv6 for Switchs provisioning, via REST API. - + Returns : Ip dict of interfaces for the Role type radius-server """ + def return_ips_dict(interfaces): return { "ipv4": [str(interface.ipv4) for interface in interfaces], - "ipv6": Ipv6List.objects.filter(interface__in=interfaces).filter(active=True).values_list( - "ipv6", flat=True - ), + "ipv6": Ipv6List.objects.filter(interface__in=interfaces) + .filter(active=True) + .values_list("ipv6", flat=True), } return return_ips_dict(self.get_radius_servers_objects) @@ -724,12 +724,7 @@ class Dormitory(AclMixin, RevMixin, models.Model): message. """ - return ( - True, - None, - None, - cls.objects.all() - ) + return (True, None, None, cls.objects.all()) def __str__(self): return self.name @@ -770,12 +765,7 @@ class Building(AclMixin, RevMixin, models.Model): message. """ - return ( - True, - None, - None, - cls.objects.all() - ) + return (True, None, None, cls.objects.all()) @cached_property def cached_name(self): @@ -820,7 +810,11 @@ class Port(AclMixin, RevMixin, models.Model): "machines.Interface", on_delete=models.SET_NULL, blank=True, null=True ) related = models.OneToOneField( - "self", null=True, blank=True, related_name="related_port", on_delete=models.SET_NULL + "self", + null=True, + blank=True, + related_name="related_port", + on_delete=models.SET_NULL, ) custom_profile = models.ForeignKey( "PortProfile", on_delete=models.PROTECT, blank=True, null=True @@ -966,12 +960,7 @@ class Room(AclMixin, RevMixin, models.Model): message. """ - return ( - True, - None, - None, - cls.objects.all() - ) + return (True, None, None, cls.objects.all()) def __str__(self): return self.building.cached_name + " " + self.name diff --git a/topologie/urls.py b/topologie/urls.py index 6e5640ee..d4718fd4 100644 --- a/topologie/urls.py +++ b/topologie/urls.py @@ -27,8 +27,7 @@ from __future__ import unicode_literals from django.urls import path -from . import views -from . import views_autocomplete +from . import views, views_autocomplete app_name = "topologie" @@ -37,9 +36,7 @@ urlpatterns = [ path("index_ap", views.index_ap, name="index-ap"), path("new_ap", views.new_ap, name="new-ap"), path("edit_ap/", views.edit_ap, name="edit-ap"), - path( - "create_ports/", views.create_ports, name="create-ports" - ), + path("create_ports/", views.create_ports, name="create-ports"), path("index_room", views.index_room, name="index-room"), path("new_room", views.new_room, name="new-room"), path("edit_room/", views.edit_room, name="edit-room"), @@ -157,9 +154,7 @@ urlpatterns = [ views.edit_module, name="edit-module", ), - path( - "del_module/", views.del_module, name="del-module" - ), + path("del_module/", views.del_module, name="del-module"), path("index_module", views.index_module, name="index-module"), path("add_module_on", views.add_module_on, name="add-module-on"), path( @@ -173,11 +168,39 @@ urlpatterns = [ name="del-module-on", ), ### Autocomplete Views - path('room-autocomplete', views_autocomplete.RoomAutocomplete.as_view(), name='room-autocomplete',), - path('building-autocomplete', views_autocomplete.BuildingAutocomplete.as_view(), name='building-autocomplete',), - path('dormitory-autocomplete', views_autocomplete.DormitoryAutocomplete.as_view(), name='dormitory-autocomplete',), - path('switch-autocomplete', views_autocomplete.SwitchAutocomplete.as_view(), name='switch-autocomplete',), - path('port-autocomplete', views_autocomplete.PortAutocomplete.as_view(), name='profile-autocomplete',), - path('portprofile-autocomplete', views_autocomplete.PortProfileAutocomplete.as_view(), name='portprofile-autocomplete',), - path('switchbay-autocomplete', views_autocomplete.SwitchBayAutocomplete.as_view(), name='switchbay-autocomplete',), + path( + "room-autocomplete", + views_autocomplete.RoomAutocomplete.as_view(), + name="room-autocomplete", + ), + path( + "building-autocomplete", + views_autocomplete.BuildingAutocomplete.as_view(), + name="building-autocomplete", + ), + path( + "dormitory-autocomplete", + views_autocomplete.DormitoryAutocomplete.as_view(), + name="dormitory-autocomplete", + ), + path( + "switch-autocomplete", + views_autocomplete.SwitchAutocomplete.as_view(), + name="switch-autocomplete", + ), + path( + "port-autocomplete", + views_autocomplete.PortAutocomplete.as_view(), + name="profile-autocomplete", + ), + path( + "portprofile-autocomplete", + views_autocomplete.PortProfileAutocomplete.as_view(), + name="portprofile-autocomplete", + ), + path( + "switchbay-autocomplete", + views_autocomplete.SwitchBayAutocomplete.as_view(), + name="switchbay-autocomplete", + ), ] diff --git a/topologie/views.py b/topologie/views.py index cddfa28e..fc25a3b5 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -34,70 +34,39 @@ They are used to create, edit and delete: """ from __future__ import unicode_literals -from django.urls import reverse -from django.shortcuts import render, redirect +import tempfile +from os.path import isfile +from subprocess import PIPE, Popen + from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.db import IntegrityError -from django.db.models import ProtectedError, Prefetch from django.core.exceptions import ValidationError +from django.db import IntegrityError +from django.db.models import Prefetch, ProtectedError +from django.shortcuts import redirect, render from django.template import Context, Template, loader +from django.urls import reverse from django.utils.translation import ugettext as _ -import tempfile - -from users.views import form -from re2o.base import re2o_paginator, SortTable -from re2o.acl import can_create, can_edit, can_delete, can_view, can_view_all -from re2o.settings import MEDIA_ROOT -from machines.forms import ( - DomainForm, - EditInterfaceForm, - AddInterfaceForm, - EditOptionVlanForm, -) +from machines.forms import (AddInterfaceForm, DomainForm, EditInterfaceForm, + EditOptionVlanForm) from machines.models import Interface, Service_link, Vlan from preferences.models import AssoOption, GeneralOption +from re2o.acl import can_create, can_delete, can_edit, can_view, can_view_all +from re2o.base import SortTable, re2o_paginator +from re2o.settings import MEDIA_ROOT +from users.views import form -from .models import ( - Switch, - Port, - Room, - Stack, - ModelSwitch, - ConstructorSwitch, - AccessPoint, - SwitchBay, - Building, - Dormitory, - Server, - PortProfile, - ModuleSwitch, - ModuleOnSwitch, -) -from .forms import ( - EditPortForm, - NewSwitchForm, - EditSwitchForm, - AddPortForm, - EditRoomForm, - StackForm, - EditModelSwitchForm, - EditConstructorSwitchForm, - CreatePortsForm, - AddAccessPointForm, - EditAccessPointForm, - EditSwitchBayForm, - EditBuildingForm, - EditDormitoryForm, - EditPortProfileForm, - EditModuleForm, - EditSwitchModuleForm, -) - -from subprocess import Popen, PIPE - -from os.path import isfile +from .forms import (AddAccessPointForm, AddPortForm, CreatePortsForm, + EditAccessPointForm, EditBuildingForm, + EditConstructorSwitchForm, EditDormitoryForm, + EditModelSwitchForm, EditModuleForm, EditPortForm, + EditPortProfileForm, EditRoomForm, EditSwitchBayForm, + EditSwitchForm, EditSwitchModuleForm, NewSwitchForm, + StackForm) +from .models import (AccessPoint, Building, ConstructorSwitch, Dormitory, + ModelSwitch, ModuleOnSwitch, ModuleSwitch, Port, + PortProfile, Room, Server, Stack, Switch, SwitchBay) @login_required @@ -261,6 +230,7 @@ def index_switch_bay(request): }, ) + @login_required @can_view_all(Stack) def index_stack(request): @@ -276,6 +246,7 @@ def index_stack(request): }, ) + @login_required @can_view_all(Building) def index_building(request): @@ -295,6 +266,7 @@ def index_building(request): }, ) + @login_required @can_view_all(Dormitory) def index_dormitory(request): @@ -314,6 +286,7 @@ def index_dormitory(request): }, ) + @login_required @can_view_all(ModelSwitch, ConstructorSwitch) def index_model_switch(request): diff --git a/topologie/views_autocomplete.py b/topologie/views_autocomplete.py index 3eb58db4..767fb258 100644 --- a/topologie/views_autocomplete.py +++ b/topologie/views_autocomplete.py @@ -31,12 +31,13 @@ Here are defined the autocomplete class based view. """ from __future__ import unicode_literals -from django.db.models import Q, Value, CharField +from django.db.models import CharField, Q, Value from django.db.models.functions import Concat -from .models import Room, Dormitory, Building, Switch, PortProfile, Port, SwitchBay +from re2o.views import AutocompleteLoggedOutViewMixin, AutocompleteViewMixin -from re2o.views import AutocompleteViewMixin, AutocompleteLoggedOutViewMixin +from .models import (Building, Dormitory, Port, PortProfile, Room, Switch, + SwitchBay) class RoomAutocomplete(AutocompleteLoggedOutViewMixin): @@ -134,12 +135,8 @@ class SwitchBayAutocomplete(AutocompleteViewMixin): def filter_results(self): # See RoomAutocomplete.filter_results self.query_set = self.query_set.annotate( - full_name=Concat( - "building__name", Value(" "), "name" - ), - dorm_name=Concat( - "building__dormitory__name", Value(" "), "name" - ), + full_name=Concat("building__name", Value(" "), "name"), + dorm_name=Concat("building__dormitory__name", Value(" "), "name"), dorm_full_name=Concat( "building__dormitory__name", Value(" "), diff --git a/users/admin.py b/users/admin.py index d083a951..e394e35b 100644 --- a/users/admin.py +++ b/users/admin.py @@ -30,27 +30,13 @@ with AdherentAdmin, ClubAdmin and ServiceUserAdmin. from __future__ import unicode_literals from django.contrib import admin -from django.contrib.auth.models import Group from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from django.contrib.auth.models import Group from reversion.admin import VersionAdmin -from .models import ( - User, - EMailAddress, - ServiceUser, - School, - ListRight, - ListShell, - Adherent, - Club, - Ban, - Whitelist, - Request, -) -from .forms import ( - UserAdminForm, - ServiceUserAdminForm, -) +from .forms import ServiceUserAdminForm, UserAdminForm +from .models import (Adherent, Ban, Club, EMailAddress, ListRight, ListShell, + Request, School, ServiceUser, User, Whitelist) class SchoolAdmin(VersionAdmin): @@ -167,7 +153,18 @@ class AdherentAdmin(VersionAdmin, BaseUserAdmin): (None, {"fields": ("pseudo",)}), ( "Personal info", - {"fields": ("surname", "name", "email", "school", "shell", "uid_number", "password1", "password2")}, + { + "fields": ( + "surname", + "name", + "email", + "school", + "shell", + "uid_number", + "password1", + "password2", + ) + }, ), ) # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin @@ -205,6 +202,7 @@ class ClubAdmin(VersionAdmin, BaseUserAdmin): Django ModelAdmin: Apply on django ModelAdmin """ + # The forms to add and change user instances add_form = UserAdminForm form = UserAdminForm @@ -223,7 +221,17 @@ class ClubAdmin(VersionAdmin, BaseUserAdmin): (None, {"fields": ("pseudo",)}), ( "Personal info", - {"fields": ("surname", "email", "school", "shell", "uid_number", "password1", "password2")}, + { + "fields": ( + "surname", + "email", + "school", + "shell", + "uid_number", + "password1", + "password2", + ) + }, ), ) @@ -269,7 +277,12 @@ class ServiceUserAdmin(VersionAdmin, BaseUserAdmin): # that reference specific fields on auth.User. list_display = ("pseudo", "access_group") list_filter = () - fieldsets = ((None, {"fields": ("pseudo", "access_group", "comment", "password1", "password2")}),) + fieldsets = ( + ( + None, + {"fields": ("pseudo", "access_group", "comment", "password1", "password2")}, + ), + ) # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin # overrides get_fieldsets to use this attribute when creating a user. add_fieldsets = ( diff --git a/users/api/serializers.py b/users/api/serializers.py index 4b77446a..048fdf52 100644 --- a/users/api/serializers.py +++ b/users/api/serializers.py @@ -22,11 +22,12 @@ from rest_framework import serializers import users.models as users -from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer +from api.serializers import (NamespacedHIField, NamespacedHMSerializer, + NamespacedHRField) + class UserSerializer(NamespacedHMSerializer): - """Serialize `users.models.User` objects. - """ + """Serialize `users.models.User` objects.""" access = serializers.BooleanField(source="has_access") uid = serializers.IntegerField(source="uid_number") @@ -56,8 +57,7 @@ class UserSerializer(NamespacedHMSerializer): class ClubSerializer(NamespacedHMSerializer): - """Serialize `users.models.Club` objects. - """ + """Serialize `users.models.Club` objects.""" name = serializers.CharField(source="surname") access = serializers.BooleanField(source="has_access") @@ -91,8 +91,7 @@ class ClubSerializer(NamespacedHMSerializer): class AdherentSerializer(NamespacedHMSerializer): - """Serialize `users.models.Adherent` objects. - """ + """Serialize `users.models.Adherent` objects.""" access = serializers.BooleanField(source="has_access") uid = serializers.IntegerField(source="uid_number") @@ -135,8 +134,7 @@ class BasicUserSerializer(NamespacedHMSerializer): class ServiceUserSerializer(NamespacedHMSerializer): - """Serialize `users.models.ServiceUser` objects. - """ + """Serialize `users.models.ServiceUser` objects.""" class Meta: model = users.ServiceUser @@ -144,8 +142,7 @@ class ServiceUserSerializer(NamespacedHMSerializer): class SchoolSerializer(NamespacedHMSerializer): - """Serialize `users.models.School` objects. - """ + """Serialize `users.models.School` objects.""" class Meta: model = users.School @@ -153,8 +150,7 @@ class SchoolSerializer(NamespacedHMSerializer): class ListRightSerializer(NamespacedHMSerializer): - """Serialize `users.models.ListRight` objects. - """ + """Serialize `users.models.ListRight` objects.""" class Meta: model = users.ListRight @@ -162,8 +158,7 @@ class ListRightSerializer(NamespacedHMSerializer): class ShellSerializer(NamespacedHMSerializer): - """Serialize `users.models.ListShell` objects. - """ + """Serialize `users.models.ListShell` objects.""" class Meta: model = users.ListShell @@ -172,8 +167,7 @@ class ShellSerializer(NamespacedHMSerializer): class BanSerializer(NamespacedHMSerializer): - """Serialize `users.models.Ban` objects. - """ + """Serialize `users.models.Ban` objects.""" active = serializers.BooleanField(source="is_active") @@ -191,8 +185,7 @@ class BanSerializer(NamespacedHMSerializer): class WhitelistSerializer(NamespacedHMSerializer): - """Serialize `users.models.Whitelist` objects. - """ + """Serialize `users.models.Whitelist` objects.""" active = serializers.BooleanField(source="is_active") @@ -202,15 +195,14 @@ class WhitelistSerializer(NamespacedHMSerializer): class EMailAddressSerializer(NamespacedHMSerializer): - """Serialize `users.models.EMailAddress` objects. - """ + """Serialize `users.models.EMailAddress` objects.""" user = serializers.CharField(source="user.pseudo", read_only=True) class Meta: model = users.EMailAddress fields = ("user", "local_part", "complete_email_address", "api_url") - + class LocalEmailUsersSerializer(NamespacedHMSerializer): email_address = EMailAddressSerializer(read_only=True, many=True) @@ -226,16 +218,14 @@ class LocalEmailUsersSerializer(NamespacedHMSerializer): class MailingMemberSerializer(UserSerializer): - """Serialize the data about a mailing member. - """ + """Serialize the data about a mailing member.""" class Meta(UserSerializer.Meta): fields = ("name", "pseudo", "get_mail") class MailingSerializer(ClubSerializer): - """Serialize the data about a mailing. - """ + """Serialize the data about a mailing.""" members = MailingMemberSerializer(many=True) admins = MailingMemberSerializer(source="administrators", many=True) diff --git a/users/api/urls.py b/users/api/urls.py index 13598746..966f42ff 100644 --- a/users/api/urls.py +++ b/users/api/urls.py @@ -34,16 +34,15 @@ urls_viewset = [ (r"users/shell", views.ShellViewSet, "shell"), (r"users/ban", views.BanViewSet, None), (r"users/whitelist", views.WhitelistViewSet, None), - (r"users/emailaddress", views.EMailAddressViewSet, None) + (r"users/emailaddress", views.EMailAddressViewSet, None), ] urls_view = [ (r"users/localemail", views.LocalEmailUsersView), (r"users/mailing-standard", views.StandardMailingView), (r"users/mailing-club", views.ClubMailingView), - # Deprecated (r"localemail/users", views.LocalEmailUsersView), (r"mailing/standard", views.StandardMailingView), (r"mailing/club", views.ClubMailingView), -] \ No newline at end of file +] diff --git a/users/api/views.py b/users/api/views.py index e9c57b8a..b36ee633 100644 --- a/users/api/views.py +++ b/users/api/views.py @@ -19,29 +19,28 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -from rest_framework import viewsets, generics, views -from django.db.models import Q from django.contrib.auth.models import Group +from django.db.models import Q +from rest_framework import generics, views, viewsets -from . import serializers +import preferences.models as preferences +import users.models as users from api.pagination import PageSizedPagination from api.permissions import ACLPermission from re2o.utils import all_has_access -import users.models as users -import preferences.models as preferences + +from . import serializers class UserViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.Users` objects. - """ + """Exposes list and details of `users.models.Users` objects.""" queryset = users.User.objects.all() serializer_class = serializers.UserSerializer class HomeCreationViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes infos of `users.models.Users` objects to create homes. - """ + """Exposes infos of `users.models.Users` objects to create homes.""" queryset = users.User.objects.exclude( Q(state=users.User.STATE_DISABLED) @@ -66,72 +65,63 @@ class CriticalUserViewSet(viewsets.ReadOnlyModelViewSet): class ClubViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.Club` objects. - """ + """Exposes list and details of `users.models.Club` objects.""" queryset = users.Club.objects.all() serializer_class = serializers.ClubSerializer class AdherentViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.Adherent` objects. - """ + """Exposes list and details of `users.models.Adherent` objects.""" queryset = users.Adherent.objects.all() serializer_class = serializers.AdherentSerializer class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.ServiceUser` objects. - """ + """Exposes list and details of `users.models.ServiceUser` objects.""" queryset = users.ServiceUser.objects.all() serializer_class = serializers.ServiceUserSerializer class SchoolViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.School` objects. - """ + """Exposes list and details of `users.models.School` objects.""" queryset = users.School.objects.all() serializer_class = serializers.SchoolSerializer class ListRightViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.ListRight` objects. - """ + """Exposes list and details of `users.models.ListRight` objects.""" queryset = users.ListRight.objects.all() serializer_class = serializers.ListRightSerializer class ShellViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.ListShell` objects. - """ + """Exposes list and details of `users.models.ListShell` objects.""" queryset = users.ListShell.objects.all() serializer_class = serializers.ShellSerializer class BanViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.Ban` objects. - """ + """Exposes list and details of `users.models.Ban` objects.""" queryset = users.Ban.objects.all() serializer_class = serializers.BanSerializer class WhitelistViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.Whitelist` objects. - """ + """Exposes list and details of `users.models.Whitelist` objects.""" queryset = users.Whitelist.objects.all() serializer_class = serializers.WhitelistSerializer class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet): - """Exposes list and details of `users.models.EMailAddress` objects. - """ + """Exposes list and details of `users.models.EMailAddress` objects.""" serializer_class = serializers.EMailAddressSerializer queryset = users.EMailAddress.objects.none() @@ -144,8 +134,7 @@ class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet): class LocalEmailUsersView(generics.ListAPIView): - """Exposes all the aliases of the users that activated the internal address - """ + """Exposes all the aliases of the users that activated the internal address""" serializer_class = serializers.LocalEmailUsersSerializer @@ -169,7 +158,7 @@ class StandardMailingView(views.APIView): adherents_data = serializers.MailingMemberSerializer( all_has_access(), many=True ).data - + data = [{"name": "adherents", "members": adherents_data}] groups = Group.objects.all() for group in groups: @@ -189,4 +178,4 @@ class ClubMailingView(generics.ListAPIView): """ queryset = users.Club.objects.all() - serializer_class = serializers.MailingSerializer \ No newline at end of file + serializer_class = serializers.MailingSerializer diff --git a/users/apps.py b/users/apps.py index 626c66e5..20c8a286 100644 --- a/users/apps.py +++ b/users/apps.py @@ -8,4 +8,4 @@ from django.apps import AppConfig class CoreConfig(AppConfig): """Configuration of users app.""" - name = "users" \ No newline at end of file + name = "users" diff --git a/users/forms.py b/users/forms.py index 172a8c54..a0bdb513 100644 --- a/users/forms.py +++ b/users/forms.py @@ -41,53 +41,35 @@ of each of the method. from __future__ import unicode_literals -from os import walk, path +from os import path, walk from django import forms -from django.forms import ModelForm, Form -from django.contrib.auth.forms import ReadOnlyPasswordHashField -from django.contrib.auth.password_validation import ( - validate_password, - password_validators_help_text_html, -) -from django.core.validators import MinLengthValidator from django.conf import settings +from django.contrib.auth.forms import ReadOnlyPasswordHashField +from django.contrib.auth.models import Group, Permission +from django.contrib.auth.password_validation import ( + password_validators_help_text_html, validate_password) +from django.core.validators import MinLengthValidator +from django.forms import Form, ModelForm from django.utils import timezone from django.utils.functional import lazy -from django.contrib.auth.models import Group, Permission -from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ from machines.models import Interface, Machine, Nas -from topologie.models import Port -from preferences.models import OptionalUser -from re2o.utils import remove_user_room +from preferences.models import GeneralOption, OptionalUser from re2o.base import get_input_formats_help_text -from re2o.mixins import FormRevMixin -from re2o.widgets import ( - AutocompleteMultipleModelWidget, - AutocompleteModelWidget, -) from re2o.field_permissions import FieldPermissionFormMixin +from re2o.mixins import FormRevMixin +from re2o.utils import remove_user_room +from re2o.widgets import (AutocompleteModelWidget, + AutocompleteMultipleModelWidget) +from topologie.models import Port -from preferences.models import GeneralOption - +from .models import (Adherent, Ban, Club, EMailAddress, ListRight, ListShell, + School, ServiceUser, User, Whitelist) from .widgets import DateTimePicker -from .models import ( - User, - ServiceUser, - School, - ListRight, - Whitelist, - EMailAddress, - ListShell, - Ban, - Adherent, - Club, -) - - #### Django Admin Custom Views @@ -126,7 +108,7 @@ class UserAdminForm(FormRevMixin, forms.ModelForm): Parameters: self : Apply on a django Form UserCreationForm instance - + Returns: password2 (string): The password2 value if all tests returned True """ @@ -182,7 +164,7 @@ class ServiceUserAdminForm(FormRevMixin, forms.ModelForm): Parameters: self : Apply on a django Form UserCreationForm instance - + Returns: password2 (string): The password2 value if all tests returned True """ @@ -194,7 +176,7 @@ class ServiceUserAdminForm(FormRevMixin, forms.ModelForm): def save(self, commit=True): """Save function. Call standard "set_password" django function, - from provided value for new password, for making hash. + from provided value for new password, for making hash. Parameters: self : Apply on a django Form ServiceUserAdminForm instance @@ -213,10 +195,10 @@ class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm): """Django form for changing password, check if 2 passwords are the same, and validate password for django base password validators provided in settings_local. - + Parameters: DjangoForm : Inherit from basic django form - + """ selfpasswd = forms.CharField( @@ -238,11 +220,11 @@ class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm): def clean_passwd2(self): """Clean password 2, check if passwd1 and 2 values match, and - apply django validator with validate_password function. - + apply django validator with validate_password function. + Parameters: self : Apply on a django Form PassForm instance - + Returns: password2 (string): The password2 value if all tests returned True """ @@ -278,7 +260,7 @@ class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm): class ResetPasswordForm(forms.Form): - """A form for asking to reset password. + """A form for asking to reset password. Parameters: DjangoForm : Inherit from basic django form @@ -368,10 +350,10 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): def clean_telephone(self): """Clean telephone, check if telephone is made mandatory, and raise error if not provided - + Parameters: self : Apply on a django Form AdherentForm instance - + Returns: telephone (string): The telephone string if clean is True """ @@ -395,10 +377,10 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Clean room, based on room policy provided by preferences. If needed, call remove_user_room to make the room empty before saving self.instance into that room. - + Parameters: self : Apply on a django Form AdherentForm instance - + Returns: room (string): The room instance """ @@ -505,11 +487,11 @@ class AdherentCreationForm(AdherentForm): def clean_password2(self): """Clean password 2, check if passwd1 and 2 values match, and - apply django validator with validate_password function. + apply django validator with validate_password function. Parameters: self : Apply on a django Form AdherentCreationForm instance - + Returns: password2 (string): The password2 value if all tests returned True """ @@ -526,7 +508,7 @@ class AdherentCreationForm(AdherentForm): return password2 def save(self, commit=True): - """Save function. If password has been set during creation, + """Save function. If password has been set during creation, call standard "set_password" django function from provided value for new password, for making hash. @@ -588,7 +570,7 @@ class AdherentEditForm(AdherentForm): class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """ClubForm. For editing club by himself or another user. Labels are provided for - help purposes. Add some instructions, and validation, fields depends + help purposes. Add some instructions, and validation, fields depends on editing user rights. Parameters: @@ -631,10 +613,10 @@ class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): def clean_telephone(self): """Clean telephone, check if telephone is made mandatory, and raise error if not provided - + Parameters: self : Apply on a django Form ClubForm instance - + Returns: telephone (string): The telephone string if clean is True """ @@ -671,7 +653,7 @@ class ClubAdminandMembersForm(FormRevMixin, ModelForm): class PasswordForm(FormRevMixin, ModelForm): """PasswordForm. Do not use directly in views without extra validations. - + Parameters: DjangoForm : Inherit from basic django form """ @@ -688,7 +670,7 @@ class PasswordForm(FormRevMixin, ModelForm): class ServiceUserForm(FormRevMixin, ModelForm): """ServiceUserForm, used for creating a service user, require a password and set it. - + Parameters: DjangoForm : Inherit from basic django form """ @@ -710,7 +692,7 @@ class ServiceUserForm(FormRevMixin, ModelForm): super(ServiceUserForm, self).__init__(*args, prefix=prefix, **kwargs) def save(self, commit=True): - """Save function. If password has been changed and provided, + """Save function. If password has been changed and provided, call standard "set_password" django function from provided value for new password, for making hash. @@ -1044,10 +1026,10 @@ class InitialRegisterForm(forms.Form): def clean_register_room(self): """Clean room, call remove_user_room to make the room empty before saving self.instance into that room. - + Parameters: self : Apply on a django Form InitialRegisterForm instance - + """ if self.cleaned_data["register_room"]: if self.user.is_class_adherent: @@ -1065,7 +1047,7 @@ class InitialRegisterForm(forms.Form): Parameters: self : Apply on a django Form InitialRegisterForm instance - + """ if self.cleaned_data["register_machine"]: if self.mac_address and self.nas_type: @@ -1073,8 +1055,7 @@ class InitialRegisterForm(forms.Form): class ThemeForm(FormRevMixin, forms.Form): - """Form to change the theme of a user. - """ + """Form to change the theme of a user.""" theme = forms.ChoiceField(widget=forms.Select()) diff --git a/users/management/commands/anonymise.py b/users/management/commands/anonymise.py index 700905b9..29617fc1 100644 --- a/users/management/commands/anonymise.py +++ b/users/management/commands/anonymise.py @@ -1,16 +1,17 @@ -from django.core.management.base import BaseCommand -from users.models import User, School, Adherent, Club -from machines.models import Domain, Machine -from reversion.models import Revision -from django.db.models import F, Value -from django.db.models import Q -from django.db.models.functions import Concat - -from re2o.login import hashNT, makeSecret - -import os, random, string +import os +import random +import string from random import randint +from django.core.management.base import BaseCommand +from django.db.models import F, Q, Value +from django.db.models.functions import Concat +from reversion.models import Revision + +from machines.models import Domain, Machine +from re2o.login import hashNT, makeSecret +from users.models import Adherent, Club, School, User + class Command(BaseCommand): help = "Anonymise the data in the database in order to use them on critical servers (dev, personal...). Every information will be overwritten using non-personal information. This script must follow any modification of the database.\nOptional argument: {id|id|id|...} to exclude users from anonymisation." diff --git a/users/management/commands/chgpass.py b/users/management/commands/chgpass.py index 5de9aa8d..d7f868eb 100644 --- a/users/management/commands/chgpass.py +++ b/users/management/commands/chgpass.py @@ -23,8 +23,9 @@ import os import pwd from django.core.management.base import BaseCommand, CommandError + +from re2o.script_utils import form_cli, get_system_user, get_user from users.forms import PassForm -from re2o.script_utils import get_user, get_system_user, form_cli class Command(BaseCommand): @@ -46,6 +47,4 @@ class Command(BaseCommand): self.stdout.write("Password change of %s" % target_user.pseudo) - form_cli( - PassForm, current_user, "Password change", instance=target_user - ) + form_cli(PassForm, current_user, "Password change", instance=target_user) diff --git a/users/management/commands/chsh.py b/users/management/commands/chsh.py index 0b815543..01fa3de6 100644 --- a/users/management/commands/chsh.py +++ b/users/management/commands/chsh.py @@ -20,15 +20,15 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os -import sys import pwd +import sys from django.core.management.base import BaseCommand, CommandError from django.db import transaction from reversion import revisions as reversion -from users.models import User, ListShell -from re2o.script_utils import get_user, get_system_user +from re2o.script_utils import get_system_user, get_user +from users.models import ListShell, User class Command(BaseCommand): diff --git a/users/management/commands/clean_notyetactive.py b/users/management/commands/clean_notyetactive.py index 14f7c826..0e771ea8 100644 --- a/users/management/commands/clean_notyetactive.py +++ b/users/management/commands/clean_notyetactive.py @@ -16,16 +16,16 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -from django.core.management.base import BaseCommand, CommandError -from django.db.models import Q - -from users.models import User -from cotisations.models import Facture -from preferences.models import OptionalUser from datetime import timedelta +from django.core.management.base import BaseCommand, CommandError +from django.db.models import Q from django.utils import timezone +from cotisations.models import Facture +from preferences.models import OptionalUser +from users.models import User + class Command(BaseCommand): help = "Delete non members users (not yet active)." diff --git a/users/management/commands/derniere_connexion.py b/users/management/commands/derniere_connexion.py index 9d753809..70de99f5 100644 --- a/users/management/commands/derniere_connexion.py +++ b/users/management/commands/derniere_connexion.py @@ -20,8 +20,8 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -import sys import re +import sys from datetime import datetime from django.core.management.base import BaseCommand, CommandError diff --git a/users/management/commands/disable_emailnotyetconfirmed.py b/users/management/commands/disable_emailnotyetconfirmed.py index 85b12699..4d50d1fa 100644 --- a/users/management/commands/disable_emailnotyetconfirmed.py +++ b/users/management/commands/disable_emailnotyetconfirmed.py @@ -14,15 +14,15 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -from django.core.management.base import BaseCommand, CommandError - -from users.models import User -from cotisations.models import Facture -from preferences.models import OptionalUser from datetime import timedelta +from django.core.management.base import BaseCommand, CommandError from django.utils import timezone +from cotisations.models import Facture +from preferences.models import OptionalUser +from users.models import User + class Command(BaseCommand): help = "Disable users who haven't confirmed their email." diff --git a/users/models.py b/users/models.py index 5256d7c5..ca8f3084 100755 --- a/users/models.py +++ b/users/models.py @@ -44,55 +44,43 @@ Here are defined the following django models : from __future__ import unicode_literals -import re -import uuid import datetime +import re import sys +import traceback +import uuid +from datetime import timedelta +from io import BytesIO -from django.db import models -from django.db.models import Q from django import forms -from django.forms import ValidationError -from django.db.models.signals import post_save, post_delete, m2m_changed +from django.contrib.auth.models import (AbstractBaseUser, BaseUserManager, + Group, PermissionsMixin) +from django.core.files.uploadedfile import InMemoryUploadedFile +from django.core.validators import RegexValidator +from django.db import models, transaction +from django.db.models import Q +from django.db.models.signals import m2m_changed, post_delete, post_save from django.dispatch import receiver -from django.utils.functional import cached_property +from django.forms import ValidationError from django.template import loader from django.urls import reverse -from django.db import transaction from django.utils import timezone -from datetime import timedelta -from django.contrib.auth.models import ( - AbstractBaseUser, - BaseUserManager, - PermissionsMixin, - Group, -) -from django.core.validators import RegexValidator -import traceback +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ -from django.core.files.uploadedfile import InMemoryUploadedFile - +from PIL import Image from reversion import revisions as reversion - -from re2o.settings import LDAP, GID_RANGES, UID_RANGES -from re2o.field_permissions import FieldPermissionModelMixin -from re2o.mixins import AclMixin, RevMixin -from re2o.base import smtp_check -from re2o.mail_utils import send_mail - from cotisations.models import Cotisation, Facture, Paiement, Vente from machines.models import Domain, Interface, Machine, regen -from preferences.models import GeneralOption, AssoOption, OptionalUser -from preferences.models import OptionalMachine, MailMessageOption - +from preferences.models import (AssoOption, GeneralOption, MailMessageOption, + OptionalMachine, OptionalUser) +from re2o.base import smtp_check +from re2o.field_permissions import FieldPermissionModelMixin +from re2o.mail_utils import send_mail +from re2o.mixins import AclMixin, RevMixin +from re2o.settings import GID_RANGES, LDAP, UID_RANGES from users import signals -from PIL import Image -from io import BytesIO -import sys - - # General utilities @@ -121,7 +109,7 @@ def linux_user_validator(login): """ if not linux_user_check(login): raise forms.ValidationError( - _("The username \"%(label)s\" contains forbidden characters."), + _('The username "%(label)s" contains forbidden characters.'), params={"label": login}, ) @@ -259,31 +247,28 @@ class User( ), ) local_email_enabled = models.BooleanField( - default=False, - help_text=_("Enable the local email account.") + default=False, help_text=_("Enable the local email account.") ) school = models.ForeignKey( "School", on_delete=models.PROTECT, null=True, blank=True, - help_text=_("Education institute.") + help_text=_("Education institute."), ) shell = models.ForeignKey( "ListShell", on_delete=models.PROTECT, null=True, blank=True, - help_text=_("Unix shell.") + help_text=_("Unix shell."), ) comment = models.CharField( help_text=_("Comment, school year."), max_length=255, blank=True ) pwd_ntlm = models.CharField(max_length=255) state = models.IntegerField( - choices=STATES, - default=STATE_NOT_YET_ACTIVE, - help_text=_("Account state.") + choices=STATES, default=STATE_NOT_YET_ACTIVE, help_text=_("Account state.") ) email_state = models.IntegerField(choices=EMAIL_STATES, default=EMAIL_STATE_PENDING) registered = models.DateTimeField(auto_now_add=True) @@ -293,7 +278,7 @@ class User( unique=True, blank=True, null=True, - help_text=_("Optionnal legacy uid, for import and transition purpose") + help_text=_("Optionnal legacy uid, for import and transition purpose"), ) shortcuts_enabled = models.BooleanField( verbose_name=_("enable shortcuts on Re2o website"), default=True @@ -596,7 +581,10 @@ class User( Returns: shadow_expire (int) : Shadow expire value. """ - if self.state == self.STATE_DISABLED or self.email_state == self.EMAIL_STATE_UNVERIFIED: + if ( + self.state == self.STATE_DISABLED + or self.email_state == self.EMAIL_STATE_UNVERIFIED + ): return str(0) else: return None @@ -675,14 +663,11 @@ class User( Returns: end_adhesion (date) : Date of the end of the membership. """ - date_max = ( - Cotisation.objects.filter( - vente__in=Vente.objects.filter( - facture__in=Facture.objects.filter(user=self).exclude(valid=False) - ) + date_max = Cotisation.objects.filter( + vente__in=Vente.objects.filter( + facture__in=Facture.objects.filter(user=self).exclude(valid=False) ) - .aggregate(models.Max("date_end_memb"))["date_end_memb__max"] - ) + ).aggregate(models.Max("date_end_memb"))["date_end_memb__max"] return date_max def end_connexion(self): @@ -695,14 +680,11 @@ class User( Returns: end_adhesion (date) : Date of the end of the connection subscription. """ - date_max = ( - Cotisation.objects.filter( - vente__in=Vente.objects.filter( - facture__in=Facture.objects.filter(user=self).exclude(valid=False) - ) + date_max = Cotisation.objects.filter( + vente__in=Vente.objects.filter( + facture__in=Facture.objects.filter(user=self).exclude(valid=False) ) - .aggregate(models.Max("date_end_con"))["date_end_con__max"] - ) + ).aggregate(models.Max("date_end_con"))["date_end_con__max"] return date_max def is_adherent(self): @@ -722,8 +704,8 @@ class User( return False else: return True - # it looks wrong, we should check if there is a cotisation where - # were date_start_memb < timezone.now() < date_end_memb, + # it looks wrong, we should check if there is a cotisation where + # were date_start_memb < timezone.now() < date_end_memb, # in case the user purshased a cotisation starting in the futur # somehow @@ -745,8 +727,8 @@ class User( return False else: return self.is_adherent() - # it looks wrong, we should check if there is a cotisation where - # were date_start_con < timezone.now() < date_end_con, + # it looks wrong, we should check if there is a cotisation where + # were date_start_con < timezone.now() < date_end_con, # in case the user purshased a cotisation starting in the futur # somehow @@ -910,10 +892,21 @@ class User( """ if self.state == self.STATE_NOT_YET_ACTIVE: # Look for ventes with non 0 subscription duration in the invoices set - not_zero = self.facture_set.filter(valid=True).exclude(Q(vente__duration_membership=0)).exists() - days_not_zero = self.facture_set.filter(valid=True).exclude(Q(vente__duration_days_membership=0)).exists() - if(not_zero or days_not_zero\ - or OptionalUser.get_cached_value("all_users_active")): + not_zero = ( + self.facture_set.filter(valid=True) + .exclude(Q(vente__duration_membership=0)) + .exists() + ) + days_not_zero = ( + self.facture_set.filter(valid=True) + .exclude(Q(vente__duration_days_membership=0)) + .exists() + ) + if ( + not_zero + or days_not_zero + or OptionalUser.get_cached_value("all_users_active") + ): self.state = self.STATE_ACTIVE self.save() if self.state == self.STATE_ARCHIVE or self.state == self.STATE_FULL_ARCHIVE: @@ -1493,7 +1486,7 @@ class User( False, _( "Impossible to edit the organisation's" - " user without the \"change_all_users\" right." + ' user without the "change_all_users" right.' ), ("users.change_all_users",), ) @@ -1547,13 +1540,13 @@ class User( ) def check_selfpasswd(self, user_request, *_args, **_kwargs): - """ Returns (True, None, None) if user_request is self, else returns + """Returns (True, None, None) if user_request is self, else returns (False, None, None) """ return user_request == self, None, None def can_change_room(self, user_request, *_args, **_kwargs): - """ Check if a user can change a room + """Check if a user can change a room :param user_request: The user who request :returns: a message and a boolean which is True if the user has @@ -1562,7 +1555,8 @@ class User( if not ( ( self.pk == user_request.pk - and OptionalUser.get_cached_value("self_room_policy") != OptionalUser.DISABLED + and OptionalUser.get_cached_value("self_room_policy") + != OptionalUser.DISABLED ) or user_request.has_perm("users.change_user") ): @@ -1576,7 +1570,7 @@ class User( @staticmethod def can_change_state(user_request, *_args, **_kwargs): - """ Check if a user can change a state + """Check if a user can change a state :param user_request: The user who request :returns: a message and a boolean which is True if the user has @@ -1590,7 +1584,7 @@ class User( ) def can_change_shell(self, user_request, *_args, **_kwargs): - """ Check if a user can change a shell + """Check if a user can change a shell :param user_request: The user who request :returns: a message and a boolean which is True if the user has @@ -1612,7 +1606,7 @@ class User( return True, None, None def can_change_pseudo(self, user_request, *_args, **_kwargs): - """ Check if a user can change a pseudo + """Check if a user can change a pseudo :param user_request: The user who request :returns: a message and a boolean which is True if the user has @@ -1636,7 +1630,7 @@ class User( @staticmethod def can_change_local_email_redirect(user_request, *_args, **_kwargs): - """ Check if a user can change local_email_redirect. + """Check if a user can change local_email_redirect. :param user_request: The user who request :returns: a message and a boolean which is True if the user has @@ -1651,7 +1645,7 @@ class User( @staticmethod def can_change_local_email_enabled(user_request, *_args, **_kwargs): - """ Check if a user can change internal address. + """Check if a user can change internal address. :param user_request: The user who request :returns: a message and a boolean which is True if the user has @@ -1666,7 +1660,7 @@ class User( @staticmethod def can_change_force(user_request, *_args, **_kwargs): - """ Check if a user can change a force + """Check if a user can change a force :param user_request: The user who request :returns: a message and a boolean which is True if the user has @@ -1681,7 +1675,7 @@ class User( @staticmethod def can_change_groups(user_request, *_args, **_kwargs): - """ Check if a user can change a group + """Check if a user can change a group :param user_request: The user who request :returns: a message and a boolean which is True if the user has @@ -1698,7 +1692,7 @@ class User( @staticmethod def can_change_is_superuser(user_request, *_args, **_kwargs): - """ Check if an user can change a is_superuser flag + """Check if an user can change a is_superuser flag :param user_request: The user who request :returns: a message and a boolean which is True if permission is granted. @@ -1707,7 +1701,7 @@ class User( can = user_request.is_superuser return ( can, - _("\"superuser\" right required to edit the superuser flag.") + _('"superuser" right required to edit the superuser flag.') if not can else None, [], @@ -1826,9 +1820,7 @@ class User( """ is_created = not self.pk if not self.email and (self.__original_email or is_created): - raise forms.ValidationError( - _("Email field cannot be empty.") - ) + raise forms.ValidationError(_("Email field cannot be empty.")) self.email = self.email.lower() @@ -1937,9 +1929,7 @@ class Adherent(User): """ if not user_request.is_authenticated: - if not OptionalUser.get_cached_value( - "self_adhesion" - ): + if not OptionalUser.get_cached_value("self_adhesion"): return False, _("Self registration is disabled."), None else: return True, None, None @@ -1969,12 +1959,7 @@ class Adherent(User): """ can, _message, _group = Club.can_view_all(user_request) if user_request.has_perm("users.view_user") or can: - return ( - True, - None, - None, - cls.objects.all() - ) + return (True, None, None, cls.objects.all()) else: return ( True, @@ -1997,7 +1982,7 @@ class Adherent(User): class Club(User): - """ A class representing a club (it is considered as a user + """A class representing a club (it is considered as a user with special informations) Attributes: @@ -2098,7 +2083,13 @@ def user_post_save(**kwargs): user.notif_inscription(user.request) user.set_active() user.state_sync() - signals.synchronise.send(sender=User, instance=user, base=True, access_refresh=True, mac_refresh=False, group_refresh=True + signals.synchronise.send( + sender=User, + instance=user, + base=True, + access_refresh=True, + mac_refresh=False, + group_refresh=True, ) regen("mailing") @@ -2112,7 +2103,13 @@ def user_group_relation_changed(**kwargs): action = kwargs["action"] if action in ("post_add", "post_remove", "post_clear"): user = kwargs["instance"] - signals.synchronise.send(sender=User, instance=user, base=False, access_refresh=False, mac_refresh=False, group_refresh=True + signals.synchronise.send( + sender=User, + instance=user, + base=False, + access_refresh=False, + mac_refresh=False, + group_refresh=True, ) @@ -2228,19 +2225,14 @@ class School(RevMixin, AclMixin, models.Model): message. """ - return ( - True, - None, - None, - cls.objects.all() - ) + return (True, None, None, cls.objects.all()) def __str__(self): return self.name class ListRight(RevMixin, AclMixin, Group): - """ A class representing a listright, inherit from basic django Group object. + """A class representing a listright, inherit from basic django Group object. Each listrights/groups gathers several users, and can have individuals django rights, like can_view, can_edit, etc. Moreover, a ListRight is also a standard unix group, usefull for creating linux @@ -2332,19 +2324,14 @@ class ListShell(RevMixin, AclMixin, models.Model): message. """ - return ( - True, - None, - None, - cls.objects.all() - ) + return (True, None, None, cls.objects.all()) def __str__(self): return self.shell class Ban(RevMixin, AclMixin, models.Model): - """ A class representing a ban, which cuts internet access, + """A class representing a ban, which cuts internet access, as a sanction. Attributes: @@ -2447,7 +2434,9 @@ def ban_post_save(**kwargs): ban = kwargs["instance"] is_created = kwargs["created"] user = ban.user - signals.synchronise.send(sender=User, instance=user, base=False, access_refresh=True, mac_refresh=False) + signals.synchronise.send( + sender=User, instance=user, base=False, access_refresh=True, mac_refresh=False + ) regen("mailing") if is_created: ban.notif_ban(ban.request) @@ -2465,14 +2454,16 @@ def ban_post_delete(**kwargs): """ user = kwargs["instance"].user - signals.synchronise.send(sender=User, instance=user, base=False, access_refresh=True, mac_refresh=False) + signals.synchronise.send( + sender=User, instance=user, base=False, access_refresh=True, mac_refresh=False + ) regen("mailing") regen("dhcp") regen("mac_ip_list") class Whitelist(RevMixin, AclMixin, models.Model): - """ A class representing a whitelist, which gives a free internet + """A class representing a whitelist, which gives a free internet access to a user for special reason. Is overrided by a ban object. @@ -2536,7 +2527,9 @@ def whitelist_post_save(**kwargs): """ whitelist = kwargs["instance"] user = whitelist.user - signals.synchronise.send(sender=User, instance=user, base=False, access_refresh=True, mac_refresh=False) + signals.synchronise.send( + sender=User, instance=user, base=False, access_refresh=True, mac_refresh=False + ) is_created = kwargs["created"] regen("mailing") if is_created: @@ -2554,14 +2547,16 @@ def whitelist_post_delete(**kwargs): """ user = kwargs["instance"].user - signals.synchronise.send(sender=User, instance=user, base=False, access_refresh=True, mac_refresh=False) + signals.synchronise.send( + sender=User, instance=user, base=False, access_refresh=True, mac_refresh=False + ) regen("mailing") regen("dhcp") regen("mac_ip_list") class Request(models.Model): - """ A class representing for user's request of reset password by email, or + """A class representing for user's request of reset password by email, or confirm a new email address, with a link. Attributes: @@ -2594,7 +2589,7 @@ class Request(models.Model): class EMailAddress(RevMixin, AclMixin, models.Model): - """ A class representing an EMailAddress, for local emailaccounts + """A class representing an EMailAddress, for local emailaccounts support. Each emailaddress belongs to a user. Attributes: diff --git a/users/signals.py b/users/signals.py index 7336e5fc..3b46ad1d 100644 --- a/users/signals.py +++ b/users/signals.py @@ -27,7 +27,15 @@ remove an object from optionnal authentication backends, e.g. LDAP. import django.dispatch -synchronise = django.dispatch.Signal(providing_args=["sender", "instance", "base", "access_refresh", "mac_refresh", "group_refresh"]) +synchronise = django.dispatch.Signal( + providing_args=[ + "sender", + "instance", + "base", + "access_refresh", + "mac_refresh", + "group_refresh", + ] +) remove = django.dispatch.Signal(providing_args=["sender", "instance"]) remove_mass = django.dispatch.Signal(providing_args=["sender", "queryset"]) - diff --git a/users/test_models.py b/users/test_models.py index bb69cb79..665ff6c4 100644 --- a/users/test_models.py +++ b/users/test_models.py @@ -1,10 +1,10 @@ -from django.test import TestCase - import datetime + +from django.test import TestCase from django.utils import timezone +from cotisations.models import Facture, Paiement, Vente from users.models import User -from cotisations.models import Vente, Facture, Paiement class UserModelTests(TestCase): diff --git a/users/tests.py b/users/tests.py index 4884f971..805fbaa8 100644 --- a/users/tests.py +++ b/users/tests.py @@ -25,11 +25,11 @@ The tests for the Users module. import os.path -from django.test import TestCase -from django.conf import settings -from . import models - import volatildap +from django.conf import settings +from django.test import TestCase + +from . import models class SchoolTestCase(TestCase): diff --git a/users/urls.py b/users/urls.py index 3dc1d5d8..be866470 100644 --- a/users/urls.py +++ b/users/urls.py @@ -30,8 +30,7 @@ from __future__ import unicode_literals from django.urls import path, re_path -from . import views -from . import views_autocomplete +from . import views, views_autocomplete app_name = "users" @@ -47,15 +46,17 @@ urlpatterns = [ path("state/", views.state, name="state"), path("groups/", views.groups, name="groups"), path("password/", views.password, name="password"), - path("confirm_email/", views.resend_confirmation_email, name="resend-confirmation-email"), + path( + "confirm_email/", + views.resend_confirmation_email, + name="resend-confirmation-email", + ), path( "del_group//", views.del_group, name="del-group", ), - path( - "del_superuser/", views.del_superuser, name="del-superuser" - ), + path("del_superuser/", views.del_superuser, name="del-superuser"), path("new_serviceuser", views.new_serviceuser, name="new-serviceuser"), path( "edit_serviceuser/", @@ -70,9 +71,7 @@ urlpatterns = [ path("add_ban/", views.add_ban, name="add-ban"), path("edit_ban/", views.edit_ban, name="edit-ban"), path("del-ban/", views.del_ban, name="del-ban"), - path( - "add_whitelist/", views.add_whitelist, name="add-whitelist" - ), + path("add_whitelist/", views.add_whitelist, name="add-whitelist"), path( "edit_whitelist/", views.edit_whitelist, @@ -132,9 +131,29 @@ urlpatterns = [ path("initial_register", views.initial_register, name="initial-register"), path("edit_theme/", views.edit_theme, name="edit-theme"), ### Autocomplete Views - path('user-autocomplete', views_autocomplete.UserAutocomplete.as_view(), name='user-autocomplete',), - path('adherent-autocomplete', views_autocomplete.AdherentAutocomplete.as_view(), name='adherent-autocomplete',), - path('club-autocomplete', views_autocomplete.ClubAutocomplete.as_view(), name='club-autocomplete',), - path('school-autocomplete', views_autocomplete.SchoolAutocomplete.as_view(), name='school-autocomplete',), - path('shell-autocomplete', views_autocomplete.ShellAutocomplete.as_view(), name='shell-autocomplete',), + path( + "user-autocomplete", + views_autocomplete.UserAutocomplete.as_view(), + name="user-autocomplete", + ), + path( + "adherent-autocomplete", + views_autocomplete.AdherentAutocomplete.as_view(), + name="adherent-autocomplete", + ), + path( + "club-autocomplete", + views_autocomplete.ClubAutocomplete.as_view(), + name="club-autocomplete", + ), + path( + "school-autocomplete", + views_autocomplete.SchoolAutocomplete.as_view(), + name="school-autocomplete", + ), + path( + "shell-autocomplete", + views_autocomplete.ShellAutocomplete.as_view(), + name="shell-autocomplete", + ), ] diff --git a/users/views.py b/users/views.py index 0b671aba..54a0f34e 100644 --- a/users/views.py +++ b/users/views.py @@ -55,83 +55,46 @@ without code duplication. from __future__ import unicode_literals -from django.urls import reverse -from django.shortcuts import get_object_or_404, render, redirect +import os +from importlib import import_module + +from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required -from django.db.models import ProtectedError, Count, Max -from django.utils import timezone from django.db import transaction -from django.http import HttpResponse -from django.http import HttpResponseRedirect -from django.views.decorators.csrf import csrf_exempt -from django.utils.translation import ugettext as _ +from django.db.models import Count, Max, ProtectedError +from django.http import HttpResponse, HttpResponseRedirect +from django.shortcuts import get_object_or_404, redirect, render from django.template import loader - +from django.urls import reverse +from django.utils import timezone +from django.utils.translation import ugettext as _ +from django.views.decorators.csrf import csrf_exempt from rest_framework.renderers import JSONRenderer from reversion import revisions as reversion from cotisations.models import Facture, Paiement -from machines.models import Machine - -from preferences.models import OptionalUser, GeneralOption, AssoOption -from importlib import import_module -from django.conf import settings -from re2o.settings import LOCAL_APPS, OPTIONNAL_APPS_RE2O -from re2o.views import form -from re2o.utils import all_has_access, permission_tree -from re2o.base import re2o_paginator, SortTable -from re2o.acl import ( - can_create, - can_edit, - can_delete_set, - can_delete, - can_view, - can_view_all, - can_change, -) from cotisations.utils import find_payment_method +from machines.models import Machine +from preferences.models import AssoOption, GeneralOption, OptionalUser +from re2o.acl import (can_change, can_create, can_delete, can_delete_set, + can_edit, can_view, can_view_all) +from re2o.base import SortTable, re2o_paginator +from re2o.settings import LOCAL_APPS, OPTIONNAL_APPS_RE2O +from re2o.utils import all_has_access, permission_tree +from re2o.views import form from topologie.models import Port -from .models import ( - User, - Ban, - Whitelist, - School, - ListRight, - Request, - ServiceUser, - Adherent, - Club, - ListShell, - EMailAddress, -) -from .forms import ( - BanForm, - WhitelistForm, - EMailAddressForm, - EmailSettingsForm, - DelSchoolForm, - DelListRightForm, - NewListRightForm, - StateForm, - SchoolForm, - ShellForm, - EditServiceUserForm, - ServiceUserForm, - ListRightForm, - AdherentCreationForm, - AdherentEditForm, - ClubForm, - MassArchiveForm, - PassForm, - ResetPasswordForm, - ClubAdminandMembersForm, - GroupForm, - InitialRegisterForm, - ThemeForm -) -import os +from .forms import (AdherentCreationForm, AdherentEditForm, BanForm, + ClubAdminandMembersForm, ClubForm, DelListRightForm, + DelSchoolForm, EditServiceUserForm, EMailAddressForm, + EmailSettingsForm, GroupForm, InitialRegisterForm, + ListRightForm, MassArchiveForm, NewListRightForm, PassForm, + ResetPasswordForm, SchoolForm, ServiceUserForm, ShellForm, + StateForm, ThemeForm, WhitelistForm) +from .models import (Adherent, Ban, Club, EMailAddress, ListRight, ListShell, + Request, School, ServiceUser, User, Whitelist) + @can_create(Adherent) def new_user(request): @@ -146,7 +109,9 @@ def new_user(request): Django User form. """ - user = AdherentCreationForm(request.POST or None, request.FILES or None, user=request.user) + user = AdherentCreationForm( + request.POST or None, request.FILES or None, user=request.user + ) user.request = request GTU_sum_up = GeneralOption.get_cached_value("GTU_sum_up") @@ -238,7 +203,9 @@ def edit_club_admin_members(request, club_instance, **_kwargs): Django User form. """ - club = ClubAdminandMembersForm(request.POST or None, request.FILES or None, instance=club_instance) + club = ClubAdminandMembersForm( + request.POST or None, request.FILES or None, instance=club_instance + ) if club.is_valid(): if club.changed_data: club.save() @@ -247,7 +214,11 @@ def edit_club_admin_members(request, club_instance, **_kwargs): reverse("users:profil", kwargs={"userid": str(club_instance.id)}) ) return form( - {"userform": club, "showCGU": False, "action_name": _("Edit"),}, + { + "userform": club, + "showCGU": False, + "action_name": _("Edit"), + }, "users/user.html", request, ) @@ -269,11 +240,17 @@ def edit_info(request, user, userid): """ if user.is_class_adherent: user_form = AdherentEditForm( - request.POST or None, request.FILES or None, instance=user.adherent, user=request.user + request.POST or None, + request.FILES or None, + instance=user.adherent, + user=request.user, ) else: user_form = ClubForm( - request.POST or None, request.FILES or None,instance=user.club, user=request.user + request.POST or None, + request.FILES or None, + instance=user.club, + user=request.user, ) if user_form.is_valid(): if user_form.changed_data: @@ -286,7 +263,9 @@ def edit_info(request, user, userid): return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {"userform": user_form, "action_name": _("Edit")}, "users/user.html", request, + {"userform": user_form, "action_name": _("Edit")}, + "users/user.html", + request, ) @@ -316,7 +295,9 @@ def state(request, user, userid): ) return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {"userform": state_form, "action_name": _("Edit")}, "users/user.html", request, + {"userform": state_form, "action_name": _("Edit")}, + "users/user.html", + request, ) @@ -342,7 +323,9 @@ def groups(request, user, userid): messages.success(request, _("The groups were edited.")) return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {"userform": group_form, "action_name": _("Edit")}, "users/user.html", request, + {"userform": group_form, "action_name": _("Edit")}, + "users/user.html", + request, ) @@ -441,7 +424,9 @@ def new_serviceuser(request): messages.success(request, _("The service user was created.")) return redirect(reverse("users:index-serviceusers")) return form( - {"userform": user, "action_name": _("Add")}, "users/user.html", request, + {"userform": user, "action_name": _("Add")}, + "users/user.html", + request, ) @@ -468,7 +453,9 @@ def edit_serviceuser(request, serviceuser, **_kwargs): messages.success(request, _("The service user was edited.")) return redirect(reverse("users:index-serviceusers")) return form( - {"userform": serviceuser, "action_name": _("Edit")}, "users/user.html", request, + {"userform": serviceuser, "action_name": _("Edit")}, + "users/user.html", + request, ) @@ -606,7 +593,9 @@ def add_whitelist(request, user, userid): request, _("Warning: this user already has an active whitelist.") ) return form( - {"userform": whitelist, "action_name": _("Add")}, "users/user.html", request, + {"userform": whitelist, "action_name": _("Add")}, + "users/user.html", + request, ) @@ -633,7 +622,9 @@ def edit_whitelist(request, whitelist_instance, **_kwargs): messages.success(request, _("The whitelist was edited.")) return redirect(reverse("users:index")) return form( - {"userform": whitelist, "action_name": _("Edit")}, "users/user.html", request, + {"userform": whitelist, "action_name": _("Edit")}, + "users/user.html", + request, ) @@ -688,7 +679,11 @@ def add_emailaddress(request, user, userid): messages.success(request, _("The local email account was created.")) return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {"userform": emailaddress, "showCGU": False, "action_name": _("Add"),}, + { + "userform": emailaddress, + "showCGU": False, + "action_name": _("Add"), + }, "users/user.html", request, ) @@ -722,7 +717,11 @@ def edit_emailaddress(request, emailaddress_instance, **_kwargs): ) ) return form( - {"userform": emailaddress, "showCGU": False, "action_name": _("Edit"),}, + { + "userform": emailaddress, + "showCGU": False, + "action_name": _("Edit"), + }, "users/user.html", request, ) @@ -819,7 +818,9 @@ def add_school(request): messages.success(request, _("The school was added.")) return redirect(reverse("users:index-school")) return form( - {"userform": school, "action_name": _("Add")}, "users/user.html", request, + {"userform": school, "action_name": _("Add")}, + "users/user.html", + request, ) @@ -845,7 +846,9 @@ def edit_school(request, school_instance, **_kwargs): messages.success(request, _("The school was edited.")) return redirect(reverse("users:index-school")) return form( - {"userform": school, "action_name": _("Edit")}, "users/user.html", request, + {"userform": school, "action_name": _("Edit")}, + "users/user.html", + request, ) @@ -934,7 +937,9 @@ def edit_shell(request, shell_instance, **_kwargs): messages.success(request, _("The shell was edited.")) return redirect(reverse("users:index-shell")) return form( - {"userform": shell, "action_name": _("Edit")}, "users/user.html", request, + {"userform": shell, "action_name": _("Edit")}, + "users/user.html", + request, ) @@ -1310,7 +1315,7 @@ def index_serviceusers(request): def mon_profil(request): """Shortcuts view to profil view, with correct arguments. Returns the view profil with users argument, users is set to - default request.user. + default request.user. Parameters: request (django request): Standard django request. @@ -1335,7 +1340,7 @@ def profil(request, users, **_kwargs): * Email Settings of User instance * Tickets belonging to User instance. Requires the acl can_view on user instance. - + Parameters: request (django request): Standard django request. users: User instance to display profil @@ -1353,7 +1358,7 @@ def profil(request, users, **_kwargs): ] nb_machines = users.user_interfaces().count() - + bans = Ban.objects.filter(user=users) bans = SortTable.sort( bans, @@ -1379,7 +1384,7 @@ def profil(request, users, **_kwargs): "users/profil.html", { "users": users, - "nb_machines":nb_machines, + "nb_machines": nb_machines, "apps_templates_list": apps_templates_list, "ban_list": bans, "white_list": whitelists, @@ -1398,7 +1403,7 @@ def reset_password(request): """Reset password form, linked to form forgotten password. If an user is found, send an email to him with a link to reset its password. - + Parameters: request (django request): Standard django request. @@ -1594,6 +1599,7 @@ def initial_register(request): request, ) + @login_required @can_edit(User) def edit_theme(request, user, userid): @@ -1608,7 +1614,7 @@ def edit_theme(request, user, userid): Django User form. """ - theme_form = ThemeForm(request.POST or None, initial={'theme':user.theme}) + theme_form = ThemeForm(request.POST or None, initial={"theme": user.theme}) if theme_form.is_valid(): user.theme = theme_form.cleaned_data["theme"] user.save() @@ -1616,5 +1622,7 @@ def edit_theme(request, user, userid): return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {"userform": theme_form, "action_name": _("Edit")}, "users/user.html", request, - ) \ No newline at end of file + {"userform": theme_form, "action_name": _("Edit")}, + "users/user.html", + request, + ) diff --git a/users/views_autocomplete.py b/users/views_autocomplete.py index 014dd146..6b6f8dbe 100644 --- a/users/views_autocomplete.py +++ b/users/views_autocomplete.py @@ -31,13 +31,13 @@ Here are defined the autocomplete class based view. """ from __future__ import unicode_literals -from .models import User, School, Adherent, Club, ListShell - -from re2o.views import AutocompleteViewMixin, AutocompleteLoggedOutViewMixin - -from django.db.models import Q, Value, CharField +from django.db.models import CharField, Q, Value from django.db.models.functions import Concat +from re2o.views import AutocompleteLoggedOutViewMixin, AutocompleteViewMixin + +from .models import Adherent, Club, ListShell, School, User + class SchoolAutocomplete(AutocompleteLoggedOutViewMixin): obj_type = School diff --git a/users/widgets.py b/users/widgets.py index 81cced82..66d5f315 100644 --- a/users/widgets.py +++ b/users/widgets.py @@ -1,23 +1,18 @@ -from django.forms.widgets import Input +from django.conf import settings from django.forms.utils import flatatt -from django.utils.safestring import mark_safe +from django.forms.widgets import Input from django.template import Template from django.template.loader import get_template -from django.conf import settings -from django.utils.translation import ugettext_lazy as _, get_language_bidi -from django.utils.dates import ( - WEEKDAYS, - WEEKDAYS_ABBR, - MONTHS, - MONTHS_3, - MONTHS_AP, - MONTHS_ALT, -) +from django.utils.dates import (MONTHS, MONTHS_3, MONTHS_ALT, MONTHS_AP, + WEEKDAYS, WEEKDAYS_ABBR) +from django.utils.safestring import mark_safe +from django.utils.translation import get_language_bidi +from django.utils.translation import ugettext_lazy as _ def list2str(str_iterable): """ - Utility function to return a string representing a list of string + Utility function to return a string representing a list of string :params str_iterable: An iterable object where each element is of type str :returns: A representation of the iterable as a list (e.g '["a", "b"]') From 378c9067200b036d097ddce77d27d451feffd04a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Pi=C3=A9tri?= Date: Wed, 10 Feb 2021 11:07:13 +0100 Subject: [PATCH 3/7] chore: :pushpin: Add pipfile --- Pipfile | 31 ++ Pipfile.lock | 725 +++++++++++++++++++++++++++++++++++++++++++ dev-requirements.txt | 71 +++++ requirements.txt | 30 ++ 4 files changed, 857 insertions(+) create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 dev-requirements.txt create mode 100644 requirements.txt diff --git a/Pipfile b/Pipfile new file mode 100644 index 00000000..fc0079e1 --- /dev/null +++ b/Pipfile @@ -0,0 +1,31 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +django = "==2.2.18" +django-autocomplete-light = "*" +django-bootstrap3 = "*" +django-rest-framework = "*" +django-reversion = "*" +mysqlclient = "*" +pillow = "*" +python-dateutil = "*" +django-macaddress = "*" +pycrypto = "*" +django-ldapdb = "*" +gitpython = "*" + +[dev-packages] +sphinx = "*" +sphinx-rtd-theme = "*" +black = "*" +rope = "*" +coverage = "*" +coveralls = "*" +docstr-coverage = "*" +pyyaml = "*" + +[pipenv] +allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 00000000..b22adc23 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,725 @@ +{ + "_meta": { + "hash": { + "sha256": "7cc33c316b8ac5b326b4d196dc67ade697b6b86f339669990dbd1399de7a4ba7" + }, + "pipfile-spec": 6, + "requires": {}, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "django": { + "hashes": [ + "sha256:0eaca08f236bf502a9773e53623f766cc3ceee6453cc41e6de1c8b80f07d2364", + "sha256:c9c994f5e0a032cbd45089798b52e4080f4dea7241c58e3e0636c54146480bb4" + ], + "index": "pypi", + "version": "==2.2.18" + }, + "django-autocomplete-light": { + "hashes": [ + "sha256:4e84a6d95d272b0d7221614332e2bd54ffff15ec06e78947279398f6507ce225" + ], + "index": "pypi", + "version": "==3.8.1" + }, + "django-bootstrap3": { + "hashes": [ + "sha256:1fc3db37f29bcd159c0b00e1f15fd2d6dedf7551ce8bcca09072e33663c110de", + "sha256:c7e6912b5127bea913bc8504399613758760954140162e048184624765e61904" + ], + "index": "pypi", + "version": "==14.2.0" + }, + "django-ldapdb": { + "hashes": [ + "sha256:2daee828a7eb1ce6ad0634ce5311339d77c08128829e575ff14d62a46771b86a", + "sha256:5ea333c3130abbb86f8629766370a7f490878706469fce4e5008e41fb566392a" + ], + "index": "pypi", + "version": "==1.5.1" + }, + "django-macaddress": { + "hashes": [ + "sha256:342aa3421ee19acc3661d1705dad2ae674eaa7d06a02799f7a5dc394d6233275", + "sha256:db8beedcbd708aba3a6c9e83de6527efa2f9cc7dbe698406cebdfdbaf98c896d" + ], + "index": "pypi", + "version": "==1.7.0" + }, + "django-rest-framework": { + "hashes": [ + "sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a" + ], + "index": "pypi", + "version": "==0.1.0" + }, + "django-reversion": { + "hashes": [ + "sha256:1b57127a136b969f4b843a915c72af271febe7f336469db6c27121f8adcad35c", + "sha256:a5af55f086a3f9c38be2f049c251e06005b9ed48ba7a109473736b1fc95a066f" + ], + "index": "pypi", + "version": "==3.0.9" + }, + "djangorestframework": { + "hashes": [ + "sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7", + "sha256:0898182b4737a7b584a2c73735d89816343369f259fea932d90dc78e35d8ac33" + ], + "markers": "python_version >= '3.5'", + "version": "==3.12.2" + }, + "gitdb": { + "hashes": [ + "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac", + "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9" + ], + "markers": "python_version >= '3.4'", + "version": "==4.0.5" + }, + "gitpython": { + "hashes": [ + "sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a", + "sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29" + ], + "index": "pypi", + "version": "==3.1.13" + }, + "mysqlclient": { + "hashes": [ + "sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7", + "sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3", + "sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5", + "sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432", + "sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6" + ], + "index": "pypi", + "version": "==2.0.3" + }, + "netaddr": { + "hashes": [ + "sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac", + "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243" + ], + "version": "==0.8.0" + }, + "pillow": { + "hashes": [ + "sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6", + "sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded", + "sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865", + "sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174", + "sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032", + "sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a", + "sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e", + "sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378", + "sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17", + "sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c", + "sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913", + "sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7", + "sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0", + "sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820", + "sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba", + "sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2", + "sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b", + "sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9", + "sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234", + "sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d", + "sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5", + "sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206", + "sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9", + "sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8", + "sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59", + "sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d", + "sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7", + "sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a", + "sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0", + "sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b", + "sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d", + "sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae" + ], + "index": "pypi", + "version": "==8.1.0" + }, + "pyasn1": { + "hashes": [ + "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", + "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", + "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", + "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", + "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", + "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", + "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", + "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", + "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", + "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", + "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", + "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", + "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" + ], + "version": "==0.4.8" + }, + "pyasn1-modules": { + "hashes": [ + "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8", + "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199", + "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811", + "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed", + "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4", + "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", + "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74", + "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb", + "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45", + "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd", + "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0", + "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d", + "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405" + ], + "version": "==0.2.8" + }, + "pycrypto": { + "hashes": [ + "sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c" + ], + "index": "pypi", + "version": "==2.6.1" + }, + "python-dateutil": { + "hashes": [ + "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", + "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" + ], + "index": "pypi", + "version": "==2.8.1" + }, + "python-ldap": { + "hashes": [ + "sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==3.3.1" + }, + "pytz": { + "hashes": [ + "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da", + "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" + ], + "version": "==2021.1" + }, + "six": { + "hashes": [ + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.15.0" + }, + "smmap": { + "hashes": [ + "sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714", + "sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==3.0.5" + }, + "sqlparse": { + "hashes": [ + "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0", + "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8" + ], + "markers": "python_version >= '3.5'", + "version": "==0.4.1" + } + }, + "develop": { + "alabaster": { + "hashes": [ + "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", + "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" + ], + "version": "==0.7.12" + }, + "appdirs": { + "hashes": [ + "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", + "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" + ], + "version": "==1.4.4" + }, + "babel": { + "hashes": [ + "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5", + "sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9.0" + }, + "black": { + "hashes": [ + "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea" + ], + "index": "pypi", + "version": "==20.8b1" + }, + "certifi": { + "hashes": [ + "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", + "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" + ], + "version": "==2020.12.5" + }, + "chardet": { + "hashes": [ + "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", + "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==4.0.0" + }, + "click": { + "hashes": [ + "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", + "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==7.1.2" + }, + "coverage": { + "hashes": [ + "sha256:03ed2a641e412e42cc35c244508cf186015c217f0e4d496bf6d7078ebe837ae7", + "sha256:04b14e45d6a8e159c9767ae57ecb34563ad93440fc1b26516a89ceb5b33c1ad5", + "sha256:0cdde51bfcf6b6bd862ee9be324521ec619b20590787d1655d005c3fb175005f", + "sha256:0f48fc7dc82ee14aeaedb986e175a429d24129b7eada1b7e94a864e4f0644dde", + "sha256:107d327071061fd4f4a2587d14c389a27e4e5c93c7cba5f1f59987181903902f", + "sha256:1375bb8b88cb050a2d4e0da901001347a44302aeadb8ceb4b6e5aa373b8ea68f", + "sha256:14a9f1887591684fb59fdba8feef7123a0da2424b0652e1b58dd5b9a7bb1188c", + "sha256:16baa799ec09cc0dcb43a10680573269d407c159325972dd7114ee7649e56c66", + "sha256:1b811662ecf72eb2d08872731636aee6559cae21862c36f74703be727b45df90", + "sha256:1ccae21a076d3d5f471700f6d30eb486da1626c380b23c70ae32ab823e453337", + "sha256:2f2cf7a42d4b7654c9a67b9d091ec24374f7c58794858bff632a2039cb15984d", + "sha256:322549b880b2d746a7672bf6ff9ed3f895e9c9f108b714e7360292aa5c5d7cf4", + "sha256:32ab83016c24c5cf3db2943286b85b0a172dae08c58d0f53875235219b676409", + "sha256:3fe50f1cac369b02d34ad904dfe0771acc483f82a1b54c5e93632916ba847b37", + "sha256:4a780807e80479f281d47ee4af2eb2df3e4ccf4723484f77da0bb49d027e40a1", + "sha256:4a8eb7785bd23565b542b01fb39115a975fefb4a82f23d407503eee2c0106247", + "sha256:5bee3970617b3d74759b2d2df2f6a327d372f9732f9ccbf03fa591b5f7581e39", + "sha256:60a3307a84ec60578accd35d7f0c71a3a971430ed7eca6567399d2b50ef37b8c", + "sha256:6625e52b6f346a283c3d563d1fd8bae8956daafc64bb5bbd2b8f8a07608e3994", + "sha256:66a5aae8233d766a877c5ef293ec5ab9520929c2578fd2069308a98b7374ea8c", + "sha256:68fb816a5dd901c6aff352ce49e2a0ffadacdf9b6fae282a69e7a16a02dad5fb", + "sha256:6b588b5cf51dc0fd1c9e19f622457cc74b7d26fe295432e434525f1c0fae02bc", + "sha256:6c4d7165a4e8f41eca6b990c12ee7f44fef3932fac48ca32cecb3a1b2223c21f", + "sha256:6d2e262e5e8da6fa56e774fb8e2643417351427604c2b177f8e8c5f75fc928ca", + "sha256:6d9c88b787638a451f41f97446a1c9fd416e669b4d9717ae4615bd29de1ac135", + "sha256:755c56beeacac6a24c8e1074f89f34f4373abce8b662470d3aa719ae304931f3", + "sha256:7e40d3f8eb472c1509b12ac2a7e24158ec352fc8567b77ab02c0db053927e339", + "sha256:812eaf4939ef2284d29653bcfee9665f11f013724f07258928f849a2306ea9f9", + "sha256:84df004223fd0550d0ea7a37882e5c889f3c6d45535c639ce9802293b39cd5c9", + "sha256:859f0add98707b182b4867359e12bde806b82483fb12a9ae868a77880fc3b7af", + "sha256:87c4b38288f71acd2106f5d94f575bc2136ea2887fdb5dfe18003c881fa6b370", + "sha256:89fc12c6371bf963809abc46cced4a01ca4f99cba17be5e7d416ed7ef1245d19", + "sha256:9564ac7eb1652c3701ac691ca72934dd3009997c81266807aef924012df2f4b3", + "sha256:9754a5c265f991317de2bac0c70a746efc2b695cf4d49f5d2cddeac36544fb44", + "sha256:a565f48c4aae72d1d3d3f8e8fb7218f5609c964e9c6f68604608e5958b9c60c3", + "sha256:a636160680c6e526b84f85d304e2f0bb4e94f8284dd765a1911de9a40450b10a", + "sha256:a839e25f07e428a87d17d857d9935dd743130e77ff46524abb992b962eb2076c", + "sha256:b62046592b44263fa7570f1117d372ae3f310222af1fc1407416f037fb3af21b", + "sha256:b7f7421841f8db443855d2854e25914a79a1ff48ae92f70d0a5c2f8907ab98c9", + "sha256:ba7ca81b6d60a9f7a0b4b4e175dcc38e8fef4992673d9d6e6879fd6de00dd9b8", + "sha256:bb32ca14b4d04e172c541c69eec5f385f9a075b38fb22d765d8b0ce3af3a0c22", + "sha256:c0ff1c1b4d13e2240821ef23c1efb1f009207cb3f56e16986f713c2b0e7cd37f", + "sha256:c669b440ce46ae3abe9b2d44a913b5fd86bb19eb14a8701e88e3918902ecd345", + "sha256:c67734cff78383a1f23ceba3b3239c7deefc62ac2b05fa6a47bcd565771e5880", + "sha256:c6809ebcbf6c1049002b9ac09c127ae43929042ec1f1dbd8bb1615f7cd9f70a0", + "sha256:cd601187476c6bed26a0398353212684c427e10a903aeafa6da40c63309d438b", + "sha256:ebfa374067af240d079ef97b8064478f3bf71038b78b017eb6ec93ede1b6bcec", + "sha256:fbb17c0d0822684b7d6c09915677a32319f16ff1115df5ec05bdcaaee40b35f3", + "sha256:fff1f3a586246110f34dc762098b5afd2de88de507559e63553d7da643053786" + ], + "index": "pypi", + "version": "==5.4" + }, + "coveralls": { + "hashes": [ + "sha256:5399c0565ab822a70a477f7031f6c88a9dd196b3de2877b3facb43b51bd13434", + "sha256:f8384968c57dee4b7133ae701ecdad88e85e30597d496dcba0d7fbb470dca41f" + ], + "index": "pypi", + "version": "==3.0.0" + }, + "docopt": { + "hashes": [ + "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" + ], + "version": "==0.6.2" + }, + "docstr-coverage": { + "hashes": [ + "sha256:c5ff8d81128d2f56204fc9ecbb9c410cb18b654438d1b104868abb6ef400767e", + "sha256:ee2c043ccbc6d1847cd93616acf4ebb3e7bc53ea84434111efddae9b69f3737a" + ], + "index": "pypi", + "version": "==2.0.0" + }, + "docutils": { + "hashes": [ + "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af", + "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.16" + }, + "idna": { + "hashes": [ + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" + }, + "imagesize": { + "hashes": [ + "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1", + "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.2.0" + }, + "jinja2": { + "hashes": [ + "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", + "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.11.3" + }, + "markupsafe": { + "hashes": [ + "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", + "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", + "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", + "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", + "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f", + "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39", + "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", + "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", + "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014", + "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f", + "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", + "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", + "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", + "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", + "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", + "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", + "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85", + "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1", + "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", + "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", + "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850", + "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0", + "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", + "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb", + "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", + "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", + "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1", + "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2", + "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", + "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", + "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7", + "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8", + "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193", + "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b", + "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", + "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", + "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5", + "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c", + "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", + "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be", + "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.1.1" + }, + "mypy-extensions": { + "hashes": [ + "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", + "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" + ], + "version": "==0.4.3" + }, + "packaging": { + "hashes": [ + "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5", + "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==20.9" + }, + "pathspec": { + "hashes": [ + "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd", + "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d" + ], + "version": "==0.8.1" + }, + "pygments": { + "hashes": [ + "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435", + "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337" + ], + "markers": "python_version >= '3.5'", + "version": "==2.7.4" + }, + "pyparsing": { + "hashes": [ + "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", + "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.4.7" + }, + "pytz": { + "hashes": [ + "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da", + "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" + ], + "version": "==2021.1" + }, + "pyyaml": { + "hashes": [ + "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", + "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", + "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", + "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", + "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", + "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", + "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", + "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", + "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", + "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", + "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", + "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", + "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", + "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", + "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", + "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", + "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", + "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", + "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", + "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", + "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc" + ], + "index": "pypi", + "version": "==5.4.1" + }, + "regex": { + "hashes": [ + "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538", + "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4", + "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc", + "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa", + "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444", + "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1", + "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af", + "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8", + "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9", + "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88", + "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba", + "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364", + "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e", + "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7", + "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0", + "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31", + "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683", + "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee", + "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b", + "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884", + "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c", + "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e", + "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562", + "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85", + "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c", + "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6", + "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d", + "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b", + "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70", + "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b", + "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b", + "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f", + "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0", + "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5", + "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5", + "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f", + "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e", + "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512", + "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d", + "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917", + "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f" + ], + "version": "==2020.11.13" + }, + "requests": { + "hashes": [ + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.25.1" + }, + "rope": { + "hashes": [ + "sha256:786b5c38c530d4846aa68a42604f61b4e69a493390e3ca11b88df0fbfdc3ed04" + ], + "index": "pypi", + "version": "==0.18.0" + }, + "snowballstemmer": { + "hashes": [ + "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2", + "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914" + ], + "version": "==2.1.0" + }, + "sphinx": { + "hashes": [ + "sha256:41cad293f954f7d37f803d97eb184158cfd90f51195131e94875bc07cd08b93c", + "sha256:c314c857e7cd47c856d2c5adff514ac2e6495f8b8e0f886a8a37e9305dfea0d8" + ], + "index": "pypi", + "version": "==3.4.3" + }, + "sphinx-rtd-theme": { + "hashes": [ + "sha256:eda689eda0c7301a80cf122dad28b1861e5605cbf455558f3775e1e8200e83a5", + "sha256:fa6bebd5ab9a73da8e102509a86f3fcc36dec04a0b52ea80e5a033b2aba00113" + ], + "index": "pypi", + "version": "==0.5.1" + }, + "sphinxcontrib-applehelp": { + "hashes": [ + "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", + "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.2" + }, + "sphinxcontrib-devhelp": { + "hashes": [ + "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", + "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.2" + }, + "sphinxcontrib-htmlhelp": { + "hashes": [ + "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f", + "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.3" + }, + "sphinxcontrib-jsmath": { + "hashes": [ + "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", + "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.1" + }, + "sphinxcontrib-qthelp": { + "hashes": [ + "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", + "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.3" + }, + "sphinxcontrib-serializinghtml": { + "hashes": [ + "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc", + "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a" + ], + "markers": "python_version >= '3.5'", + "version": "==1.1.4" + }, + "toml": { + "hashes": [ + "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", + "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.10.2" + }, + "typed-ast": { + "hashes": [ + "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1", + "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d", + "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6", + "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd", + "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37", + "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151", + "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07", + "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440", + "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70", + "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496", + "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea", + "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400", + "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc", + "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606", + "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc", + "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581", + "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412", + "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a", + "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2", + "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787", + "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f", + "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937", + "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64", + "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487", + "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b", + "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41", + "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a", + "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3", + "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166", + "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10" + ], + "version": "==1.4.2" + }, + "typing-extensions": { + "hashes": [ + "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", + "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", + "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" + ], + "version": "==3.7.4.3" + }, + "urllib3": { + "hashes": [ + "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", + "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.26.3" + } + } +} diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 00000000..c1aa0101 --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1,71 @@ +# +# These requirements were autogenerated by pipenv +# To regenerate from the project's Pipfile, run: +# +# pipenv lock --requirements --dev +# + +# Note: in pipenv 2020.x, "--dev" changed to emit both default and development +# requirements. To emit only development requirements, pass "--dev-only". + +-i https://pypi.org/simple +alabaster==0.7.12 +appdirs==1.4.4 +babel==2.9.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +black==20.8b1 +certifi==2020.12.5 +chardet==4.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +click==7.1.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +coverage==5.4 +coveralls==3.0.0 +django-autocomplete-light==3.8.1 +django-bootstrap3==14.2.0 +django-ldapdb==1.5.1 +django-macaddress==1.7.0 +django-rest-framework==0.1.0 +django-reversion==3.0.9 +django==2.2.18 +djangorestframework==3.12.2; python_version >= '3.5' +docopt==0.6.2 +docstr-coverage==2.0.0 +docutils==0.16; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +gitdb==4.0.5; python_version >= '3.4' +gitpython==3.1.13 +idna==2.10; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +imagesize==1.2.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +jinja2==2.11.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +markupsafe==1.1.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +mypy-extensions==0.4.3 +mysqlclient==2.0.3 +netaddr==0.8.0 +packaging==20.9; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +pathspec==0.8.1 +pillow==8.1.0 +pyasn1-modules==0.2.8 +pyasn1==0.4.8 +pycrypto==2.6.1 +pygments==2.7.4; python_version >= '3.5' +pyparsing==2.4.7; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' +python-dateutil==2.8.1 +python-ldap==3.3.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +pytz==2021.1 +pyyaml==5.4.1 +regex==2020.11.13 +requests==2.25.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +rope==0.18.0 +six==1.15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +smmap==3.0.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +snowballstemmer==2.1.0 +sphinx-rtd-theme==0.5.1 +sphinx==3.4.3 +sphinxcontrib-applehelp==1.0.2; python_version >= '3.5' +sphinxcontrib-devhelp==1.0.2; python_version >= '3.5' +sphinxcontrib-htmlhelp==1.0.3; python_version >= '3.5' +sphinxcontrib-jsmath==1.0.1; python_version >= '3.5' +sphinxcontrib-qthelp==1.0.3; python_version >= '3.5' +sphinxcontrib-serializinghtml==1.1.4; python_version >= '3.5' +sqlparse==0.4.1; python_version >= '3.5' +toml==0.10.2; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' +typed-ast==1.4.2 +typing-extensions==3.7.4.3 +urllib3==1.26.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..f7f38e3d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,30 @@ +# +# These requirements were autogenerated by pipenv +# To regenerate from the project's Pipfile, run: +# +# pipenv lock --requirements +# + +-i https://pypi.org/simple +django-autocomplete-light==3.8.1 +django-bootstrap3==14.2.0 +django-ldapdb==1.5.1 +django-macaddress==1.7.0 +django-rest-framework==0.1.0 +django-reversion==3.0.9 +django==2.2.18 +djangorestframework==3.12.2; python_version >= '3.5' +gitdb==4.0.5; python_version >= '3.4' +gitpython==3.1.13 +mysqlclient==2.0.3 +netaddr==0.8.0 +pillow==8.1.0 +pyasn1-modules==0.2.8 +pyasn1==0.4.8 +pycrypto==2.6.1 +python-dateutil==2.8.1 +python-ldap==3.3.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +pytz==2021.1 +six==1.15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +smmap==3.0.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +sqlparse==0.4.1; python_version >= '3.5' From 7c8eabe6132695fec1160d7ab6a4588b52f2524f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Pi=C3=A9tri?= Date: Sat, 13 Feb 2021 23:01:11 +0100 Subject: [PATCH 4/7] chore: :pushpin: Use poetry instead of pipenv Pipenv doesn't seem to support extra dependencies. This commit also add requirements.txt files --- Pipfile | 31 - Pipfile.lock | 725 --------------------- dev-requirements.txt | 117 ++-- ldap-requirements.txt | 142 ++++ mysql-requirements.txt | 142 ++++ poetry.lock | 1208 +++++++++++++++++++++++++++++++++++ postgresql-requirements.txt | 142 ++++ pyproject.toml | 68 ++ requirements.txt | 172 ++++- 9 files changed, 1892 insertions(+), 855 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock create mode 100644 ldap-requirements.txt create mode 100644 mysql-requirements.txt create mode 100644 poetry.lock create mode 100644 postgresql-requirements.txt create mode 100644 pyproject.toml diff --git a/Pipfile b/Pipfile deleted file mode 100644 index fc0079e1..00000000 --- a/Pipfile +++ /dev/null @@ -1,31 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -django = "==2.2.18" -django-autocomplete-light = "*" -django-bootstrap3 = "*" -django-rest-framework = "*" -django-reversion = "*" -mysqlclient = "*" -pillow = "*" -python-dateutil = "*" -django-macaddress = "*" -pycrypto = "*" -django-ldapdb = "*" -gitpython = "*" - -[dev-packages] -sphinx = "*" -sphinx-rtd-theme = "*" -black = "*" -rope = "*" -coverage = "*" -coveralls = "*" -docstr-coverage = "*" -pyyaml = "*" - -[pipenv] -allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index b22adc23..00000000 --- a/Pipfile.lock +++ /dev/null @@ -1,725 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "7cc33c316b8ac5b326b4d196dc67ade697b6b86f339669990dbd1399de7a4ba7" - }, - "pipfile-spec": 6, - "requires": {}, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "django": { - "hashes": [ - "sha256:0eaca08f236bf502a9773e53623f766cc3ceee6453cc41e6de1c8b80f07d2364", - "sha256:c9c994f5e0a032cbd45089798b52e4080f4dea7241c58e3e0636c54146480bb4" - ], - "index": "pypi", - "version": "==2.2.18" - }, - "django-autocomplete-light": { - "hashes": [ - "sha256:4e84a6d95d272b0d7221614332e2bd54ffff15ec06e78947279398f6507ce225" - ], - "index": "pypi", - "version": "==3.8.1" - }, - "django-bootstrap3": { - "hashes": [ - "sha256:1fc3db37f29bcd159c0b00e1f15fd2d6dedf7551ce8bcca09072e33663c110de", - "sha256:c7e6912b5127bea913bc8504399613758760954140162e048184624765e61904" - ], - "index": "pypi", - "version": "==14.2.0" - }, - "django-ldapdb": { - "hashes": [ - "sha256:2daee828a7eb1ce6ad0634ce5311339d77c08128829e575ff14d62a46771b86a", - "sha256:5ea333c3130abbb86f8629766370a7f490878706469fce4e5008e41fb566392a" - ], - "index": "pypi", - "version": "==1.5.1" - }, - "django-macaddress": { - "hashes": [ - "sha256:342aa3421ee19acc3661d1705dad2ae674eaa7d06a02799f7a5dc394d6233275", - "sha256:db8beedcbd708aba3a6c9e83de6527efa2f9cc7dbe698406cebdfdbaf98c896d" - ], - "index": "pypi", - "version": "==1.7.0" - }, - "django-rest-framework": { - "hashes": [ - "sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a" - ], - "index": "pypi", - "version": "==0.1.0" - }, - "django-reversion": { - "hashes": [ - "sha256:1b57127a136b969f4b843a915c72af271febe7f336469db6c27121f8adcad35c", - "sha256:a5af55f086a3f9c38be2f049c251e06005b9ed48ba7a109473736b1fc95a066f" - ], - "index": "pypi", - "version": "==3.0.9" - }, - "djangorestframework": { - "hashes": [ - "sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7", - "sha256:0898182b4737a7b584a2c73735d89816343369f259fea932d90dc78e35d8ac33" - ], - "markers": "python_version >= '3.5'", - "version": "==3.12.2" - }, - "gitdb": { - "hashes": [ - "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac", - "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9" - ], - "markers": "python_version >= '3.4'", - "version": "==4.0.5" - }, - "gitpython": { - "hashes": [ - "sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a", - "sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29" - ], - "index": "pypi", - "version": "==3.1.13" - }, - "mysqlclient": { - "hashes": [ - "sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7", - "sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3", - "sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5", - "sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432", - "sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6" - ], - "index": "pypi", - "version": "==2.0.3" - }, - "netaddr": { - "hashes": [ - "sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac", - "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243" - ], - "version": "==0.8.0" - }, - "pillow": { - "hashes": [ - "sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6", - "sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded", - "sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865", - "sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174", - "sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032", - "sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a", - "sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e", - "sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378", - "sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17", - "sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c", - "sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913", - "sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7", - "sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0", - "sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820", - "sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba", - "sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2", - "sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b", - "sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9", - "sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234", - "sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d", - "sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5", - "sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206", - "sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9", - "sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8", - "sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59", - "sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d", - "sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7", - "sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a", - "sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0", - "sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b", - "sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d", - "sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae" - ], - "index": "pypi", - "version": "==8.1.0" - }, - "pyasn1": { - "hashes": [ - "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", - "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", - "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", - "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", - "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", - "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", - "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", - "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", - "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", - "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", - "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", - "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", - "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" - ], - "version": "==0.4.8" - }, - "pyasn1-modules": { - "hashes": [ - "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8", - "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199", - "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811", - "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed", - "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4", - "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", - "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74", - "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb", - "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45", - "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd", - "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0", - "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d", - "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405" - ], - "version": "==0.2.8" - }, - "pycrypto": { - "hashes": [ - "sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c" - ], - "index": "pypi", - "version": "==2.6.1" - }, - "python-dateutil": { - "hashes": [ - "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", - "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" - ], - "index": "pypi", - "version": "==2.8.1" - }, - "python-ldap": { - "hashes": [ - "sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==3.3.1" - }, - "pytz": { - "hashes": [ - "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da", - "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" - ], - "version": "==2021.1" - }, - "six": { - "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.15.0" - }, - "smmap": { - "hashes": [ - "sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714", - "sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==3.0.5" - }, - "sqlparse": { - "hashes": [ - "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0", - "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8" - ], - "markers": "python_version >= '3.5'", - "version": "==0.4.1" - } - }, - "develop": { - "alabaster": { - "hashes": [ - "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", - "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" - ], - "version": "==0.7.12" - }, - "appdirs": { - "hashes": [ - "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", - "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" - ], - "version": "==1.4.4" - }, - "babel": { - "hashes": [ - "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5", - "sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.9.0" - }, - "black": { - "hashes": [ - "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea" - ], - "index": "pypi", - "version": "==20.8b1" - }, - "certifi": { - "hashes": [ - "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", - "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" - ], - "version": "==2020.12.5" - }, - "chardet": { - "hashes": [ - "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", - "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.0.0" - }, - "click": { - "hashes": [ - "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", - "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==7.1.2" - }, - "coverage": { - "hashes": [ - "sha256:03ed2a641e412e42cc35c244508cf186015c217f0e4d496bf6d7078ebe837ae7", - "sha256:04b14e45d6a8e159c9767ae57ecb34563ad93440fc1b26516a89ceb5b33c1ad5", - "sha256:0cdde51bfcf6b6bd862ee9be324521ec619b20590787d1655d005c3fb175005f", - "sha256:0f48fc7dc82ee14aeaedb986e175a429d24129b7eada1b7e94a864e4f0644dde", - "sha256:107d327071061fd4f4a2587d14c389a27e4e5c93c7cba5f1f59987181903902f", - "sha256:1375bb8b88cb050a2d4e0da901001347a44302aeadb8ceb4b6e5aa373b8ea68f", - "sha256:14a9f1887591684fb59fdba8feef7123a0da2424b0652e1b58dd5b9a7bb1188c", - "sha256:16baa799ec09cc0dcb43a10680573269d407c159325972dd7114ee7649e56c66", - "sha256:1b811662ecf72eb2d08872731636aee6559cae21862c36f74703be727b45df90", - "sha256:1ccae21a076d3d5f471700f6d30eb486da1626c380b23c70ae32ab823e453337", - "sha256:2f2cf7a42d4b7654c9a67b9d091ec24374f7c58794858bff632a2039cb15984d", - "sha256:322549b880b2d746a7672bf6ff9ed3f895e9c9f108b714e7360292aa5c5d7cf4", - "sha256:32ab83016c24c5cf3db2943286b85b0a172dae08c58d0f53875235219b676409", - "sha256:3fe50f1cac369b02d34ad904dfe0771acc483f82a1b54c5e93632916ba847b37", - "sha256:4a780807e80479f281d47ee4af2eb2df3e4ccf4723484f77da0bb49d027e40a1", - "sha256:4a8eb7785bd23565b542b01fb39115a975fefb4a82f23d407503eee2c0106247", - "sha256:5bee3970617b3d74759b2d2df2f6a327d372f9732f9ccbf03fa591b5f7581e39", - "sha256:60a3307a84ec60578accd35d7f0c71a3a971430ed7eca6567399d2b50ef37b8c", - "sha256:6625e52b6f346a283c3d563d1fd8bae8956daafc64bb5bbd2b8f8a07608e3994", - "sha256:66a5aae8233d766a877c5ef293ec5ab9520929c2578fd2069308a98b7374ea8c", - "sha256:68fb816a5dd901c6aff352ce49e2a0ffadacdf9b6fae282a69e7a16a02dad5fb", - "sha256:6b588b5cf51dc0fd1c9e19f622457cc74b7d26fe295432e434525f1c0fae02bc", - "sha256:6c4d7165a4e8f41eca6b990c12ee7f44fef3932fac48ca32cecb3a1b2223c21f", - "sha256:6d2e262e5e8da6fa56e774fb8e2643417351427604c2b177f8e8c5f75fc928ca", - "sha256:6d9c88b787638a451f41f97446a1c9fd416e669b4d9717ae4615bd29de1ac135", - "sha256:755c56beeacac6a24c8e1074f89f34f4373abce8b662470d3aa719ae304931f3", - "sha256:7e40d3f8eb472c1509b12ac2a7e24158ec352fc8567b77ab02c0db053927e339", - "sha256:812eaf4939ef2284d29653bcfee9665f11f013724f07258928f849a2306ea9f9", - "sha256:84df004223fd0550d0ea7a37882e5c889f3c6d45535c639ce9802293b39cd5c9", - "sha256:859f0add98707b182b4867359e12bde806b82483fb12a9ae868a77880fc3b7af", - "sha256:87c4b38288f71acd2106f5d94f575bc2136ea2887fdb5dfe18003c881fa6b370", - "sha256:89fc12c6371bf963809abc46cced4a01ca4f99cba17be5e7d416ed7ef1245d19", - "sha256:9564ac7eb1652c3701ac691ca72934dd3009997c81266807aef924012df2f4b3", - "sha256:9754a5c265f991317de2bac0c70a746efc2b695cf4d49f5d2cddeac36544fb44", - "sha256:a565f48c4aae72d1d3d3f8e8fb7218f5609c964e9c6f68604608e5958b9c60c3", - "sha256:a636160680c6e526b84f85d304e2f0bb4e94f8284dd765a1911de9a40450b10a", - "sha256:a839e25f07e428a87d17d857d9935dd743130e77ff46524abb992b962eb2076c", - "sha256:b62046592b44263fa7570f1117d372ae3f310222af1fc1407416f037fb3af21b", - "sha256:b7f7421841f8db443855d2854e25914a79a1ff48ae92f70d0a5c2f8907ab98c9", - "sha256:ba7ca81b6d60a9f7a0b4b4e175dcc38e8fef4992673d9d6e6879fd6de00dd9b8", - "sha256:bb32ca14b4d04e172c541c69eec5f385f9a075b38fb22d765d8b0ce3af3a0c22", - "sha256:c0ff1c1b4d13e2240821ef23c1efb1f009207cb3f56e16986f713c2b0e7cd37f", - "sha256:c669b440ce46ae3abe9b2d44a913b5fd86bb19eb14a8701e88e3918902ecd345", - "sha256:c67734cff78383a1f23ceba3b3239c7deefc62ac2b05fa6a47bcd565771e5880", - "sha256:c6809ebcbf6c1049002b9ac09c127ae43929042ec1f1dbd8bb1615f7cd9f70a0", - "sha256:cd601187476c6bed26a0398353212684c427e10a903aeafa6da40c63309d438b", - "sha256:ebfa374067af240d079ef97b8064478f3bf71038b78b017eb6ec93ede1b6bcec", - "sha256:fbb17c0d0822684b7d6c09915677a32319f16ff1115df5ec05bdcaaee40b35f3", - "sha256:fff1f3a586246110f34dc762098b5afd2de88de507559e63553d7da643053786" - ], - "index": "pypi", - "version": "==5.4" - }, - "coveralls": { - "hashes": [ - "sha256:5399c0565ab822a70a477f7031f6c88a9dd196b3de2877b3facb43b51bd13434", - "sha256:f8384968c57dee4b7133ae701ecdad88e85e30597d496dcba0d7fbb470dca41f" - ], - "index": "pypi", - "version": "==3.0.0" - }, - "docopt": { - "hashes": [ - "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" - ], - "version": "==0.6.2" - }, - "docstr-coverage": { - "hashes": [ - "sha256:c5ff8d81128d2f56204fc9ecbb9c410cb18b654438d1b104868abb6ef400767e", - "sha256:ee2c043ccbc6d1847cd93616acf4ebb3e7bc53ea84434111efddae9b69f3737a" - ], - "index": "pypi", - "version": "==2.0.0" - }, - "docutils": { - "hashes": [ - "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af", - "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.16" - }, - "idna": { - "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.10" - }, - "imagesize": { - "hashes": [ - "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1", - "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.2.0" - }, - "jinja2": { - "hashes": [ - "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", - "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.11.3" - }, - "markupsafe": { - "hashes": [ - "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", - "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", - "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", - "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", - "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", - "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f", - "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39", - "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", - "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", - "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014", - "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f", - "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", - "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", - "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", - "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", - "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", - "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", - "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", - "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", - "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85", - "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1", - "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", - "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", - "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", - "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850", - "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0", - "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", - "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", - "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb", - "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", - "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", - "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", - "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1", - "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2", - "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", - "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", - "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", - "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7", - "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", - "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8", - "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", - "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193", - "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", - "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b", - "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", - "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5", - "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c", - "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", - "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be", - "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.1.1" - }, - "mypy-extensions": { - "hashes": [ - "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", - "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" - ], - "version": "==0.4.3" - }, - "packaging": { - "hashes": [ - "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5", - "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.9" - }, - "pathspec": { - "hashes": [ - "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd", - "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d" - ], - "version": "==0.8.1" - }, - "pygments": { - "hashes": [ - "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435", - "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337" - ], - "markers": "python_version >= '3.5'", - "version": "==2.7.4" - }, - "pyparsing": { - "hashes": [ - "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", - "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.7" - }, - "pytz": { - "hashes": [ - "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da", - "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" - ], - "version": "==2021.1" - }, - "pyyaml": { - "hashes": [ - "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", - "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", - "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", - "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", - "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", - "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", - "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", - "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", - "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", - "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", - "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", - "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", - "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", - "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", - "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", - "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", - "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", - "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", - "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", - "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", - "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc" - ], - "index": "pypi", - "version": "==5.4.1" - }, - "regex": { - "hashes": [ - "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538", - "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4", - "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc", - "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa", - "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444", - "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1", - "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af", - "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8", - "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9", - "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88", - "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba", - "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364", - "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e", - "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7", - "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0", - "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31", - "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683", - "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee", - "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b", - "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884", - "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c", - "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e", - "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562", - "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85", - "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c", - "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6", - "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d", - "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b", - "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70", - "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b", - "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b", - "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f", - "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0", - "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5", - "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5", - "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f", - "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e", - "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512", - "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d", - "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917", - "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f" - ], - "version": "==2020.11.13" - }, - "requests": { - "hashes": [ - "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", - "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.25.1" - }, - "rope": { - "hashes": [ - "sha256:786b5c38c530d4846aa68a42604f61b4e69a493390e3ca11b88df0fbfdc3ed04" - ], - "index": "pypi", - "version": "==0.18.0" - }, - "snowballstemmer": { - "hashes": [ - "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2", - "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914" - ], - "version": "==2.1.0" - }, - "sphinx": { - "hashes": [ - "sha256:41cad293f954f7d37f803d97eb184158cfd90f51195131e94875bc07cd08b93c", - "sha256:c314c857e7cd47c856d2c5adff514ac2e6495f8b8e0f886a8a37e9305dfea0d8" - ], - "index": "pypi", - "version": "==3.4.3" - }, - "sphinx-rtd-theme": { - "hashes": [ - "sha256:eda689eda0c7301a80cf122dad28b1861e5605cbf455558f3775e1e8200e83a5", - "sha256:fa6bebd5ab9a73da8e102509a86f3fcc36dec04a0b52ea80e5a033b2aba00113" - ], - "index": "pypi", - "version": "==0.5.1" - }, - "sphinxcontrib-applehelp": { - "hashes": [ - "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", - "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.2" - }, - "sphinxcontrib-devhelp": { - "hashes": [ - "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", - "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.2" - }, - "sphinxcontrib-htmlhelp": { - "hashes": [ - "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f", - "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.3" - }, - "sphinxcontrib-jsmath": { - "hashes": [ - "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", - "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.1" - }, - "sphinxcontrib-qthelp": { - "hashes": [ - "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", - "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.3" - }, - "sphinxcontrib-serializinghtml": { - "hashes": [ - "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc", - "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a" - ], - "markers": "python_version >= '3.5'", - "version": "==1.1.4" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, - "typed-ast": { - "hashes": [ - "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1", - "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d", - "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6", - "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd", - "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37", - "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151", - "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07", - "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440", - "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70", - "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496", - "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea", - "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400", - "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc", - "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606", - "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc", - "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581", - "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412", - "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a", - "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2", - "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787", - "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f", - "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937", - "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64", - "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487", - "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b", - "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41", - "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a", - "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3", - "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166", - "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10" - ], - "version": "==1.4.2" - }, - "typing-extensions": { - "hashes": [ - "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", - "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", - "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" - ], - "version": "==3.7.4.3" - }, - "urllib3": { - "hashes": [ - "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", - "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.3" - } - } -} diff --git a/dev-requirements.txt b/dev-requirements.txt index c1aa0101..595c946b 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,71 +1,50 @@ -# -# These requirements were autogenerated by pipenv -# To regenerate from the project's Pipfile, run: -# -# pipenv lock --requirements --dev -# -# Note: in pipenv 2020.x, "--dev" changed to emit both default and development -# requirements. To emit only development requirements, pass "--dev-only". + Stack trace: --i https://pypi.org/simple -alabaster==0.7.12 -appdirs==1.4.4 -babel==2.9.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -black==20.8b1 -certifi==2020.12.5 -chardet==4.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -click==7.1.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -coverage==5.4 -coveralls==3.0.0 -django-autocomplete-light==3.8.1 -django-bootstrap3==14.2.0 -django-ldapdb==1.5.1 -django-macaddress==1.7.0 -django-rest-framework==0.1.0 -django-reversion==3.0.9 -django==2.2.18 -djangorestframework==3.12.2; python_version >= '3.5' -docopt==0.6.2 -docstr-coverage==2.0.0 -docutils==0.16; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -gitdb==4.0.5; python_version >= '3.4' -gitpython==3.1.13 -idna==2.10; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -imagesize==1.2.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -jinja2==2.11.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -markupsafe==1.1.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -mypy-extensions==0.4.3 -mysqlclient==2.0.3 -netaddr==0.8.0 -packaging==20.9; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -pathspec==0.8.1 -pillow==8.1.0 -pyasn1-modules==0.2.8 -pyasn1==0.4.8 -pycrypto==2.6.1 -pygments==2.7.4; python_version >= '3.5' -pyparsing==2.4.7; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' -python-dateutil==2.8.1 -python-ldap==3.3.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -pytz==2021.1 -pyyaml==5.4.1 -regex==2020.11.13 -requests==2.25.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -rope==0.18.0 -six==1.15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -smmap==3.0.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -snowballstemmer==2.1.0 -sphinx-rtd-theme==0.5.1 -sphinx==3.4.3 -sphinxcontrib-applehelp==1.0.2; python_version >= '3.5' -sphinxcontrib-devhelp==1.0.2; python_version >= '3.5' -sphinxcontrib-htmlhelp==1.0.3; python_version >= '3.5' -sphinxcontrib-jsmath==1.0.1; python_version >= '3.5' -sphinxcontrib-qthelp==1.0.3; python_version >= '3.5' -sphinxcontrib-serializinghtml==1.1.4; python_version >= '3.5' -sqlparse==0.4.1; python_version >= '3.5' -toml==0.10.2; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' -typed-ast==1.4.2 -typing-extensions==3.7.4.3 -urllib3==1.26.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' + 11 /usr/lib/python3.9/site-packages/clikit/console_application.py:123 in run + io = io_factory( + + 10 /usr/lib/python3.9/site-packages/poetry/console/config/application_config.py:221 in create_io + resolved_command = application.resolve_command(args) + + 9 /usr/lib/python3.9/site-packages/clikit/console_application.py:110 in resolve_command + return self._config.command_resolver.resolve(args, self) + + 8 /usr/lib/python3.9/site-packages/clikit/resolver/default_resolver.py:34 in resolve + return self.create_resolved_command(result) + + 7 /usr/lib/python3.9/site-packages/clikit/resolver/default_resolver.py:166 in create_resolved_command + if not result.is_parsable(): + + 6 /usr/lib/python3.9/site-packages/clikit/resolver/resolve_result.py:43 in is_parsable + self._parse() + + 5 /usr/lib/python3.9/site-packages/clikit/resolver/resolve_result.py:49 in _parse + self._parsed_args = self._command.parse(self._raw_args) + + 4 /usr/lib/python3.9/site-packages/clikit/api/command/command.py:113 in parse + return self._config.args_parser.parse(args, self._args_format, lenient) + + 3 /usr/lib/python3.9/site-packages/clikit/args/default_args_parser.py:53 in parse + self._parse(args, _fmt, lenient) + + 2 /usr/lib/python3.9/site-packages/clikit/args/default_args_parser.py:103 in _parse + self._parse_short_option(token, tokens, fmt, lenient) + + 1 /usr/lib/python3.9/site-packages/clikit/args/default_args_parser.py:272 in _parse_short_option + self._add_short_option(name, None, tokens, fmt, lenient) + + NoSuchOptionException + + The "-D" option does not exist. + + at /usr/lib/python3.9/site-packages/clikit/args/default_args_parser.py:349 in _add_short_option + 345│ def _add_short_option( + 346│ self, name, value, tokens, fmt, lenient + 347│ ): # type: (str, Optional[str], List[str], ArgsFormat, bool) -> None + 348│ if not fmt.has_option(name): + → 349│ raise NoSuchOptionException(name) + 350│ + 351│ self._add_long_option( + 352│ fmt.get_option(name).long_name, value, tokens, fmt, lenient + 353│ ) diff --git a/ldap-requirements.txt b/ldap-requirements.txt new file mode 100644 index 00000000..ead30d77 --- /dev/null +++ b/ldap-requirements.txt @@ -0,0 +1,142 @@ +django-autocomplete-light==3.8.1 \ + --hash=sha256:4e84a6d95d272b0d7221614332e2bd54ffff15ec06e78947279398f6507ce225 +django-bootstrap3==14.2.0; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:1fc3db37f29bcd159c0b00e1f15fd2d6dedf7551ce8bcca09072e33663c110de \ + --hash=sha256:c7e6912b5127bea913bc8504399613758760954140162e048184624765e61904 +django-ldapdb==1.5.1; python_version >= "3.6" \ + --hash=sha256:5ea333c3130abbb86f8629766370a7f490878706469fce4e5008e41fb566392a \ + --hash=sha256:2daee828a7eb1ce6ad0634ce5311339d77c08128829e575ff14d62a46771b86a +django-macaddress==1.7.0 \ + --hash=sha256:342aa3421ee19acc3661d1705dad2ae674eaa7d06a02799f7a5dc394d6233275 \ + --hash=sha256:db8beedcbd708aba3a6c9e83de6527efa2f9cc7dbe698406cebdfdbaf98c896d +django-rest-framework==0.1.0 \ + --hash=sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a +django-reversion==3.0.9; python_version >= "3.6" \ + --hash=sha256:a5af55f086a3f9c38be2f049c251e06005b9ed48ba7a109473736b1fc95a066f \ + --hash=sha256:1b57127a136b969f4b843a915c72af271febe7f336469db6c27121f8adcad35c +django==2.2.18; python_version >= "3.5" \ + --hash=sha256:0eaca08f236bf502a9773e53623f766cc3ceee6453cc41e6de1c8b80f07d2364 \ + --hash=sha256:c9c994f5e0a032cbd45089798b52e4080f4dea7241c58e3e0636c54146480bb4 +djangorestframework==3.12.2; python_version >= "3.5" \ + --hash=sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7 \ + --hash=sha256:0898182b4737a7b584a2c73735d89816343369f259fea932d90dc78e35d8ac33 +gitdb==4.0.5; python_version >= "3.4" \ + --hash=sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac \ + --hash=sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9 +gitpython==3.1.13; python_version >= "3.4" \ + --hash=sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29 \ + --hash=sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a +importlib-metadata==1.7.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_version < "3.8" and python_full_version >= "3.5.0" \ + --hash=sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070 \ + --hash=sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83 +importlib-resources==5.1.0; python_version >= "3.6" and python_version < "3.7" \ + --hash=sha256:885b8eae589179f661c909d699a546cf10d83692553e34dca1bf5eb06f7f6217 \ + --hash=sha256:bfdad047bce441405a49cf8eb48ddce5e56c696e185f59147a8b79e75e9e6380 +mysqlclient==2.0.3; python_version >= "3.5" \ + --hash=sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3 \ + --hash=sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7 \ + --hash=sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5 \ + --hash=sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6 \ + --hash=sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432 +netaddr==0.8.0 \ + --hash=sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac \ + --hash=sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243 +pillow==8.1.0; python_version >= "3.6" \ + --hash=sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a \ + --hash=sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2 \ + --hash=sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174 \ + --hash=sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded \ + --hash=sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d \ + --hash=sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d \ + --hash=sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234 \ + --hash=sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8 \ + --hash=sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17 \ + --hash=sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7 \ + --hash=sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e \ + --hash=sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b \ + --hash=sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0 \ + --hash=sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a \ + --hash=sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d \ + --hash=sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae \ + --hash=sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59 \ + --hash=sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c \ + --hash=sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6 \ + --hash=sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378 \ + --hash=sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7 \ + --hash=sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0 \ + --hash=sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b \ + --hash=sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865 \ + --hash=sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9 \ + --hash=sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913 \ + --hash=sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206 \ + --hash=sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9 \ + --hash=sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032 \ + --hash=sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820 \ + --hash=sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5 \ + --hash=sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba +psycopg2==2.8.6; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \ + --hash=sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725 \ + --hash=sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5 \ + --hash=sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad \ + --hash=sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3 \ + --hash=sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821 \ + --hash=sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301 \ + --hash=sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a \ + --hash=sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d \ + --hash=sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84 \ + --hash=sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5 \ + --hash=sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e \ + --hash=sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051 \ + --hash=sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3 \ + --hash=sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7 \ + --hash=sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543 +pyasn1-modules==0.2.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199 \ + --hash=sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405 \ + --hash=sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb \ + --hash=sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8 \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 \ + --hash=sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d \ + --hash=sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45 \ + --hash=sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4 \ + --hash=sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811 \ + --hash=sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed \ + --hash=sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0 \ + --hash=sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd +pyasn1==0.4.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3 \ + --hash=sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf \ + --hash=sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00 \ + --hash=sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86 \ + --hash=sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7 \ + --hash=sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576 \ + --hash=sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12 \ + --hash=sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2 \ + --hash=sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359 \ + --hash=sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776 \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba +pycrypto==2.6.1 \ + --hash=sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c +python-dateutil==2.8.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +python-ldap==3.3.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5 +pytz==2021.1; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 \ + --hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da +six==1.15.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 +smmap==3.0.5; python_version >= "3.4" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.4" \ + --hash=sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714 \ + --hash=sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50 +sqlparse==0.4.1; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0 \ + --hash=sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8 +zipp==3.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.5.0" \ + --hash=sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108 \ + --hash=sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb diff --git a/mysql-requirements.txt b/mysql-requirements.txt new file mode 100644 index 00000000..ead30d77 --- /dev/null +++ b/mysql-requirements.txt @@ -0,0 +1,142 @@ +django-autocomplete-light==3.8.1 \ + --hash=sha256:4e84a6d95d272b0d7221614332e2bd54ffff15ec06e78947279398f6507ce225 +django-bootstrap3==14.2.0; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:1fc3db37f29bcd159c0b00e1f15fd2d6dedf7551ce8bcca09072e33663c110de \ + --hash=sha256:c7e6912b5127bea913bc8504399613758760954140162e048184624765e61904 +django-ldapdb==1.5.1; python_version >= "3.6" \ + --hash=sha256:5ea333c3130abbb86f8629766370a7f490878706469fce4e5008e41fb566392a \ + --hash=sha256:2daee828a7eb1ce6ad0634ce5311339d77c08128829e575ff14d62a46771b86a +django-macaddress==1.7.0 \ + --hash=sha256:342aa3421ee19acc3661d1705dad2ae674eaa7d06a02799f7a5dc394d6233275 \ + --hash=sha256:db8beedcbd708aba3a6c9e83de6527efa2f9cc7dbe698406cebdfdbaf98c896d +django-rest-framework==0.1.0 \ + --hash=sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a +django-reversion==3.0.9; python_version >= "3.6" \ + --hash=sha256:a5af55f086a3f9c38be2f049c251e06005b9ed48ba7a109473736b1fc95a066f \ + --hash=sha256:1b57127a136b969f4b843a915c72af271febe7f336469db6c27121f8adcad35c +django==2.2.18; python_version >= "3.5" \ + --hash=sha256:0eaca08f236bf502a9773e53623f766cc3ceee6453cc41e6de1c8b80f07d2364 \ + --hash=sha256:c9c994f5e0a032cbd45089798b52e4080f4dea7241c58e3e0636c54146480bb4 +djangorestframework==3.12.2; python_version >= "3.5" \ + --hash=sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7 \ + --hash=sha256:0898182b4737a7b584a2c73735d89816343369f259fea932d90dc78e35d8ac33 +gitdb==4.0.5; python_version >= "3.4" \ + --hash=sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac \ + --hash=sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9 +gitpython==3.1.13; python_version >= "3.4" \ + --hash=sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29 \ + --hash=sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a +importlib-metadata==1.7.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_version < "3.8" and python_full_version >= "3.5.0" \ + --hash=sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070 \ + --hash=sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83 +importlib-resources==5.1.0; python_version >= "3.6" and python_version < "3.7" \ + --hash=sha256:885b8eae589179f661c909d699a546cf10d83692553e34dca1bf5eb06f7f6217 \ + --hash=sha256:bfdad047bce441405a49cf8eb48ddce5e56c696e185f59147a8b79e75e9e6380 +mysqlclient==2.0.3; python_version >= "3.5" \ + --hash=sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3 \ + --hash=sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7 \ + --hash=sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5 \ + --hash=sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6 \ + --hash=sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432 +netaddr==0.8.0 \ + --hash=sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac \ + --hash=sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243 +pillow==8.1.0; python_version >= "3.6" \ + --hash=sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a \ + --hash=sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2 \ + --hash=sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174 \ + --hash=sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded \ + --hash=sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d \ + --hash=sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d \ + --hash=sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234 \ + --hash=sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8 \ + --hash=sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17 \ + --hash=sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7 \ + --hash=sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e \ + --hash=sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b \ + --hash=sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0 \ + --hash=sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a \ + --hash=sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d \ + --hash=sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae \ + --hash=sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59 \ + --hash=sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c \ + --hash=sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6 \ + --hash=sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378 \ + --hash=sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7 \ + --hash=sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0 \ + --hash=sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b \ + --hash=sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865 \ + --hash=sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9 \ + --hash=sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913 \ + --hash=sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206 \ + --hash=sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9 \ + --hash=sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032 \ + --hash=sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820 \ + --hash=sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5 \ + --hash=sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba +psycopg2==2.8.6; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \ + --hash=sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725 \ + --hash=sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5 \ + --hash=sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad \ + --hash=sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3 \ + --hash=sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821 \ + --hash=sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301 \ + --hash=sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a \ + --hash=sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d \ + --hash=sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84 \ + --hash=sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5 \ + --hash=sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e \ + --hash=sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051 \ + --hash=sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3 \ + --hash=sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7 \ + --hash=sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543 +pyasn1-modules==0.2.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199 \ + --hash=sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405 \ + --hash=sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb \ + --hash=sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8 \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 \ + --hash=sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d \ + --hash=sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45 \ + --hash=sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4 \ + --hash=sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811 \ + --hash=sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed \ + --hash=sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0 \ + --hash=sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd +pyasn1==0.4.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3 \ + --hash=sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf \ + --hash=sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00 \ + --hash=sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86 \ + --hash=sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7 \ + --hash=sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576 \ + --hash=sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12 \ + --hash=sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2 \ + --hash=sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359 \ + --hash=sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776 \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba +pycrypto==2.6.1 \ + --hash=sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c +python-dateutil==2.8.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +python-ldap==3.3.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5 +pytz==2021.1; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 \ + --hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da +six==1.15.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 +smmap==3.0.5; python_version >= "3.4" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.4" \ + --hash=sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714 \ + --hash=sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50 +sqlparse==0.4.1; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0 \ + --hash=sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8 +zipp==3.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.5.0" \ + --hash=sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108 \ + --hash=sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..7a1ec92b --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1208 @@ +[[package]] +name = "alabaster" +version = "0.7.12" +description = "A configurable sidebar-enabled Sphinx theme" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "babel" +version = "2.9.0" +description = "Internationalization utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +pytz = ">=2015.7" + +[[package]] +name = "black" +version = "20.8b1" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +appdirs = "*" +click = ">=7.1.2" +dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} +mypy-extensions = ">=0.4.3" +pathspec = ">=0.6,<1" +regex = ">=2020.1.8" +toml = ">=0.10.1" +typed-ast = ">=1.4.0" +typing-extensions = ">=3.7.4" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] + +[[package]] +name = "certifi" +version = "2020.12.5" +description = "Python package for providing Mozilla's CA Bundle." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "chardet" +version = "4.0.0" +description = "Universal encoding detector for Python 2 and 3" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "click" +version = "7.1.2" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "coverage" +version = "5.4" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +toml = ["toml"] + +[[package]] +name = "dataclasses" +version = "0.8" +description = "A backport of the dataclasses module for Python 3.6" +category = "dev" +optional = false +python-versions = ">=3.6, <3.7" + +[[package]] +name = "django" +version = "2.2.18" +description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +pytz = "*" +sqlparse = ">=0.2.2" + +[package.extras] +argon2 = ["argon2-cffi (>=16.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "django-autocomplete-light" +version = "3.8.1" +description = "Fresh autocompletes for Django" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" + +[package.extras] +genericm2m = ["django-generic-m2m"] +gfk = ["django-querysetsequence (>=0.11)"] +nested = ["django-nested-admin (>=3.0.21)"] +tags = ["django-taggit"] + +[[package]] +name = "django-bootstrap3" +version = "14.2.0" +description = "Bootstrap 3 support for Django projects" +category = "main" +optional = false +python-versions = ">=3.6,<4.0" + +[package.dependencies] +django = ">=2.2,<4.0" +importlib-metadata = {version = ">=1.5.0,<2.0.0", markers = "python_version < \"3.8\""} + +[package.extras] +docs = ["sphinx (>=2.4,<3.0)", "sphinx_rtd_theme (>=0.4.3,<0.5.0)", "m2r2 (>=0.2.5,<0.3.0)"] + +[[package]] +name = "django-ldapdb" +version = "1.5.1" +description = "A LDAP database backend for Django" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +Django = ">=2.2" +python-ldap = ">=3.0" + +[package.extras] +dev = ["check-manifest", "flake8", "isort (>=5.0.0)", "tox", "factory-boy", "volatildap (>=1.1.0)", "wheel", "zest.releaser"] + +[[package]] +name = "django-macaddress" +version = "1.7.0" +description = "MAC address model and form fields for Django apps." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +netaddr = "*" + +[[package]] +name = "django-rest-framework" +version = "0.1.0" +description = "alias." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +djangorestframework = "*" + +[[package]] +name = "django-reversion" +version = "3.0.9" +description = "An extension to the Django web framework that provides version control for model instances." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +django = ">=1.11" + +[[package]] +name = "djangorestframework" +version = "3.12.2" +description = "Web APIs for Django, made easy." +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +django = ">=2.2" + +[[package]] +name = "docstr-coverage" +version = "2.0.0" +description = "Utility for examining python source files to ensure proper documentation. Lists missing docstrings, and calculates overall docstring coverage percentage rating." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +click = "*" +PyYAML = "*" + +[package.extras] +lint = ["flake8 (==3.8.2)", "black (==19.10b0)", "isort (==5.6.4)"] +test = ["pytest (==5.4.2)", "pytest-mock (==3.4.0)"] + +[[package]] +name = "docutils" +version = "0.16" +description = "Docutils -- Python Documentation Utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "gitdb" +version = "4.0.5" +description = "Git Object Database" +category = "main" +optional = false +python-versions = ">=3.4" + +[package.dependencies] +smmap = ">=3.0.1,<4" + +[[package]] +name = "gitpython" +version = "3.1.13" +description = "Python Git Library" +category = "main" +optional = false +python-versions = ">=3.4" + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[[package]] +name = "idna" +version = "2.10" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "imagesize" +version = "1.2.0" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "importlib-metadata" +version = "1.7.0" +description = "Read metadata from Python packages" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "rst.linker"] +testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] + +[[package]] +name = "importlib-resources" +version = "5.1.0" +description = "Read resources from Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +zipp = {version = ">=0.4", markers = "python_version < \"3.8\""} + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[[package]] +name = "jinja2" +version = "2.11.3" +description = "A very fast and expressive template engine." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +MarkupSafe = ">=0.23" + +[package.extras] +i18n = ["Babel (>=0.8)"] + +[[package]] +name = "markupsafe" +version = "1.1.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "mysqlclient" +version = "2.0.3" +description = "Python interface to MySQL" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "netaddr" +version = "0.8.0" +description = "A network address manipulation library for Python" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +importlib-resources = {version = "*", markers = "python_version < \"3.7\""} + +[[package]] +name = "packaging" +version = "20.9" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +pyparsing = ">=2.0.2" + +[[package]] +name = "pathspec" +version = "0.8.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pillow" +version = "8.1.0" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "psycopg2" +version = "2.8.6" +description = "psycopg2 - Python-PostgreSQL Database Adapter" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[[package]] +name = "pyasn1" +version = "0.4.8" +description = "ASN.1 types and codecs" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyasn1-modules" +version = "0.2.8" +description = "A collection of ASN.1-based protocols modules." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pyasn1 = ">=0.4.6,<0.5.0" + +[[package]] +name = "pycrypto" +version = "2.6.1" +description = "Cryptographic modules for Python." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pygments" +version = "2.7.4" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "python-dateutil" +version = "2.8.1" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-ldap" +version = "3.3.1" +description = "Python modules for implementing LDAP clients" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +pyasn1 = ">=0.3.7" +pyasn1_modules = ">=0.1.5" + +[[package]] +name = "pytz" +version = "2021.1" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyyaml" +version = "5.4.1" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[[package]] +name = "regex" +version = "2020.11.13" +description = "Alternative regular expression module, to replace re." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "requests" +version = "2.25.1" +description = "Python HTTP for Humans." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +certifi = ">=2017.4.17" +chardet = ">=3.0.2,<5" +idna = ">=2.5,<3" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] + +[[package]] +name = "rope" +version = "0.18.0" +description = "a python refactoring library..." +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +dev = ["pytest"] + +[[package]] +name = "six" +version = "1.15.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "smmap" +version = "3.0.5" +description = "A pure Python implementation of a sliding window memory map manager" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "snowballstemmer" +version = "2.1.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "sphinx" +version = "3.4.3" +description = "Python documentation generator" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +alabaster = ">=0.7,<0.8" +babel = ">=1.3" +colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.12" +imagesize = "*" +Jinja2 = ">=2.3" +packaging = "*" +Pygments = ">=2.0" +requests = ">=2.5.0" +snowballstemmer = ">=1.1" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = "*" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = "*" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.790)", "docutils-stubs"] +test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] + +[[package]] +name = "sphinx-rtd-theme" +version = "0.5.1" +description = "Read the Docs theme for Sphinx" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +sphinx = "*" + +[package.extras] +dev = ["transifex-client", "sphinxcontrib-httpdomain", "bump2version"] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "1.0.2" +description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "1.0.2" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "1.0.3" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest", "html5lib"] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +test = ["pytest", "flake8", "mypy"] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.3" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "1.1.4" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] + +[[package]] +name = "sqlparse" +version = "0.4.1" +description = "A non-validating SQL parser." +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "typed-ast" +version = "1.4.2" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "typing-extensions" +version = "3.7.4.3" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "urllib3" +version = "1.26.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "zipp" +version = "3.4.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[metadata] +lock-version = "1.1" +python-versions = ">=3.6,<4.0" +content-hash = "2b09b64cff09acd37cc7aef057626140845e0a60f2658a4bf45a6eea443d1b09" + +[metadata.files] +alabaster = [ + {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, + {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, +] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] +babel = [ + {file = "Babel-2.9.0-py2.py3-none-any.whl", hash = "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5"}, + {file = "Babel-2.9.0.tar.gz", hash = "sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05"}, +] +black = [ + {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, +] +certifi = [ + {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, + {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, +] +chardet = [ + {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, + {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, +] +click = [ + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +coverage = [ + {file = "coverage-5.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:6d9c88b787638a451f41f97446a1c9fd416e669b4d9717ae4615bd29de1ac135"}, + {file = "coverage-5.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:66a5aae8233d766a877c5ef293ec5ab9520929c2578fd2069308a98b7374ea8c"}, + {file = "coverage-5.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9754a5c265f991317de2bac0c70a746efc2b695cf4d49f5d2cddeac36544fb44"}, + {file = "coverage-5.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:fbb17c0d0822684b7d6c09915677a32319f16ff1115df5ec05bdcaaee40b35f3"}, + {file = "coverage-5.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b7f7421841f8db443855d2854e25914a79a1ff48ae92f70d0a5c2f8907ab98c9"}, + {file = "coverage-5.4-cp27-cp27m-win32.whl", hash = "sha256:4a780807e80479f281d47ee4af2eb2df3e4ccf4723484f77da0bb49d027e40a1"}, + {file = "coverage-5.4-cp27-cp27m-win_amd64.whl", hash = "sha256:87c4b38288f71acd2106f5d94f575bc2136ea2887fdb5dfe18003c881fa6b370"}, + {file = "coverage-5.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c6809ebcbf6c1049002b9ac09c127ae43929042ec1f1dbd8bb1615f7cd9f70a0"}, + {file = "coverage-5.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ba7ca81b6d60a9f7a0b4b4e175dcc38e8fef4992673d9d6e6879fd6de00dd9b8"}, + {file = "coverage-5.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:89fc12c6371bf963809abc46cced4a01ca4f99cba17be5e7d416ed7ef1245d19"}, + {file = "coverage-5.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a8eb7785bd23565b542b01fb39115a975fefb4a82f23d407503eee2c0106247"}, + {file = "coverage-5.4-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:7e40d3f8eb472c1509b12ac2a7e24158ec352fc8567b77ab02c0db053927e339"}, + {file = "coverage-5.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1ccae21a076d3d5f471700f6d30eb486da1626c380b23c70ae32ab823e453337"}, + {file = "coverage-5.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:755c56beeacac6a24c8e1074f89f34f4373abce8b662470d3aa719ae304931f3"}, + {file = "coverage-5.4-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:322549b880b2d746a7672bf6ff9ed3f895e9c9f108b714e7360292aa5c5d7cf4"}, + {file = "coverage-5.4-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:60a3307a84ec60578accd35d7f0c71a3a971430ed7eca6567399d2b50ef37b8c"}, + {file = "coverage-5.4-cp35-cp35m-win32.whl", hash = "sha256:1375bb8b88cb050a2d4e0da901001347a44302aeadb8ceb4b6e5aa373b8ea68f"}, + {file = "coverage-5.4-cp35-cp35m-win_amd64.whl", hash = "sha256:16baa799ec09cc0dcb43a10680573269d407c159325972dd7114ee7649e56c66"}, + {file = "coverage-5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2f2cf7a42d4b7654c9a67b9d091ec24374f7c58794858bff632a2039cb15984d"}, + {file = "coverage-5.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b62046592b44263fa7570f1117d372ae3f310222af1fc1407416f037fb3af21b"}, + {file = "coverage-5.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:812eaf4939ef2284d29653bcfee9665f11f013724f07258928f849a2306ea9f9"}, + {file = "coverage-5.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:859f0add98707b182b4867359e12bde806b82483fb12a9ae868a77880fc3b7af"}, + {file = "coverage-5.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:04b14e45d6a8e159c9767ae57ecb34563ad93440fc1b26516a89ceb5b33c1ad5"}, + {file = "coverage-5.4-cp36-cp36m-win32.whl", hash = "sha256:ebfa374067af240d079ef97b8064478f3bf71038b78b017eb6ec93ede1b6bcec"}, + {file = "coverage-5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:84df004223fd0550d0ea7a37882e5c889f3c6d45535c639ce9802293b39cd5c9"}, + {file = "coverage-5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1b811662ecf72eb2d08872731636aee6559cae21862c36f74703be727b45df90"}, + {file = "coverage-5.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6b588b5cf51dc0fd1c9e19f622457cc74b7d26fe295432e434525f1c0fae02bc"}, + {file = "coverage-5.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:3fe50f1cac369b02d34ad904dfe0771acc483f82a1b54c5e93632916ba847b37"}, + {file = "coverage-5.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:32ab83016c24c5cf3db2943286b85b0a172dae08c58d0f53875235219b676409"}, + {file = "coverage-5.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:68fb816a5dd901c6aff352ce49e2a0ffadacdf9b6fae282a69e7a16a02dad5fb"}, + {file = "coverage-5.4-cp37-cp37m-win32.whl", hash = "sha256:a636160680c6e526b84f85d304e2f0bb4e94f8284dd765a1911de9a40450b10a"}, + {file = "coverage-5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:bb32ca14b4d04e172c541c69eec5f385f9a075b38fb22d765d8b0ce3af3a0c22"}, + {file = "coverage-5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4d7165a4e8f41eca6b990c12ee7f44fef3932fac48ca32cecb3a1b2223c21f"}, + {file = "coverage-5.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a565f48c4aae72d1d3d3f8e8fb7218f5609c964e9c6f68604608e5958b9c60c3"}, + {file = "coverage-5.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fff1f3a586246110f34dc762098b5afd2de88de507559e63553d7da643053786"}, + {file = "coverage-5.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a839e25f07e428a87d17d857d9935dd743130e77ff46524abb992b962eb2076c"}, + {file = "coverage-5.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:6625e52b6f346a283c3d563d1fd8bae8956daafc64bb5bbd2b8f8a07608e3994"}, + {file = "coverage-5.4-cp38-cp38-win32.whl", hash = "sha256:5bee3970617b3d74759b2d2df2f6a327d372f9732f9ccbf03fa591b5f7581e39"}, + {file = "coverage-5.4-cp38-cp38-win_amd64.whl", hash = "sha256:03ed2a641e412e42cc35c244508cf186015c217f0e4d496bf6d7078ebe837ae7"}, + {file = "coverage-5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14a9f1887591684fb59fdba8feef7123a0da2424b0652e1b58dd5b9a7bb1188c"}, + {file = "coverage-5.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9564ac7eb1652c3701ac691ca72934dd3009997c81266807aef924012df2f4b3"}, + {file = "coverage-5.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:0f48fc7dc82ee14aeaedb986e175a429d24129b7eada1b7e94a864e4f0644dde"}, + {file = "coverage-5.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:107d327071061fd4f4a2587d14c389a27e4e5c93c7cba5f1f59987181903902f"}, + {file = "coverage-5.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:0cdde51bfcf6b6bd862ee9be324521ec619b20590787d1655d005c3fb175005f"}, + {file = "coverage-5.4-cp39-cp39-win32.whl", hash = "sha256:c67734cff78383a1f23ceba3b3239c7deefc62ac2b05fa6a47bcd565771e5880"}, + {file = "coverage-5.4-cp39-cp39-win_amd64.whl", hash = "sha256:c669b440ce46ae3abe9b2d44a913b5fd86bb19eb14a8701e88e3918902ecd345"}, + {file = "coverage-5.4-pp36-none-any.whl", hash = "sha256:c0ff1c1b4d13e2240821ef23c1efb1f009207cb3f56e16986f713c2b0e7cd37f"}, + {file = "coverage-5.4-pp37-none-any.whl", hash = "sha256:cd601187476c6bed26a0398353212684c427e10a903aeafa6da40c63309d438b"}, + {file = "coverage-5.4.tar.gz", hash = "sha256:6d2e262e5e8da6fa56e774fb8e2643417351427604c2b177f8e8c5f75fc928ca"}, +] +dataclasses = [ + {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, + {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, +] +django = [ + {file = "Django-2.2.18-py3-none-any.whl", hash = "sha256:0eaca08f236bf502a9773e53623f766cc3ceee6453cc41e6de1c8b80f07d2364"}, + {file = "Django-2.2.18.tar.gz", hash = "sha256:c9c994f5e0a032cbd45089798b52e4080f4dea7241c58e3e0636c54146480bb4"}, +] +django-autocomplete-light = [ + {file = "django-autocomplete-light-3.8.1.tar.gz", hash = "sha256:4e84a6d95d272b0d7221614332e2bd54ffff15ec06e78947279398f6507ce225"}, +] +django-bootstrap3 = [ + {file = "django-bootstrap3-14.2.0.tar.gz", hash = "sha256:1fc3db37f29bcd159c0b00e1f15fd2d6dedf7551ce8bcca09072e33663c110de"}, + {file = "django_bootstrap3-14.2.0-py3-none-any.whl", hash = "sha256:c7e6912b5127bea913bc8504399613758760954140162e048184624765e61904"}, +] +django-ldapdb = [ + {file = "django-ldapdb-1.5.1.tar.gz", hash = "sha256:5ea333c3130abbb86f8629766370a7f490878706469fce4e5008e41fb566392a"}, + {file = "django_ldapdb-1.5.1-py2.py3-none-any.whl", hash = "sha256:2daee828a7eb1ce6ad0634ce5311339d77c08128829e575ff14d62a46771b86a"}, +] +django-macaddress = [ + {file = "django-macaddress-1.7.0.tar.gz", hash = "sha256:342aa3421ee19acc3661d1705dad2ae674eaa7d06a02799f7a5dc394d6233275"}, + {file = "django_macaddress-1.7.0-py2.py3-none-any.whl", hash = "sha256:db8beedcbd708aba3a6c9e83de6527efa2f9cc7dbe698406cebdfdbaf98c896d"}, +] +django-rest-framework = [ + {file = "django-rest-framework-0.1.0.tar.gz", hash = "sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a"}, +] +django-reversion = [ + {file = "django-reversion-3.0.9.tar.gz", hash = "sha256:a5af55f086a3f9c38be2f049c251e06005b9ed48ba7a109473736b1fc95a066f"}, + {file = "django_reversion-3.0.9-py3-none-any.whl", hash = "sha256:1b57127a136b969f4b843a915c72af271febe7f336469db6c27121f8adcad35c"}, +] +djangorestframework = [ + {file = "djangorestframework-3.12.2-py3-none-any.whl", hash = "sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7"}, + {file = "djangorestframework-3.12.2.tar.gz", hash = "sha256:0898182b4737a7b584a2c73735d89816343369f259fea932d90dc78e35d8ac33"}, +] +docstr-coverage = [ + {file = "docstr_coverage-2.0.0-py3-none-any.whl", hash = "sha256:c5ff8d81128d2f56204fc9ecbb9c410cb18b654438d1b104868abb6ef400767e"}, + {file = "docstr_coverage-2.0.0.tar.gz", hash = "sha256:ee2c043ccbc6d1847cd93616acf4ebb3e7bc53ea84434111efddae9b69f3737a"}, +] +docutils = [ + {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, + {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, +] +gitdb = [ + {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"}, + {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, +] +gitpython = [ + {file = "GitPython-3.1.13-py3-none-any.whl", hash = "sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29"}, + {file = "GitPython-3.1.13.tar.gz", hash = "sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a"}, +] +idna = [ + {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, + {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, +] +imagesize = [ + {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, + {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, +] +importlib-metadata = [ + {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, + {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, +] +importlib-resources = [ + {file = "importlib_resources-5.1.0-py3-none-any.whl", hash = "sha256:885b8eae589179f661c909d699a546cf10d83692553e34dca1bf5eb06f7f6217"}, + {file = "importlib_resources-5.1.0.tar.gz", hash = "sha256:bfdad047bce441405a49cf8eb48ddce5e56c696e185f59147a8b79e75e9e6380"}, +] +jinja2 = [ + {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, + {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, +] +markupsafe = [ + {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-win32.whl", hash = "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, + {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +mysqlclient = [ + {file = "mysqlclient-2.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3"}, + {file = "mysqlclient-2.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7"}, + {file = "mysqlclient-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5"}, + {file = "mysqlclient-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6"}, + {file = "mysqlclient-2.0.3.tar.gz", hash = "sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432"}, +] +netaddr = [ + {file = "netaddr-0.8.0-py2.py3-none-any.whl", hash = "sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac"}, + {file = "netaddr-0.8.0.tar.gz", hash = "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243"}, +] +packaging = [ + {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, + {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, +] +pathspec = [ + {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, + {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, +] +pillow = [ + {file = "Pillow-8.1.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a"}, + {file = "Pillow-8.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2"}, + {file = "Pillow-8.1.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174"}, + {file = "Pillow-8.1.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded"}, + {file = "Pillow-8.1.0-cp36-cp36m-win32.whl", hash = "sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d"}, + {file = "Pillow-8.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d"}, + {file = "Pillow-8.1.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234"}, + {file = "Pillow-8.1.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8"}, + {file = "Pillow-8.1.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17"}, + {file = "Pillow-8.1.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7"}, + {file = "Pillow-8.1.0-cp37-cp37m-win32.whl", hash = "sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e"}, + {file = "Pillow-8.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b"}, + {file = "Pillow-8.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0"}, + {file = "Pillow-8.1.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a"}, + {file = "Pillow-8.1.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d"}, + {file = "Pillow-8.1.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae"}, + {file = "Pillow-8.1.0-cp38-cp38-win32.whl", hash = "sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59"}, + {file = "Pillow-8.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c"}, + {file = "Pillow-8.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6"}, + {file = "Pillow-8.1.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378"}, + {file = "Pillow-8.1.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7"}, + {file = "Pillow-8.1.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0"}, + {file = "Pillow-8.1.0-cp39-cp39-win32.whl", hash = "sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b"}, + {file = "Pillow-8.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865"}, + {file = "Pillow-8.1.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9"}, + {file = "Pillow-8.1.0-pp36-pypy36_pp73-manylinux2010_i686.whl", hash = "sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913"}, + {file = "Pillow-8.1.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206"}, + {file = "Pillow-8.1.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9"}, + {file = "Pillow-8.1.0-pp37-pypy37_pp73-manylinux2010_i686.whl", hash = "sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032"}, + {file = "Pillow-8.1.0-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820"}, + {file = "Pillow-8.1.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5"}, + {file = "Pillow-8.1.0.tar.gz", hash = "sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba"}, +] +psycopg2 = [ + {file = "psycopg2-2.8.6-cp27-cp27m-win32.whl", hash = "sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725"}, + {file = "psycopg2-2.8.6-cp27-cp27m-win_amd64.whl", hash = "sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5"}, + {file = "psycopg2-2.8.6-cp34-cp34m-win32.whl", hash = "sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad"}, + {file = "psycopg2-2.8.6-cp34-cp34m-win_amd64.whl", hash = "sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3"}, + {file = "psycopg2-2.8.6-cp35-cp35m-win32.whl", hash = "sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821"}, + {file = "psycopg2-2.8.6-cp35-cp35m-win_amd64.whl", hash = "sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301"}, + {file = "psycopg2-2.8.6-cp36-cp36m-win32.whl", hash = "sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a"}, + {file = "psycopg2-2.8.6-cp36-cp36m-win_amd64.whl", hash = "sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d"}, + {file = "psycopg2-2.8.6-cp37-cp37m-win32.whl", hash = "sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84"}, + {file = "psycopg2-2.8.6-cp37-cp37m-win_amd64.whl", hash = "sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5"}, + {file = "psycopg2-2.8.6-cp38-cp38-win32.whl", hash = "sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e"}, + {file = "psycopg2-2.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051"}, + {file = "psycopg2-2.8.6-cp39-cp39-win32.whl", hash = "sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3"}, + {file = "psycopg2-2.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7"}, + {file = "psycopg2-2.8.6.tar.gz", hash = "sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543"}, +] +pyasn1 = [ + {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, + {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, + {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, + {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, + {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, + {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, + {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, + {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, + {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, + {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, + {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, + {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, + {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, +] +pyasn1-modules = [ + {file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"}, + {file = "pyasn1_modules-0.2.8-py2.4.egg", hash = "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199"}, + {file = "pyasn1_modules-0.2.8-py2.5.egg", hash = "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"}, + {file = "pyasn1_modules-0.2.8-py2.6.egg", hash = "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb"}, + {file = "pyasn1_modules-0.2.8-py2.7.egg", hash = "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8"}, + {file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"}, + {file = "pyasn1_modules-0.2.8-py3.1.egg", hash = "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d"}, + {file = "pyasn1_modules-0.2.8-py3.2.egg", hash = "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45"}, + {file = "pyasn1_modules-0.2.8-py3.3.egg", hash = "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4"}, + {file = "pyasn1_modules-0.2.8-py3.4.egg", hash = "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811"}, + {file = "pyasn1_modules-0.2.8-py3.5.egg", hash = "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed"}, + {file = "pyasn1_modules-0.2.8-py3.6.egg", hash = "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0"}, + {file = "pyasn1_modules-0.2.8-py3.7.egg", hash = "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd"}, +] +pycrypto = [ + {file = "pycrypto-2.6.1.tar.gz", hash = "sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c"}, +] +pygments = [ + {file = "Pygments-2.7.4-py3-none-any.whl", hash = "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435"}, + {file = "Pygments-2.7.4.tar.gz", hash = "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, + {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, +] +python-ldap = [ + {file = "python-ldap-3.3.1.tar.gz", hash = "sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5"}, +] +pytz = [ + {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, + {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, +] +pyyaml = [ + {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, + {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, + {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, + {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, + {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, + {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, + {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, + {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, +] +regex = [ + {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, + {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, + {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, + {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, + {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, + {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, + {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, + {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, + {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, + {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, + {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, + {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, + {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, +] +requests = [ + {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, + {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, +] +rope = [ + {file = "rope-0.18.0.tar.gz", hash = "sha256:786b5c38c530d4846aa68a42604f61b4e69a493390e3ca11b88df0fbfdc3ed04"}, +] +six = [ + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, +] +smmap = [ + {file = "smmap-3.0.5-py2.py3-none-any.whl", hash = "sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714"}, + {file = "smmap-3.0.5.tar.gz", hash = "sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50"}, +] +snowballstemmer = [ + {file = "snowballstemmer-2.1.0-py2.py3-none-any.whl", hash = "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2"}, + {file = "snowballstemmer-2.1.0.tar.gz", hash = "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"}, +] +sphinx = [ + {file = "Sphinx-3.4.3-py3-none-any.whl", hash = "sha256:c314c857e7cd47c856d2c5adff514ac2e6495f8b8e0f886a8a37e9305dfea0d8"}, + {file = "Sphinx-3.4.3.tar.gz", hash = "sha256:41cad293f954f7d37f803d97eb184158cfd90f51195131e94875bc07cd08b93c"}, +] +sphinx-rtd-theme = [ + {file = "sphinx_rtd_theme-0.5.1-py2.py3-none-any.whl", hash = "sha256:fa6bebd5ab9a73da8e102509a86f3fcc36dec04a0b52ea80e5a033b2aba00113"}, + {file = "sphinx_rtd_theme-0.5.1.tar.gz", hash = "sha256:eda689eda0c7301a80cf122dad28b1861e5605cbf455558f3775e1e8200e83a5"}, +] +sphinxcontrib-applehelp = [ + {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, + {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, +] +sphinxcontrib-devhelp = [ + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, +] +sphinxcontrib-htmlhelp = [ + {file = "sphinxcontrib-htmlhelp-1.0.3.tar.gz", hash = "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"}, + {file = "sphinxcontrib_htmlhelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f"}, +] +sphinxcontrib-jsmath = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] +sphinxcontrib-qthelp = [ + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, +] +sphinxcontrib-serializinghtml = [ + {file = "sphinxcontrib-serializinghtml-1.1.4.tar.gz", hash = "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc"}, + {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"}, +] +sqlparse = [ + {file = "sqlparse-0.4.1-py3-none-any.whl", hash = "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0"}, + {file = "sqlparse-0.4.1.tar.gz", hash = "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +typed-ast = [ + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, + {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, + {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, + {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, + {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, + {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, + {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, + {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, + {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, + {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, + {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, + {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, + {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, + {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, + {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, + {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, +] +typing-extensions = [ + {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, + {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, + {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, +] +urllib3 = [ + {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"}, + {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"}, +] +zipp = [ + {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, + {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, +] diff --git a/postgresql-requirements.txt b/postgresql-requirements.txt new file mode 100644 index 00000000..ead30d77 --- /dev/null +++ b/postgresql-requirements.txt @@ -0,0 +1,142 @@ +django-autocomplete-light==3.8.1 \ + --hash=sha256:4e84a6d95d272b0d7221614332e2bd54ffff15ec06e78947279398f6507ce225 +django-bootstrap3==14.2.0; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:1fc3db37f29bcd159c0b00e1f15fd2d6dedf7551ce8bcca09072e33663c110de \ + --hash=sha256:c7e6912b5127bea913bc8504399613758760954140162e048184624765e61904 +django-ldapdb==1.5.1; python_version >= "3.6" \ + --hash=sha256:5ea333c3130abbb86f8629766370a7f490878706469fce4e5008e41fb566392a \ + --hash=sha256:2daee828a7eb1ce6ad0634ce5311339d77c08128829e575ff14d62a46771b86a +django-macaddress==1.7.0 \ + --hash=sha256:342aa3421ee19acc3661d1705dad2ae674eaa7d06a02799f7a5dc394d6233275 \ + --hash=sha256:db8beedcbd708aba3a6c9e83de6527efa2f9cc7dbe698406cebdfdbaf98c896d +django-rest-framework==0.1.0 \ + --hash=sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a +django-reversion==3.0.9; python_version >= "3.6" \ + --hash=sha256:a5af55f086a3f9c38be2f049c251e06005b9ed48ba7a109473736b1fc95a066f \ + --hash=sha256:1b57127a136b969f4b843a915c72af271febe7f336469db6c27121f8adcad35c +django==2.2.18; python_version >= "3.5" \ + --hash=sha256:0eaca08f236bf502a9773e53623f766cc3ceee6453cc41e6de1c8b80f07d2364 \ + --hash=sha256:c9c994f5e0a032cbd45089798b52e4080f4dea7241c58e3e0636c54146480bb4 +djangorestframework==3.12.2; python_version >= "3.5" \ + --hash=sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7 \ + --hash=sha256:0898182b4737a7b584a2c73735d89816343369f259fea932d90dc78e35d8ac33 +gitdb==4.0.5; python_version >= "3.4" \ + --hash=sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac \ + --hash=sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9 +gitpython==3.1.13; python_version >= "3.4" \ + --hash=sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29 \ + --hash=sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a +importlib-metadata==1.7.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_version < "3.8" and python_full_version >= "3.5.0" \ + --hash=sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070 \ + --hash=sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83 +importlib-resources==5.1.0; python_version >= "3.6" and python_version < "3.7" \ + --hash=sha256:885b8eae589179f661c909d699a546cf10d83692553e34dca1bf5eb06f7f6217 \ + --hash=sha256:bfdad047bce441405a49cf8eb48ddce5e56c696e185f59147a8b79e75e9e6380 +mysqlclient==2.0.3; python_version >= "3.5" \ + --hash=sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3 \ + --hash=sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7 \ + --hash=sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5 \ + --hash=sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6 \ + --hash=sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432 +netaddr==0.8.0 \ + --hash=sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac \ + --hash=sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243 +pillow==8.1.0; python_version >= "3.6" \ + --hash=sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a \ + --hash=sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2 \ + --hash=sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174 \ + --hash=sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded \ + --hash=sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d \ + --hash=sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d \ + --hash=sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234 \ + --hash=sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8 \ + --hash=sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17 \ + --hash=sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7 \ + --hash=sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e \ + --hash=sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b \ + --hash=sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0 \ + --hash=sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a \ + --hash=sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d \ + --hash=sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae \ + --hash=sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59 \ + --hash=sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c \ + --hash=sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6 \ + --hash=sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378 \ + --hash=sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7 \ + --hash=sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0 \ + --hash=sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b \ + --hash=sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865 \ + --hash=sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9 \ + --hash=sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913 \ + --hash=sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206 \ + --hash=sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9 \ + --hash=sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032 \ + --hash=sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820 \ + --hash=sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5 \ + --hash=sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba +psycopg2==2.8.6; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \ + --hash=sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725 \ + --hash=sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5 \ + --hash=sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad \ + --hash=sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3 \ + --hash=sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821 \ + --hash=sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301 \ + --hash=sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a \ + --hash=sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d \ + --hash=sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84 \ + --hash=sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5 \ + --hash=sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e \ + --hash=sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051 \ + --hash=sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3 \ + --hash=sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7 \ + --hash=sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543 +pyasn1-modules==0.2.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199 \ + --hash=sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405 \ + --hash=sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb \ + --hash=sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8 \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 \ + --hash=sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d \ + --hash=sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45 \ + --hash=sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4 \ + --hash=sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811 \ + --hash=sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed \ + --hash=sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0 \ + --hash=sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd +pyasn1==0.4.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3 \ + --hash=sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf \ + --hash=sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00 \ + --hash=sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86 \ + --hash=sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7 \ + --hash=sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576 \ + --hash=sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12 \ + --hash=sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2 \ + --hash=sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359 \ + --hash=sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776 \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba +pycrypto==2.6.1 \ + --hash=sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c +python-dateutil==2.8.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +python-ldap==3.3.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5 +pytz==2021.1; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 \ + --hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da +six==1.15.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 +smmap==3.0.5; python_version >= "3.4" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.4" \ + --hash=sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714 \ + --hash=sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50 +sqlparse==0.4.1; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0 \ + --hash=sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8 +zipp==3.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.5.0" \ + --hash=sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108 \ + --hash=sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..89381319 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,68 @@ +[tool.poetry] +name = "re2o" +version = "2.9.0" +description = "Re2o is a management software initially developed at Rézo Metz. It is now in use in several student organizations. It aims to remain agnostic of the organization that uses it and be easy to setup." +authors = [ + "Gabriel Detraz", + "Hugo Levy-falk", + "Maël Kervella", + "Jean-romain Garnier", + "Arthur Grisel-davy", + "Laouen Fernet", + "Augustin Lemesle", + "Lara Kermarec", + "Alexandre Iooss", + "Yoann Piétri", + "Charlie Jacomme", + "Corentin Canebier", + "Bombar Maxime", + "Guillaume Goessel", + "Matthieu Michelet", + "Edpibu", + "Fardale", + "Jean-marie Mineau", + "David Sinquin", + "Gabriel Le Bouder", + "Simon Brélivet", + "Benjamin Graillot", + "Leïla Bekaddour", + "Éloi Alain", + "Pierre Cadart", + "Antoine Vintache", + "Thibault De Boutray", + "Delphine Salvy", + "Joanne Steiner", + "Krokmou", + "B", + "Daniel Stan", + "Gwenael Le Hir", + "Hugo Hervieux", + "Mikachu", + "Nymous", + "Pierre-antoine Comby", + "Vincent Le Gallic", +] + +[tool.poetry.dependencies] +python = ">=3.6,<4.0" +Django = "2.2.18" +django-autocomplete-light = "^3.8.1" +django-bootstrap3 = "^14.2.0" +django-rest-framework = "^0.1.0" +django-reversion = "^3.0.9" +Pillow = "^8.1.0" +python-dateutil = "^2.8.1" +django-macaddress = "^1.7.0" +pycrypto = "^2.6.1" +GitPython = "^3.1.13" +mysqlclient = {version = "^2.0.3", extras = ["mysql"]} +psycopg2 = {version = "^2.8.6", extras = ["postgresql"]} +django-ldapdb = {version = "^1.5.1", extras = ["ldap"]} + +[tool.poetry.dev-dependencies] +Sphinx = "^3.4.3" +sphinx-rtd-theme = "^0.5.1" +black = "^20.8b1" +rope = "^0.18.0" +coverage = "^5.4" +docstr-coverage = "^2.0.0" diff --git a/requirements.txt b/requirements.txt index f7f38e3d..ead30d77 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,142 @@ -# -# These requirements were autogenerated by pipenv -# To regenerate from the project's Pipfile, run: -# -# pipenv lock --requirements -# - --i https://pypi.org/simple -django-autocomplete-light==3.8.1 -django-bootstrap3==14.2.0 -django-ldapdb==1.5.1 -django-macaddress==1.7.0 -django-rest-framework==0.1.0 -django-reversion==3.0.9 -django==2.2.18 -djangorestframework==3.12.2; python_version >= '3.5' -gitdb==4.0.5; python_version >= '3.4' -gitpython==3.1.13 -mysqlclient==2.0.3 -netaddr==0.8.0 -pillow==8.1.0 -pyasn1-modules==0.2.8 -pyasn1==0.4.8 -pycrypto==2.6.1 -python-dateutil==2.8.1 -python-ldap==3.3.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -pytz==2021.1 -six==1.15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -smmap==3.0.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -sqlparse==0.4.1; python_version >= '3.5' +django-autocomplete-light==3.8.1 \ + --hash=sha256:4e84a6d95d272b0d7221614332e2bd54ffff15ec06e78947279398f6507ce225 +django-bootstrap3==14.2.0; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:1fc3db37f29bcd159c0b00e1f15fd2d6dedf7551ce8bcca09072e33663c110de \ + --hash=sha256:c7e6912b5127bea913bc8504399613758760954140162e048184624765e61904 +django-ldapdb==1.5.1; python_version >= "3.6" \ + --hash=sha256:5ea333c3130abbb86f8629766370a7f490878706469fce4e5008e41fb566392a \ + --hash=sha256:2daee828a7eb1ce6ad0634ce5311339d77c08128829e575ff14d62a46771b86a +django-macaddress==1.7.0 \ + --hash=sha256:342aa3421ee19acc3661d1705dad2ae674eaa7d06a02799f7a5dc394d6233275 \ + --hash=sha256:db8beedcbd708aba3a6c9e83de6527efa2f9cc7dbe698406cebdfdbaf98c896d +django-rest-framework==0.1.0 \ + --hash=sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a +django-reversion==3.0.9; python_version >= "3.6" \ + --hash=sha256:a5af55f086a3f9c38be2f049c251e06005b9ed48ba7a109473736b1fc95a066f \ + --hash=sha256:1b57127a136b969f4b843a915c72af271febe7f336469db6c27121f8adcad35c +django==2.2.18; python_version >= "3.5" \ + --hash=sha256:0eaca08f236bf502a9773e53623f766cc3ceee6453cc41e6de1c8b80f07d2364 \ + --hash=sha256:c9c994f5e0a032cbd45089798b52e4080f4dea7241c58e3e0636c54146480bb4 +djangorestframework==3.12.2; python_version >= "3.5" \ + --hash=sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7 \ + --hash=sha256:0898182b4737a7b584a2c73735d89816343369f259fea932d90dc78e35d8ac33 +gitdb==4.0.5; python_version >= "3.4" \ + --hash=sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac \ + --hash=sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9 +gitpython==3.1.13; python_version >= "3.4" \ + --hash=sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29 \ + --hash=sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a +importlib-metadata==1.7.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_version < "3.8" and python_full_version >= "3.5.0" \ + --hash=sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070 \ + --hash=sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83 +importlib-resources==5.1.0; python_version >= "3.6" and python_version < "3.7" \ + --hash=sha256:885b8eae589179f661c909d699a546cf10d83692553e34dca1bf5eb06f7f6217 \ + --hash=sha256:bfdad047bce441405a49cf8eb48ddce5e56c696e185f59147a8b79e75e9e6380 +mysqlclient==2.0.3; python_version >= "3.5" \ + --hash=sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3 \ + --hash=sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7 \ + --hash=sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5 \ + --hash=sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6 \ + --hash=sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432 +netaddr==0.8.0 \ + --hash=sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac \ + --hash=sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243 +pillow==8.1.0; python_version >= "3.6" \ + --hash=sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a \ + --hash=sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2 \ + --hash=sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174 \ + --hash=sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded \ + --hash=sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d \ + --hash=sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d \ + --hash=sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234 \ + --hash=sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8 \ + --hash=sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17 \ + --hash=sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7 \ + --hash=sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e \ + --hash=sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b \ + --hash=sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0 \ + --hash=sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a \ + --hash=sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d \ + --hash=sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae \ + --hash=sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59 \ + --hash=sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c \ + --hash=sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6 \ + --hash=sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378 \ + --hash=sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7 \ + --hash=sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0 \ + --hash=sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b \ + --hash=sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865 \ + --hash=sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9 \ + --hash=sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913 \ + --hash=sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206 \ + --hash=sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9 \ + --hash=sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032 \ + --hash=sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820 \ + --hash=sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5 \ + --hash=sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba +psycopg2==2.8.6; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \ + --hash=sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725 \ + --hash=sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5 \ + --hash=sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad \ + --hash=sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3 \ + --hash=sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821 \ + --hash=sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301 \ + --hash=sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a \ + --hash=sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d \ + --hash=sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84 \ + --hash=sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5 \ + --hash=sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e \ + --hash=sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051 \ + --hash=sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3 \ + --hash=sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7 \ + --hash=sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543 +pyasn1-modules==0.2.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199 \ + --hash=sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405 \ + --hash=sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb \ + --hash=sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8 \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 \ + --hash=sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d \ + --hash=sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45 \ + --hash=sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4 \ + --hash=sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811 \ + --hash=sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed \ + --hash=sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0 \ + --hash=sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd +pyasn1==0.4.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3 \ + --hash=sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf \ + --hash=sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00 \ + --hash=sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86 \ + --hash=sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7 \ + --hash=sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576 \ + --hash=sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12 \ + --hash=sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2 \ + --hash=sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359 \ + --hash=sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776 \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba +pycrypto==2.6.1 \ + --hash=sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c +python-dateutil==2.8.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +python-ldap==3.3.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5 +pytz==2021.1; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 \ + --hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da +six==1.15.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 +smmap==3.0.5; python_version >= "3.4" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.4" \ + --hash=sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714 \ + --hash=sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50 +sqlparse==0.4.1; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0 \ + --hash=sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8 +zipp==3.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.5.0" \ + --hash=sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108 \ + --hash=sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb From 7691905b82ac11266e9032f4cc1c5dbc9b2a2ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Pi=C3=A9tri?= Date: Sat, 13 Feb 2021 23:07:33 +0100 Subject: [PATCH 5/7] chore: :pushpin: Error in dev-requirements.txt --- dev-requirements.txt | 488 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 438 insertions(+), 50 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 595c946b..0b6ba4aa 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,50 +1,438 @@ - - Stack trace: - - 11 /usr/lib/python3.9/site-packages/clikit/console_application.py:123 in run - io = io_factory( - - 10 /usr/lib/python3.9/site-packages/poetry/console/config/application_config.py:221 in create_io - resolved_command = application.resolve_command(args) - - 9 /usr/lib/python3.9/site-packages/clikit/console_application.py:110 in resolve_command - return self._config.command_resolver.resolve(args, self) - - 8 /usr/lib/python3.9/site-packages/clikit/resolver/default_resolver.py:34 in resolve - return self.create_resolved_command(result) - - 7 /usr/lib/python3.9/site-packages/clikit/resolver/default_resolver.py:166 in create_resolved_command - if not result.is_parsable(): - - 6 /usr/lib/python3.9/site-packages/clikit/resolver/resolve_result.py:43 in is_parsable - self._parse() - - 5 /usr/lib/python3.9/site-packages/clikit/resolver/resolve_result.py:49 in _parse - self._parsed_args = self._command.parse(self._raw_args) - - 4 /usr/lib/python3.9/site-packages/clikit/api/command/command.py:113 in parse - return self._config.args_parser.parse(args, self._args_format, lenient) - - 3 /usr/lib/python3.9/site-packages/clikit/args/default_args_parser.py:53 in parse - self._parse(args, _fmt, lenient) - - 2 /usr/lib/python3.9/site-packages/clikit/args/default_args_parser.py:103 in _parse - self._parse_short_option(token, tokens, fmt, lenient) - - 1 /usr/lib/python3.9/site-packages/clikit/args/default_args_parser.py:272 in _parse_short_option - self._add_short_option(name, None, tokens, fmt, lenient) - - NoSuchOptionException - - The "-D" option does not exist. - - at /usr/lib/python3.9/site-packages/clikit/args/default_args_parser.py:349 in _add_short_option - 345│ def _add_short_option( - 346│ self, name, value, tokens, fmt, lenient - 347│ ): # type: (str, Optional[str], List[str], ArgsFormat, bool) -> None - 348│ if not fmt.has_option(name): - → 349│ raise NoSuchOptionException(name) - 350│ - 351│ self._add_long_option( - 352│ fmt.get_option(name).long_name, value, tokens, fmt, lenient - 353│ ) +alabaster==0.7.12; python_version >= "3.5" \ + --hash=sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359 \ + --hash=sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02 +appdirs==1.4.4; python_version >= "3.6" \ + --hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128 \ + --hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 +babel==2.9.0; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.5" \ + --hash=sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5 \ + --hash=sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05 +black==20.8b1; python_version >= "3.6" \ + --hash=sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea +certifi==2020.12.5; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5" \ + --hash=sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830 \ + --hash=sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c +chardet==4.0.0; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5" \ + --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5 \ + --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa +click==7.1.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" \ + --hash=sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc \ + --hash=sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a +colorama==0.4.4; python_version >= "3.5" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.5" and python_full_version >= "3.5.0" \ + --hash=sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2 \ + --hash=sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b +coverage==5.4; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0" and python_version < "4") \ + --hash=sha256:6d9c88b787638a451f41f97446a1c9fd416e669b4d9717ae4615bd29de1ac135 \ + --hash=sha256:66a5aae8233d766a877c5ef293ec5ab9520929c2578fd2069308a98b7374ea8c \ + --hash=sha256:9754a5c265f991317de2bac0c70a746efc2b695cf4d49f5d2cddeac36544fb44 \ + --hash=sha256:fbb17c0d0822684b7d6c09915677a32319f16ff1115df5ec05bdcaaee40b35f3 \ + --hash=sha256:b7f7421841f8db443855d2854e25914a79a1ff48ae92f70d0a5c2f8907ab98c9 \ + --hash=sha256:4a780807e80479f281d47ee4af2eb2df3e4ccf4723484f77da0bb49d027e40a1 \ + --hash=sha256:87c4b38288f71acd2106f5d94f575bc2136ea2887fdb5dfe18003c881fa6b370 \ + --hash=sha256:c6809ebcbf6c1049002b9ac09c127ae43929042ec1f1dbd8bb1615f7cd9f70a0 \ + --hash=sha256:ba7ca81b6d60a9f7a0b4b4e175dcc38e8fef4992673d9d6e6879fd6de00dd9b8 \ + --hash=sha256:89fc12c6371bf963809abc46cced4a01ca4f99cba17be5e7d416ed7ef1245d19 \ + --hash=sha256:4a8eb7785bd23565b542b01fb39115a975fefb4a82f23d407503eee2c0106247 \ + --hash=sha256:7e40d3f8eb472c1509b12ac2a7e24158ec352fc8567b77ab02c0db053927e339 \ + --hash=sha256:1ccae21a076d3d5f471700f6d30eb486da1626c380b23c70ae32ab823e453337 \ + --hash=sha256:755c56beeacac6a24c8e1074f89f34f4373abce8b662470d3aa719ae304931f3 \ + --hash=sha256:322549b880b2d746a7672bf6ff9ed3f895e9c9f108b714e7360292aa5c5d7cf4 \ + --hash=sha256:60a3307a84ec60578accd35d7f0c71a3a971430ed7eca6567399d2b50ef37b8c \ + --hash=sha256:1375bb8b88cb050a2d4e0da901001347a44302aeadb8ceb4b6e5aa373b8ea68f \ + --hash=sha256:16baa799ec09cc0dcb43a10680573269d407c159325972dd7114ee7649e56c66 \ + --hash=sha256:2f2cf7a42d4b7654c9a67b9d091ec24374f7c58794858bff632a2039cb15984d \ + --hash=sha256:b62046592b44263fa7570f1117d372ae3f310222af1fc1407416f037fb3af21b \ + --hash=sha256:812eaf4939ef2284d29653bcfee9665f11f013724f07258928f849a2306ea9f9 \ + --hash=sha256:859f0add98707b182b4867359e12bde806b82483fb12a9ae868a77880fc3b7af \ + --hash=sha256:04b14e45d6a8e159c9767ae57ecb34563ad93440fc1b26516a89ceb5b33c1ad5 \ + --hash=sha256:ebfa374067af240d079ef97b8064478f3bf71038b78b017eb6ec93ede1b6bcec \ + --hash=sha256:84df004223fd0550d0ea7a37882e5c889f3c6d45535c639ce9802293b39cd5c9 \ + --hash=sha256:1b811662ecf72eb2d08872731636aee6559cae21862c36f74703be727b45df90 \ + --hash=sha256:6b588b5cf51dc0fd1c9e19f622457cc74b7d26fe295432e434525f1c0fae02bc \ + --hash=sha256:3fe50f1cac369b02d34ad904dfe0771acc483f82a1b54c5e93632916ba847b37 \ + --hash=sha256:32ab83016c24c5cf3db2943286b85b0a172dae08c58d0f53875235219b676409 \ + --hash=sha256:68fb816a5dd901c6aff352ce49e2a0ffadacdf9b6fae282a69e7a16a02dad5fb \ + --hash=sha256:a636160680c6e526b84f85d304e2f0bb4e94f8284dd765a1911de9a40450b10a \ + --hash=sha256:bb32ca14b4d04e172c541c69eec5f385f9a075b38fb22d765d8b0ce3af3a0c22 \ + --hash=sha256:6c4d7165a4e8f41eca6b990c12ee7f44fef3932fac48ca32cecb3a1b2223c21f \ + --hash=sha256:a565f48c4aae72d1d3d3f8e8fb7218f5609c964e9c6f68604608e5958b9c60c3 \ + --hash=sha256:fff1f3a586246110f34dc762098b5afd2de88de507559e63553d7da643053786 \ + --hash=sha256:a839e25f07e428a87d17d857d9935dd743130e77ff46524abb992b962eb2076c \ + --hash=sha256:6625e52b6f346a283c3d563d1fd8bae8956daafc64bb5bbd2b8f8a07608e3994 \ + --hash=sha256:5bee3970617b3d74759b2d2df2f6a327d372f9732f9ccbf03fa591b5f7581e39 \ + --hash=sha256:03ed2a641e412e42cc35c244508cf186015c217f0e4d496bf6d7078ebe837ae7 \ + --hash=sha256:14a9f1887591684fb59fdba8feef7123a0da2424b0652e1b58dd5b9a7bb1188c \ + --hash=sha256:9564ac7eb1652c3701ac691ca72934dd3009997c81266807aef924012df2f4b3 \ + --hash=sha256:0f48fc7dc82ee14aeaedb986e175a429d24129b7eada1b7e94a864e4f0644dde \ + --hash=sha256:107d327071061fd4f4a2587d14c389a27e4e5c93c7cba5f1f59987181903902f \ + --hash=sha256:0cdde51bfcf6b6bd862ee9be324521ec619b20590787d1655d005c3fb175005f \ + --hash=sha256:c67734cff78383a1f23ceba3b3239c7deefc62ac2b05fa6a47bcd565771e5880 \ + --hash=sha256:c669b440ce46ae3abe9b2d44a913b5fd86bb19eb14a8701e88e3918902ecd345 \ + --hash=sha256:c0ff1c1b4d13e2240821ef23c1efb1f009207cb3f56e16986f713c2b0e7cd37f \ + --hash=sha256:cd601187476c6bed26a0398353212684c427e10a903aeafa6da40c63309d438b \ + --hash=sha256:6d2e262e5e8da6fa56e774fb8e2643417351427604c2b177f8e8c5f75fc928ca +dataclasses==0.8; python_version >= "3.6" and python_version < "3.7" \ + --hash=sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf \ + --hash=sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97 +django-autocomplete-light==3.8.1 \ + --hash=sha256:4e84a6d95d272b0d7221614332e2bd54ffff15ec06e78947279398f6507ce225 +django-bootstrap3==14.2.0; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:1fc3db37f29bcd159c0b00e1f15fd2d6dedf7551ce8bcca09072e33663c110de \ + --hash=sha256:c7e6912b5127bea913bc8504399613758760954140162e048184624765e61904 +django-ldapdb==1.5.1; python_version >= "3.6" \ + --hash=sha256:5ea333c3130abbb86f8629766370a7f490878706469fce4e5008e41fb566392a \ + --hash=sha256:2daee828a7eb1ce6ad0634ce5311339d77c08128829e575ff14d62a46771b86a +django-macaddress==1.7.0 \ + --hash=sha256:342aa3421ee19acc3661d1705dad2ae674eaa7d06a02799f7a5dc394d6233275 \ + --hash=sha256:db8beedcbd708aba3a6c9e83de6527efa2f9cc7dbe698406cebdfdbaf98c896d +django-rest-framework==0.1.0 \ + --hash=sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a +django-reversion==3.0.9; python_version >= "3.6" \ + --hash=sha256:a5af55f086a3f9c38be2f049c251e06005b9ed48ba7a109473736b1fc95a066f \ + --hash=sha256:1b57127a136b969f4b843a915c72af271febe7f336469db6c27121f8adcad35c +django==2.2.18; python_version >= "3.5" \ + --hash=sha256:0eaca08f236bf502a9773e53623f766cc3ceee6453cc41e6de1c8b80f07d2364 \ + --hash=sha256:c9c994f5e0a032cbd45089798b52e4080f4dea7241c58e3e0636c54146480bb4 +djangorestframework==3.12.2; python_version >= "3.5" \ + --hash=sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7 \ + --hash=sha256:0898182b4737a7b584a2c73735d89816343369f259fea932d90dc78e35d8ac33 +docstr-coverage==2.0.0 \ + --hash=sha256:c5ff8d81128d2f56204fc9ecbb9c410cb18b654438d1b104868abb6ef400767e \ + --hash=sha256:ee2c043ccbc6d1847cd93616acf4ebb3e7bc53ea84434111efddae9b69f3737a +docutils==0.16; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5" \ + --hash=sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af \ + --hash=sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc +gitdb==4.0.5; python_version >= "3.4" \ + --hash=sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac \ + --hash=sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9 +gitpython==3.1.13; python_version >= "3.4" \ + --hash=sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29 \ + --hash=sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a +idna==2.10; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5" \ + --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0 \ + --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 +imagesize==1.2.0; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.5" \ + --hash=sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1 \ + --hash=sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1 +importlib-metadata==1.7.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_version < "3.8" and python_full_version >= "3.5.0" \ + --hash=sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070 \ + --hash=sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83 +importlib-resources==5.1.0; python_version >= "3.6" and python_version < "3.7" \ + --hash=sha256:885b8eae589179f661c909d699a546cf10d83692553e34dca1bf5eb06f7f6217 \ + --hash=sha256:bfdad047bce441405a49cf8eb48ddce5e56c696e185f59147a8b79e75e9e6380 +jinja2==2.11.3; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5" \ + --hash=sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419 \ + --hash=sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6 +markupsafe==1.1.1; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5" \ + --hash=sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161 \ + --hash=sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7 \ + --hash=sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183 \ + --hash=sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b \ + --hash=sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e \ + --hash=sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f \ + --hash=sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1 \ + --hash=sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5 \ + --hash=sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1 \ + --hash=sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735 \ + --hash=sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21 \ + --hash=sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235 \ + --hash=sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b \ + --hash=sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f \ + --hash=sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905 \ + --hash=sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1 \ + --hash=sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d \ + --hash=sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff \ + --hash=sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5 \ + --hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \ + --hash=sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e \ + --hash=sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f \ + --hash=sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0 \ + --hash=sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7 \ + --hash=sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66 \ + --hash=sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5 \ + --hash=sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d \ + --hash=sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193 \ + --hash=sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e \ + --hash=sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6 \ + --hash=sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1 \ + --hash=sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1 \ + --hash=sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f \ + --hash=sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2 \ + --hash=sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c \ + --hash=sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15 \ + --hash=sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2 \ + --hash=sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42 \ + --hash=sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2 \ + --hash=sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032 \ + --hash=sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b \ + --hash=sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b \ + --hash=sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be \ + --hash=sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c \ + --hash=sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb \ + --hash=sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014 \ + --hash=sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850 \ + --hash=sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85 \ + --hash=sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621 \ + --hash=sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39 \ + --hash=sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8 \ + --hash=sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b +mypy-extensions==0.4.3; python_version >= "3.6" \ + --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ + --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 +mysqlclient==2.0.3; python_version >= "3.5" \ + --hash=sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3 \ + --hash=sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7 \ + --hash=sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5 \ + --hash=sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6 \ + --hash=sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432 +netaddr==0.8.0 \ + --hash=sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac \ + --hash=sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243 +packaging==20.9; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.5" \ + --hash=sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a \ + --hash=sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5 +pathspec==0.8.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" \ + --hash=sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d \ + --hash=sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd +pillow==8.1.0; python_version >= "3.6" \ + --hash=sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a \ + --hash=sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2 \ + --hash=sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174 \ + --hash=sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded \ + --hash=sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d \ + --hash=sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d \ + --hash=sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234 \ + --hash=sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8 \ + --hash=sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17 \ + --hash=sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7 \ + --hash=sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e \ + --hash=sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b \ + --hash=sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0 \ + --hash=sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a \ + --hash=sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d \ + --hash=sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae \ + --hash=sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59 \ + --hash=sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c \ + --hash=sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6 \ + --hash=sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378 \ + --hash=sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7 \ + --hash=sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0 \ + --hash=sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b \ + --hash=sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865 \ + --hash=sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9 \ + --hash=sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913 \ + --hash=sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206 \ + --hash=sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9 \ + --hash=sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032 \ + --hash=sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820 \ + --hash=sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5 \ + --hash=sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba +psycopg2==2.8.6; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \ + --hash=sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725 \ + --hash=sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5 \ + --hash=sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad \ + --hash=sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3 \ + --hash=sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821 \ + --hash=sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301 \ + --hash=sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a \ + --hash=sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d \ + --hash=sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84 \ + --hash=sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5 \ + --hash=sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e \ + --hash=sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051 \ + --hash=sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3 \ + --hash=sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7 \ + --hash=sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543 +pyasn1-modules==0.2.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199 \ + --hash=sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405 \ + --hash=sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb \ + --hash=sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8 \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 \ + --hash=sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d \ + --hash=sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45 \ + --hash=sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4 \ + --hash=sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811 \ + --hash=sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed \ + --hash=sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0 \ + --hash=sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd +pyasn1==0.4.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3 \ + --hash=sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf \ + --hash=sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00 \ + --hash=sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86 \ + --hash=sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7 \ + --hash=sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576 \ + --hash=sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12 \ + --hash=sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2 \ + --hash=sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359 \ + --hash=sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776 \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba +pycrypto==2.6.1 \ + --hash=sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c +pygments==2.7.4; python_version >= "3.5" \ + --hash=sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435 \ + --hash=sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337 +pyparsing==2.4.7; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.5" \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 +python-dateutil==2.8.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") \ + --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ + --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a +python-ldap==3.3.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" \ + --hash=sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5 +pytz==2021.1; python_version >= "3.6" and python_version < "4.0" and (python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.5") \ + --hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 \ + --hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da +pyyaml==5.4.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" \ + --hash=sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922 \ + --hash=sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393 \ + --hash=sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8 \ + --hash=sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185 \ + --hash=sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253 \ + --hash=sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc \ + --hash=sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5 \ + --hash=sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df \ + --hash=sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018 \ + --hash=sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63 \ + --hash=sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b \ + --hash=sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf \ + --hash=sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46 \ + --hash=sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb \ + --hash=sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc \ + --hash=sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696 \ + --hash=sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77 \ + --hash=sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183 \ + --hash=sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10 \ + --hash=sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db \ + --hash=sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e +regex==2020.11.13; python_version >= "3.6" \ + --hash=sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85 \ + --hash=sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70 \ + --hash=sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee \ + --hash=sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5 \ + --hash=sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7 \ + --hash=sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31 \ + --hash=sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa \ + --hash=sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6 \ + --hash=sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e \ + --hash=sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884 \ + --hash=sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b \ + --hash=sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88 \ + --hash=sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0 \ + --hash=sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1 \ + --hash=sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0 \ + --hash=sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512 \ + --hash=sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba \ + --hash=sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538 \ + --hash=sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4 \ + --hash=sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444 \ + --hash=sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f \ + --hash=sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d \ + --hash=sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af \ + --hash=sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f \ + --hash=sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b \ + --hash=sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8 \ + --hash=sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5 \ + --hash=sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b \ + --hash=sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c \ + --hash=sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683 \ + --hash=sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc \ + --hash=sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364 \ + --hash=sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e \ + --hash=sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e \ + --hash=sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917 \ + --hash=sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b \ + --hash=sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9 \ + --hash=sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c \ + --hash=sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f \ + --hash=sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d \ + --hash=sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562 +requests==2.25.1; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5" \ + --hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e \ + --hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 +rope==0.18.0 \ + --hash=sha256:786b5c38c530d4846aa68a42604f61b4e69a493390e3ca11b88df0fbfdc3ed04 +six==1.15.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 +smmap==3.0.5; python_version >= "3.4" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.4" \ + --hash=sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714 \ + --hash=sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50 +snowballstemmer==2.1.0; python_version >= "3.5" \ + --hash=sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2 \ + --hash=sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914 +sphinx-rtd-theme==0.5.1 \ + --hash=sha256:fa6bebd5ab9a73da8e102509a86f3fcc36dec04a0b52ea80e5a033b2aba00113 \ + --hash=sha256:eda689eda0c7301a80cf122dad28b1861e5605cbf455558f3775e1e8200e83a5 +sphinx==3.4.3; python_version >= "3.5" \ + --hash=sha256:c314c857e7cd47c856d2c5adff514ac2e6495f8b8e0f886a8a37e9305dfea0d8 \ + --hash=sha256:41cad293f954f7d37f803d97eb184158cfd90f51195131e94875bc07cd08b93c +sphinxcontrib-applehelp==1.0.2; python_version >= "3.5" \ + --hash=sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58 \ + --hash=sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a +sphinxcontrib-devhelp==1.0.2; python_version >= "3.5" \ + --hash=sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4 \ + --hash=sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e +sphinxcontrib-htmlhelp==1.0.3; python_version >= "3.5" \ + --hash=sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b \ + --hash=sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f +sphinxcontrib-jsmath==1.0.1; python_version >= "3.5" \ + --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8 \ + --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 +sphinxcontrib-qthelp==1.0.3; python_version >= "3.5" \ + --hash=sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72 \ + --hash=sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6 +sphinxcontrib-serializinghtml==1.1.4; python_version >= "3.5" \ + --hash=sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc \ + --hash=sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a +sqlparse==0.4.1; python_version >= "3.6" and python_version < "4.0" \ + --hash=sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0 \ + --hash=sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8 +toml==0.10.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" \ + --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ + --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f +typed-ast==1.4.2; python_version >= "3.6" \ + --hash=sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70 \ + --hash=sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487 \ + --hash=sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412 \ + --hash=sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400 \ + --hash=sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606 \ + --hash=sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64 \ + --hash=sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07 \ + --hash=sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc \ + --hash=sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a \ + --hash=sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151 \ + --hash=sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3 \ + --hash=sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41 \ + --hash=sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f \ + --hash=sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581 \ + --hash=sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37 \ + --hash=sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd \ + --hash=sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496 \ + --hash=sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc \ + --hash=sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10 \ + --hash=sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea \ + --hash=sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787 \ + --hash=sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2 \ + --hash=sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937 \ + --hash=sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1 \ + --hash=sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6 \ + --hash=sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166 \ + --hash=sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d \ + --hash=sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b \ + --hash=sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440 \ + --hash=sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a +typing-extensions==3.7.4.3; python_version >= "3.6" \ + --hash=sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f \ + --hash=sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918 \ + --hash=sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c +urllib3==1.26.3; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.5" \ + --hash=sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80 \ + --hash=sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73 +zipp==3.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.5.0" \ + --hash=sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108 \ + --hash=sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb From 2f4b26999ecb76e8972e6d0a45f50d4b48bcb48c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Pi=C3=A9tri?= Date: Sat, 13 Feb 2021 23:24:50 +0100 Subject: [PATCH 6/7] fix: :bug: Remove clashes in permissions for the ticket app Permissions clashes of view_* are removed for the ticket app. --- tickets/models.py | 2 -- tickets/preferences/models.py | 1 - 2 files changed, 3 deletions(-) diff --git a/tickets/models.py b/tickets/models.py index bc62e22b..dc25215f 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -87,7 +87,6 @@ class Ticket(AclMixin, models.Model): request = None class Meta: - permissions = (("view_ticket", _("Can view a ticket object")),) verbose_name = _("ticket") verbose_name_plural = _("tickets") @@ -197,7 +196,6 @@ class CommentTicket(AclMixin, models.Model): request = None class Meta: - permissions = (("view_commentticket", _("Can view a ticket object")),) verbose_name = _("ticket") verbose_name_plural = _("tickets") diff --git a/tickets/preferences/models.py b/tickets/preferences/models.py index 92d8e8c5..aa6bde63 100644 --- a/tickets/preferences/models.py +++ b/tickets/preferences/models.py @@ -44,4 +44,3 @@ class TicketOption(AclMixin, PreferencesModel): class Meta: verbose_name = _("tickets options") - permissions = (("view_ticketoption", _("Can view tickets options")),) From 4976b6fb79d1f4809f3a51b625c3a2bba9264294 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sun, 14 Feb 2021 09:26:29 +0100 Subject: [PATCH 7/7] fix: correct management of extra dependencies. --- poetry.lock | 29 +++++++++++++++++------------ pyproject.toml | 11 ++++++++--- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7a1ec92b..d2100b7e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -152,7 +152,7 @@ name = "django-ldapdb" version = "1.5.1" description = "A LDAP database backend for Django" category = "main" -optional = false +optional = true python-versions = ">=3.6" [package.dependencies] @@ -333,7 +333,7 @@ name = "mysqlclient" version = "2.0.3" description = "Python interface to MySQL" category = "main" -optional = false +optional = true python-versions = ">=3.5" [[package]] @@ -379,7 +379,7 @@ name = "psycopg2" version = "2.8.6" description = "psycopg2 - Python-PostgreSQL Database Adapter" category = "main" -optional = false +optional = true python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" [[package]] @@ -387,7 +387,7 @@ name = "pyasn1" version = "0.4.8" description = "ASN.1 types and codecs" category = "main" -optional = false +optional = true python-versions = "*" [[package]] @@ -395,7 +395,7 @@ name = "pyasn1-modules" version = "0.2.8" description = "A collection of ASN.1-based protocols modules." category = "main" -optional = false +optional = true python-versions = "*" [package.dependencies] @@ -441,7 +441,7 @@ name = "python-ldap" version = "3.3.1" description = "Python modules for implementing LDAP clients" category = "main" -optional = false +optional = true python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" [package.dependencies] @@ -527,7 +527,7 @@ python-versions = "*" [[package]] name = "sphinx" -version = "3.4.3" +version = "3.5.0" description = "Python documentation generator" category = "dev" optional = false @@ -552,9 +552,9 @@ sphinxcontrib-qthelp = "*" sphinxcontrib-serializinghtml = "*" [package.extras] -docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.790)", "docutils-stubs"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "isort", "mypy (>=0.800)"] test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] +docs = ["sphinxcontrib-websupport"] [[package]] name = "sphinx-rtd-theme" @@ -698,10 +698,15 @@ python-versions = ">=3.6" docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +[extras] +ldap = ["django-ldapdb"] +mysql = ["mysqlclient"] +postgresql = ["psycopg2"] + [metadata] lock-version = "1.1" python-versions = ">=3.6,<4.0" -content-hash = "2b09b64cff09acd37cc7aef057626140845e0a60f2658a4bf45a6eea443d1b09" +content-hash = "c914e5f3cc676263f65d9489e9ea748770edb046ec45625424a67375760c791a" [metadata.files] alabaster = [ @@ -1122,8 +1127,8 @@ snowballstemmer = [ {file = "snowballstemmer-2.1.0.tar.gz", hash = "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"}, ] sphinx = [ - {file = "Sphinx-3.4.3-py3-none-any.whl", hash = "sha256:c314c857e7cd47c856d2c5adff514ac2e6495f8b8e0f886a8a37e9305dfea0d8"}, - {file = "Sphinx-3.4.3.tar.gz", hash = "sha256:41cad293f954f7d37f803d97eb184158cfd90f51195131e94875bc07cd08b93c"}, + {file = "Sphinx-3.5.0-py3-none-any.whl", hash = "sha256:68da66ca3d6b35b22bea5c53d938d5f8988663dca042f0a46429a1eba1010051"}, + {file = "Sphinx-3.5.0.tar.gz", hash = "sha256:deb468efb3abaa70d790add4147d18782d86fdeacf648d6e8afb7a99807f1546"}, ] sphinx-rtd-theme = [ {file = "sphinx_rtd_theme-0.5.1-py2.py3-none-any.whl", hash = "sha256:fa6bebd5ab9a73da8e102509a86f3fcc36dec04a0b52ea80e5a033b2aba00113"}, diff --git a/pyproject.toml b/pyproject.toml index 89381319..008450ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,9 +55,14 @@ python-dateutil = "^2.8.1" django-macaddress = "^1.7.0" pycrypto = "^2.6.1" GitPython = "^3.1.13" -mysqlclient = {version = "^2.0.3", extras = ["mysql"]} -psycopg2 = {version = "^2.8.6", extras = ["postgresql"]} -django-ldapdb = {version = "^1.5.1", extras = ["ldap"]} +mysqlclient = {version = "^2.0.3", optional=true} +psycopg2 = {version = "^2.8.6", optional=true} +django-ldapdb = {version = "^1.5.1", optional=true} + +[tool.poetry.extras] +mysql = ["mysqlclient"] +postgresql = ["psycopg2"] +ldap = ["django-ldapdb"] [tool.poetry.dev-dependencies] Sphinx = "^3.4.3"