Skip to content

Commit 5ebcb92

Browse files
authored
Merge pull request #26 from renderbox/develop
Release v0.2.9
2 parents 2692262 + b063e41 commit 5ebcb92

File tree

5 files changed

+227
-92
lines changed

5 files changed

+227
-92
lines changed

permafrost/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION = "0.2.8"
1+
VERSION = "0.2.9"

permafrost/forms.py

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
from django.conf import settings
33
from django.contrib.auth.models import Permission
44
from django.core.exceptions import ValidationError
5-
from django.forms import ModelForm, MultipleChoiceField, CheckboxSelectMultiple
5+
from django.forms import ModelForm
66
from django.forms.fields import CharField, ChoiceField, BooleanField
7-
from django.forms.widgets import CheckboxInput, Textarea
7+
from django.forms.models import ModelMultipleChoiceField
8+
from django.forms.widgets import CheckboxInput
89
from django.utils.translation import ugettext_lazy as _
9-
from .models import PermafrostRole, get_optional_by_category, get_required_by_category, get_choices
10+
from .models import PermafrostRole, get_optional_by_category, get_choices
1011

1112
CHOICES = [('', _("Choose Role Type"))] + get_choices()
1213

@@ -41,7 +42,7 @@ def bootstrappify(fields):
4142

4243
class SelectPermafrostRoleTypeForm(ModelForm):
4344
name = CharField(required=False)
44-
description = CharField(required=False, widget=Textarea())
45+
description = CharField(required=False)
4546
category = ChoiceField(choices=CHOICES)
4647

4748
class Meta:
@@ -57,43 +58,41 @@ def __init__(self, *args, **kwargs):
5758

5859

5960
class PermafrostRoleCreateForm(ModelForm):
61+
permissions = ModelMultipleChoiceField(queryset=Permission.objects.all(), required=False)
6062
class Meta:
6163
model = PermafrostRole
62-
fields = ('name', 'description', 'category',)
63-
widgets = {
64-
'description': Textarea(),
65-
}
64+
fields = ('name', 'description', 'category', 'permissions')
6665
labels = LABELS
6766

6867
def __init__(self, *args, **kwargs):
6968
super().__init__(*args, **kwargs)
7069

7170
self.fields['category'].choices = CHOICES
71+
7272
category = self.initial.get(
7373
'category',
7474
self.data.get('category', None)
7575
)
7676

77-
bootstrappify(self.fields)
77+
if self.instance:
78+
category = self.instance.category if self.instance.category else category
7879

79-
if category:
80-
81-
required_perms = get_required_by_category(category)
82-
optional_perms = get_optional_by_category(category)
83-
required_choices = assemble_optiongroups_for_widget(required_perms)
84-
optional_choices = assemble_optiongroups_for_widget(optional_perms)
85-
86-
initial = [perm.pk for perm in required_perms]
87-
self.fields[f'optional_{category}_perms'] = MultipleChoiceField(label=_("Optional Permissions"), choices=optional_choices, widget=CheckboxSelectMultiple(), required=False)
88-
self.fields[f'required_{category}_perms'] = MultipleChoiceField(label=_("Required Permissions"), initial=initial, choices=required_choices, widget=CheckboxSelectMultiple(attrs={'readonly':True, 'disabled': True}), required=False)
80+
if category:
81+
all_optional_permissions = get_optional_by_category(category=category)
82+
ids = [perm.pk for perm in all_optional_permissions]
83+
84+
self.fields['permissions'].queryset = Permission.objects.filter(id__in=ids)
8985

86+
bootstrappify(self.fields)
87+
9088
def save(self, commit=True):
91-
instance = super().save(commit)
89+
instance = super().save(commit)
9290
category = instance.category
93-
if self.cleaned_data and f'optional_{category}_perms' in self.cleaned_data:
91+
92+
if 'permissions' in self.cleaned_data:
9493
perm_ids = []
9594
if category:
96-
perm_ids = self.cleaned_data[f'optional_{category}_perms' ]
95+
perm_ids = self.cleaned_data['permissions']
9796
if perm_ids:
9897
instance.permissions_set(Permission.objects.filter(id__in=perm_ids))
9998
else:
@@ -144,31 +143,14 @@ def __init__(self, *args, **kwargs):
144143
self.fields['category'].widget.attrs.update({'readonly': True, 'disabled': True})
145144
self.fields['category'].disabled = True
146145
self.fields['category'].required = False
146+
self.fields['category'].choices = [choice for choice in CHOICES if choice[0] == self.instance.category]
147147
self.fields['category'].initial = self.instance.category
148-
148+
## limit choices to saved category
149149
self.fields['deleted'].initial = self.instance.deleted
150-
151-
category = self.instance.category
152-
153-
optional_perms = get_optional_by_category(category)
154-
optional_choices = assemble_optiongroups_for_widget(optional_perms)
155-
156-
available_optional_ids = [permission.id for permission in optional_perms]
157-
preselected_optional = [permission.id for permission in self.instance.permissions().all() if permission.id in available_optional_ids]
158-
159-
self.fields.update({
160-
f'optional_{category}_perms': MultipleChoiceField(
161-
label=_("Optional Permissions"),
162-
initial=preselected_optional,
163-
choices=optional_choices,
164-
widget=CheckboxSelectMultiple(),
165-
required=False
166-
)
167-
})
168150

169151
def save(self, commit=True):
170152
if self.cleaned_data['deleted']:
171153
self.instance.deleted = self.cleaned_data['deleted']
172154
instance = super().save(commit)
173155
return instance
174-
156+

permafrost/templates/permafrost/permafrostrole_form.html

Lines changed: 129 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@
66

77
{% block content %}
88
<form method="POST" id="role_form">
9-
<div class="d-sm-flex align-items-center justify-content-between mb-4">
10-
<h2> {% trans 'Roles & Permissions' %}</h2>
11-
<a href="{% if object %}{{ object.get_absolute_url }}{% else %}{% url 'permafrost:roles-manage' %}{% endif %}" class="btn btn-success btn-outline ml-auto">{% trans 'Cancel' %}</a>
12-
<button type="submit" class="btn btn-success ml-1">
13-
{% if object %}
14-
{% trans 'Save' %}
15-
{% else %}
16-
{% trans 'Create' %}
17-
{% endif %}
18-
</button>
19-
</div>
20-
{% csrf_token %}
21-
<div class="card">
9+
{% csrf_token %}
10+
<div class="d-sm-flex align-items-center justify-content-between my-3">
11+
<h1 class="text-gray-800 m-0"> {% trans 'Roles & Permissions' %}</h1>
12+
<a href="{% if object %}{{ object.get_absolute_url }}{% else %}{% url 'permafrost:roles-manage' %}{% endif %}" class="btn btn-outline-success ml-auto">{% trans 'Cancel' %}</a>
13+
<button type="submit" class="btn btn-success ml-1">
14+
{% if object %}
15+
{% trans 'Save' %}
16+
{% else %}
17+
{% trans 'Create' %}
18+
{% endif %}
19+
</button>
20+
</div>
21+
<div class="card text-gray-800 pb-5">
2222
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
2323
<h6 class="m-0 text-primary font-weight-bold">
2424
{% if object %}
@@ -30,26 +30,132 @@ <h6 class="m-0 text-primary font-weight-bold">
3030
</div>
3131
<div class="card-body">
3232
{{ form.non_field_errors }}
33-
{% for field in form %}
34-
<div class="fieldWrapper form-group" aria-required={% if field.field.required %}"true"{% else %}"false"{% endif %}>
35-
{{ field.label_tag }}{% if field.field.required %}<span class="required">*</span>{% endif %}
33+
<div class="form-row">
34+
<div class="form-group col-12 col-md-4">
35+
<label class="text-gray-600" for="{{ form.name.id_for_label }}">
36+
{{ form.name.label }}
37+
</label>
38+
{% if form.name.required %}<span class="required">*</span>{% endif %}
39+
<input
40+
name="{{ form.name.name }}"
41+
type="text"
42+
id="{{form.name.id_for_label}}"
43+
class="form-control{% if form.name.errors %} is-invalid{% endif %}"
44+
placeholder="{{ form.name.help_text }}" value="{% firstof form.initial.name form.data.name form.instance.name '' %}" >
45+
46+
{% if form.name.errors %}
47+
<div class="invalid-feedback">
48+
{% for error in form.name.errors %}
49+
{{ error }}
50+
{% endfor %}
51+
</div>
52+
{% endif %}
53+
54+
</div>
55+
</div>
56+
<div class="form-row">
57+
<div class="form-group col">
58+
<label class="text-gray-600" for="{{ form.description.id_for_label }}">
59+
{{ form.description.label }}
60+
</label>
61+
{% if form.description.required %}<span class="required">*</span>{% endif %}
62+
<input
63+
name="{{ form.description.name }}"
64+
type="text" id="{{ form.description.id_for_label }}"
65+
class="form-control{% if form.name.errors %} is-invalid{% endif %}"
66+
placeholder="{{ form.description.help_text }}"
67+
value="{% firstof form.initial.description form.data.description form.instance.description '' %}" >
68+
69+
{% if form.description.errors %}
70+
<div class="invalid-feedback">
71+
{% for error in form.description.errors %}
72+
{{ error }}
73+
{% endfor %}
74+
</div>
75+
{% endif %}
76+
</div>
77+
</div>
78+
<div class="form-row">
79+
<div class="form-group col-12 col-md-4">
80+
<label class="text-gray-600" for="{{ form.category.id_for_label }}">
81+
{{ form.category.label }}
82+
</label>
83+
{% if form.category.required %}<span class="required">*</span>{% endif %}
3684

37-
{{ field }}
85+
{% if object %}
86+
<div class="disabled-select-wrapper">
87+
{% endif %}
88+
89+
{{ form.category }}
3890

39-
{% if field.help_text %}
40-
<p class="help">{{ field.help_text|safe }}</p>
91+
{% if object %}
92+
<i class="fas fa-lock"></i>
93+
</div> {# end disabled-select-wrapper #}
94+
{% endif %}
95+
96+
{% if form.category.errors %}
97+
<div class="invalid-feedback">
98+
{% for error in form.category.errors %}
99+
{{ error }}
100+
{% endfor %}
101+
</div>
41102
{% endif %}
42-
{{ field.errors }}
43103
</div>
104+
</div>
105+
<div class="form-row border-bottom-gray-300">
106+
<p class="col-6 font-weight-bold">{% trans 'Required Permissions' %}</p>
107+
<p class="col-6 font-weight-bold">{% trans 'Optional Permissions' %}</p>
108+
</div>
109+
<div class="form-row">
110+
{% if form.permissions.errors %}
111+
<div class="invalid-feedback">
112+
{% for error in form.permissions.errors %}
113+
{{ error }}
114+
{% endfor %}
115+
</div>
116+
{% endif %}
117+
</div>
118+
{% for content_type, category in permission_categories.items %}
119+
<div class="row">
120+
<p class="small font-weight-bold col-12 text-gray-600 mt-3 text-capitalize">{{ category.name }}</p>
121+
<div class="col-6">
122+
{% for permission in category.required %}
123+
<div class="d-flex align-items-center">
124+
<span>{{ permission.name }}</span>
125+
{% if permission.short_description %} {# TODO: extend permission to include short_description for tooltip #}
126+
<i class="ml-2 fas fa-info-circle text-gray-600" aria-label="{% trans 'Info' %}"></i>
127+
{% endif %}
128+
<i class="ml-auto fas fa-lock" aria-label="{% trans 'Default Permission' %}"></i>
129+
</div>
130+
{% endfor %}
131+
</div>
132+
<div class="col-6">
133+
{% for permission in category.optional %}
134+
<div class="d-flex align-items-center">
135+
<span>{{ permission.name }}</span>
136+
137+
{% if permission.short_description %}
138+
<i class="ml-2 fas fa-info-circle text-gray-600" aria-label="{% trans 'Info' %}"></i>
139+
{% endif %}
140+
<input
141+
class="ml-auto"
142+
type="checkbox"
143+
name="{{ form.permissions.name }}"
144+
value="{{ permission.id }}"
145+
{% if permission.selected %} checked{% endif %}
146+
>
147+
</div>
148+
{% endfor %}
149+
</div>
150+
</div>
151+
{% empty %}
152+
<div class="pb-5 row">{# used for spacing when empty #}</div>
44153
{% endfor %}
45154
</div>
46-
<div class="card-footer">
47-
</div>
48155
</div>
49156
</form>
50157
{% endblock %}
51158

52-
53159
{% block extra_js %}
54160
{% if not object %} {# "Hide JS change handler on edit " #}
55161
<script>

0 commit comments

Comments
 (0)