Skip to content

Commit

Permalink
refactor: [ACI-978] some enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrii committed May 17, 2024
1 parent 8555c35 commit 20bd0f0
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 9 deletions.
41 changes: 41 additions & 0 deletions credentials/apps/badges/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class BadgeRequirementInline(admin.TabularInline):
"group",
)
readonly_fields = ("rules",)
ordering = ("group",)
form = BadgeRequirementForm
formset = BadgeRequirementFormSet

Expand All @@ -77,6 +78,12 @@ class BadgePenaltyInline(admin.TabularInline):
model = BadgePenalty
show_change_link = True
extra = 0
fields = (
"event_type",
"rules",
"requirements",
)
readonly_fields = ("rules",)
form = BadgePenaltyForm

def formfield_for_manytomany(self, db_field, request, **kwargs):
Expand All @@ -88,6 +95,20 @@ def formfield_for_manytomany(self, db_field, request, **kwargs):
if template_id:
kwargs["queryset"] = BadgeRequirement.objects.filter(template_id=template_id)
return super().formfield_for_manytomany(db_field, request, **kwargs)

def rules(self, obj):
"""
Display all data rules for the penalty.
"""
return format_html(
"<ul>{}</ul>",
mark_safe(
"".join(
f"<li>{rule.data_path} {rule.OPERATORS[rule.operator]} {rule.value}</li>"
for rule in obj.rules.all()
)
),
) if obj.rules.exists() else _("No rules specified.")


class FulfillmentInline(admin.TabularInline):
Expand Down Expand Up @@ -309,6 +330,7 @@ class BadgeRequirementAdmin(admin.ModelAdmin):
"template",
"event_type",
"template_link",
"group",
]

fields = [
Expand Down Expand Up @@ -358,11 +380,30 @@ class BadgePenaltyAdmin(admin.ModelAdmin):
"template",
"requirements",
]
fields = [
"template_link",
"event_type",
"requirements",
]
readonly_fields = [
"template_link",
"event_type",
"requirements",
]
form = BadgePenaltyForm

def has_add_permission(self, request):
return False

def template_link(self, instance):
"""
Interactive link to parent (badge template).
"""
url = reverse("admin:badges_credlybadgetemplate_change", args=[instance.template.pk])
return format_html('<a href="{}">{}</a>', url, instance.template)

template_link.short_description = _("badge template")

def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "requirements":
object_id = request.resolver_match.kwargs.get("object_id")
Expand Down
25 changes: 22 additions & 3 deletions credentials/apps/badges/admin_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from credentials.apps.badges.credly.api_client import CredlyAPIClient
from credentials.apps.badges.credly.exceptions import CredlyAPIError
from credentials.apps.badges.models import BadgePenalty, BadgeRequirement, CredlyOrganization, DataRule, PenaltyDataRule
from credentials.apps.badges.models import AbstractDataRule, BadgePenalty, BadgeRequirement, CredlyOrganization, DataRule, PenaltyDataRule
from credentials.apps.badges.utils import get_event_type_keypaths


Expand Down Expand Up @@ -84,6 +84,25 @@ def clean(self):
return cleaned_data


class DataRuleBoolValidationMixin:
"""
Mixin for DataRule form to validate boolean fields.
"""

def clean(self):
"""
Validate boolean fields.
"""

cleaned_data = super().clean()

last_key = cleaned_data.get("data_path").split(".")[-1]
if "is_" in last_key and cleaned_data.get("value") not in AbstractDataRule.BOOL_VALUES:
raise forms.ValidationError(_("Value must be a boolean."))

return cleaned_data


class DataRuleFormSet(forms.BaseInlineFormSet):
"""
Formset for DataRule model.
Expand All @@ -98,7 +117,7 @@ def get_form_kwargs(self, index):
return kwargs


class DataRuleForm(forms.ModelForm):
class DataRuleForm(DataRuleBoolValidationMixin, forms.ModelForm):
"""
Form for DataRule model.
"""
Expand Down Expand Up @@ -158,7 +177,7 @@ def get_form_kwargs(self, index):
return kwargs


class PenaltyDataRuleForm(forms.ModelForm):
class PenaltyDataRuleForm(DataRuleBoolValidationMixin, forms.ModelForm):
"""
Form for PenaltyDataRule model.
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.2.20 on 2024-05-17 14:26

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('badges', '0019_fulfillment_group'),
]

operations = [
migrations.RemoveField(
model_name='badgepenalty',
name='description',
),
]
12 changes: 6 additions & 6 deletions credentials/apps/badges/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ class AbstractDataRule(models.Model):
# ('gt', '>'),
)

TRUE_VALUES = ["True", "true", "Yes", "yes", "+"]
FALSE_VALUES = ["False", "false", "No", "no", "-"]
BOOL_VALUES = TRUE_VALUES + FALSE_VALUES

data_path = models.CharField(
max_length=255,
help_text=_('Public signal\'s data payload nested property path, e.g: "user.pii.username".'),
Expand Down Expand Up @@ -324,12 +328,9 @@ def _value_to_bool(self):
Converts the value to a boolean or returns the original value if it is not a boolean string.
"""

TRUE_VALUES = ["True", "true", "Yes", "yes", "+"]
FALSE_VALUES = ["False", "false", "No", "no", "-"]

if self.value in TRUE_VALUES:
if self.value in self.TRUE_VALUES:
return "True"
if self.value in FALSE_VALUES:
if self.value in self.FALSE_VALUES:
return "False"
return self.value

Expand Down Expand Up @@ -381,7 +382,6 @@ class BadgePenalty(models.Model):
BadgeRequirement,
help_text=_("Badge requirements for which this penalty is defined."),
)
description = models.TextField(null=True, blank=True, help_text=_("Provide more details if needed."))

class Meta:
verbose_name_plural = _("Badge penalties")
Expand Down
4 changes: 4 additions & 0 deletions credentials/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,10 @@
"user.pii.username",
"user.pii.email",
"user.pii.name",

"course.display_name",
"course.start",
"course.end",
],
},
}

0 comments on commit 20bd0f0

Please sign in to comment.