accrete 0.0.26__tar.gz → 0.0.28__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {accrete-0.0.26 → accrete-0.0.28}/PKG-INFO +2 -1
- accrete-0.0.28/accrete/contrib/sequence/migrations/0002_alter_sequence_name.py +18 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/models.py +1 -1
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/queries.py +2 -2
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/tasks.py +10 -3
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/__init__.py +2 -1
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/components.py +29 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/context.py +16 -11
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/filter.py +24 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/querystring.py +1 -1
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/js/filter.js +20 -2
- accrete-0.0.28/accrete/contrib/ui/templates/ui/detail.html +35 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/layout.html +5 -3
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/list.html +0 -5
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/filter.html +1 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/header.html +3 -1
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/table.html +3 -6
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templatetags/accrete_ui.py +12 -0
- accrete-0.0.28/accrete/contrib/user/forms.py +119 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/templates/user/accrete_navbar_end.html +5 -1
- accrete-0.0.28/accrete/contrib/user/templates/user/change_email.html +29 -0
- accrete-0.0.28/accrete/contrib/user/templates/user/change_password.html +40 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/urls.py +3 -2
- accrete-0.0.28/accrete/contrib/user/views.py +105 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/forms.py +6 -2
- {accrete-0.0.26 → accrete-0.0.28}/accrete/forms.py +6 -5
- accrete-0.0.28/accrete/utils/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/utils/dates.py +10 -2
- {accrete-0.0.26 → accrete-0.0.28}/pyproject.toml +3 -2
- accrete-0.0.26/accrete/contrib/ui/static/js/filter_old.js +0 -734
- accrete-0.0.26/accrete/contrib/ui/templates/ui/detail.html +0 -17
- accrete-0.0.26/accrete/contrib/user/forms.py +0 -28
- accrete-0.0.26/accrete/contrib/user/views.py +0 -60
- {accrete-0.0.26 → accrete-0.0.28}/.gitignore +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/LICENSE +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/README.md +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/admin.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/apps.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/config.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/admin.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/apps.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/forms.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/migrations/0001_initial.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/migrations/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/tests.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/sequence/views.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/admin.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/apps.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/forms.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/migrations/0001_initial.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/migrations/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/models.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/tests.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/system_mail/views.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/admin.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/apps.py +0 -0
- /accrete-0.0.26/accrete/contrib/ui/migrations/__init__.py → /accrete-0.0.28/accrete/contrib/ui/elements.py +0 -0
- {accrete-0.0.26/accrete/contrib/ui/templatetags → accrete-0.0.28/accrete/contrib/ui/migrations}/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/LICENSE +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/README.md +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/bulma.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/css/bulma-rtl.css +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/css/bulma-rtl.css.map +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/css/bulma-rtl.min.css +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/css/bulma.css +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/css/bulma.css.map +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/css/bulma.min.css +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/package.json +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/base/_all.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/base/animations.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/base/generic.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/base/helpers.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/base/minireset.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/_all.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/breadcrumb.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/card.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/dropdown.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/level.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/media.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/menu.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/message.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/modal.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/navbar.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/pagination.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/panel.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/components/tabs.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/_all.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/box.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/button.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/container.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/content.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/form.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/icon.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/image.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/notification.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/other.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/progress.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/table.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/tag.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/elements/title.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/form/_all.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/form/checkbox-radio.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/form/file.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/form/input-textarea.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/form/select.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/form/shared.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/form/tools.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/grid/_all.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/grid/columns.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/grid/tiles.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/_all.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/color.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/flexbox.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/float.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/other.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/overflow.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/position.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/spacing.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/typography.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/helpers/visibility.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/layout/_all.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/layout/footer.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/layout/hero.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/layout/section.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/utilities/_all.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/utilities/animations.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/utilities/controls.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/utilities/derived-variables.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/utilities/extends.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/utilities/functions.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/utilities/initial-variables.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/bulma/sass/utilities/mixins.sass +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/css/accrete.css +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/css/accrete.css.bak +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/css/accrete.css.map +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/css/accrete.scss +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/css/icons.css +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/icons/Logo.svg +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/icons/accrete.svg +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/js/list.js +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/js/navbar.js +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/static/js/utils.js +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/django/forms/widgets/attrs.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/django/forms/widgets/email.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/django/forms/widgets/file.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/django/forms/widgets/input.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/django/forms/widgets/select.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/django/forms/widgets/text.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/django/forms/widgets/textarea.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/form.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/form_errors.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/form_modal.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/onchange_form.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/pagination_detail.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/pagination_list.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/table_field.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/table_field_float.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/table_field_monetary.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/templates/ui/partials/table_field_string.html +0 -0
- {accrete-0.0.26/accrete/contrib/user → accrete-0.0.28/accrete/contrib/ui/templatetags}/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/tests.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/urls.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/ui/views.py +0 -0
- {accrete-0.0.26/accrete/contrib/user/migrations → accrete-0.0.28/accrete/contrib/user}/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/admin.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/apps.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/locale/de/LC_MESSAGES/django.mo +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/locale/de/LC_MESSAGES/django.po +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/middleware.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/migrations/0001_initial.py +0 -0
- {accrete-0.0.26/accrete/contrib/user_registration → accrete-0.0.28/accrete/contrib/user/migrations}/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/models.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/templates/user/login.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/templates/user/user_detail.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/templates/user/user_form.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/tests.py +0 -0
- {accrete-0.0.26/accrete/contrib/user_registration/migrations → accrete-0.0.28/accrete/contrib/user_registration}/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/admin.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/apps.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/config.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/migrations/0001_initial.py +0 -0
- {accrete-0.0.26/accrete → accrete-0.0.28/accrete/contrib/user_registration}/migrations/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/models.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/templates/user_registration/mail_templates/confirmation_mail.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/templates/user_registration/registration.html +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/tests.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/urls.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user_registration/views.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/decorators.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/middleware.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/migrations/0001_initial.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/migrations/0002_initial.py +0 -0
- {accrete-0.0.26/accrete/utils → accrete-0.0.28/accrete/migrations}/__init__.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/models.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/queries.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/querystring.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/tenant.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/tests.py +0 -0
- {accrete-0.0.26 → accrete-0.0.28}/accrete/views.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: accrete
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.28
|
4
4
|
Summary: Django Shared Schema Multi Tenant
|
5
5
|
Author-email: Benedikt Jilek <benedikt.jilek@pm.me>
|
6
6
|
License: Copyright (c) 2023 Benedikt Jilek
|
@@ -35,6 +35,7 @@ Requires-Dist: django>=4.2
|
|
35
35
|
Provides-Extra: contrib
|
36
36
|
Requires-Dist: celery>=5.3.4; extra == 'contrib'
|
37
37
|
Requires-Dist: django-celery-beat; extra == 'contrib'
|
38
|
+
Requires-Dist: sqlalchemy; extra == 'contrib'
|
38
39
|
Provides-Extra: dev
|
39
40
|
Requires-Dist: build; extra == 'dev'
|
40
41
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Generated by Django 4.2.9 on 2024-01-27 07:50
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
('sequence', '0001_initial'),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AlterField(
|
14
|
+
model_name='sequence',
|
15
|
+
name='name',
|
16
|
+
field=models.CharField(max_length=255, verbose_name='Name'),
|
17
|
+
),
|
18
|
+
]
|
@@ -9,11 +9,11 @@ def get_nextval(name, create_if_none=True):
|
|
9
9
|
tenant = get_tenant()
|
10
10
|
with transaction.atomic():
|
11
11
|
seq = Sequence.objects.filter(
|
12
|
-
tenant=tenant
|
12
|
+
tenant=tenant, name=name
|
13
13
|
).select_for_update().first()
|
14
14
|
|
15
15
|
if seq is None and not create_if_none:
|
16
|
-
raise
|
16
|
+
raise ValueError(f'Sequence "{name}" does not exist.')
|
17
17
|
elif seq is None:
|
18
18
|
seq = Sequence(name=name, tenant=tenant)
|
19
19
|
seq.save()
|
@@ -1,15 +1,22 @@
|
|
1
1
|
import logging
|
2
|
-
from celery import shared_task
|
3
|
-
|
2
|
+
from celery import shared_task, current_app
|
3
|
+
from celery.schedules import crontab
|
4
4
|
from django.core import mail
|
5
5
|
from django.db import transaction
|
6
6
|
from django.utils.html import strip_tags
|
7
|
-
|
8
7
|
from .models import SystemMail
|
9
8
|
|
10
9
|
_logger = logging.getLogger(__name__)
|
11
10
|
|
12
11
|
|
12
|
+
@current_app.on_after_finalize.connect
|
13
|
+
def setup_periodic_tasks(sender, **kwargs):
|
14
|
+
sender.add_periodic_task(
|
15
|
+
crontab(hour='*', minute='*/5'),
|
16
|
+
run_mail_queue.s()
|
17
|
+
)
|
18
|
+
|
19
|
+
|
13
20
|
@shared_task()
|
14
21
|
def run_mail_queue():
|
15
22
|
with transaction.atomic():
|
@@ -6,9 +6,10 @@ from .context import (
|
|
6
6
|
)
|
7
7
|
from .components import (
|
8
8
|
ClientAction,
|
9
|
+
ActionMethod,
|
9
10
|
BreadCrumb,
|
10
11
|
TableField,
|
11
12
|
TableFieldAlignment,
|
12
13
|
TableFieldType
|
13
14
|
)
|
14
|
-
from .querystring import load_querystring,
|
15
|
+
from .querystring import load_querystring, build_querystring
|
@@ -1,5 +1,17 @@
|
|
1
1
|
from dataclasses import dataclass, field
|
2
2
|
from enum import Enum
|
3
|
+
from django.db.models import Model, QuerySet, Q
|
4
|
+
|
5
|
+
DEFAULT_PAGINATE_BY = 40
|
6
|
+
|
7
|
+
|
8
|
+
class ActionMethod(Enum):
|
9
|
+
|
10
|
+
HREF = 'href'
|
11
|
+
GET = 'hx-get'
|
12
|
+
POST = 'hx-post'
|
13
|
+
PUT = 'hx-put'
|
14
|
+
DELETE = 'hx-delete'
|
3
15
|
|
4
16
|
|
5
17
|
class TableFieldAlignment(Enum):
|
@@ -37,6 +49,7 @@ class BreadCrumb:
|
|
37
49
|
|
38
50
|
name: str
|
39
51
|
url: str
|
52
|
+
add_url_params: bool = True
|
40
53
|
|
41
54
|
|
42
55
|
@dataclass
|
@@ -44,8 +57,24 @@ class ClientAction:
|
|
44
57
|
|
45
58
|
name: str
|
46
59
|
url: str = ''
|
60
|
+
method: ActionMethod = ActionMethod.HREF
|
47
61
|
query_params: str = ''
|
48
62
|
attrs: list[tuple[str, str]] = field(default_factory=list)
|
49
63
|
submit: bool = False
|
50
64
|
form_id: str = 'form'
|
51
65
|
class_list: list[str] = field(default_factory=list)
|
66
|
+
add_url_params: bool = True
|
67
|
+
|
68
|
+
def attrs_str(self):
|
69
|
+
return ' '.join(['='.join(attr) for attr in self.attrs])
|
70
|
+
|
71
|
+
|
72
|
+
@dataclass
|
73
|
+
class List:
|
74
|
+
|
75
|
+
queryset: QuerySet
|
76
|
+
title: str = None
|
77
|
+
paginate_by: int = DEFAULT_PAGINATE_BY
|
78
|
+
breadcrumbs: list[BreadCrumb] = field(default_factory=list)
|
79
|
+
actions: list[ClientAction] = field(default_factory=list)
|
80
|
+
fields: list[TableField] = field(default_factory=list)
|
@@ -4,9 +4,10 @@ from dataclasses import dataclass, field
|
|
4
4
|
from django.utils.translation import gettext_lazy as _
|
5
5
|
from django.db.models import Model, QuerySet, Q
|
6
6
|
from django.core.paginator import Paginator
|
7
|
+
from django.forms import Form, ModelForm
|
7
8
|
from accrete.querystring import parse_querystring
|
8
9
|
|
9
|
-
from .querystring import load_querystring,
|
10
|
+
from .querystring import load_querystring, build_querystring
|
10
11
|
from .components import ClientAction, BreadCrumb, TableField
|
11
12
|
from .filter import Filter
|
12
13
|
|
@@ -42,16 +43,16 @@ class ListContext:
|
|
42
43
|
|
43
44
|
order = self.order_by or self.model._meta.ordering
|
44
45
|
|
45
|
-
pks = self.model.objects.filter(
|
46
|
-
|
47
|
-
).distinct().values_list('pk', flat=True)
|
46
|
+
# pks = self.model.objects.filter(
|
47
|
+
# parse_querystring(self.model, self.get_params.get('q', '[]'))
|
48
|
+
# ).distinct().values_list('pk', flat=True)
|
48
49
|
|
49
50
|
queryset = self.model.objects.select_related(
|
50
51
|
*self.select_related
|
51
52
|
).prefetch_related(
|
52
53
|
*self.prefetch_related
|
53
54
|
).filter(
|
54
|
-
|
55
|
+
parse_querystring(self.model, self.get_params.get('q', '[]'))
|
55
56
|
).annotate(
|
56
57
|
**self.get_annotations()
|
57
58
|
).order_by(
|
@@ -109,7 +110,7 @@ class ListContext:
|
|
109
110
|
'default_filter_term': self.default_filter_term,
|
110
111
|
'breadcrumbs': self.breadcrumbs,
|
111
112
|
'querystring': load_querystring(self.get_params),
|
112
|
-
'url_params':
|
113
|
+
'url_params': build_querystring(self.get_params),
|
113
114
|
'actions': self.actions,
|
114
115
|
'fields': self.fields
|
115
116
|
}
|
@@ -208,7 +209,7 @@ class DetailContext:
|
|
208
209
|
'paginate_by': paginate_by,
|
209
210
|
'detail_pagination': False,
|
210
211
|
'breadcrumbs': self.breadcrumbs,
|
211
|
-
'url_params':
|
212
|
+
'url_params': build_querystring(self.get_params, ['page']),
|
212
213
|
'actions': self.actions
|
213
214
|
}
|
214
215
|
if self.paginate_by > 0:
|
@@ -221,6 +222,7 @@ class DetailContext:
|
|
221
222
|
class FormContext:
|
222
223
|
|
223
224
|
model: Model | type[Model]
|
225
|
+
form: Form | ModelForm
|
224
226
|
get_params: dict
|
225
227
|
title: str = None
|
226
228
|
context: dict = field(default_factory=dict)
|
@@ -228,6 +230,7 @@ class FormContext:
|
|
228
230
|
add_default_actions: bool = True
|
229
231
|
discard_url: str = None
|
230
232
|
actions: list[ClientAction] = field(default_factory=list)
|
233
|
+
breadcrumbs: list[BreadCrumb] = field(default_factory=list)
|
231
234
|
|
232
235
|
def get_default_form_actions(self):
|
233
236
|
actions = [
|
@@ -266,16 +269,18 @@ class FormContext:
|
|
266
269
|
return self.title
|
267
270
|
try:
|
268
271
|
int(self.model.pk)
|
269
|
-
return
|
272
|
+
return _('Edit')
|
270
273
|
except TypeError:
|
271
|
-
return
|
274
|
+
return _('Add')
|
272
275
|
|
273
276
|
def dict(self):
|
274
277
|
ctx = {
|
275
278
|
'title': self.get_title(),
|
279
|
+
'form': self.form,
|
276
280
|
'form_id': self.form_id,
|
277
|
-
'url_params':
|
278
|
-
'actions': []
|
281
|
+
'url_params': build_querystring(self.get_params, ['page']),
|
282
|
+
'actions': [],
|
283
|
+
'breadcrumbs': self.breadcrumbs,
|
279
284
|
}
|
280
285
|
if self.add_default_actions:
|
281
286
|
ctx.update({'actions': self.get_default_form_actions()})
|
@@ -115,6 +115,28 @@ class Filter:
|
|
115
115
|
]
|
116
116
|
}
|
117
117
|
|
118
|
+
def get_choice_int_query_term(self, label, param, choices):
|
119
|
+
choices = [(choice[0], str(choice[1])) for choice in choices]
|
120
|
+
return {
|
121
|
+
'label': str(label),
|
122
|
+
'param': param,
|
123
|
+
'params': [
|
124
|
+
{
|
125
|
+
'label': str(self.LABEL_EXACT),
|
126
|
+
'data_type': 'selection',
|
127
|
+
'choices': choices,
|
128
|
+
'param': 'exact'
|
129
|
+
},
|
130
|
+
{
|
131
|
+
'label': str(self.LABEL_EXACT_NOT),
|
132
|
+
'data_type': 'selection',
|
133
|
+
'choices': choices,
|
134
|
+
'invert': True,
|
135
|
+
'param': 'exact'
|
136
|
+
}
|
137
|
+
]
|
138
|
+
}
|
139
|
+
|
118
140
|
def get_int_query_term(self, label, param):
|
119
141
|
return {
|
120
142
|
'label': str(label),
|
@@ -258,6 +280,8 @@ class Filter:
|
|
258
280
|
label, param, self.cast_decimal_places_to_step(field.decimal_places or 0)
|
259
281
|
)
|
260
282
|
elif internal_type in self.query_int_fields:
|
283
|
+
if field.choices:
|
284
|
+
return self.get_choice_int_query_term(label, param, field.choices)
|
261
285
|
return self.get_int_query_term(label, param)
|
262
286
|
elif internal_type in self.query_boolean_fields:
|
263
287
|
return self.get_boolean_query_term(label, param)
|
@@ -5,7 +5,7 @@ def load_querystring(get_params: dict) -> list:
|
|
5
5
|
return json.loads(get_params.get('q', '[]'))
|
6
6
|
|
7
7
|
|
8
|
-
def
|
8
|
+
def build_querystring(get_params: dict, extra_params: list[str] = None) -> str:
|
9
9
|
querystring = f'?q={get_params.get("q", "[]")}'
|
10
10
|
if paginate_by := get_params.get('paginate_by', False):
|
11
11
|
querystring += f'&paginate_by={paginate_by}'
|
@@ -8,6 +8,7 @@ function buildQueryTagsFromUrl() {
|
|
8
8
|
const queryGroup = createQueryGroup();
|
9
9
|
queryTags.appendChild(queryGroup)
|
10
10
|
buildQueryFromQueryString(normalizeQueryString(), queryGroup, '&');
|
11
|
+
toggleFilterModalButton();
|
11
12
|
}
|
12
13
|
|
13
14
|
function removeQueryTagsChildren() {
|
@@ -18,7 +19,6 @@ function removeQueryTagsChildren() {
|
|
18
19
|
}
|
19
20
|
|
20
21
|
function buildQueryFromQueryString(jsonQuery, queryGroup, operator='&') {
|
21
|
-
console.log(jsonQuery)
|
22
22
|
for (let item of jsonQuery) {
|
23
23
|
if (isString(item)) {
|
24
24
|
operator = item
|
@@ -229,6 +229,9 @@ function appendAfterTag(queryTagContainer) {
|
|
229
229
|
function resetInput() {
|
230
230
|
const input = document.getElementById('query-input');
|
231
231
|
const queryParam = getParamElement(input.getAttribute('data-default-term'))
|
232
|
+
if (!queryParam) {
|
233
|
+
return
|
234
|
+
}
|
232
235
|
const queryLabel = getCompleteQueryText(queryParam);
|
233
236
|
const queryNotificationLabel = document.getElementById('query-label');
|
234
237
|
queryNotificationLabel.innerText = queryLabel;
|
@@ -244,6 +247,18 @@ function fetchQuery(queryString=null) {
|
|
244
247
|
queryApply.setAttribute('hx-get', url.toString());
|
245
248
|
htmx.process(queryApply);
|
246
249
|
queryApply.dispatchEvent(queryApplyEvent);
|
250
|
+
toggleFilterModalButton();
|
251
|
+
}
|
252
|
+
|
253
|
+
function toggleFilterModalButton() {
|
254
|
+
const button = document.getElementById('modal-filter-button');
|
255
|
+
const query = document.getElementById('query-tags');
|
256
|
+
if (query.firstElementChild && query.firstElementChild.childElementCount) {
|
257
|
+
button.classList.add('is-primary');
|
258
|
+
}
|
259
|
+
else {
|
260
|
+
button.classList.remove('is-primary');
|
261
|
+
}
|
247
262
|
}
|
248
263
|
|
249
264
|
//-----------------------------------------------------------------------------
|
@@ -253,6 +268,9 @@ function fetchQuery(queryString=null) {
|
|
253
268
|
function showHide() {
|
254
269
|
const target = this.event.target;
|
255
270
|
const queryInput = document.getElementById('query-input-fieldset');
|
271
|
+
if (!queryInput) {
|
272
|
+
return;
|
273
|
+
}
|
256
274
|
const queryParamDropDown = document.getElementById('query-params-dropdown');
|
257
275
|
const operation = document.getElementById('query-operation');
|
258
276
|
if (queryInput.contains(target)
|
@@ -683,4 +701,4 @@ function isBoolean(value) {
|
|
683
701
|
return value.toLowerCase() === 'false' || value.toLowerCase() === 'true'
|
684
702
|
}
|
685
703
|
return false
|
686
|
-
}
|
704
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
{% extends 'ui/layout.html' %}
|
2
|
+
{% load i18n %}
|
3
|
+
{% load accrete_ui %}
|
4
|
+
|
5
|
+
{% block messages %}
|
6
|
+
{% if messages %}
|
7
|
+
<div class="columns is-desktop">
|
8
|
+
<div class="column is-8">
|
9
|
+
{% for message in messages %}
|
10
|
+
<div class="columns py-0">
|
11
|
+
<div class="column is-12">
|
12
|
+
<div class="notification {{ message|message_class }} is-light">
|
13
|
+
<p>{{ message }}</p>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
{% endfor %}
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
{% endif %}
|
21
|
+
{% endblock %}
|
22
|
+
|
23
|
+
{% block content %}
|
24
|
+
<div class="columns is-desktop">
|
25
|
+
<div class="column p-0 is-8-desktop">
|
26
|
+
{% block detail_content %}{% endblock %}
|
27
|
+
</div>
|
28
|
+
<div class="info-panel column is-4">
|
29
|
+
<nav class="panel">
|
30
|
+
{% block info_panel %}
|
31
|
+
{% endblock %}
|
32
|
+
</nav>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
{% endblock %}
|
@@ -93,12 +93,14 @@
|
|
93
93
|
{% if action.submit %}
|
94
94
|
<input class="button is-fullwidth {{ action.class_list|join:' ' }}"
|
95
95
|
type="submit" form={{ action.form_id }} value="{{ action.name }}"
|
96
|
-
{
|
96
|
+
{{ action.attrs_str }}
|
97
97
|
>
|
98
98
|
{% else %}
|
99
99
|
<a class="button is-fullwidth {{ action.class_list|join:' ' }}"
|
100
|
-
|
101
|
-
|
100
|
+
{% if action.url %}
|
101
|
+
{{ action.method.value }}="{{ action.url }}{% if action.add_url_params %}{{ url_params|default_if_none:'?' }}{% endif %}{% if page %}&page={{ page.number }}{% endif %}{{ action.query_params }}"
|
102
|
+
{% endif %}
|
103
|
+
{{ action.attrs_str }}
|
102
104
|
>{{ action.name }}
|
103
105
|
</a>
|
104
106
|
{% endif %}
|
@@ -2,11 +2,6 @@
|
|
2
2
|
{% load static %}
|
3
3
|
{% load i18n %}
|
4
4
|
|
5
|
-
{% block script %}
|
6
|
-
{{ block.super }}
|
7
|
-
<script src="{% static "js/filter.js" %}" defer type="text/javascript"></script>
|
8
|
-
{% endblock %}
|
9
|
-
|
10
5
|
{% block content %}
|
11
6
|
<div class="columns is-multiline">
|
12
7
|
{% for obj in page %}
|
@@ -4,6 +4,7 @@
|
|
4
4
|
{% load accrete_ui %}
|
5
5
|
|
6
6
|
<div id="query-block" class="panel-block pt-0" style="position: relative; display: inline-block; width: 100%">
|
7
|
+
<script src="{% static "js/filter.js" %}" defer type="text/javascript"></script>
|
7
8
|
<div id="query-apply" hx-get="" hx-trigger="click" hx-replace-url="true"
|
8
9
|
hx-select-oob="#content,#list-pagination,#panel-actions,#header-actions,#query-apply">
|
9
10
|
|
@@ -7,7 +7,9 @@
|
|
7
7
|
<nav id="breadcrumbs" class="breadcrumb" aria-label="breadcrumbs" style="white-space: unset; word-break: break-word">
|
8
8
|
<ul>
|
9
9
|
{% for crumb in breadcrumbs %}
|
10
|
-
<li><a class="is-underlined"
|
10
|
+
<li><a class="is-underlined" hx-get="{{ crumb.url|default_if_none:'#' }}{% if crumb.add_url_params %}{{ url_params }}{% endif %}"
|
11
|
+
hx-target="body" hx-push-url="true" aria-current="page"
|
12
|
+
>{{ crumb.name }}</a></li>
|
11
13
|
{% endfor %}
|
12
14
|
<li class="is-active"><a aria-current="page">{{ title }}</a></li>
|
13
15
|
</ul>
|
@@ -3,11 +3,6 @@
|
|
3
3
|
{% load i18n %}
|
4
4
|
{% load accrete_ui %}
|
5
5
|
|
6
|
-
{% block script %}
|
7
|
-
{{ block.super }}
|
8
|
-
<script src="{% static "js/filter.js" %}" defer type="text/javascript"></script>
|
9
|
-
{% endblock %}
|
10
|
-
|
11
6
|
{% block content %}
|
12
7
|
<table class="table hax-box is-fullwidth is-hoverable" hx-indicator=".htmx-indicator">
|
13
8
|
<thead style="position: sticky; top: 0; background: white; z-index: 10">
|
@@ -36,7 +31,9 @@
|
|
36
31
|
hx-swap="afterend"
|
37
32
|
{% endif %}>
|
38
33
|
{% block table_data %}
|
39
|
-
<td><a class="is-underlined"
|
34
|
+
<td><a class="is-underlined" hx-get="{{ obj.get_absolute_url }}{{ url_params }}&page={{ page.number }}"
|
35
|
+
hx-target="body" hx-push-url="true"
|
36
|
+
>{{ obj }}</a></td>
|
40
37
|
{% for field in fields %}
|
41
38
|
{% if field.template %}
|
42
39
|
{% include field.template %}
|
@@ -3,6 +3,7 @@ from django import template
|
|
3
3
|
from django.conf import settings
|
4
4
|
from django.template.loader import render_to_string
|
5
5
|
from django.utils.safestring import mark_safe
|
6
|
+
from django.contrib import messages
|
6
7
|
|
7
8
|
_logger = logging.getLogger(__name__)
|
8
9
|
register = template.Library()
|
@@ -34,6 +35,17 @@ def get_attr_from_string(param, value):
|
|
34
35
|
return attr
|
35
36
|
|
36
37
|
|
38
|
+
@register.filter(name='message_class')
|
39
|
+
def message_class(param):
|
40
|
+
if param.level == 25:
|
41
|
+
return 'is-success'
|
42
|
+
if param.level == 30:
|
43
|
+
return 'is-warning'
|
44
|
+
if param.level == 40:
|
45
|
+
return 'is-danger'
|
46
|
+
|
47
|
+
|
48
|
+
|
37
49
|
@register.filter(name='render_query_params')
|
38
50
|
def query_params_to_html(params):
|
39
51
|
html = ''
|
@@ -0,0 +1,119 @@
|
|
1
|
+
from django.conf import settings
|
2
|
+
from django.core.validators import validate_email
|
3
|
+
from django.utils.translation import gettext_lazy as _
|
4
|
+
from django.forms import ModelForm, fields, ValidationError, PasswordInput, EmailInput
|
5
|
+
from .models import User
|
6
|
+
|
7
|
+
|
8
|
+
class UserForm(ModelForm):
|
9
|
+
|
10
|
+
language_code = fields.ChoiceField(
|
11
|
+
label=_('Language'),
|
12
|
+
choices=settings.LANGUAGES,
|
13
|
+
required=True
|
14
|
+
)
|
15
|
+
|
16
|
+
class Meta:
|
17
|
+
model = User
|
18
|
+
fields = [
|
19
|
+
'username',
|
20
|
+
'first_name',
|
21
|
+
'last_name',
|
22
|
+
]
|
23
|
+
|
24
|
+
def save(self, commit=True):
|
25
|
+
super().save(commit=False)
|
26
|
+
self.instance.language_code = self.cleaned_data['language_code']
|
27
|
+
if commit:
|
28
|
+
self.instance.save()
|
29
|
+
self.save_m2m()
|
30
|
+
|
31
|
+
|
32
|
+
class ChangePasswordForm(ModelForm):
|
33
|
+
|
34
|
+
old_password = fields.CharField(
|
35
|
+
label=_('Old password'),
|
36
|
+
widget=PasswordInput(render_value=True),
|
37
|
+
max_length=128,
|
38
|
+
)
|
39
|
+
|
40
|
+
new_password = fields.CharField(
|
41
|
+
label=_('New password'),
|
42
|
+
widget=PasswordInput(render_value=True),
|
43
|
+
max_length=128
|
44
|
+
)
|
45
|
+
|
46
|
+
new_password_confirm = fields.CharField(
|
47
|
+
label=_('New password confirmation'),
|
48
|
+
widget=PasswordInput(render_value=True),
|
49
|
+
max_length=128
|
50
|
+
)
|
51
|
+
|
52
|
+
class Meta:
|
53
|
+
model = User
|
54
|
+
fields = []
|
55
|
+
|
56
|
+
def clean_old_password(self):
|
57
|
+
old_password = self.cleaned_data['old_password']
|
58
|
+
if not self.instance.check_password(old_password):
|
59
|
+
raise ValidationError(_(
|
60
|
+
'Password Validation failed'
|
61
|
+
))
|
62
|
+
return old_password
|
63
|
+
|
64
|
+
def clean(self):
|
65
|
+
super().clean()
|
66
|
+
new_password = self.cleaned_data.get('new_password')
|
67
|
+
new_password_confirm = self.cleaned_data.get('new_password_confirm')
|
68
|
+
if not new_password or not new_password_confirm:
|
69
|
+
raise ValidationError(_(
|
70
|
+
'New password and password confirmation are required'
|
71
|
+
))
|
72
|
+
if new_password != new_password_confirm:
|
73
|
+
raise ValidationError(
|
74
|
+
_('New password and confirmation did not match.')
|
75
|
+
)
|
76
|
+
return self.cleaned_data
|
77
|
+
|
78
|
+
def save(self, commit=True):
|
79
|
+
user = self.instance
|
80
|
+
user.set_password(self.cleaned_data['new_password'])
|
81
|
+
user.save()
|
82
|
+
|
83
|
+
|
84
|
+
class ChangeEmailForm(ModelForm):
|
85
|
+
|
86
|
+
email = fields.EmailField(
|
87
|
+
label=_('New Email Address'),
|
88
|
+
widget=EmailInput(),
|
89
|
+
)
|
90
|
+
|
91
|
+
password = fields.CharField(
|
92
|
+
label=_('Password'),
|
93
|
+
widget=PasswordInput()
|
94
|
+
)
|
95
|
+
|
96
|
+
class Meta:
|
97
|
+
model = User
|
98
|
+
fields = []
|
99
|
+
|
100
|
+
def clean_email(self):
|
101
|
+
email = self.cleaned_data.get('email', '').lower()
|
102
|
+
validate_email(email)
|
103
|
+
if User.objects.filter(email=email):
|
104
|
+
raise ValidationError(
|
105
|
+
_('This email address is already bound to an account.')
|
106
|
+
)
|
107
|
+
return email
|
108
|
+
|
109
|
+
def clean_password(self):
|
110
|
+
password = self.cleaned_data.get('password')
|
111
|
+
if not self.instance.check_password(password):
|
112
|
+
raise ValidationError(_(
|
113
|
+
'Password incorrect'
|
114
|
+
))
|
115
|
+
return password
|
116
|
+
|
117
|
+
def save(self, commit=True):
|
118
|
+
self.instance.email = self.cleaned_data['email']
|
119
|
+
self.instance.save()
|
{accrete-0.0.26 → accrete-0.0.28}/accrete/contrib/user/templates/user/accrete_navbar_end.html
RENAMED
@@ -6,4 +6,8 @@
|
|
6
6
|
<a class="navbar-item" href="/admin/">Admin</a>
|
7
7
|
{% endif %}
|
8
8
|
<hr class="navbar-divider">
|
9
|
-
<
|
9
|
+
<form id="logout-form" method="post" action="{% url 'user:logout' %}">
|
10
|
+
{% csrf_token %}
|
11
|
+
<a class="navbar-item" href="#" onclick="document.getElementById('logout-form').submit()">{% translate "Log out" %}</a>
|
12
|
+
</form>
|
13
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
{% extends 'ui/form.html' %}
|
2
|
+
|
3
|
+
{% block form %}
|
4
|
+
<form id="form" method="post" action="">
|
5
|
+
{% csrf_token %}
|
6
|
+
<div class="columns">
|
7
|
+
<div class="column is-6">
|
8
|
+
<label class="label has-field is-required">
|
9
|
+
{{ form.email.label_tag }}
|
10
|
+
<span class="has-text-danger is-size-7">{{ form.email.errors }}</span>
|
11
|
+
<div class="field">
|
12
|
+
<p class="control is-fullwidth">{{ form.email }}</p>
|
13
|
+
</div>
|
14
|
+
</label>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
<div class="columns">
|
18
|
+
<div class="column is-6">
|
19
|
+
<label class="label has-field is-required">
|
20
|
+
{{ form.password.label_tag }}
|
21
|
+
<span class="has-text-danger is-size-7">{{ form.password.errors }}</span>
|
22
|
+
<div class="field">
|
23
|
+
<p class="control is-fullwidth">{{ form.password }}</p>
|
24
|
+
</div>
|
25
|
+
</label>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</form>
|
29
|
+
{% endblock %}
|