Admin: add rule admin
This commit is contained in:
parent
2aa12801a8
commit
caf6580ccb
11
passbook/admin/templates/administration/rule/create.html
Normal file
11
passbook/admin/templates/administration/rule/create.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends "generic/create.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{% blocktrans with type=request.GET.type %}Create {{ type }}{% endblocktrans %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block above_form %}
|
||||||
|
<h1>{% blocktrans with type=request.GET.type %}Create {{ type }}{% endblocktrans %}</h1>
|
||||||
|
{% endblock %}
|
45
passbook/admin/templates/administration/rule/list.html
Normal file
45
passbook/admin/templates/administration/rule/list.html
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
{% extends "administration/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load utils %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{% title %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-primary dropdown-toggle" type="button" id="createDropdown" data-toggle="dropdown">
|
||||||
|
{% trans 'Create...' %}
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" role="menu" aria-labelledby="createDropdown">
|
||||||
|
{% for type, name in types.items %}
|
||||||
|
<li role="presentation"><a role="menuitem" tabindex="-1" href="{% url 'passbook_admin:rule-create' %}?type={{ type }}">{{ name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<table class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Name' %}</th>
|
||||||
|
<th>{% trans 'Class' %}</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for rule in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ rule.name }}</td>
|
||||||
|
<td>{{ rule|fieldtype }}</td>
|
||||||
|
<td><a href="{% url 'passbook_admin:rule-update' pk=rule.uuid %}">{% trans 'Edit' %}</a></td>
|
||||||
|
<td><a href="{% url 'passbook_admin:rule-delete' pk=rule.uuid %}">{% trans 'Delete' %}</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -18,5 +18,10 @@ urlpatterns = [
|
||||||
path('sources/create/', sources.SourceCreateView.as_view(), name='source-create'),
|
path('sources/create/', sources.SourceCreateView.as_view(), name='source-create'),
|
||||||
path('sources/<uuid:pk>/update/', sources.SourceUpdateView.as_view(), name='source-update'),
|
path('sources/<uuid:pk>/update/', sources.SourceUpdateView.as_view(), name='source-update'),
|
||||||
path('sources/<uuid:pk>/delete/', sources.SourceDeleteView.as_view(), name='source-delete'),
|
path('sources/<uuid:pk>/delete/', sources.SourceDeleteView.as_view(), name='source-delete'),
|
||||||
|
# Rules
|
||||||
|
path('rules/', rules.RuleListView.as_view(), name='rules'),
|
||||||
|
path('rules/create/', rules.RuleCreateView.as_view(), name='rule-create'),
|
||||||
|
path('rules/<uuid:pk>/update/', rules.RuleUpdateView.as_view(), name='rule-update'),
|
||||||
|
path('rules/<uuid:pk>/delete/', rules.RuleDeleteView.as_view(), name='rule-delete'),
|
||||||
# path('api/v1/', include('passbook.admin.api.v1.urls'))
|
# path('api/v1/', include('passbook.admin.api.v1.urls'))
|
||||||
]
|
]
|
||||||
|
|
72
passbook/admin/views/rules.py
Normal file
72
passbook/admin/views/rules.py
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
"""passbook Rule administration"""
|
||||||
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.http import Http404
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
||||||
|
|
||||||
|
from passbook.admin.mixins import AdminRequiredMixin
|
||||||
|
from passbook.core.models import Rule
|
||||||
|
from passbook.lib.utils.reflection import path_to_class
|
||||||
|
|
||||||
|
|
||||||
|
class RuleListView(AdminRequiredMixin, ListView):
|
||||||
|
"""Show list of all rules"""
|
||||||
|
|
||||||
|
model = Rule
|
||||||
|
template_name = 'administration/rule/list.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
kwargs['types'] = {
|
||||||
|
x.__name__: x._meta.verbose_name for x in Rule.__subclasses__()}
|
||||||
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return super().get_queryset().order_by('order').select_subclasses()
|
||||||
|
|
||||||
|
|
||||||
|
class RuleCreateView(SuccessMessageMixin, AdminRequiredMixin, CreateView):
|
||||||
|
"""Create new Rule"""
|
||||||
|
|
||||||
|
template_name = 'administration/rule/create.html'
|
||||||
|
success_url = reverse_lazy('passbook_admin:rules')
|
||||||
|
success_message = _('Successfully created Rule')
|
||||||
|
|
||||||
|
def get_form_class(self):
|
||||||
|
rule_type = self.request.GET.get('type')
|
||||||
|
model = next(x for x in Rule.__subclasses__()
|
||||||
|
if x.__name__ == rule_type)
|
||||||
|
if not model:
|
||||||
|
raise Http404
|
||||||
|
return path_to_class(model.form)
|
||||||
|
|
||||||
|
|
||||||
|
class RuleUpdateView(SuccessMessageMixin, AdminRequiredMixin, UpdateView):
|
||||||
|
"""Update rule"""
|
||||||
|
|
||||||
|
model = Rule
|
||||||
|
template_name = 'generic/update.html'
|
||||||
|
success_url = reverse_lazy('passbook_admin:rules')
|
||||||
|
success_message = _('Successfully updated Rule')
|
||||||
|
|
||||||
|
def get_form_class(self):
|
||||||
|
form_class_path = self.get_object().form
|
||||||
|
form_class = path_to_class(form_class_path)
|
||||||
|
return form_class
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
obj = Rule.objects.get(pk=self.kwargs.get('pk'))
|
||||||
|
return obj.cast()
|
||||||
|
|
||||||
|
|
||||||
|
class RuleDeleteView(SuccessMessageMixin, AdminRequiredMixin, DeleteView):
|
||||||
|
"""Delete rule"""
|
||||||
|
|
||||||
|
model = Rule
|
||||||
|
|
||||||
|
success_url = reverse_lazy('passbook_admin:rules')
|
||||||
|
success_message = _('Successfully updated Rule')
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
obj = Rule.objects.get(pk=self.kwargs.get('pk'))
|
||||||
|
return obj.cast()
|
20
passbook/core/forms/rules.py
Normal file
20
passbook/core/forms/rules.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
"""passbook rule forms"""
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
from passbook.core.models import FieldMatcherRule
|
||||||
|
|
||||||
|
|
||||||
|
class FieldMatcherRuleForm(forms.ModelForm):
|
||||||
|
"""FieldMatcherRule Form"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = FieldMatcherRule
|
||||||
|
fields = ['name', 'action', 'negate', 'order',
|
||||||
|
'user_field', 'match_action', 'value', ]
|
||||||
|
widgets = {
|
||||||
|
'name': forms.TextInput(),
|
||||||
|
'user_field': forms.TextInput(),
|
||||||
|
'value': forms.TextInput(),
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ from logging import getLogger
|
||||||
import reversion
|
import reversion
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
from model_utils.managers import InheritanceManager
|
from model_utils.managers import InheritanceManager
|
||||||
|
|
||||||
from passbook.lib.models import CreatedUpdatedModel, UUIDModel
|
from passbook.lib.models import CreatedUpdatedModel, UUIDModel
|
||||||
|
@ -128,17 +129,19 @@ class FieldMatcherRule(Rule):
|
||||||
MATCH_REGEXP = 'regexp'
|
MATCH_REGEXP = 'regexp'
|
||||||
MATCH_EXACT = 'exact'
|
MATCH_EXACT = 'exact'
|
||||||
MATCHES = (
|
MATCHES = (
|
||||||
(MATCH_STARTSWITH, MATCH_STARTSWITH),
|
(MATCH_STARTSWITH, _('Starts with')),
|
||||||
(MATCH_ENDSWITH, MATCH_ENDSWITH),
|
(MATCH_ENDSWITH, _('Ends with')),
|
||||||
(MATCH_ENDSWITH, MATCH_CONTAINS),
|
(MATCH_ENDSWITH, _('Contains')),
|
||||||
(MATCH_REGEXP, MATCH_REGEXP),
|
(MATCH_REGEXP, _('Regexp')),
|
||||||
(MATCH_EXACT, MATCH_EXACT),
|
(MATCH_EXACT, _('Exact')),
|
||||||
)
|
)
|
||||||
|
|
||||||
user_field = models.TextField()
|
user_field = models.TextField()
|
||||||
match_action = models.CharField(max_length=50, choices=MATCHES)
|
match_action = models.CharField(max_length=50, choices=MATCHES)
|
||||||
value = models.TextField()
|
value = models.TextField()
|
||||||
|
|
||||||
|
form = 'passbook.core.forms.rules.FieldMatcherRuleForm'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
description = "%s, user.%s %s '%s'" % (self.name, self.user_field,
|
description = "%s, user.%s %s '%s'" % (self.name, self.user_field,
|
||||||
self.match_action, self.value)
|
self.match_action, self.value)
|
||||||
|
@ -167,3 +170,8 @@ class FieldMatcherRule(Rule):
|
||||||
passes = not passes
|
passes = not passes
|
||||||
LOGGER.debug("User got '%r'", passes)
|
LOGGER.debug("User got '%r'", passes)
|
||||||
return passes
|
return passes
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
verbose_name = _('Field matcher Rule')
|
||||||
|
verbose_name_plural = _('Field matcher Rules')
|
||||||
|
|
Reference in a new issue