Commit a79c3dd1 authored by ibuler's avatar ibuler

[Fixture] 添加command log backends, 未来支持es

parent 0869931e
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from collections import OrderedDict
from django.core.cache import cache from django.core.cache import cache
from django.conf import settings from django.conf import settings
import copy import copy
...@@ -35,7 +36,7 @@ class TerminalRegisterView(ListCreateAPIView): ...@@ -35,7 +36,7 @@ class TerminalRegisterView(ListCreateAPIView):
if serializer.is_valid(): if serializer.is_valid():
terminal = serializer.save() terminal = serializer.save()
app_user, access_key = terminal.create_related_app_user() app_user, access_key = terminal.create_related_app_user()
data = {} data = OrderedDict()
data['terminal'] = copy.deepcopy(serializer.data) data['terminal'] = copy.deepcopy(serializer.data)
data['user'] = app_user.to_json() data['user'] = app_user.to_json()
data['access_key_id'] = access_key.id data['access_key_id'] = access_key.id
......
...@@ -167,6 +167,16 @@ class SystemUser(models.Model): ...@@ -167,6 +167,16 @@ class SystemUser(models.Model):
def asset_group_amount(self): def asset_group_amount(self):
return self.asset_groups.count() return self.asset_groups.count()
def to_json(self):
return {
'id': self.id,
'name': self.name,
'username': self.username,
'protocol': self.protocol,
'auth_method': self.auth_method,
'auto_push': self.auto_push,
}
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
......
...@@ -233,9 +233,6 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView): ...@@ -233,9 +233,6 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
form_class = forms.AssetGroupForm form_class = forms.AssetGroupForm
template_name = 'assets/asset_group_create.html' template_name = 'assets/asset_group_create.html'
success_url = reverse_lazy('assets:asset-group-list') success_url = reverse_lazy('assets:asset-group-list')
#ordering = '-id'
# Todo: Asset group create template select assets so hard, need be resolve next
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
...@@ -249,7 +246,8 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView): ...@@ -249,7 +246,8 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
def form_valid(self, form): def form_valid(self, form):
asset_group = form.save() asset_group = form.save()
assets_id_list = self.request.POST.getlist('assets', []) assets_id_list = self.request.POST.getlist('assets', [])
assets = [get_object_or_404(Asset, id=int(asset_id)) for asset_id in assets_id_list] assets = [get_object_or_404(Asset, id=int(asset_id))
for asset_id in assets_id_list]
asset_group.created_by = self.request.user.username or 'Admin' asset_group.created_by = self.request.user.username or 'Admin'
asset_group.assets.add(*tuple(assets)) asset_group.assets.add(*tuple(assets))
asset_group.save() asset_group.save()
...@@ -284,7 +282,8 @@ class AssetGroupDetailView(AdminUserRequiredMixin, DetailView): ...@@ -284,7 +282,8 @@ class AssetGroupDetailView(AdminUserRequiredMixin, DetailView):
'app': _('Assets'), 'app': _('Assets'),
'action': _('Asset group detail'), 'action': _('Asset group detail'),
'assets_remain': assets_remain, 'assets_remain': assets_remain,
'assets': [asset for asset in Asset.objects.all() if asset not in assets_remain], 'assets': [asset for asset in Asset.objects.all()
if asset not in assets_remain],
'system_users': system_users, 'system_users': system_users,
'system_users_remain': system_users_remain, 'system_users_remain': system_users_remain,
} }
...@@ -349,10 +348,9 @@ class IDCCreateView(AdminUserRequiredMixin, CreateView): ...@@ -349,10 +348,9 @@ class IDCCreateView(AdminUserRequiredMixin, CreateView):
return super(IDCCreateView, self).get_context_data(**kwargs) return super(IDCCreateView, self).get_context_data(**kwargs)
def form_valid(self, form): def form_valid(self, form):
IDC = form.save(commit=False) idc = form.save(commit=False)
IDC.created_by = self.request.user.username or 'System' idc.created_by = self.request.user.username or 'System'
IDC.save() idc.save()
# IDC_add_success_next(user)
return super(IDCCreateView, self).form_valid(form) return super(IDCCreateView, self).form_valid(form)
......
...@@ -5,11 +5,12 @@ ...@@ -5,11 +5,12 @@
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from rest_framework import generics, viewsets from rest_framework import generics, viewsets
from rest_framework.views import APIView, Response
from rest_framework_bulk import BulkModelViewSet from rest_framework_bulk import BulkModelViewSet
from audits.backends import command_store
from audits.backends.command.serializers import CommandLogSerializer
from . import models, serializers from . import models, serializers
from .hands import IsSuperUserOrAppUser, Terminal, IsAppUser from .hands import IsSuperUserOrAppUser, IsAppUser
class ProxyLogReceiveView(generics.CreateAPIView): class ProxyLogReceiveView(generics.CreateAPIView):
...@@ -47,8 +48,21 @@ class ProxyLogViewSet(viewsets.ModelViewSet): ...@@ -47,8 +48,21 @@ class ProxyLogViewSet(viewsets.ModelViewSet):
permission_classes = (IsSuperUserOrAppUser,) permission_classes = (IsSuperUserOrAppUser,)
class CommandLogViewSet(viewsets.ModelViewSet): class CommandLogViewSet(BulkModelViewSet):
queryset = models.CommandLog.objects.all() """接受app发送来的command log, 格式如下
serializer_class = serializers.CommandLogSerializer {
"proxy_log_id": 23,
"user": "admin",
"asset": "localhost",
"system_user": "web",
"command_no": 1,
"command": "whoami",
"output": "d2hvbWFp", # base64.b64encode(s)
"timestamp": 1485238673.0
}
"""
queryset = command_store.all()
serializer_class = CommandLogSerializer
permission_classes = (IsSuperUserOrAppUser,) permission_classes = (IsSuperUserOrAppUser,)
from importlib import import_module
from django.conf import settings
command_engine = import_module(settings.COMMAND_STORE_BACKEND)
command_store = command_engine.CommandStore()
from .command.serializers import CommandLogSerializer
# coding: utf-8
import abc
class CommandBase(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def save(self, proxy_log_id, user, asset, system_user,
command_no, command, output, timestamp):
pass
@abc.abstractmethod
def filter(self, date_from=None, date_to=None, user='',
asset='', system_user='', command=''):
pass
# ~*~ coding: utf-8 ~*~
from .base import CommandBase
from audits.models import CommandLog
class CommandStore(CommandBase):
model = CommandLog
queryset = []
def save(self, proxy_log_id, user, asset, system_user,
command_no, command, output, timestamp):
self.model.objects.create(
proxy_log_id=proxy_log_id, user=user, asset=asset,
system_user=system_user, command_no=command_no,
command=command, output=output, timestamp=timestamp
)
def filter(self, date_from_ts=None, date_to_ts=None, user='',
asset='', system_user='', command='', proxy_log_id=''):
filter_kwargs = {}
if date_from_ts:
filter_kwargs['timestamp__gte'] = date_from_ts
if date_to_ts:
filter_kwargs['timestamp__lte'] = date_to_ts
if user:
filter_kwargs['user'] = user
if asset:
filter_kwargs['asset'] = asset
if system_user:
filter_kwargs['system_user'] = system_user
if command:
filter_kwargs['command__icontains'] = command
if proxy_log_id:
filter_kwargs['proxy_log_id'] = proxy_log_id
if filter_kwargs:
self.queryset = self.model.objects.filter(**filter_kwargs)
return self.queryset
def all(self):
"""返回所有数据"""
return self.model.objects.iterator()
# ~*~ coding: utf-8 ~*~
import base64
from rest_framework import serializers
from audits.models import CommandLog
from audits.backends import command_store
class CommandLogSerializer(serializers.ModelSerializer):
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
class Meta:
model = CommandLog
fields = '__all__'
def save(self):
try:
output = self.validated_data['output']
self.validated_data['output'] = base64.b64decode(output)
except IndexError:
pass
return command_store.save(**dict(self.validated_data))
...@@ -24,7 +24,8 @@ class LoginLog(models.Model): ...@@ -24,7 +24,8 @@ class LoginLog(models.Model):
verbose_name=_('Login city')) verbose_name=_('Login city'))
user_agent = models.CharField(max_length=100, blank=True, null=True, user_agent = models.CharField(max_length=100, blank=True, null=True,
verbose_name=_('User agent')) verbose_name=_('User agent'))
date_login = models.DateTimeField(auto_now_add=True, verbose_name=_('Date login')) date_login = models.DateTimeField(auto_now_add=True,
verbose_name=_('Date login'))
class Meta: class Meta:
db_table = 'login_log' db_table = 'login_log'
...@@ -37,56 +38,52 @@ class ProxyLog(models.Model): ...@@ -37,56 +38,52 @@ class ProxyLog(models.Model):
('WT', 'Web Terminal'), ('WT', 'Web Terminal'),
) )
username = models.CharField(max_length=20, verbose_name=_('Username')) user = models.CharField(max_length=32, verbose_name=_('User'))
name = models.CharField(max_length=20, blank=True, verbose_name=_('Name')) asset = models.CharField(max_length=32, verbose_name=_('Asset'))
hostname = models.CharField(max_length=128, blank=True, verbose_name=_('Hostname')) system_user = models.CharField(max_length=32, verbose_name=_('System user'))
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP')) login_type = models.CharField(
system_user = models.CharField(max_length=20, verbose_name=_('System user')) choices=LOGIN_TYPE_CHOICE, max_length=2, blank=True,
login_type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2, blank=True, null=True, verbose_name=_('Login type'))
null=True, verbose_name=_('Login type')) terminal = models.CharField(
terminal = models.CharField(max_length=32, blank=True, null=True, verbose_name=_('Terminal')) max_length=32, blank=True, null=True, verbose_name=_('Terminal'))
log_file = models.CharField(max_length=1000, blank=True, null=True) log_file = models.CharField(max_length=1000, blank=True, null=True)
was_failed = models.BooleanField(default=False, verbose_name=_('Did connect failed')) is_failed = models.BooleanField(
is_finished = models.BooleanField(default=False, verbose_name=_('Is finished')) default=False, verbose_name=_('Did connect failed'))
date_start = models.DateTimeField(auto_created=True, verbose_name=_('Date start')) is_finished = models.BooleanField(
date_finished = models.DateTimeField(null=True, verbose_name=_('Date finished')) default=False, verbose_name=_('Is finished'))
date_start = models.DateTimeField(
auto_created=True, verbose_name=_('Date start'))
date_finished = models.DateTimeField(
null=True, verbose_name=_('Date finished'))
def __unicode__(self): def __unicode__(self):
return '%s-%s-%s-%s' % (self.username, self.hostname, self.system_user, self.id) return '%s-%s-%s' % (self.user, self.asset, self.system_user)
@property
def commands_dict(self):
commands = self.command_log.all()
return [{
"command_no": command.command_no,
"command": command.command,
"output": command.output_decode,
"datetime": command.datetime,
} for command in commands]
class Meta: class Meta:
ordering = ['-date_start', 'username'] ordering = ['-date_start', 'user']
class CommandLog(models.Model): class CommandLog(models.Model):
proxy_log = models.ForeignKey(ProxyLog, on_delete=models.CASCADE, proxy_log_id = models.IntegerField()
related_name='commands') user = models.CharField(max_length=48, db_index=True)
asset = models.CharField(max_length=128, db_index=True)
system_user = models.CharField(max_length=48, db_index=True)
command_no = models.IntegerField() command_no = models.IntegerField()
command = models.CharField(max_length=1000, blank=True) command = models.CharField(max_length=1000, blank=True, db_index=True)
output = models.TextField(blank=True) output = models.TextField(blank=True)
datetime = models.DateTimeField(null=True) timestamp = models.FloatField(null=True, db_index=True)
def __unicode__(self): def __unicode__(self):
return '%s: %s' % (self.id, self.command) return '%s: %s' % (self.id, self.command)
@property
def output_decode(self):
try:
return base64.b64decode(self.output).decode('utf-8') \
.replace('\n', '<br />')
except UnicodeDecodeError:
return 'UnicodeDecodeError'
class Meta: class Meta:
db_table = 'command_log'
ordering = ['command_no', 'command'] ordering = ['command_no', 'command']
class RecordLog(models.Model):
proxy_log_id = models.IntegerField()
output = models.TextField(verbose_name=_('Output'))
timestamp = models.FloatField(null=True)
def __unicode__(self):
return 'Record: %s' % self.proxy_log_id
...@@ -13,10 +13,7 @@ class ProxyLogSerializer(serializers.ModelSerializer): ...@@ -13,10 +13,7 @@ class ProxyLogSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.ProxyLog model = models.ProxyLog
fields = ['id', 'name', 'username', 'hostname', 'ip', 'system_user', fields = '__all__'
'login_type', 'terminal', 'log_file', 'was_failed',
'is_finished', 'date_start', 'date_finished', 'time',
'command_length', "commands_dict"]
@staticmethod @staticmethod
def get_time(obj): def get_time(obj):
...@@ -27,10 +24,5 @@ class ProxyLogSerializer(serializers.ModelSerializer): ...@@ -27,10 +24,5 @@ class ProxyLogSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_command_length(obj): def get_command_length(obj):
return len(obj.commands.all()) return 2
class CommandLogSerializer(serializers.ModelSerializer):
class Meta:
model = models.CommandLog
fields = '__all__'
...@@ -23,32 +23,31 @@ ...@@ -23,32 +23,31 @@
</div> </div>
</div> </div>
<div class="input-group"> <div class="input-group">
<select class="select2 form-control" name="username"> <select class="select2 form-control" name="user">
<option value="">{% trans 'User' %}</option> <option value="">{% trans 'User' %}</option>
{% for user in user_list %} {% for u in user_list %}
<option value="{{ user.username }}" {% if user.username == username %} selected {% endif %}>{{ user.username }}</option> <option value="{{ u.username }}" {% if user == u.username %} selected {% endif %}>{{ u.username }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="input-group"> <div class="input-group">
<select class="select2 form-control" name="ip"> <select class="select2 form-control" name="asset">
<option value="">{% trans 'Asset' %}</option> <option value="">{% trans 'Asset' %}</option>
{% for asset in asset_list %} {% for a in asset_list %}
<option value="{{ asset.ip }}" {% if asset.ip == ip %} selected {% endif %}>{{ asset.ip }}</option> <option value="{{ a.ip }}" {% if asset == a.ip %} selected {% endif %}>{{ a.ip }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="input-group"> <div class="input-group">
<select class="select2 form-control" name="system_user"> <select class="select2 form-control" name="system_user">
{# <option value="">{{ system_user }}</option>#}
<option value="">{% trans 'System user' %}</option> <option value="">{% trans 'System user' %}</option>
{% for system_user in system_user_list %} {% for s in system_user_list %}
<option value="{{ system_user.username }}" {% if system_user.username == system_user %} selected {% endif %}>{{ system_user.username }}</option> <option value="{{ s.username }}" {% if s.username == system_user %} selected {% endif %}>{{ s.username }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}"> <input type="text" class="form-control input-sm" name="command" placeholder="Command" value="{{ command }}">
</div> </div>
<div class="input-group"> <div class="input-group">
<div class="input-group-btn"> <div class="input-group-btn">
...@@ -78,12 +77,12 @@ ...@@ -78,12 +77,12 @@
<tr> <tr>
<td>{{ command.id }}</td> <td>{{ command.id }}</td>
<td>{{ command.command }}</td> <td>{{ command.command }}</td>
<td>{{ command.proxy_log.username }}</td> <td>{{ command.user }}</td>
<td>{{ command.proxy_log.ip }}</td> <td>{{ command.asset }}</td>
<td>{{ command.proxy_log.system_user }}</td> <td>{{ command.system_user }}</td>
<td><a href="{% url 'audits:proxy-log-detail' pk=command.proxy_log.id %}">{{ command.proxy_log.id}}</a></td> <td><a href="{% url 'audits:proxy-log-detail' pk=command.proxy_log_id %}">{{ command.proxy_log_id}}</a></td>
<td>{{ command.datetime }}</td> <td>{{ command.timestamp|ts_to_date }}</td>
<td>{{ command.output_decode|safe }}</td> <td><pre style="border: none; background: none">{{ command.output|to_html|safe }}</pre></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
</ul> </ul>
</div> </div>
<div class="tab-content"> <div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;"> <div class="col-sm-11" 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 'Command log list' %} <b>{{ user_object.name }}</b></span> <span style="float: left">{% trans 'Command log list' %} <b>{{ user_object.name }}</b></span>
...@@ -52,8 +52,8 @@ ...@@ -52,8 +52,8 @@
<tr> <tr>
<td>{{ command.command_no }}</td> <td>{{ command.command_no }}</td>
<td>{{ command.command }}</td> <td>{{ command.command }}</td>
<td>{{ command.output_decode|safe }}</td> <td><pre style="border: none;background: none">{{ command.output|to_html|safe}}</pre></td>
<td>{{ command.datetime }}</td> <td>{{ command.timestamp|ts_to_date}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
</select> </select>
</div> </div>
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Command" value="{{ keyword }}"> <input type="text" class="form-control input-sm" name="keyword" placeholder="Keyword" value="{{ keyword }}">
</div> </div>
<div class="input-group"> <div class="input-group">
<div class="input-group-btn"> <div class="input-group-btn">
...@@ -61,44 +61,53 @@ ...@@ -61,44 +61,53 @@
{% block table_head %} {% block table_head %}
<th class="text-center">{% trans 'ID' %}</th> <th class="text-center">{% trans 'ID' %}</th>
<th class="text-center">{% trans 'Username' %}</th> <th class="text-center">{% trans 'User' %}</th>
<th class="text-center">{% trans 'IP' %}</th> <th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'System user' %}</th> <th class="text-center">{% trans 'System user' %}</th>
<th class="text-center">{% trans 'Command' %}</th> <th class="text-center">{% trans 'Command' %}</th>
<th class="text-center">{% trans 'Success' %}</th> <th class="text-center">{% trans 'Success' %}</th>
<th class="text-center">{% trans 'Finished' %}</th> <th class="text-center">{% trans 'Finished' %}</th>
<th class="text-center">{% trans 'R/M' %}</th>
<th class="text-center">{% trans 'Date start' %}</th> <th class="text-center">{% trans 'Date start' %}</th>
<th class="text-center">{% trans 'Time' %}</th> <th class="text-center">{% trans 'Time' %}</th>
{% endblock %} {% endblock %}
{% block table_body %} {% block table_body %}
{% for proxy_log in proxy_log_list %} {% for proxy_log in proxy_log_list %}
<tr class="gradeX"> <tr class="gradeX">
<td class="text-center"> <td class="text-center">
<a href="{% url 'audits:proxy-log-detail' pk=proxy_log.id %}">{{ proxy_log.id }}</a> <a href="{% url 'audits:proxy-log-detail' pk=proxy_log.id %}">{{ proxy_log.id }}</a>
</td> </td>
<td class="text-center">{{ proxy_log.username }}</td> <td class="text-center">{{ proxy_log.user }}</td>
<td class="text-center">{{ proxy_log.ip }}</td> <td class="text-center">{{ proxy_log.asset }}</td>
<td class="text-center">{{ proxy_log.system_user }}</td> <td class="text-center">{{ proxy_log.system_user }}</td>
<td class="text-center">{{ proxy_log.commands.all|length}}</td> <td class="text-center">{{ proxy_log.commands.all|length}}</td>
<td class="text-center"> <td class="text-center">
{% if proxy_log.was_failed %} {% if proxy_log.is_failed %}
<i class="fa fa-times text-danger"></i> <i class="fa fa-times text-danger"></i>
{% else %} {% else %}
<i class="fa fa-check text-navy"></i> <i class="fa fa-check text-navy"></i>
{% endif %} {% endif %}
</td> </td>
<td class="text-center"> {% if proxy_log.is_finished %}
{% if proxy_log.is_finished %} <td class="text-center">
<i class="fa fa-check text-navy"></i> <i class="fa fa-check text-navy"></i>
{% else %} </td>
<i class="fa fa-times text-danger"></i> <td class="text-center">
{% endif %} <a><span class="text-navy"><i class="fa fa-play-circle"></i></span></a>
</td> </td>
<td class="text-center">{{ proxy_log.date_start }}</td> {% else %}
<td class="text-center">{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}</td> <td class="text-center">
</tr> <i class="fa fa-times text-danger"></i>
{% endfor %} </td>
<td class="text-center">
<a><span class="text-danger"><i class="fa fa-eye"></i></span></a>
</td>
{% endif %}
<td class="text-center">{{ proxy_log.date_start }}</td>
<td class="text-center">{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}</td>
</tr>
{% endfor %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
......
...@@ -10,7 +10,8 @@ router.register(r'v1/proxy-log', api.ProxyLogViewSet, 'proxy-log') ...@@ -10,7 +10,8 @@ router.register(r'v1/proxy-log', api.ProxyLogViewSet, 'proxy-log')
router.register(r'v1/command-log', api.CommandLogViewSet, 'command-log') router.register(r'v1/command-log', api.CommandLogViewSet, 'command-log')
urlpatterns = [ urlpatterns = [
url(r'^v1/proxy-log/receive/$', api.ProxyLogReceiveView.as_view(), name='proxy-log-receive'), url(r'^v1/proxy-log/receive/$', api.ProxyLogReceiveView.as_view(),
name='proxy-log-receive'),
] ]
urlpatterns += router.urls urlpatterns += router.urls
This diff is collapsed.
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
from django import template from django import template
from django.utils import timezone from django.utils import timezone
from django.conf import settings from django.conf import settings
from django.utils.html import escape
from audits.backends import command_store
register = template.Library() register = template.Library()
...@@ -41,10 +42,30 @@ def join_attr(seq, attr=None, sep=None): ...@@ -41,10 +42,30 @@ def join_attr(seq, attr=None, sep=None):
sep = ', ' sep = ', '
if attr is not None: if attr is not None:
seq = [getattr(obj, attr) for obj in seq] seq = [getattr(obj, attr) for obj in seq]
print(seq)
return sep.join(seq) return sep.join(seq)
@register.filter @register.filter
def int_to_str(value): def int_to_str(value):
return str(value) return str(value)
\ No newline at end of file
@register.filter
def ts_to_date(ts):
try:
ts = float(ts)
except TypeError:
ts = 0
dt = timezone.datetime.fromtimestamp(ts).\
replace(tzinfo=timezone.get_current_timezone())
return dt.strftime('%Y-%m-%d %H:%M:%S')
@register.filter
def to_html(s):
return escape(s).replace('\n', '<br />')
@register.filter
def proxy_log_commands(log_id):
return command_store.filter(proxy_log_id=log_id)
\ No newline at end of file
...@@ -33,8 +33,10 @@ from .compat import to_bytes, to_string ...@@ -33,8 +33,10 @@ from .compat import to_bytes, to_string
SECRET_KEY = settings.SECRET_KEY SECRET_KEY = settings.SECRET_KEY
def reverse(view_name, urlconf=None, args=None, kwargs=None, current_app=None, external=False): def reverse(view_name, urlconf=None, args=None, kwargs=None,
url = dj_reverse(view_name, urlconf=urlconf, args=args, kwargs=kwargs, current_app=current_app) current_app=None, external=False):
url = dj_reverse(view_name, urlconf=urlconf, args=args,
kwargs=kwargs, current_app=current_app)
if external: if external:
url = settings.SITE_URL.strip('/') + url url = settings.SITE_URL.strip('/') + url
...@@ -44,8 +46,8 @@ def reverse(view_name, urlconf=None, args=None, kwargs=None, current_app=None, e ...@@ -44,8 +46,8 @@ def reverse(view_name, urlconf=None, args=None, kwargs=None, current_app=None, e
def get_object_or_none(model, **kwargs): def get_object_or_none(model, **kwargs):
try: try:
obj = model.objects.get(**kwargs) obj = model.objects.get(**kwargs)
except model.DoesNotExist: except (model.FieldError, model.DoesNotExist):
obj = None return None
return obj return obj
......
# ~*~ coding: utf-8 ~*~
import pytz
from django.utils import timezone
from django.utils.deprecation import MiddlewareMixin
class TimezoneMiddleware(MiddlewareMixin):
def process_request(self, request):
tzname = request.META.get('TZ')
if tzname:
timezone.activate(pytz.timezone(tzname))
else:
timezone.deactivate()
...@@ -79,6 +79,7 @@ MIDDLEWARE = [ ...@@ -79,6 +79,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'jumpserver.middleware.TimezoneMiddleware',
] ]
ROOT_URLCONF = 'jumpserver.urls' ROOT_URLCONF = 'jumpserver.urls'
...@@ -323,3 +324,5 @@ CACHES = { ...@@ -323,3 +324,5 @@ CACHES = {
CAPTCHA_IMAGE_SIZE = (75, 33) CAPTCHA_IMAGE_SIZE = (75, 33)
CAPTCHA_FOREGROUND_COLOR = '#001100' CAPTCHA_FOREGROUND_COLOR = '#001100'
COMMAND_STORE_BACKEND = 'audits.backends.command.db'
...@@ -14,6 +14,7 @@ from .models import AssetPermission ...@@ -14,6 +14,7 @@ from .models import AssetPermission
from .hands import AssetGrantedSerializer, User, UserGroup, AssetGroup, Asset, \ from .hands import AssetGrantedSerializer, User, UserGroup, AssetGroup, Asset, \
AssetGroup, AssetGroupSerializer, SystemUser AssetGroup, AssetGroupSerializer, SystemUser
from . import serializers from . import serializers
from .utils import associate_system_users_and_assets
class AssetPermissionViewSet(viewsets.ModelViewSet): class AssetPermissionViewSet(viewsets.ModelViewSet):
...@@ -35,11 +36,32 @@ class AssetPermissionViewSet(viewsets.ModelViewSet): ...@@ -35,11 +36,32 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
queryset = get_user_group_asset_permissions(user_group) queryset = get_user_group_asset_permissions(user_group)
return queryset return queryset
# Todo: 忘记为何要重写get_serializer_class了
def get_serializer_class(self): def get_serializer_class(self):
if getattr(self, 'user_id', ''): if getattr(self, 'user_id', ''):
return serializers.UserAssetPermissionSerializer return serializers.UserAssetPermissionSerializer
return serializers.AssetPermissionSerializer return serializers.AssetPermissionSerializer
def associate_system_users_and_assets(self, serializer):
assets = serializer.validated_data.get('assets', [])
asset_groups = serializer.validated_data.get('asset_groups', [])
system_users = serializer.validated_data.get('system_users', [])
if serializer.partial:
instance = self.get_object()
assets.extend(list(instance.assets.all()))
asset_groups.extend(list(instance.asset_groups.all()))
system_users.extend(list(instance.system_users.all()))
print('Run')
associate_system_users_and_assets(system_users, assets, asset_groups)
def perform_create(self, serializer):
self.associate_system_users_and_assets(serializer)
return super(AssetPermissionViewSet, self).perform_create(serializer)
def perform_update(self, serializer):
self.associate_system_users_and_assets(serializer)
return super(AssetPermissionViewSet, self).perform_update(serializer)
class RevokeUserAssetPermission(APIView): class RevokeUserAssetPermission(APIView):
permission_classes = (IsSuperUser,) permission_classes = (IsSuperUser,)
...@@ -58,6 +80,27 @@ class RevokeUserAssetPermission(APIView): ...@@ -58,6 +80,27 @@ class RevokeUserAssetPermission(APIView):
return Response({'msg': 'failed'}, status=404) return Response({'msg': 'failed'}, status=404)
class RemoveSystemUserAssetPermission(APIView):
"""将系统用户从授权中移除, Detail页面会调用"""
permission_classes = (IsSuperUser,)
def put(self, request, *args, **kwargs):
response = []
asset_permission_id = kwargs.pop('pk')
system_users_id = request.data.get('system_users')
print(system_users_id)
asset_permission = get_object_or_404(
AssetPermission, id=asset_permission_id)
if not isinstance(system_users_id, list):
system_users_id = [system_users_id]
for system_user_id in system_users_id:
system_user = get_object_or_none(SystemUser, id=system_user_id)
if system_user:
asset_permission.system_users.remove(system_user)
response.append(system_user.to_json())
return Response(response, status=200)
class RevokeUserGroupAssetPermission(APIView): class RevokeUserGroupAssetPermission(APIView):
permission_classes = (IsSuperUser,) permission_classes = (IsSuperUser,)
......
...@@ -6,19 +6,9 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -6,19 +6,9 @@ from django.utils.translation import ugettext_lazy as _
# from .hands import User, UserGroup, Asset, AssetGroup, SystemUser # from .hands import User, UserGroup, Asset, AssetGroup, SystemUser
from .models import AssetPermission from .models import AssetPermission
from .hands import associate_system_users_with_assets
class AssetPermissionForm(forms.ModelForm): class AssetPermissionForm(forms.ModelForm):
def save(self, commit=True):
instance = super(AssetPermissionForm, self).save(commit=commit)
assets = instance.assets.all()
asset_groups = instance.asset_groups.all()
system_users = instance.system_users.all()
associate_system_users_with_assets(system_users, assets, asset_groups)
return instance
class Meta: class Meta:
model = AssetPermission model = AssetPermission
fields = [ fields = [
...@@ -48,4 +38,3 @@ class AssetPermissionForm(forms.ModelForm): ...@@ -48,4 +38,3 @@ class AssetPermissionForm(forms.ModelForm):
'asset_groups': '* Asset or Asset group at least one required', 'asset_groups': '* Asset or Asset group at least one required',
'system_users': '* required', 'system_users': '* required',
} }
...@@ -7,9 +7,9 @@ from assets.models import Asset, AssetGroup, SystemUser ...@@ -7,9 +7,9 @@ from assets.models import Asset, AssetGroup, SystemUser
from assets.serializers import AssetGrantedSerializer, AssetGroupSerializer from assets.serializers import AssetGrantedSerializer, AssetGroupSerializer
def associate_system_users_with_assets(system_users, assets, asset_groups): def push_system_user(assets, system_user):
print('Push system user %s' % system_user.name)
for asset in assets: for asset in assets:
asset.system_users.add(*tuple(system_users)) print('\tAsset: %s' % asset.ip)
for asset_group in asset_groups:
asset_group.system_users.add(*tuple(system_users))
...@@ -4,6 +4,7 @@ import functools ...@@ -4,6 +4,7 @@ import functools
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django.db.models.signals import m2m_changed
from users.models import User, UserGroup from users.models import User, UserGroup
from assets.models import Asset, AssetGroup, SystemUser from assets.models import Asset, AssetGroup, SystemUser
...@@ -16,18 +17,26 @@ class AssetPermission(models.Model): ...@@ -16,18 +17,26 @@ class AssetPermission(models.Model):
# ('U', 'user'), # ('U', 'user'),
# ('G', 'user group'), # ('G', 'user group'),
# ) # )
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) name = models.CharField(
users = models.ManyToManyField(User, related_name='asset_permissions', blank=True) max_length=128, unique=True, verbose_name=_('Name'))
user_groups = models.ManyToManyField(UserGroup, related_name='asset_permissions', blank=True) users = models.ManyToManyField(
assets = models.ManyToManyField(Asset, related_name='granted_by_permissions', blank=True) User, related_name='asset_permissions', blank=True)
asset_groups = models.ManyToManyField(AssetGroup, related_name='granted_by_permissions', blank=True) user_groups = models.ManyToManyField(
system_users = models.ManyToManyField(SystemUser, related_name='granted_by_permissions') UserGroup, related_name='asset_permissions', blank=True)
# private_for = models.CharField(choices=PRIVATE_FOR_CHOICE, max_length=1, default='N', blank=True, assets = models.ManyToManyField(
# verbose_name=_('Private for')) Asset, related_name='granted_by_permissions', blank=True)
is_active = models.BooleanField(default=True, verbose_name=_('Active')) asset_groups = models.ManyToManyField(
date_expired = models.DateTimeField(default=date_expired_default, verbose_name=_('Date expired')) AssetGroup, related_name='granted_by_permissions', blank=True)
created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by')) system_users = models.ManyToManyField(
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created')) SystemUser, related_name='granted_by_permissions')
is_active = models.BooleanField(
default=True, verbose_name=_('Active'))
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'))
date_created = models.DateTimeField(
auto_now_add=True, verbose_name=_('Date created'))
comment = models.TextField(verbose_name=_('Comment'), blank=True) comment = models.TextField(verbose_name=_('Comment'), blank=True)
def __unicode__(self): def __unicode__(self):
...@@ -68,3 +77,15 @@ class AssetPermission(models.Model): ...@@ -68,3 +77,15 @@ class AssetPermission(models.Model):
class Meta: class Meta:
db_table = 'asset_permission' db_table = 'asset_permission'
# def change_permission(sender, **kwargs):
# print('Sender: %s' % sender)
# for k, v in kwargs.items():
# print('%s: %s' % (k, v))
# print()
#
# m2m_changed.connect(change_permission, sender=AssetPermission.assets.through)
...@@ -169,16 +169,16 @@ ...@@ -169,16 +169,16 @@
</tr> </tr>
<tr> <tr>
<td colspan="2" class="no-borders"> <td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-small" id="btn_add_user_group">{% trans 'Join' %}</button> <button type="button" class="btn btn-info btn-small" id="btn_add_system_user">{% trans 'Join' %}</button>
</td> </td>
</tr> </tr>
</form> </form>
{% for system_user in system_users %} {% for system_user in system_users %}
<tr> <tr>
<td ><b class="bdg_user_group" data-gid={{ system_user.id }}>{{ system_user.name }}</b></td> <td ><b class="bdg-system-user" data-uid={{ system_user.id }}>{{ system_user.name }}</b></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 class="btn btn-danger btn-xs btn-del" data-uid="{{ system_user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
...@@ -196,8 +196,47 @@ ...@@ -196,8 +196,47 @@
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
jumpserver.system_users_selected = {};
function addSystemUser(system_users) {
var the_url = "{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}";
var body = {
system_users: Object.assign([], system_users)
};
var success = function(data) {
window.location.reload();
};
APIUpdateAttr({
url: the_url,
body: JSON.stringify(body),
success: success
});
}
function removeSystemUser(system_users, tr) {
var the_url = "{% url 'api-perms:remove-system-user-asset-permission' pk=asset_permission.id %}";
var body = {
system_users: system_users
};
var success = function (data) {
tr.remove()
};
APIUpdateAttr({
url: the_url,
body: JSON.stringify(body),
method: 'PUT',
success: success
})
}
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2(); $('.select2').select2()
.on('select2:select', function(evt) {
var data = evt.params.data;
jumpserver.system_users_selected[data.id] = data.text;
})
.on('select2:unselect', function(evt) {
var data = evt.params.data;
delete jumpserver.system_users_selected[data.id]
})
}).on('click', '.btn-delete-perm', function () { }).on('click', '.btn-delete-perm', function () {
var $this = $(this); var $this = $(this);
var name = "{{ asset_permission.name }}"; var name = "{{ asset_permission.name }}";
...@@ -205,6 +244,28 @@ ...@@ -205,6 +244,28 @@
var the_url = '{% url "api-perms:asset-permission-detail" pk=99991937 %}'.replace('99991937', uid); var the_url = '{% url "api-perms:asset-permission-detail" pk=99991937 %}'.replace('99991937', uid);
var redirect_url = "{% url 'perms:asset-permission-list' %}"; var redirect_url = "{% url 'perms:asset-permission-list' %}";
objectDelete($this, name, the_url, redirect_url); objectDelete($this, name, the_url, redirect_url);
}).on('click', '#btn_add_system_user', function () {
if (Object.keys(jumpserver.system_users_selected).length === 0) {
return false;
}
var system_users = $('.bdg-system-user').map(function() {
return $(this).data('uid');
}).get();
$.map(jumpserver.system_users_selected, function(value, index) {
system_users.push(parseInt(index));
$('#opt_' + index).remove();
});
addSystemUser(system_users)
}).on('click', '.btn-del', function () {
var $this = $(this);
var $uid = $this.data('uid');
var $tr = $this.closest('tr');
var $badge = $tr.find('.bdg-system-user');
var $system_user = $badge.html() || $badge.text();
$('#groups_selected').append(
'<option value="' + $uid + '" id="opt_' + $uid + '">' + $system_user + '</option>'
);
removeSystemUser($uid, $tr)
}) })
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -108,7 +108,7 @@ ...@@ -108,7 +108,7 @@
<form> <form>
<tr class="no-borders-tr"> <tr class="no-borders-tr">
<td colspan="2"> <td colspan="2">
<select data-placeholder="{% trans 'Select user' %}" class="select2" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Select user' %}" class="select2 user" style="width: 100%" multiple="" tabindex="4">
{% for user in users_remain %} {% for user in users_remain %}
<option value="{{ user.id }}">{{ user.name }}: {{ user.username }}</option> <option value="{{ user.id }}">{{ user.name }}: {{ user.username }}</option>
{% endfor %} {% endfor %}
...@@ -117,7 +117,7 @@ ...@@ -117,7 +117,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 btn-add-user">{% trans 'Add' %}</button>
</td> </td>
</tr> </tr>
</form> </form>
...@@ -136,7 +136,7 @@ ...@@ -136,7 +136,7 @@
<form> <form>
<tr> <tr>
<td colspan="2" class="no-borders"> <td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Select user groups' %}" class="select2" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Select user groups' %}" class="select2 user-group" style="width: 100%" multiple="" tabindex="4">
{% for user_group in user_groups_remain %} {% for user_group in user_groups_remain %}
<option value="{{ user_group.id }}" id="opt_{{ user_group.id }}">{{ user_group.name }}</option> <option value="{{ user_group.id }}" id="opt_{{ user_group.id }}">{{ user_group.name }}</option>
{% endfor %} {% endfor %}
...@@ -145,7 +145,7 @@ ...@@ -145,7 +145,7 @@
</tr> </tr>
<tr> <tr>
<td colspan="2" class="no-borders"> <td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-small" id="btn_add_user_group">{% trans 'Join' %}</button> <button type="button" class="btn btn-info btn-small" id="btn_add_user_group">{% trans 'Add' %}</button>
</td> </td>
</tr> </tr>
</form> </form>
...@@ -172,25 +172,29 @@ ...@@ -172,25 +172,29 @@
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
{# function switch_user_status(obj) {#} jumpserver.users_selected = {};
{# var status = $(obj).prop('checked');#} jumpserver.user_groups_selected = {};
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2(); $('.select2.user').select2()
}); .on('select2:select', function(evt) {
var data = evt.params.data;
jumpserver.users_selected[data.id] = data.text;
})
.on('select2:unselect', function(evt) {
var data = evt.params.data;
delete jumpserver.users_selected[data.id]
});
$('.select2.user-group').select2()
.on('select2:select', function(evt) {
var data = evt.params.data;
jumpserver.user_groups_selected[data.id] = data.text;
})
.on('select2:unselect', function(evt) {
var data = evt.params.data;
delete jumpserver.user_groups_selected[data.id]
})
}).on('click', '.btn-add-user', function () {
console.log(jumpserver.users_selected)
})
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
from django.test import TestCase from django.test import TestCase
# Create your tests here. from django.contrib.sessions.backends import file, db, cache
from django.contrib.auth.views import login
\ No newline at end of file
...@@ -50,7 +50,12 @@ urlpatterns = [ ...@@ -50,7 +50,12 @@ urlpatterns = [
# 验证用户是否有某个资产和系统用户的权限 # 验证用户是否有某个资产和系统用户的权限
url(r'v1/asset-permission/user/validate/$', url(r'v1/asset-permission/user/validate/$',
api.ValidateUserAssetPermissionView.as_view(), api.ValidateUserAssetPermissionView.as_view(),
name='validate-user-asset-permission') name='validate-user-asset-permission'),
# 删除asset permission中的某个系统用户
url(r'^v1/asset-permissions/(?P<pk>[0-9]+)/system-user/remove/$',
api.RemoveSystemUserAssetPermission.as_view(),
name='remove-system-user-asset-permission'),
] ]
urlpatterns += router.urls urlpatterns += router.urls
......
# coding: utf-8
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from common.utils import setattr_bulk from common.utils import setattr_bulk
from .hands import User, UserGroup, Asset, AssetGroup, SystemUser from .hands import User, UserGroup, Asset, AssetGroup, SystemUser, \
push_system_user
def get_user_group_granted_asset_groups(user_group): def get_user_group_granted_asset_groups(user_group):
"""Return asset groups granted of the user group """Return asset groups granted of the user group
:param user_group: Instance of :class: ``UserGroup`` :param user_group: Instance of :class: ``UserGroup``
:return: {asset_group1: {system_user1, }, asset_group2: {system_user1, system_user2}} :return: {asset_group1: {system_user1, },
asset_group2: {system_user1, system_user2}}
""" """
asset_groups = {} asset_groups = {}
asset_permissions = user_group.asset_permissions.all() asset_permissions = user_group.asset_permissions.all()
...@@ -50,7 +54,8 @@ def get_user_granted_asset_groups_direct(user): ...@@ -50,7 +54,8 @@ def get_user_granted_asset_groups_direct(user):
"""Return asset groups granted of the user direct nor inherit from user group """Return asset groups granted of the user direct nor inherit from user group
:param user: Instance of :class: ``User`` :param user: Instance of :class: ``User``
:return: {asset_group: {system_user1, }, asset_group2: {system_user1, system_user2]} :return: {asset_group: {system_user1, },
asset_group2: {system_user1, system_user2]}
""" """
asset_groups = {} asset_groups = {}
asset_permissions_direct = user.asset_permissions.all() asset_permissions_direct = user.asset_permissions.all()
...@@ -72,7 +77,8 @@ def get_user_granted_asset_groups_inherit_from_user_groups(user): ...@@ -72,7 +77,8 @@ def get_user_granted_asset_groups_inherit_from_user_groups(user):
"""Return asset groups granted of the user and inherit from user group """Return asset groups granted of the user and inherit from user group
:param user: Instance of :class: ``User`` :param user: Instance of :class: ``User``
:return: {asset_group: {system_user1, }, asset_group2: {system_user1, system_user2]} :return: {asset_group: {system_user1, },
asset_group2: {system_user1, system_user2]}
""" """
asset_groups = {} asset_groups = {}
user_groups = user.groups.all() user_groups = user.groups.all()
...@@ -103,7 +109,8 @@ def get_user_granted_asset_groups(user): ...@@ -103,7 +109,8 @@ def get_user_granted_asset_groups(user):
:return: {asset1: {system_user1, system_user2}, asset2: {...}} :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_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_direct = get_user_granted_asset_groups_direct(user)
asset_groups = asset_groups_inherit_from_user_groups asset_groups = asset_groups_inherit_from_user_groups
...@@ -211,3 +218,27 @@ def get_user_groups_granted_in_asset_group(asset): ...@@ -211,3 +218,27 @@ def get_user_groups_granted_in_asset_group(asset):
def get_users_granted_in_asset_group(asset): def get_users_granted_in_asset_group(asset):
pass pass
def associate_system_users_and_assets(system_users, assets, asset_groups):
"""关联系统用户和资产, 目的是保存它们的关系, 然后新加入的资产或系统
用户时,推送系统用户到资产
Todo: 这里需要最终Api定下来更改一下, 现在策略是以系统用户为核心推送, 一个系统用户
推送一次
"""
assets_all = set(assets)
for asset_group in asset_groups:
assets_all |= set(asset_group.assets.all())
for system_user in system_users:
assets_need_push = []
if system_user.auto_push:
assets_need_push.extend(
[asset for asset in assets_all
if asset not in system_user.assets.all()
]
)
system_user.assets.add(*(tuple(assets_all)))
push_system_user(assets_need_push, system_user)
...@@ -6,16 +6,18 @@ import functools ...@@ -6,16 +6,18 @@ import functools
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.conf import settings from django.conf import settings
from django.db.models import Q from django.db.models import Q
from django.views.generic import TemplateView, ListView from django.views.generic import ListView, CreateView, UpdateView
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView from django.views.generic.edit import DeleteView, FormView
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.detail import DetailView, SingleObjectMixin from django.views.generic.detail import DetailView, SingleObjectMixin
from common.utils import search_object_attr from common.utils import search_object_attr
from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, Asset, AssetGroup from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, \
Asset, AssetGroup
from .models import AssetPermission from .models import AssetPermission
from .forms import AssetPermissionForm from .forms import AssetPermissionForm
from .utils import associate_system_users_and_assets
class AssetPermissionListView(AdminUserRequiredMixin, ListView): class AssetPermissionListView(AdminUserRequiredMixin, ListView):
...@@ -79,6 +81,16 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, ...@@ -79,6 +81,16 @@ class AssetPermissionCreateView(AdminUserRequiredMixin,
self.object.name,)) self.object.name,))
return success_message return success_message
def form_valid(self, form):
assets = form.cleaned_data['assets']
asset_groups = form.cleaned_data['asset_groups']
system_users = form.cleaned_data['system_users']
associate_system_users_and_assets(system_users, assets, asset_groups)
response = super(AssetPermissionCreateView, self).form_valid(form)
self.object.created_by = self.request.user.name
self.object.save()
return response
class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView): class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
model = AssetPermission model = AssetPermission
...@@ -100,6 +112,13 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView): ...@@ -100,6 +112,13 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
kwargs={'pk': self.object.pk}) kwargs={'pk': self.object.pk})
return success_url return success_url
def form_valid(self, form):
assets = form.cleaned_data['assets']
asset_groups = form.cleaned_data['asset_groups']
system_users = form.cleaned_data['system_users']
associate_system_users_and_assets(system_users, assets, asset_groups)
return super(AssetPermissionUpdateView, self).form_valid(form)
class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView): class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
template_name = 'perms/asset_permission_detail.html' template_name = 'perms/asset_permission_detail.html'
......
...@@ -187,28 +187,28 @@ function activeNav() { ...@@ -187,28 +187,28 @@ function activeNav() {
} }
function APIUpdateAttr(props) { function APIUpdateAttr(props) {
// props = {url: .., body: , success: , error: , method: ,} // props = {url: .., body: , success: , error: , method: ,}
props = props || {}; props = props || {};
var success_message = props.success_message || 'Update Successfully!'; var success_message = props.success_message || 'Update Successfully!';
var fail_message = props.fail_message || 'Error occurred while updating.'; var fail_message = props.fail_message || 'Error occurred while updating.';
$.ajax({ $.ajax({
url: props.url, url: props.url,
type: props.method || "PATCH", type: props.method || "PATCH",
data: props.body, data: props.body,
contentType: props.content_type || "application/json; charset=utf-8", contentType: props.content_type || "application/json; charset=utf-8",
dataType: props.data_type || "json" dataType: props.data_type || "json"
}).done(function(data, textStatue, jqXHR) { }).done(function(data, textStatue, jqXHR) {
toastr.success(success_message); toastr.success(success_message);
if (typeof props.success === 'function') { if (typeof props.success === 'function') {
return props.success(data); return props.success(data);
} }
}).fail(function(jqXHR, textStatue, errorThrown) { }).fail(function(jqXHR, textStatue, errorThrown) {
toastr.error(fail_message); toastr.error(fail_message);
if (typeof props.error === 'function') { if (typeof props.error === 'function') {
return props.error(errorThrown); return props.error(errorThrown);
} }
}); });
// return true; // return true;
} }
......
...@@ -107,7 +107,6 @@ class AccessKeyAuthentication(authentication.BaseAuthentication): ...@@ -107,7 +107,6 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
if not access_key.user.is_active: if not access_key.user.is_active:
raise exceptions.AuthenticationFailed(_('User disabled.')) raise exceptions.AuthenticationFailed(_('User disabled.'))
return access_key.user, None return access_key.user, None
......
...@@ -31,7 +31,9 @@ class UserCreateUpdateForm(forms.ModelForm): ...@@ -31,7 +31,9 @@ class UserCreateUpdateForm(forms.ModelForm):
'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')}),
} }
...@@ -41,29 +43,11 @@ class UserBulkImportForm(forms.ModelForm): ...@@ -41,29 +43,11 @@ class UserBulkImportForm(forms.ModelForm):
fields = ['username', 'email', 'enable_otp', 'role'] fields = ['username', 'email', 'enable_otp', 'role']
# class UserUpdateForm(forms.ModelForm):
#
# class Meta:
# model = User
# fields = [
# 'name', 'email', 'groups', 'wechat',
# 'phone', 'enable_otp', 'role', 'date_expired', 'comment',
# ]
# help_texts = {
# 'username': '* required',
# 'email': '* required',
# 'groups': '* required'
# }
# widgets = {
# 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}),
# }
class UserGroupForm(forms.ModelForm): 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'
...@@ -87,7 +71,8 @@ class UserKeyForm(forms.Form): ...@@ -87,7 +71,8 @@ class UserKeyForm(forms.Form):
def clean_public_key(self): def clean_public_key(self):
public_key = self.cleaned_data['public_key'] public_key = self.cleaned_data['public_key']
if self.user.public_key and public_key == self.user.public_key: if self.user.public_key and public_key == self.user.public_key:
raise forms.ValidationError(_('Public key should not be the same as your old one.')) raise forms.ValidationError(_('Public key should not be the '
'same as your old one.'))
if not validate_ssh_public_key(public_key): if not validate_ssh_public_key(public_key):
raise forms.ValidationError(_('Not a valid ssh public key')) raise forms.ValidationError(_('Not a valid ssh public key'))
...@@ -97,7 +82,8 @@ class UserKeyForm(forms.Form): ...@@ -97,7 +82,8 @@ class UserKeyForm(forms.Form):
class UserPrivateAssetPermissionForm(forms.ModelForm): class UserPrivateAssetPermissionForm(forms.ModelForm):
def save(self, commit=True): def save(self, commit=True):
self.instance = super(UserPrivateAssetPermissionForm, self).save(commit=commit) self.instance = super(UserPrivateAssetPermissionForm, self)\
.save(commit=commit)
self.instance.users = [self.user] self.instance.users = [self.user]
self.instance.save() self.instance.save()
return self.instance return self.instance
...@@ -108,19 +94,23 @@ class UserPrivateAssetPermissionForm(forms.ModelForm): ...@@ -108,19 +94,23 @@ class UserPrivateAssetPermissionForm(forms.ModelForm):
'assets', 'asset_groups', 'system_users', 'name', 'assets', 'asset_groups', 'system_users', 'name',
] ]
widgets = { widgets = {
'assets': forms.SelectMultiple(attrs={'class': 'select2', 'assets': forms.SelectMultiple(
'data-placeholder': _('Select assets')}), attrs={'class': 'select2',
'asset_groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Select assets')}),
'data-placeholder': _('Select asset groups')}), 'asset_groups': forms.SelectMultiple(
'system_users': forms.SelectMultiple(attrs={'class': 'select2', attrs={'class': 'select2',
'data-placeholder': _('Select system users')}), 'data-placeholder': _('Select asset groups')}),
'system_users': forms.SelectMultiple(
attrs={'class': 'select2',
'data-placeholder': _('Select system users')}),
} }
class UserGroupPrivateAssetPermissionForm(forms.ModelForm): class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
def save(self, commit=True): def save(self, commit=True):
self.instance = super(UserGroupPrivateAssetPermissionForm, self).save(commit=commit) self.instance = super(UserGroupPrivateAssetPermissionForm, self)\
.save(commit=commit)
self.instance.user_groups = [self.user_group] self.instance.user_groups = [self.user_group]
self.instance.save() self.instance.save()
return self.instance return self.instance
...@@ -131,12 +121,15 @@ class UserGroupPrivateAssetPermissionForm(forms.ModelForm): ...@@ -131,12 +121,15 @@ class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
'assets', 'asset_groups', 'system_users', 'name', 'assets', 'asset_groups', 'system_users', 'name',
] ]
widgets = { widgets = {
'assets': forms.SelectMultiple(attrs={'class': 'select2', 'assets': forms.SelectMultiple(
'data-placeholder': _('Select assets')}), attrs={'class': 'select2',
'asset_groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Select assets')}),
'data-placeholder': _('Select asset groups')}), 'asset_groups': forms.SelectMultiple(
'system_users': forms.SelectMultiple(attrs={'class': 'select2', attrs={'class': 'select2',
'data-placeholder': _('Select system users')}), 'data-placeholder': _('Select asset groups')}),
'system_users': forms.SelectMultiple(
attrs={'class': 'select2',
'data-placeholder': _('Select system users')}),
} }
......
...@@ -44,6 +44,7 @@ class UserGroupCreateView(AdminUserRequiredMixin, CreateView): ...@@ -44,6 +44,7 @@ class UserGroupCreateView(AdminUserRequiredMixin, CreateView):
'users': users}) 'users': users})
return context return context
# 需要添加组下用户, 而user并不是group的多对多,所以需要手动建立关系
def form_valid(self, form): def form_valid(self, form):
user_group = form.save() user_group = form.save()
users_id_list = self.request.POST.getlist('users', []) users_id_list = self.request.POST.getlist('users', [])
......
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