Skip to content

Commit

Permalink
[#1769] Replace deprecated djchoices with native Django choices
Browse files Browse the repository at this point in the history
  • Loading branch information
pi-sigma committed Nov 13, 2023
1 parent 3579d7f commit 40586b6
Show file tree
Hide file tree
Showing 20 changed files with 238 additions and 159 deletions.
1 change: 0 additions & 1 deletion requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ tinycss2
Django>=3.2.11<4.0
django-admin-index
django-axes
django-choices
django-filer
django-hijack
django-ordered-model
Expand Down
7 changes: 2 additions & 5 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,8 @@ django-better-admin-arrayfield==1.4.2
# via
# -r requirements/base.in
# mozilla-django-oidc-db
django-choices==1.7.2
# via
# -r requirements/base.in
# mail-editor
django-choices==2.0.0
# via mail-editor
django-ckeditor==6.2.0
# via mail-editor
django-classy-tags==4.0.0
Expand Down Expand Up @@ -474,7 +472,6 @@ six==1.16.0
# via
# click-repl
# django-appdata
# django-choices
# django-elasticsearch-dsl
# elasticsearch-dsl
# furl
Expand Down
3 changes: 1 addition & 2 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ django-better-admin-arrayfield==1.4.2
# -c requirements/base.txt
# -r requirements/base.txt
# mozilla-django-oidc-db
django-choices==1.7.2
django-choices==2.0.0
# via
# -c requirements/base.txt
# -r requirements/base.txt
Expand Down Expand Up @@ -843,7 +843,6 @@ six==1.16.0
# -r requirements/base.txt
# click-repl
# django-appdata
# django-choices
# django-elasticsearch-dsl
# elasticsearch-dsl
# furl
Expand Down
3 changes: 1 addition & 2 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ django-better-admin-arrayfield==1.4.2
# -c requirements/ci.txt
# -r requirements/ci.txt
# mozilla-django-oidc-db
django-choices==1.7.2
django-choices==2.0.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
Expand Down Expand Up @@ -936,7 +936,6 @@ six==1.16.0
# -r requirements/ci.txt
# click-repl
# django-appdata
# django-choices
# django-elasticsearch-dsl
# elasticsearch-dsl
# furl
Expand Down
70 changes: 41 additions & 29 deletions src/open_inwoner/accounts/choices.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,55 @@
from django.db import models
from django.utils.translation import gettext_lazy as _

from djchoices import ChoiceItem, DjangoChoices


class LoginTypeChoices(DjangoChoices):
default = ChoiceItem("default", _("E-mail en Wachtwoord"))
digid = ChoiceItem("digid", _("DigiD"))
eherkenning = ChoiceItem("eherkenning", _("eHerkenning"))
oidc = ChoiceItem("oidc", _("OpenId connect"))
class LoginTypeChoices(models.TextChoices):
default = "default", _("E-mail en Wachtwoord")
digid = "digid", _("DigiD")
eherkenning = "eherkenning", _("eHerkenning")
oidc = "oidc", _("OpenId connect")


# Created because of a filter that needs to happen. This way the form can take the empty choice and the modal is still filled.
class AllEmptyChoice(DjangoChoices):
empty = ChoiceItem("", _("Alle"))
class AllEmptyChoice(models.TextChoices):
empty = "", _("Alle")


class ContactTypeChoices(DjangoChoices):
contact = ChoiceItem("contact", _("Contactpersoon"))
begeleider = ChoiceItem("begeleider", _("Begeleider"))
organization = ChoiceItem("organization", _("Organisatie"))
class ContactTypeChoices(models.TextChoices):
contact = "contact", _("Contactpersoon")
begeleider = "begeleider", _("Begeleider")
organization = "organization", _("Organisatie")


class EmptyContactTypeChoices(AllEmptyChoice, ContactTypeChoices):
pass
class EmptyContactTypeChoices(models.TextChoices):
empty = "", _("Alle")
contact = "contact", _("Contactpersoon")
begeleider = "begeleider", _("Begeleider")
organization = "organization", _("Organisatie")


# Created because of a filter that needs to happen. This way the form can take the empty choice and the modal is still filled.
class StatusEmptyChoice(DjangoChoices):
empty = ChoiceItem("", _("Status"))
class StatusEmptyChoice(models.TextChoices):
empty = "", _("Status")


class StatusChoices(DjangoChoices):
open = ChoiceItem("open", _("Open"), icon="format_list_bulleted")
approval = ChoiceItem("approval", _("Accordering"), icon="question_mark")
closed = ChoiceItem("closed", _("Afgerond"), icon="check")
class StatusChoices(models.TextChoices):
open = "open", _("Open")
approval = "approval", _("Accordering")
closed = "closed", _("Afgerond")

# note the icons are names from Material Symbols and Icons - Google Fonts
@staticmethod
def get_icon_mapping():
return {
"open": "format_list_bulleted",
"approval": "question_mark",
"closed": "check",
}

@classmethod
def get_icon(cls, status, default="label"):
def get_icon(cls, status: str, default="label"):
if status in cls.values:
return cls.get_choice(status).icon
icon_mapping = cls.get_icon_mapping()
return icon_mapping[status]
else:
return default

Expand All @@ -49,10 +58,13 @@ def choices_with_icons(cls):
return [(value, label, cls.get_icon(value)) for value, label in cls.choices]


class EmptyStatusChoices(StatusEmptyChoice, StatusChoices):
pass
class EmptyStatusChoices(models.TextChoices):
empty = "", _("Status")
open = "open", _("Open")
approval = "approval", _("Accordering")
closed = "closed", _("Afgerond")


class TypeChoices(DjangoChoices):
incidental = ChoiceItem("incidental", _("Incidentieel"))
recurring = ChoiceItem("recurring", _("Terugkerend"))
class TypeChoices(models.TextChoices):
incidental = "incidental", _("Incidentieel")
recurring = "recurring", _("Terugkerend")
4 changes: 2 additions & 2 deletions src/open_inwoner/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,8 @@ def get_contact_message_url(self) -> str:
return f"{url}#messages-last"

def get_contact_type_display(self) -> str:
choice = ContactTypeChoices.get_choice(self.contact_type)
return choice.label
choices_mapping = dict(ContactTypeChoices.choices)
return choices_mapping[self.contact_type]

def get_contact_email(self):
return self.email if "@example.org" not in self.email else ""
Expand Down
25 changes: 10 additions & 15 deletions src/open_inwoner/accounts/tests/test_action_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,17 +354,14 @@ def test_action_status(self, mock_solo):
dropdown_button = action_element.locator(".actions__status-selector")
dropdown_content = action_element.locator(".dropdown__content")

# check state
expect(dropdown_button).to_contain_text(
str(StatusChoices.labels[StatusChoices.open])
)
approval_label = str(StatusChoices.approval.label)
closed_label = str(StatusChoices.closed.label)

# grab buttonss
status_closed_button = dropdown_content.get_by_role(
"button", name=str(StatusChoices.labels[StatusChoices.closed])
)
expect(dropdown_button).to_contain_text("Open")
# grab buttons
status_closed_button = dropdown_content.get_by_role("button", name=closed_label)
status_approval_button = dropdown_content.get_by_role(
"button", name=str(StatusChoices.labels[StatusChoices.approval])
"button", name=approval_label
)
expect(status_approval_button).to_be_visible(visible=False)

Expand All @@ -376,9 +373,7 @@ def test_action_status(self, mock_solo):
status_approval_button.click()

# status should change to approval
expect(dropdown_button).to_contain_text(
str(StatusChoices.labels[StatusChoices.approval])
)
expect(dropdown_button).to_contain_text(approval_label)

# dropdown widget is closed
expect(status_approval_button).to_be_visible(visible=False)
Expand All @@ -394,10 +389,10 @@ def test_action_status(self, mock_solo):
# click on status-closed button
status_closed_button.click()

# import pdb;pdb.set_trace()

# status should change
expect(dropdown_button).to_contain_text(
str(StatusChoices.labels[StatusChoices.closed])
)
expect(dropdown_button).to_contain_text(closed_label)

# dropdown widget is closed
expect(status_closed_button).to_be_visible(visible=False)
Expand Down
25 changes: 12 additions & 13 deletions src/open_inwoner/cms/extensions/constants.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
from django.db import models
from django.utils.translation import gettext_lazy as _

from djchoices import ChoiceItem, DjangoChoices

class IndicatorChoices(models.TextChoices):
plan_new_contacts = "plan_new_contacts", _("Plans > new contacts")
inbox_new_messages = "inbox_new_messages", _("Inbox > new messages")

class IndicatorChoices(DjangoChoices):
plan_new_contacts = ChoiceItem("plan_new_contacts", _("Plans > new contacts"))
inbox_new_messages = ChoiceItem("inbox_new_messages", _("Inbox > new messages"))


class Icons(DjangoChoices):
person = ChoiceItem("person", _("Home"))
description = ChoiceItem("description", _("Products"))
inbox = ChoiceItem("inbox", _("Inbox"))
inventory_2 = ChoiceItem("inventory_2", _("Cases"))
group = ChoiceItem("group", _("Collaborate"))
help_outline = ChoiceItem("help_outline", _("Help"))
euro_outline = ChoiceItem("euro_outline", _("Benefits"))
class Icons(models.TextChoices):
person = "person", _("Home")
description = "description", _("Products")
inbox = "inbox", _("Inbox")
inventory_2 = "inventory_2", _("Cases")
group = "group", _("Collaborate")
help_outline = "help_outline", _("Help")
euro_outline = "euro_outline", _("Benefits")
1 change: 1 addition & 0 deletions src/open_inwoner/conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@
"open_inwoner.cms.footer",
"open_inwoner.cms.plugins",
"open_inwoner.cms.benefits",
"djchoices",
]

MIDDLEWARE = [
Expand Down
15 changes: 7 additions & 8 deletions src/open_inwoner/configurations/choices.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _

from djchoices import ChoiceItem, DjangoChoices

class ColorTypeChoices(models.TextChoices):
light = "#FFFFFF", _("light")
dark = "#4B4B4B", _("dark")

class ColorTypeChoices(DjangoChoices):
light = ChoiceItem("#FFFFFF", _("light"))
dark = ChoiceItem("#4B4B4B", _("dark"))


class OpenIDDisplayChoices(DjangoChoices):
admin = ChoiceItem("admin", _("Admin"))
regular = ChoiceItem("regular", _("Regular user"))
class OpenIDDisplayChoices(models.TextChoices):
admin = "admin", _("Admin")
regular = "regular", _("Regular user")
2 changes: 1 addition & 1 deletion src/open_inwoner/configurations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ class SiteConfiguration(SingletonModel):
openid_display = models.CharField(
verbose_name=_("Show option to login via OpenId"),
max_length=24,
choices=OpenIDDisplayChoices,
choices=OpenIDDisplayChoices.choices,
default=OpenIDDisplayChoices.admin,
validators=[validate_oidc_config],
help_text=_("Only selected groups will see the option to login via OpenId."),
Expand Down
98 changes: 46 additions & 52 deletions src/open_inwoner/custom_csp/constants.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,49 @@
from djchoices import ChoiceItem, DjangoChoices
from django.db import models


class CSPDirective(DjangoChoices):
class CSPDirective(models.TextChoices):
# via https://django-csp.readthedocs.io/en/latest/configuration.html
DEFAULT_SRC = ChoiceItem("default-src", label="default-src")
SCRIPT_SRC = ChoiceItem("script-src", label="script-src")
SCRIPT_SRC_ATTR = ChoiceItem("script-src-attr", label="script-src-attr")
SCRIPT_SRC_ELEM = ChoiceItem("script-src-elem", label="script-src-elem")
IMG_SRC = ChoiceItem("img-src", label="img-src")
OBJECT_SRC = ChoiceItem("object-src", label="object-src")
PREFETCH_SRC = ChoiceItem("prefetch-src", label="prefetch-src")
MEDIA_SRC = ChoiceItem("media-src", label="media-src")
FRAME_SRC = ChoiceItem("frame-src", label="frame-src")
FONT_SRC = ChoiceItem("font-src", label="font-src")
CONNECT_SRC = ChoiceItem("connect-src", label="connect-src")
STYLE_SRC = ChoiceItem("style-src", label="style-src")
STYLE_SRC_ATTR = ChoiceItem("style-src-attr", label="style-src-attr")
STYLE_SRC_ELEM = ChoiceItem("style-src-elem", label="style-src-elem")
BASE_URI = ChoiceItem(
"base-uri", label="base-uri"
) # Note: This doesn’t use default-src as a fall-back.
CHILD_SRC = ChoiceItem(
"child-src", label="child-src"
) # Note: Deprecated in CSP v3. Use frame-src and worker-src instead.
FRAME_ANCESTORS = ChoiceItem(
"frame-ancestors", label="frame-ancestors"
) # Note: This doesn’t use default-src as a fall-back.
NAVIGATE_TO = ChoiceItem(
"navigate-to", label="navigate-to"
) # Note: This doesn’t use default-src as a fall-back.
FORM_ACTION = ChoiceItem(
"form-action", label="form-action"
) # Note: This doesn’t use default-src as a fall-back.
SANDBOX = ChoiceItem(
"sandbox", label="sandbox"
) # Note: This doesn’t use default-src as a fall-back.
REPORT_URI = ChoiceItem(
"report-uri", label="report-uri"
) # Each URI can be a full or relative URI. None Note: This doesn’t use default-src as a fall-back.
REPORT_TO = ChoiceItem(
"report-to", label="report-to"
) # A string describing a reporting group. None Note: This doesn’t use default-src as a fall-back. See Section 1.2: https://w3c.github.io/reporting/#group
MANIFEST_SRC = ChoiceItem("manifest-src", label="manifest-src")
WORKER_SRC = ChoiceItem("worker-src", label="worker-src")
PLUGIN_TYPES = ChoiceItem(
"plugin-types", label="plugin-types"
) # Note: This doesn’t use default-src as a fall-back.
REQUIRE_SRI_FOR = ChoiceItem(
"require-sri-for", label="require-sri-for"
) # Valid values: script, style, or both. See: require-sri-for-known-tokens Note: This doesn’t use default-src as a fall-back.

# CSP_UPGRADE_INSECURE_REQUESTS # Include upgrade-insecure-requests directive. A boolean. False See: upgrade-insecure-requests
# CSP_BLOCK_ALL_MIXED_CONTENT # Include block-all-mixed-content directive. A boolean. False See: block-all-mixed-content
# CSP_INCLUDE_NONCE_IN # Include dynamically generated nonce in all listed directives, e.g. CSP_INCLUDE_NONCE_IN=['script-src'] will add 'nonce-<b64-value>' to the script-src directive.
DEFAULT_SRC = "default-src", "default-src"
SCRIPT_SRC = "script-src", "script-src"
SCRIPT_SRC_ATTR = "script-src-attr", "script-src-attr"
SCRIPT_SRC_ELEM = "script-src-elem", "script-src-elem"
IMG_SRC = "img-src", "img-src"
OBJECT_SRC = "object-src", "object-src"
PREFETCH_SRC = "prefetch-src", "prefetch-src"
MEDIA_SRC = "media-src", "media-src"
FRAME_SRC = "frame-src", "frame-src"
FONT_SRC = "font-src", "font-src"
CONNECT_SRC = "connect-src", "connect-src"
STYLE_SRC = "style-src", "style-src"
STYLE_SRC_ATTR = "style-src-attr", "style-src-attr"
STYLE_SRC_ELEM = "style-src-elem", "style-src-elem"
BASE_URI = (
"base-uri",
"base-uri",
) # Note: This doesn’t use default-src as a fall-back
CHILD_SRC = (
"child-src",
"child-src",
) # Note: This doesn’t use default-src as a fall-back
FRAME_ANCESTORS = (
"frame-ancestors",
"frame-ancestors",
) # Note: This doesn’t use default-src as a fall-back
NAVIGATE_TO = (
"navigate-to",
"navigate-to",
) # Note: This doesn’t use default-src as a fall-back
FORM_ACTION = (
"form-action",
"form-action",
) # Note: This doesn’t use default-src as a fall-back
SANDBOX = "sandbox", "sandbox" # Note: This doesn’t use default-src as a fall-back
REPORT_URI = (
"report-uri",
"report-uri",
) # Note: This doesn’t use default-src as a fall-back
REPORT_TO = "report-to", "report-to"
MANIFEST_SRC = "manifest-src", "manifest-src"
WORKER_SRC = "worker-src", "worker-src"
PLUGIN_TYPES = "plugin-types", "plugin-types"
REQUIRE_SRI_FOR = "require-sri-for", "require-sri-for"
Empty file.
Empty file.
Loading

0 comments on commit 40586b6

Please sign in to comment.