Commit 7fd224e6 authored by ibuler's avatar ibuler

Merge with user-perm

parents 343f1399 dc4d388d
...@@ -12,7 +12,7 @@ class AssetForm(forms.ModelForm): ...@@ -12,7 +12,7 @@ class AssetForm(forms.ModelForm):
fields = [ fields = [
"ip", "other_ip", "remote_card_ip", "hostname", "port", "groups", "username", "password", "ip", "other_ip", "remote_card_ip", "hostname", "port", "groups", "username", "password",
"idc", "mac_address", "brand", "cpu", "memory", "disk", "os", "cabinet_no", "cabinet_pos", "idc", "mac_address", "brand", "cpu", "memory", "disk", "os", "cabinet_no", "cabinet_pos",
"number", "status", "type", "env", "sn", "is_active", "comment", "admin_user", "system_user" "number", "status", "type", "env", "sn", "is_active", "comment", "admin_user", "system_users"
] ]
widgets = { widgets = {
......
...@@ -194,6 +194,21 @@ class SystemUser(models.Model): ...@@ -194,6 +194,21 @@ class SystemUser(models.Model):
def public_key(self, public_key_raw): def public_key(self, public_key_raw):
self._public_key = encrypt(public_key_raw) self._public_key = encrypt(public_key_raw)
def get_assets_inherit_from_asset_groups(self):
assets = set()
asset_groups = self.asset_groups.all()
for asset_group in asset_groups:
for asset in asset_group.assets.all():
setattr(asset, 'is_inherit_from_asset_groups', True)
setattr(asset, 'inherit_from_asset_groups',
getattr(asset, b'inherit_from_asset_groups', set()).add(asset_group))
assets.add(asset)
return assets
def get_assets(self):
assets = set(self.assets.all()) | self.get_assets_inherit_from_asset_groups()
return list(assets)
class Meta: class Meta:
db_table = 'system_user' db_table = 'system_user'
...@@ -266,8 +281,8 @@ class Asset(models.Model): ...@@ -266,8 +281,8 @@ class Asset(models.Model):
password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_("Admin password")) password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_("Admin password"))
admin_user = models.ForeignKey(AdminUser, null=True, blank=True, related_name='assets', admin_user = models.ForeignKey(AdminUser, null=True, blank=True, related_name='assets',
on_delete=models.SET_NULL, verbose_name=_("Admin user")) on_delete=models.SET_NULL, verbose_name=_("Admin user"))
system_user = models.ManyToManyField(SystemUser, blank=True, related_name='assets', verbose_name=_("System User")) system_users = models.ManyToManyField(SystemUser, blank=True, related_name='assets', verbose_name=_("System User"))
idc = models.ForeignKey(IDC, null=True, blank=True, related_name='assets', on_delete=models.SET_NULL, verbose_name=_('IDC')) idc = models.ForeignKey(IDC, null=True, related_name='assets', on_delete=models.SET_NULL, verbose_name=_('IDC'))
mac_address = models.CharField(max_length=20, null=True, blank=True, verbose_name=_("Mac address")) mac_address = models.CharField(max_length=20, null=True, blank=True, verbose_name=_("Mac address"))
brand = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Brand')) brand = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Brand'))
cpu = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('CPU')) cpu = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('CPU'))
...@@ -301,7 +316,7 @@ class Asset(models.Model): ...@@ -301,7 +316,7 @@ class Asset(models.Model):
@classmethod @classmethod
def generate_fake(cls, count=100): def generate_fake(cls, count=100):
from random import seed from random import seed, choice
import forgery_py import forgery_py
from django.db import IntegrityError from django.db import IntegrityError
...@@ -309,10 +324,14 @@ class Asset(models.Model): ...@@ -309,10 +324,14 @@ class Asset(models.Model):
for i in range(count): for i in range(count):
asset = cls(ip='%s.%s.%s.%s' % tuple([forgery_py.forgery.basic.text(length=3, digits=True) asset = cls(ip='%s.%s.%s.%s' % tuple([forgery_py.forgery.basic.text(length=3, digits=True)
for i in range(0, 4)]), for i in range(0, 4)]),
admin_user=choice(AdminUser.objects.all()),
idc=choice(IDC.objects.all()),
port=22, port=22,
created_by='Fake') created_by='Fake')
try: try:
asset.save() asset.save()
asset.system_users = [choice(SystemUser.objects.all()) for i in range(3)]
asset.groups = [choice(AssetGroup.objects.all()) for i in range(3)]
logger.debug('Generate fake asset : %s' % asset.ip) logger.debug('Generate fake asset : %s' % asset.ip)
except IntegrityError: except IntegrityError:
print('Error continue') print('Error continue')
...@@ -335,5 +354,5 @@ class Label(models.Model): ...@@ -335,5 +354,5 @@ class Label(models.Model):
def generate_fake(): def generate_fake():
for cls in (Asset, AssetGroup, IDC): for cls in (AssetGroup, IDC, AdminUser, SystemUser, Asset):
cls.generate_fake() cls.generate_fake()
\ No newline at end of file
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="panel-options"> <div class="panel-options">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a> <li class="active">
<a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li> </li>
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Associate assets' %}</a></li>
</ul> </ul>
</div> </div>
<div class="tab-content"> <div class="tab-content">
...@@ -33,10 +33,6 @@ ...@@ -33,10 +33,6 @@
<i class="fa fa-wrench"></i> <i class="fa fa-wrench"></i>
</a> </a>
<ul class="dropdown-menu dropdown-user"> <ul class="dropdown-menu dropdown-user">
<li><a href="#"></a>
</li>
<li><a href="#"></a>
</li>
</ul> </ul>
<a class="close-link"> <a class="close-link">
<i class="fa fa-times"></i> <i class="fa fa-times"></i>
...@@ -73,7 +69,7 @@ ...@@ -73,7 +69,7 @@
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span style="float: left">{% trans 'Asset list of ' %} <b>{{ admin_user.name }}</b></span> <span style="float: left">{% trans 'Asset list of ' %} <b>{{ admin_user.name }}</b> <span class="badge"> {{ paginator.count }}</span></span>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -82,10 +78,6 @@ ...@@ -82,10 +78,6 @@
<i class="fa fa-wrench"></i> <i class="fa fa-wrench"></i>
</a> </a>
<ul class="dropdown-menu dropdown-user"> <ul class="dropdown-menu dropdown-user">
<li><a href="#"></a>
</li>
<li><a href="#"></a>
</li>
</ul> </ul>
<a class="close-link"> <a class="close-link">
<i class="fa fa-times"></i> <i class="fa fa-times"></i>
...@@ -185,6 +177,34 @@ ...@@ -185,6 +177,34 @@
</table> </table>
</div> </div>
</div> </div>
<div class="panel panel-warning">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Replace asset admin user with this admin user' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<form>
<tr class="no-borders-tr">
<td colspan="2">
<select data-placeholder="{% trans 'Select asset groups' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for group in groups %}
<option value="{{ group.id }}">{{ group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="2">
<button type="button" class="btn btn-warning btn-sm">{% trans 'Replace' %}</button>
</td>
</tr>
</form>
</tbody>
</table>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -19,10 +19,7 @@ ...@@ -19,10 +19,7 @@
<a href="{% url 'assets:system-user-detail' pk=system_user.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a> <a href="{% url 'assets:system-user-detail' pk=system_user.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li> </li>
<li class="active"><a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center"> <li class="active"><a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate assets' %}</a> <i class="fa fa-bar-chart-o"></i> {% trans 'Associate assets and asset groups' %}</a>
</li>
<li><a href="{% url 'assets:system-user-asset-group' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate asset groups' %}</a>
</li> </li>
</ul> </ul>
</div> </div>
...@@ -30,7 +27,7 @@ ...@@ -30,7 +27,7 @@
<div class="col-sm-7" style="padding-left: 0;"> <div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span style="float: left">{% trans 'Asset list of ' %} <b>{{ admin_user.name }}</b></span> <span style="float: left">{% trans 'Assets attached of ' %} <b>{{ system_user.name }} </b><span class="badge">{{ paginator.count }}</span></span>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -52,7 +49,8 @@ ...@@ -52,7 +49,8 @@
<th>{% trans 'Hostname' %}</th> <th>{% trans 'Hostname' %}</th>
<th>{% trans 'IP' %}</th> <th>{% trans 'IP' %}</th>
<th>{% trans 'Port' %}</th> <th>{% trans 'Port' %}</th>
<th>{% trans 'Alive' %}</th> <th>{% trans 'Reachable' %}</th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -61,7 +59,12 @@ ...@@ -61,7 +59,12 @@
<td>{{ asset.hostname }}</td> <td>{{ asset.hostname }}</td>
<td>{{ asset.ip }}</td> <td>{{ asset.ip }}</td>
<td>{{ asset.port }}</td> <td>{{ asset.port }}</td>
<td>Alive</td> <td>
<i class="fa fa-check text-navy"></i>
</td>
<td>
<button class="btn btn-danger pull-right btn-xs {% if asset.is_inherit_from_asset_groups %} disabled {% endif %}" type="button"><i class="fa fa-minus"></i></button>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
...@@ -75,7 +78,7 @@ ...@@ -75,7 +78,7 @@
<div class="col-sm-5" style="padding-left: 0;padding-right: 0"> <div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary"> <div class="panel panel-primary">
<div class="panel-heading"> <div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Add asset to this system user' %} <i class="fa fa-info-circle"></i> {% trans 'Attach to assets ' %}
</div> </div>
<div class="panel-body"> <div class="panel-body">
<table class="table"> <table class="table">
...@@ -84,7 +87,7 @@ ...@@ -84,7 +87,7 @@
<tr class="no-borders-tr"> <tr class="no-borders-tr">
<td colspan="2"> <td colspan="2">
<select data-placeholder="{% trans 'Select asset' %}" class="select2" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Select asset' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for asset in assets %} {% for asset in assets_remain %}
<option value="{{ asset.id }}">{{ asset.ip}}:{{ asset.port }}</option> <option value="{{ asset.id }}">{{ asset.ip}}:{{ asset.port }}</option>
{% endfor %} {% endfor %}
</select> </select>
...@@ -92,7 +95,7 @@ ...@@ -92,7 +95,7 @@
</tr> </tr>
<tr class="no-borders-tr"> <tr class="no-borders-tr">
<td colspan="2"> <td colspan="2">
<button type="button" class="btn btn-primary btn-sm">{% trans 'Add' %}</button> <button type="button" class="btn btn-primary btn-sm">{% trans 'Attach' %}</button>
</td> </td>
</tr> </tr>
</form> </form>
...@@ -100,6 +103,43 @@ ...@@ -100,6 +103,43 @@
</table> </table>
</div> </div>
</div> </div>
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Attach to asset groups' %}
</div>
<div class="panel-body">
<table class="table group_edit">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Add asset group' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for asset_group in asset_groups_remain %}
<option value="{{ asset_group.id }}">{{ asset_group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-sm" id="btn_add_user_group">{% trans 'Attach' %}</button>
</td>
</tr>
</form>
{% for asset_group in asset_groups %}
<tr>
<td ><b data-gid={{ asset_group.id }}>{{ asset_group.name }}</b></td>
<td>
<button class="btn btn-danger pull-right btn-xs" type="button"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -20,13 +20,9 @@ ...@@ -20,13 +20,9 @@
</li> </li>
<li> <li>
<a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center"> <a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate assets' %} <i class="fa fa-bar-chart-o"></i> {% trans 'Associate assets and asset groups' %}
</a> </a>
</li> </li>
<li>
<a href="{% url 'assets:system-user-asset-group' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate asset groups' %}</a>
</li>
</ul> </ul>
</div> </div>
<div class="tab-content"> <div class="tab-content">
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<th class="text-center"><a href="{% url 'assets:system-user-list' %}?sort=username">{% trans 'Username' %}</a></th> <th class="text-center"><a href="{% url 'assets:system-user-list' %}?sort=username">{% trans 'Username' %}</a></th>
<th class="text-center">{% trans 'Asset num' %}</th> <th class="text-center">{% trans 'Asset num' %}</th>
<th class="text-center">{% trans 'Asset group num' %}</th> <th class="text-center">{% trans 'Asset group num' %}</th>
<th class="text-center">{% trans 'Unavailable' %}</th> <th class="text-center">{% trans 'Unreachable' %}</th>
<th class="text-center">{% trans 'Comment' %}</th> <th class="text-center">{% trans 'Comment' %}</th>
<th class="text-center"></th> <th class="text-center"></th>
{% endblock %} {% endblock %}
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
</a> </a>
</td> </td>
<td class="text-center">{{ system_user.username }}</td> <td class="text-center">{{ system_user.username }}</td>
<td class="text-center">{{ system_user.assets.count }}</td> <td class="text-center">{{ system_user.get_assets|length }}</td>
<td class="text-center">{{ system_user.asset_groups.count }}</td> <td class="text-center">{{ system_user.asset_groups.count }}</td>
<td class="text-center">{{ system_user.assets.count }}</td> <td class="text-center">{{ system_user.assets.count }}</td>
<td class="text-center">{{ system_user.comment|truncatewords:4 }}</td> <td class="text-center">{{ system_user.comment|truncatewords:4 }}</td>
......
...@@ -48,7 +48,7 @@ urlpatterns = [ ...@@ -48,7 +48,7 @@ urlpatterns = [
url(r'^system-user/(?P<pk>[0-9]+)/update', views.SystemUserUpdateView.as_view(), name='system-user-update'), url(r'^system-user/(?P<pk>[0-9]+)/update', views.SystemUserUpdateView.as_view(), name='system-user-update'),
url(r'^system-user/(?P<pk>[0-9]+)/delete$', views.SystemUserDeleteView.as_view(), name='system-user-delete'), url(r'^system-user/(?P<pk>[0-9]+)/delete$', views.SystemUserDeleteView.as_view(), name='system-user-delete'),
url(r'^system-user/(?P<pk>[0-9]+)/asset$', views.SystemUserAssetView.as_view(), name='system-user-asset'), url(r'^system-user/(?P<pk>[0-9]+)/asset$', views.SystemUserAssetView.as_view(), name='system-user-asset'),
url(r'^system-user/(?P<pk>[0-9]+)/asset-group$', views.SystemUserAssetGroupView.as_view(), # url(r'^system-user/(?P<pk>[0-9]+)/asset-group$', views.SystemUserAssetGroupView.as_view(),
name='system-user-asset-group'), # name='system-user-asset-group'),
# url(r'^api/v1.0/', include(router.urls)), # url(r'^api/v1.0/', include(router.urls)),
] ]
...@@ -368,14 +368,13 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi ...@@ -368,14 +368,13 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi
self.object.name, self.object.name,
)) ))
return self.success_message return success_message
class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView): class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView):
model = SystemUser model = SystemUser
form_class = SystemUserForm form_class = SystemUserForm
template_name = 'assets/system_user_create_update.html' template_name = 'assets/system_user_create_update.html'
success_message = _('Update system user <a href="%s">%s</a> successfully.')
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
...@@ -386,7 +385,7 @@ class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView): ...@@ -386,7 +385,7 @@ class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView):
return super(SystemUserUpdateView, self).get_context_data(**kwargs) return super(SystemUserUpdateView, self).get_context_data(**kwargs)
def get_success_url(self): def get_success_url(self):
success_url = reverse_lazy('assets:system-user-detail', pk=self.object.pk) success_url = reverse_lazy('assets:system-user-detail', kwargs={'pk': self.object.pk})
return success_url return success_url
...@@ -419,39 +418,47 @@ class SystemUserAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView): ...@@ -419,39 +418,47 @@ class SystemUserAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
self.object = self.get_object(queryset=SystemUser.objects.all()) self.object = self.get_object(queryset=SystemUser.objects.all())
return super(SystemUserAssetView, self).get(request, *args, **kwargs) return super(SystemUserAssetView, self).get(request, *args, **kwargs)
def get_asset_groups(self):
return self.object.asset_groups.all()
# Todo: queryset default order by connectivity, need ops support # Todo: queryset default order by connectivity, need ops support
def get_queryset(self): def get_queryset(self):
return self.object.assets.all() return list(self.object.get_assets())
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
asset_groups = self.get_asset_groups()
assets = self.get_queryset()
context = { context = {
'app': 'assets', 'app': 'assets',
'action': 'System user asset', 'action': 'System user asset',
'assets': self.get_queryset(), 'assets_remain': [asset for asset in Asset.objects.all() if asset not in assets],
'asset_groups': asset_groups,
'asset_groups_remain': [asset_group for asset_group in AssetGroup.objects.all()
if asset_group not in asset_groups]
} }
kwargs.update(context) kwargs.update(context)
return super(SystemUserAssetView, self).get_context_data(**kwargs) return super(SystemUserAssetView, self).get_context_data(**kwargs)
class SystemUserAssetGroupView(AdminUserRequiredMixin, SingleObjectMixin, ListView): # class SystemUserAssetGroupView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE # paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
template_name = 'assets/system_user_asset_group.html' # template_name = 'assets/system_user_asset_group.html'
context_object_name = 'system_user' # context_object_name = 'system_user'
#
def get(self, request, *args, **kwargs): # def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=SystemUser.objects.all()) # self.object = self.get_object(queryset=SystemUser.objects.all())
return super(SystemUserAssetGroupView, self).get(request, *args, **kwargs) # return super(SystemUserAssetGroupView, self).get(request, *args, **kwargs)
#
# Todo: queryset default order by connectivity, need ops support # Todo: queryset default order by connectivity, need ops support
def get_queryset(self): # def get_queryset(self):
return self.object.asset_groups.all() # return self.object.asset_groups.all()
#
def get_context_data(self, **kwargs): # def get_context_data(self, **kwargs):
context = { # context = {
'app': 'assets', # 'app': 'assets',
'action': 'System user asset group', # 'action': 'System user asset group',
'asset_groups': self.get_queryset(), # 'asset_groups': self.get_queryset(),
} # }
kwargs.update(context) # kwargs.update(context)
return super(SystemUserAssetGroupView, self).get_context_data(**kwargs) # return super(SystemUserAssetGroupView, self).get_context_data(**kwargs)
...@@ -32,4 +32,14 @@ def pagination_range(total_page, current_num=1, display=5): ...@@ -32,4 +32,14 @@ def pagination_range(total_page, current_num=1, display=5):
start = current_num - display/2 if current_num > display/2 else 1 start = current_num - display/2 if current_num > display/2 else 1
end = start + display if start + display <= total_page else total_page + 1 end = start + display if start + display <= total_page else total_page + 1
return range(start, end) return range(start, end)
\ No newline at end of file
@register.filter
def join_attr(seq, attr=None, sep=None):
if sep is None:
sep = ', '
if attr is not None:
seq = [getattr(obj, attr) for obj in seq]
print(seq)
return sep.join(seq)
...@@ -14,7 +14,7 @@ class AssetPermissionForm(forms.ModelForm): ...@@ -14,7 +14,7 @@ class AssetPermissionForm(forms.ModelForm):
model = AssetPermission model = AssetPermission
fields = [ fields = [
'name', 'users', 'user_groups', 'assets', 'asset_groups', 'name', 'users', 'user_groups', 'assets', 'asset_groups',
'system_users', 'action', 'is_active', 'date_expired', 'comment', 'system_users', 'is_active', 'date_expired', 'comment',
] ]
widgets = { widgets = {
'users': forms.SelectMultiple(attrs={'class': 'select2', 'users': forms.SelectMultiple(attrs={'class': 'select2',
......
...@@ -11,18 +11,19 @@ from common.utils import date_expired_default, combine_seq ...@@ -11,18 +11,19 @@ from common.utils import date_expired_default, combine_seq
class AssetPermission(models.Model): class AssetPermission(models.Model):
ACTION_CHOICE = ( PRIVATE_FOR_CHOICE = (
('1', 'Allow'), ('N', 'None'),
('0', 'Deny'), ('U', 'user'),
('G', 'user group'),
) )
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
name = models.CharField(max_length=128, verbose_name=_('Name'))
users = models.ManyToManyField(User, related_name='asset_permissions', blank=True) users = models.ManyToManyField(User, related_name='asset_permissions', blank=True)
user_groups = models.ManyToManyField(UserGroup, related_name='asset_permissions', blank=True) user_groups = models.ManyToManyField(UserGroup, related_name='asset_permissions', blank=True)
assets = models.ManyToManyField(Asset, related_name='granted_by_permissions', blank=True) assets = models.ManyToManyField(Asset, related_name='granted_by_permissions', blank=True)
asset_groups = models.ManyToManyField(AssetGroup, related_name='granted_by_permissions', blank=True) asset_groups = models.ManyToManyField(AssetGroup, related_name='granted_by_permissions', blank=True)
system_users = models.ManyToManyField(SystemUser, related_name='granted_by_permissions') system_users = models.ManyToManyField(SystemUser, related_name='granted_by_permissions')
action = models.CharField(choices=ACTION_CHOICE, max_length=8, default='1') private_for = models.CharField(choices=PRIVATE_FOR_CHOICE, max_length=1, default='N', blank=True,
verbose_name=_('Private for'))
is_active = models.BooleanField(default=True, verbose_name=_('Active')) is_active = models.BooleanField(default=True, verbose_name=_('Active'))
date_expired = models.DateTimeField(default=date_expired_default, verbose_name=_('Date expired')) date_expired = models.DateTimeField(default=date_expired_default, verbose_name=_('Date expired'))
created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by')) created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by'))
...@@ -30,7 +31,7 @@ class AssetPermission(models.Model): ...@@ -30,7 +31,7 @@ class AssetPermission(models.Model):
comment = models.TextField(verbose_name=_('Comment'), blank=True) comment = models.TextField(verbose_name=_('Comment'), blank=True)
def __unicode__(self): def __unicode__(self):
return '%(name)s: %(action)s' % {'name': self.name, 'action': self.action} return self.name
@property @property
def is_valid(self): def is_valid(self):
...@@ -38,32 +39,31 @@ class AssetPermission(models.Model): ...@@ -38,32 +39,31 @@ class AssetPermission(models.Model):
return True return True
return True return True
@staticmethod
def set_inherit(obj):
setattr(obj, 'inherited', True)
return obj
def get_granted_users(self): def get_granted_users(self):
return list(set(self.users.all() or []) | set(self.get_granted_user_groups_member())) return list(set(self.users.all()) | self.get_granted_user_groups_member())
def get_granted_user_groups_member(self): def get_granted_user_groups_member(self):
combine_users = functools.partial(combine_seq, callback=AssetPermission.set_inherit) users = set()
try: for user_group in self.user_groups.all():
return functools.reduce(combine_users, [user_group.users.all() for user in user_group.users.all():
for user_group in self.user_groups.iterator()]) setattr(user, 'is_inherit_from_user_groups', True)
except TypeError: setattr(user, 'inherit_from_user_groups',
return [] getattr(user, b'inherit_from_user_groups', set()).add(user_group))
users.add(user)
return users
def get_granted_assets(self): def get_granted_assets(self):
return list(set(self.assets.all() or []) | set(self.get_granted_asset_groups_member())) return list(set(self.assets.all()) | self.get_granted_asset_groups_member())
def get_granted_asset_groups_member(self): def get_granted_asset_groups_member(self):
combine_assets = functools.partial(combine_seq, callback=AssetPermission.set_inherit) assets = set()
try: for asset_group in self.asset_groups.all():
return functools.reduce(combine_assets, [asset_group.users.all() for asset in asset_group.assets.all():
for asset_group in self.asset_groups.iterator()]) setattr(asset, 'is_inherit_from_asset_groups', True)
except TypeError: setattr(asset, 'inherit_from_asset_groups',
return [] getattr(asset, b'inherit_from_user_groups', set()).add(asset_group))
assets.add(asset)
return assets
class Meta: class Meta:
db_table = 'asset_permission' db_table = 'asset_permission'
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
</li> </li>
<li class="active"> <li class="active">
<a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center"> <a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset gruops' %}</a> <i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset groups' %}</a>
</li> </li>
<form id="search_form" method="get" action="" class="pull-right mail-search"> <form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group"> <div class="input-group">
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
</td> </td>
<td> <td>
<button class="btn btn-danger btn-xs btn_delete_user_group" type="button" style="float: right;"><i class="fa fa-minus"></i></button> <button title="{{ asset.inherit_from_asset_groups }}" class="btn btn-danger btn-xs {% if asset.is_inherit_from_asset_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
...@@ -43,8 +43,6 @@ ...@@ -43,8 +43,6 @@
{{ form.system_users |bootstrap_horizontal }} {{ form.system_users |bootstrap_horizontal }}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3> <h3>{% trans 'Other' %}</h3>
{{ form.action|bootstrap_horizontal }}
<div class="form-group"> <div class="form-group">
<label for="{{ form.is_active.id_for_label }}" class="col-sm-2 control-label">{% trans 'Active' %}</label> <label for="{{ form.is_active.id_for_label }}" class="col-sm-2 control-label">{% trans 'Active' %}</label>
<div class="col-sm-8"> <div class="col-sm-8">
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
</li> </li>
<li> <li>
<a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center"> <a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset gruops' %}</a> <i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset groups' %}</a>
</li> </li>
</ul> </ul>
</div> </div>
...@@ -76,14 +76,6 @@ ...@@ -76,14 +76,6 @@
<td>{% trans 'System user count' %}:</td> <td>{% trans 'System user count' %}:</td>
<td><b>{{ asset_permission.system_users.count }}</b></td> <td><b>{{ asset_permission.system_users.count }}</b></td>
</tr> </tr>
<tr>
<td>{% trans 'Action' %}:</td>
<td><b>{{ asset_permission.get_action_display }}</b></td>
</tr>
<tr>
<td>{% trans 'Is active' %}:</td>
<td><b>{{ asset_permission.is_active|yesno:'Yes, No, Unkown' }}</b></td>
</tr>
<tr> <tr>
<td>{% trans 'Date expired' %}:</td> <td>{% trans 'Date expired' %}:</td>
<td><b>{{ asset_permission.date_expired }}</b></td> <td><b>{{ asset_permission.date_expired }}</b></td>
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
</li> </li>
<li> <li>
<a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center"> <a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset gruops' %}</a> <i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset groups' %}</a>
</li> </li>
<form id="search_form" method="get" action="" class="pull-right mail-search"> <form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group"> <div class="input-group">
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
</td> </td>
<td> <td>
<button class="btn btn-danger btn-xs btn_delete_user_group {% if user.inherited %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button> <button class="btn btn-danger btn-xs btn_delete_user_group {% if user.is_inherit_from_user_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
{% extends '_list_base.html' %}
{% load i18n %}
{% load common_tags %}
{% block content_left_head %}
<a href="{% url 'users:user-create' %}" class="btn btn-sm btn-primary "> {% trans "Create perm " %} </a>
{% endblock %}
{% block table_head %}
<th class="text-center">
<input type="checkbox" id="check_all" onclick="checkAll('check_all', 'checked')">
</th>
<th class="text-center"><a href="{% url 'users:user-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center"><a href="{% url 'users:user-list' %}?sort=username">{% trans 'Username' %}</a></th>
<th class="text-center">{% trans 'Role' %}</th>
<th class="text-center">{% trans 'Asset num' %}</th>
<th class="text-center">{% trans 'Asset group' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th class="text-center"><a href="{% url 'users:user-list' %}?sort=date_expired">{% trans 'Active' %}</a></th>
<th class="text-center"></th>
{% endblock %}
{% block table_body %}
{% for perm in page_obj %}
<tr class="gradeX">
<td class="text-center">
<input type="checkbox" name="checked" value="{{ user.id }}">
</td>
<td class="text-center">
<a href="{% url 'users:user-detail' pk=user.id %}">
{{ user.name }}
</a>
</td>
<td class="text-center">{{ user.username }}</td>
<td class="text-center">{{ user.get_role_display }}</td>
<th class="text-center">35/40</th>
<th class="text-center">20</th>
<th class="text-center">3</th>
<td class="text-center">
<a href="{% url 'perms:perm-user-asset-create' pk=user.id %}" class="btn btn-xs btn-info">{% trans 'Create perm' %}</a>
<a href="{% url 'users:user-delete' pk=user.id %}" class="btn btn-xs btn-danger del {% if user.id == request.user.id or user.username == 'admin' %} disabled {% endif %}">{% trans 'Flush' %}</a>
</td>
</tr>
{% endfor %}
{% endblock %}
{% block content_bottom_left %}
<form id="" method="get" action="" class=" mail-search">
<div class="input-group">
<select class="form-control m-b" style="width: auto">
<option>{% trans 'Delete selected' %}</option>
<option>{% trans 'Update selected' %}</option>
<option>{% trans 'Deactive selected' %}</option>
<option>{% trans 'Export selected' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='search_btn' type="submit" style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
</form>
{% endblock %}
...@@ -14,9 +14,9 @@ urlpatterns = [ ...@@ -14,9 +14,9 @@ urlpatterns = [
name='asset-permission-detail'), name='asset-permission-detail'),
url(r'^asset-permission/(?P<pk>[0-9]+)/delete$', views.AssetPermissionDeleteView.as_view(), url(r'^asset-permission/(?P<pk>[0-9]+)/delete$', views.AssetPermissionDeleteView.as_view(),
name='asset-permission-delete'), name='asset-permission-delete'),
url(r'^asset-permission/(?P<pk>[0-9]+)/user$', views.AssetPermissionUserListView.as_view(), url(r'^asset-permission/(?P<pk>[0-9]+)/user$', views.AssetPermissionUserView.as_view(),
name='asset-permission-user-list'), name='asset-permission-user-list'),
url(r'^asset-permission/(?P<pk>[0-9]+)/asset$', views.AssetPermissionAssetListView.as_view(), url(r'^asset-permission/(?P<pk>[0-9]+)/asset$', views.AssetPermissionAssetView.as_view(),
name='asset-permission-asset-list'), name='asset-permission-asset-list'),
] ]
# ~*~ coding: utf-8 ~*~ from __future__ import absolute_import, unicode_literals
#
from .hands import User, UserGroup, Asset, AssetGroup, SystemUser
def get_user_group_granted_asset_groups(user_group):
"""Return asset groups granted of the user group
:param user_group: Instance of :class: ``UserGroup``
:return: {asset1: {system_user1, }, asset1: {system_user1, system_user2]}
"""
asset_groups = {}
asset_permissions = user_group.asset_permissions.all()
for asset_permission in asset_permissions:
if not asset_permission.is_valid:
continue
for asset_group in asset_permission.asset_groups.all():
if asset_group in asset_groups:
asset_groups[asset_group] |= set(asset_permission.system_users.all())
else:
asset_groups[asset_group] = set(asset_permission.system_users.all())
return asset_groups
def get_user_group_granted_assets(user_group):
"""Return assets granted of the user group
:param user_group: Instance of :class: ``UserGroup``
:return: {asset1: {system_user1, }, asset1: {system_user1, system_user2]}
"""
assets = {}
asset_permissions = user_group.asset_permissions.all()
for asset_permission in asset_permissions:
if not asset_permission.is_valid:
continue
for asset in asset_permission.get_granted_assets():
if asset in assets:
assets[asset] |= set(asset_permission.system_users.all())
else:
assets[asset] = set(asset_permission.system_users.all())
return assets
def get_user_granted_asset_groups_direct(user):
"""Return asset groups granted of the user direct nor inherit from user group
:param user: Instance of :class: ``User``
:return: {asset_group: {system_user1, }, asset_group2: {system_user1, system_user2]}
"""
asset_groups = {}
asset_permissions_direct = user.asset_permissions.all()
for asset_permission in asset_permissions_direct:
if not asset_permission.is_valid:
continue
for asset_group in asset_permission.asset_groups.all():
if asset_group in asset_groups:
asset_groups[asset_group] |= set(asset_permission.system_users.all())
else:
setattr(asset_group, 'is_inherit_from_user_group', False)
asset_groups[asset_group] = set(asset_permission.system_users.all())
return asset_groups
def get_user_granted_asset_groups_inherit_from_user_groups(user):
"""Return asset groups granted of the user and inherit from user group
:param user: Instance of :class: ``User``
:return: {asset_group: {system_user1, }, asset_group2: {system_user1, system_user2]}
"""
asset_groups = {}
user_groups = user.groups.all()
asset_permissions = set()
# Get asset permission list of user groups for this user
for user_group in user_groups:
asset_permissions |= set(user_group.asset_permissions.all())
# Get asset groups granted from user groups
for asset_permission in asset_permissions:
if not asset_permission.is_valid:
continue
for asset_group in asset_permission.asset_groups.all():
if asset_group in asset_groups:
asset_groups[asset_group] |= set(asset_permission.system_users.all())
else:
setattr(asset_group, 'is_inherit_from_user_group', True)
asset_groups[asset_group] = set(asset_permission.system_users.all())
return asset_groups
def get_user_granted_asset_groups(user):
"""Get user granted asset groups all, include direct and inherit from user group
:param user: Instance of :class: ``User``
:return: {asset1: {system_user1, system_user2}, asset2: {...}}
"""
asset_groups_inherit_from_user_groups = get_user_granted_asset_groups_inherit_from_user_groups(user)
asset_groups_direct = get_user_granted_asset_groups_direct(user)
asset_groups = asset_groups_inherit_from_user_groups
# Merge direct granted and inherit from user group
for asset_group, system_users in asset_groups_direct.items():
if asset_group in asset_groups:
asset_groups[asset_group] |= asset_groups_direct[asset_group]
else:
asset_groups[asset_group] = asset_groups_direct[asset_group]
return asset_groups
def get_user_granted_assets_direct(user):
"""Return assets granted of the user directly
:param user: Instance of :class: ``User``
:return: {asset1: {system_user1, system_user2}, asset2: {...}}
"""
assets = {}
asset_permissions_direct = user.asset_permissions.all()
for asset_permission in asset_permissions_direct:
if not asset_permission.is_valid:
continue
for asset in asset_permission.get_granted_assets():
if asset in assets:
assets[asset] |= set(asset_permission.system_users.all())
else:
setattr(asset, 'is_inherit_from_user_groups', False)
setattr(asset, 'is_inherit_from_user_groups', False)
assets[asset] = set(asset_permission.system_users.all())
return assets
def get_user_granted_assets_inherit_from_user_groups(user):
"""Return assets granted of the user inherit from user groups
:param user: Instance of :class: ``User``
:return: {asset1: {system_user1, system_user2}, asset2: {...}}
"""
assets = {}
user_groups = user.groups.all()
for user_group in user_groups:
assets_inherited = get_user_group_granted_assets(user_group)
for asset in assets_inherited:
if asset in assets:
assets[asset] |= assets_inherited[asset]
else:
setattr(asset, 'is_inherit_from_user_groups', True)
assets[asset] = assets_inherited[asset]
return assets
def get_user_granted_assets(user):
"""Return assets granted of the user inherit from user groups
:param user: Instance of :class: ``User``
:return: {asset1: {system_user1, system_user2}, asset2: {...}}
"""
assets_direct = get_user_granted_assets_direct(user)
assets_inherited = get_user_granted_assets_inherit_from_user_groups(user)
assets = assets_inherited
for asset in assets_direct:
if asset in assets:
assets[asset] |= assets_direct[asset]
else:
assets[asset] = assets_direct[asset]
return assets
def get_user_groups_granted_in_asset(asset):
pass
def get_users_granted_in_asset(asset):
pass
def get_user_groups_granted_in_asset_group(asset):
pass
def get_users_granted_in_asset_group(asset):
pass
...@@ -120,15 +120,15 @@ class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView): ...@@ -120,15 +120,15 @@ class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView):
success_url = reverse_lazy('perms:asset-permission-list') success_url = reverse_lazy('perms:asset-permission-list')
class AssetPermissionUserListView(AdminUserRequiredMixin, SingleObjectMixin, ListView): class AssetPermissionUserView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
template_name = 'perms/asset_permission_user_list.html' template_name = 'perms/asset_permission_user.html'
context_object_name = 'asset_permission' context_object_name = 'asset_permission'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=AssetPermission.objects.all()) self.object = self.get_object(queryset=AssetPermission.objects.all())
self.keyword = self.request.GET.get('keyword', '') self.keyword = self.request.GET.get('keyword', '')
return super(AssetPermissionUserListView, self).get(request, *args, **kwargs) return super(AssetPermissionUserView, self).get(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
queryset = self.object.get_granted_users() queryset = self.object.get_granted_users()
...@@ -152,18 +152,18 @@ class AssetPermissionUserListView(AdminUserRequiredMixin, SingleObjectMixin, Lis ...@@ -152,18 +152,18 @@ class AssetPermissionUserListView(AdminUserRequiredMixin, SingleObjectMixin, Lis
'keyword': self.keyword, 'keyword': self.keyword,
} }
kwargs.update(context) kwargs.update(context)
return super(AssetPermissionUserListView, self).get_context_data(**kwargs) return super(AssetPermissionUserView, self).get_context_data(**kwargs)
class AssetPermissionAssetListView(AdminUserRequiredMixin, SingleObjectMixin, ListView): class AssetPermissionAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
template_name = 'perms/asset_permission_asset_list.html' template_name = 'perms/asset_permission_asset.html'
context_object_name = 'asset_permission' context_object_name = 'asset_permission'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=AssetPermission.objects.all()) self.object = self.get_object(queryset=AssetPermission.objects.all())
self.keyword = self.request.GET.get('keyword', '') self.keyword = self.request.GET.get('keyword', '')
return super(AssetPermissionAssetListView, self).get(request, *args, **kwargs) return super(AssetPermissionAssetView, self).get(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
queryset = self.object.get_granted_assets() queryset = self.object.get_granted_assets()
...@@ -187,4 +187,4 @@ class AssetPermissionAssetListView(AdminUserRequiredMixin, SingleObjectMixin, Li ...@@ -187,4 +187,4 @@ class AssetPermissionAssetListView(AdminUserRequiredMixin, SingleObjectMixin, Li
'keyword': self.keyword, 'keyword': self.keyword,
} }
kwargs.update(context) kwargs.update(context)
return super(AssetPermissionAssetListView, self).get_context_data(**kwargs) return super(AssetPermissionAssetView, self).get_context_data(**kwargs)
...@@ -77,3 +77,5 @@ th a { ...@@ -77,3 +77,5 @@ th a {
.no-borders-tr td { .no-borders-tr td {
border-top: none !important; border-top: none !important;
} }
/* @import url("https://fonts.useso.com/css?family=Open+Sans:300,400,600,700");
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700"); @import url("https://fonts.useso.com/css?family=Roboto:400,300,500,700");
@import url("https://fonts.googleapis.com/css?family=Roboto:400,300,500,700");
*/
/* /*
* *
* INSPINIA - Responsive Admin Theme * INSPINIA - Responsive Admin Theme
......
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
from django import forms from django import forms
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from captcha.fields import CaptchaField from captcha.fields import CaptchaField
from .models import User, UserGroup from .models import User, UserGroup
from .hands import AssetPermission
class UserLoginForm(AuthenticationForm): class UserLoginForm(AuthenticationForm):
...@@ -25,12 +25,10 @@ class UserCreateForm(forms.ModelForm): ...@@ -25,12 +25,10 @@ class UserCreateForm(forms.ModelForm):
'username', 'name', 'email', 'groups', 'wechat', 'username', 'name', 'email', 'groups', 'wechat',
'phone', 'enable_otp', 'role', 'date_expired', 'comment', 'phone', 'enable_otp', 'role', 'date_expired', 'comment',
] ]
help_texts = { help_texts = {
'username': '* required', 'username': '* required',
'email': '* required', 'email': '* required',
} }
widgets = { widgets = {
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}), 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}),
} }
...@@ -44,13 +42,11 @@ class UserUpdateForm(forms.ModelForm): ...@@ -44,13 +42,11 @@ class UserUpdateForm(forms.ModelForm):
'name', 'email', 'groups', 'wechat', 'name', 'email', 'groups', 'wechat',
'phone', 'enable_otp', 'role', 'date_expired', 'comment', 'phone', 'enable_otp', 'role', 'date_expired', 'comment',
] ]
help_texts = { help_texts = {
'username': '* required', 'username': '* required',
'email': '* required', 'email': '* required',
'groups': '* required' 'groups': '* required'
} }
widgets = { widgets = {
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}), 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}),
} }
...@@ -60,11 +56,9 @@ class UserGroupForm(forms.ModelForm): ...@@ -60,11 +56,9 @@ class UserGroupForm(forms.ModelForm):
class Meta: class Meta:
model = UserGroup model = UserGroup
fields = [ fields = [
'name', 'comment', 'name', 'comment',
] ]
help_texts = { help_texts = {
'name': '* required' 'name': '* required'
} }
...@@ -98,3 +92,27 @@ class UserKeyForm(forms.Form): ...@@ -98,3 +92,27 @@ class UserKeyForm(forms.Form):
print e print e
raise forms.ValidationError(_('Not a valid ssh public key')) raise forms.ValidationError(_('Not a valid ssh public key'))
return public_key return public_key
class UserPrivateAssetPermissionForm(forms.ModelForm):
def save(self, commit=True):
self.instance = super(UserPrivateAssetPermissionForm, self).save(commit=commit)
self.instance.private_for = 'U'
self.instance.users = [self.user]
self.instance.save()
return self.instance
class Meta:
model = AssetPermission
fields = [
'assets', 'asset_groups', 'system_users', 'private_for', 'name',
]
widgets = {
'assets': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select assets')}),
'asset_groups': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select asset groups')}),
'system_users': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select system users')}),
}
...@@ -10,5 +10,5 @@ ...@@ -10,5 +10,5 @@
:license: GPL v2, see LICENSE for more details. :license: GPL v2, see LICENSE for more details.
""" """
from perms.models import AssetPermission
from perms.utils import get_user_granted_assets, get_user_granted_asset_groups
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'users:user-detail' pk=user_object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'User detail' %} </a>
</li>
<li class="active">
<a href="{% url 'users:user-asset-permission' pk=user_object.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset permission' %}</a>
</li>
<li>
<a href="{% url 'users:user-granted-asset' pk=user_object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
</li>
<li>
<a href="{% url 'users:user-login-history' pk=user_object.id %}" class="text-center"><i class="fa fa-calculator-o"></i> {% trans 'Login history' %}</a>
</li>
<form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
<div class="input-group-btn">
<button id="search_btn" type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Asset permission of ' %} <b>{{ user_object.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table table-hover">
<thead>
<tr>
<th class="text-center"><a href="{% url 'perms:asset-permission-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center">{% trans 'User ' %}</th>
<th class="text-center">{% trans 'User group ' %}</th>
<th class="text-center">{% trans 'Asset ' %}</th>
<th class="text-center">{% trans 'Asset group ' %}</th>
<th class="text-center">{% trans 'System user ' %}</th>
<th class="text-center">
<a href="#">{% trans 'Is valid' %}</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
{% for asset_permission in object_list %}
<tr class="gradeX">
<td class="text-center">
<a href="{% url 'perms:asset-permission-detail' pk=asset_permission.id %}">
{{ asset_permission.name }}
</a>
</td>
<td class="text-center">{{ asset_permission.users.count}}</td>
<td class="text-center">{{ asset_permission.user_groups.count}}</td>
<td class="text-center">{{ asset_permission.assets.count }}</td>
<td class="text-center">{{ asset_permission.asset_groups.count }}</td>
<td class="text-center">{{ asset_permission.system_users.count }}</td>
<td class="text-center">
{% if asset_permission.is_valid %}
<i class="fa fa-check text-navy"></i>
{% else %}
<i class="fa fa-times text-danger"></i>
{% endif %}
</td>
<td>
<button class="btn btn-danger btn-xs btn_delete_user_group {% if asset_permission.is_inherit_from_user_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick create permission for user' %}
</div>
<div class="panel-body">
<form method="post" action="{% url 'users:user-asset-permission-create' pk=user_object.id %}">
<table class="table">
<tbody>
{% csrf_token %}
<tr class="no-borders-tr">
<td colspan="1" style="padding-top: 0">
{{ form.name|bootstrap }}
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="1" style="padding-top: 0">
{{ form.assets|bootstrap }}
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="1" style="padding-top: 0">
{{ form.asset_groups|bootstrap }}
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="1" style="padding-top: 0">
{{ form.system_users|bootstrap }}
</td>
</tr>
<tr class="no-borders-tr">
<td>
<button type="submit" class="btn btn-primary btn-sm">{% trans 'Submit' %}</button>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user_object.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
});
</script>
{% endblock %}
\ No newline at end of file
...@@ -17,10 +17,14 @@ ...@@ -17,10 +17,14 @@
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="panel-options"> <div class="panel-options">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'User detail' %} </a> <li class="active">
<a href="{% url 'users:user-detail' pk=user_object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'User detail' %} </a>
</li> </li>
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'User assets' %}</a></li> <li>
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'User log' %}</a></li> <a href="{% url 'users:user-asset-permission' pk=user_object.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset permission' %}</a>
</li>
<li><a href="{% url 'users:user-granted-asset' pk=user_object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a></li>
<li><a href="{% url 'users:user-login-history' pk=user_object.id %}" class="text-center"><i class="fa fa-calculator-o"></i> {% trans 'Login history' %}</a></li>
</ul> </ul>
</div> </div>
<div class="tab-content"> <div class="tab-content">
...@@ -189,7 +193,7 @@ ...@@ -189,7 +193,7 @@
<tr> <tr>
<td ><b class="bdg_user_group" data-gid={{ group.id }}>{{ group.name }}</b></td> <td ><b class="bdg_user_group" data-gid={{ group.id }}>{{ group.name }}</b></td>
<td> <td>
<button class="btn btn-danger pull-right btn-sm btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button> <button class="btn btn-danger pull-right btn-xs btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'users:user-detail' pk=user_object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'User detail' %} </a>
</li>
<li>
<a href="{% url 'users:user-asset-permission' pk=user_object.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset permission' %}</a>
</li>
<li class="active">
<a href="{% url 'users:user-granted-asset' pk=user_object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
</li>
<li>
<a href="{% url 'users:user-login-history' pk=user_object.id %}" class="text-center"><i class="fa fa-calculator-o"></i> {% trans 'Login history' %}</a>
</li>
<form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
<div class="input-group-btn">
<button id="search_btn" type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Granted assets of ' %} <b>{{ user_object.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table table-hover">
<thead>
<tr>
<th class="text-center"><a href="{% url 'perms:asset-permission-list' %}?sort=name">{% trans 'Hostname' %}</a></th>
<th class="text-center">{% trans 'IP' %}</th>
<th class="text-center">{% trans 'Port' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th class="text-center">
<a href="#">{% trans 'Is valid' %}</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
{% for asset, system_users in object_list %}
<tr class="gradeX">
<td class="text-center">
<a href="{% url 'assets:asset-detail' pk=asset.id %}">
{{ asset.hostname }}
</a>
</td>
<td class="text-center">{{ asset.ip }}</td>
<td class="text-center">{{ asset.port }}</td>
<td class="text-center">{{ system_users|join_attr:"name" }}</td>
<td class="text-center">
{% if asset.is_valid %}
<i class="fa fa-check text-navy"></i>
{% else %}
<i class="fa fa-times text-danger"></i>
{% endif %}
</td>
<td>
<button class="btn btn-danger btn-xs btn_delete_user_group {% if asset.is_inherit_from_user_groups or asset.is_inherit_from_asset_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Asset groups granted of ' %} <b>{{ user_object.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table table-hover">
<thead>
<tr>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Asset count' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for asset_group, system_users in asset_groups %}
<tr class="gradeX">
<td class="text-center">
<a href="{% url 'assets:asset-group-detail' pk=asset_group.id %}">
{{ asset_group.name }}
</a>
</td>
<td class="text-center">{{ asset_group.assets.count }}</td>
<td class="text-center">{{ system_users|join_attr:"name" }}</td>
<td>
<button class="btn btn-danger btn-xs btn_delete_user_group {% if not asset_group.is_inherit_from_user_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user_object.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
});
</script>
{% endblock %}
\ No newline at end of file
...@@ -16,6 +16,12 @@ urlpatterns = [ ...@@ -16,6 +16,12 @@ urlpatterns = [
name='reset-password-success'), name='reset-password-success'),
url(r'^user$', views.UserListView.as_view(), name='user-list'), url(r'^user$', views.UserListView.as_view(), name='user-list'),
url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'), url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'),
url(r'^user/(?P<pk>[0-9]+)/asset-permission$', views.UserAssetPermissionView.as_view(),
name='user-asset-permission'),
url(r'^user/(?P<pk>[0-9]+)/asset-permission/create$', views.UserAssetPermissionCreateView.as_view(),
name='user-asset-permission-create'),
url(r'^user/(?P<pk>[0-9]+)/granted-asset', views.UserGrantedAssetView.as_view(), name='user-granted-asset'),
url(r'^user/(?P<pk>[0-9]+)/login-history', views.UserDetailView.as_view(), name='user-login-history'),
url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'), url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'),
url(r'^user/(?P<pk>[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'), url(r'^user/(?P<pk>[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'),
url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'), url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'),
......
...@@ -18,16 +18,17 @@ from django.views.decorators.csrf import csrf_protect ...@@ -18,16 +18,17 @@ from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.list import ListView from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, DeleteView, UpdateView, FormView from django.views.generic.edit import CreateView, DeleteView, UpdateView, FormView, SingleObjectMixin, \
FormMixin, ModelFormMixin, ProcessFormView, BaseCreateView
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
from formtools.wizard.views import SessionWizardView from formtools.wizard.views import SessionWizardView
from common.utils import get_object_or_none, get_logger from common.utils import get_object_or_none, get_logger
from .models import User, UserGroup from .models import User, UserGroup
from .forms import UserCreateForm, UserUpdateForm, UserGroupForm, UserLoginForm, UserInfoForm, UserKeyForm from .forms import UserCreateForm, UserUpdateForm, UserGroupForm, UserLoginForm, UserInfoForm, UserKeyForm, \
UserPrivateAssetPermissionForm
from .utils import AdminUserRequiredMixin, user_add_success_next, send_reset_password_mail from .utils import AdminUserRequiredMixin, user_add_success_next, send_reset_password_mail
from .hands import AssetPermission, get_user_granted_asset_groups, get_user_granted_assets
logger = get_logger(__name__) logger = get_logger(__name__)
...@@ -349,3 +350,93 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView): ...@@ -349,3 +350,93 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
'phone': user.phone or '' 'phone': user.phone or ''
} }
return super(UserFirstLoginView, self).get_form_initial(step) return super(UserFirstLoginView, self).get_form_initial(step)
class UserAssetPermissionView(AdminUserRequiredMixin, FormMixin, SingleObjectMixin, ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
template_name = 'users/user_asset_permission.html'
context_object_name = 'user_object'
form_class = UserPrivateAssetPermissionForm
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=User.objects.all())
return super(UserAssetPermissionView, self).get(request, *args, **kwargs)
def get_asset_permission_inherit_from_user_group(self):
asset_permissions = set()
user_groups = self.object.groups.all()
for user_group in user_groups:
for asset_permission in user_group.asset_permissions.all():
setattr(asset_permission, 'is_inherit_from_user_groups', True)
setattr(asset_permission, 'inherit_from_user_groups',
getattr(asset_permission, b'inherit_from_user_groups', set()).add(user_group))
asset_permissions.add(asset_permission)
return asset_permissions
def get_queryset(self):
asset_permissions = set(self.object.asset_permissions.all()) \
| self.get_asset_permission_inherit_from_user_group()
return list(asset_permissions)
def get_context_data(self, **kwargs):
context = {
'app': 'Users',
'action': 'User asset permissions',
}
kwargs.update(context)
return super(UserAssetPermissionView, self).get_context_data(**kwargs)
class UserAssetPermissionCreateView(AdminUserRequiredMixin, CreateView):
form_class = UserPrivateAssetPermissionForm
model = AssetPermission
def get(self, request, *args, **kwargs):
user_object = self.get_object(queryset=User.objects.all())
return redirect(reverse('users:user-asset-permission', kwargs={'pk': user_object.id}))
def post(self, request, *args, **kwargs):
self.user_object = self.get_object(queryset=User.objects.all())
return super(UserAssetPermissionCreateView, self).post(request, *args, **kwargs)
def get_form(self, form_class=None):
form = super(UserAssetPermissionCreateView, self).get_form(form_class=form_class)
form.user = self.user_object
return form
def form_invalid(self, form):
print(form.errors)
return redirect(reverse('users:user-asset-permission', kwargs={'pk': self.user_object.id}))
def get_success_url(self):
return reverse('users:user-asset-permission', kwargs={'pk': self.user_object.id})
class UserGrantedAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
template_name = 'users/user_granted_asset.html'
context_object_name = 'user_object'
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=User.objects.all())
return super(UserGrantedAssetView, self).get(request, *args, **kwargs)
def get_queryset(self):
# Convert format from {'asset': ['system_users'], ..} to
# [('asset', ['system_users']), ('asset', ['system_users']))
assets_granted = [(asset, system_users) for asset, system_users in
get_user_granted_assets(self.object).items()]
return assets_granted
def get_context_data(self, **kwargs):
asset_groups = [(asset_group, system_users) for asset_group, system_users in
get_user_granted_asset_groups(self.object).items()]
context = {
'app': 'User',
'action': 'User granted asset',
'asset_groups': asset_groups,
}
kwargs.update(context)
return super(UserGrantedAssetView, self).get_context_data(**kwargs)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment