50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
"""passbook expression Policy Models"""
|
|
from django.core.exceptions import ValidationError
|
|
from django.db import models
|
|
from django.utils.translation import gettext as _
|
|
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
|
|
from jinja2.nativetypes import NativeEnvironment
|
|
from structlog import get_logger
|
|
|
|
from passbook.core.models import Policy
|
|
from passbook.policies.struct import PolicyRequest, PolicyResult
|
|
|
|
LOGGER = get_logger()
|
|
NATIVE_ENVIRONMENT = NativeEnvironment()
|
|
|
|
|
|
class ExpressionPolicy(Policy):
|
|
"""Jinja2-based Expression policy that allows Admins to write their own logic"""
|
|
|
|
expression = models.TextField()
|
|
|
|
form = "passbook.policies.expression.forms.ExpressionPolicyForm"
|
|
|
|
def passes(self, request: PolicyRequest) -> PolicyResult:
|
|
"""Evaluate and render expression. Returns PolicyResult(false) on error."""
|
|
try:
|
|
expression = NATIVE_ENVIRONMENT.from_string(self.expression)
|
|
except TemplateSyntaxError as exc:
|
|
return PolicyResult(False, str(exc))
|
|
try:
|
|
result = expression.render(request=request)
|
|
if isinstance(result, list) and len(result) == 2:
|
|
return PolicyResult(*result)
|
|
if result:
|
|
return PolicyResult(result)
|
|
return PolicyResult(False)
|
|
except UndefinedError as exc:
|
|
return PolicyResult(False, str(exc))
|
|
|
|
def save(self, *args, **kwargs):
|
|
try:
|
|
NATIVE_ENVIRONMENT.from_string(self.expression)
|
|
except TemplateSyntaxError as exc:
|
|
raise ValidationError("Expression Syntax Error") from exc
|
|
return super().save(*args, **kwargs)
|
|
|
|
class Meta:
|
|
|
|
verbose_name = _("Expression Policy")
|
|
verbose_name_plural = _("Expression Policies")
|