Commit 08e17884 authored by ibuler's avatar ibuler

[Feature] 打算拆分下载和上传为独立模块,时间有限暂时放弃

parent 160b01ec
......@@ -9,6 +9,7 @@ from common.utils import validate_ssh_private_key, ssh_pubkey_gen, ssh_key_gen,
logger = get_logger(__file__)
from rest_framework import serializers
class AssetCreateForm(forms.ModelForm):
......@@ -240,7 +241,7 @@ class SystemUserForm(forms.ModelForm):
fields = [
'name', 'username', 'protocol', 'auto_generate_key',
'password', 'private_key_file', 'auto_push', 'sudo',
'comment', 'shell', 'cluster'
'comment', 'shell', 'cluster', 'priority',
]
widgets = {
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
......@@ -254,6 +255,7 @@ class SystemUserForm(forms.ModelForm):
'username': '* required',
'cluster': 'If auto push checked, system user will be create at cluster assets',
'auto_push': 'Auto push system user to asset',
'priority': 'High level will be using login asset as default, if user was granted more than 2 system user',
}
......@@ -261,7 +263,7 @@ class SystemUserUpdateForm(forms.ModelForm):
class Meta:
model = SystemUser
fields = [
'name', 'username', 'protocol',
'name', 'username', 'protocol', 'priority',
'sudo', 'comment', 'shell', 'cluster'
]
widgets = {
......@@ -275,6 +277,7 @@ class SystemUserUpdateForm(forms.ModelForm):
'name': '* required',
'username': '* required',
'cluster': 'If auto push checked, then push system user to that cluster assets',
'priority': 'High level will be using login asset as default, if user was granted more than 2 system user',
}
......
......@@ -7,6 +7,7 @@ import logging
import uuid
from hashlib import md5
import sshpubkeys
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
......@@ -27,7 +28,8 @@ class AssetUser(models.Model):
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
_public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now_add=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
created_by = models.CharField(max_length=32, null=True, verbose_name=_('Created by'))
@property
......@@ -45,16 +47,21 @@ class AssetUser(models.Model):
@property
def private_key(self):
if self._private_key:
key_str = signer.unsign(self._private_key)
return ssh_key_string_to_obj(key_str, password=self.password)
else:
return None
return signer.unsign(self._private_key)
@private_key.setter
def private_key(self, private_key_raw):
raise AttributeError("Using set_auth do that")
# self._private_key = signer.sign(private_key_raw)
@property
def private_key_obj(self):
if self._private_key:
key_str = signer.unsign(self._private_key)
return ssh_key_string_to_obj(key_str, password=self.password)
else:
return None
@property
def private_key_file(self):
if not self.private_key:
......@@ -74,6 +81,15 @@ class AssetUser(models.Model):
def public_key(self):
return signer.unsign(self._public_key)
@property
def public_key_obj(self):
if self.public_key:
try:
return sshpubkeys.SSHKey(self.public_key)
except TabError:
pass
return None
def set_auth(self, password=None, private_key=None, public_key=None):
update_fields = []
if password:
......@@ -170,6 +186,7 @@ class SystemUser(AssetUser):
('K', 'Public key'),
)
cluster = models.ManyToManyField('assets.Cluster', verbose_name=_("Cluster"))
priority = models.IntegerField(default=10, verbose_name=_("Priority")) # Todo: If user granted more priority user, default will be login as the hign
protocol = models.CharField(max_length=16, choices=PROTOCOL_CHOICES, default='ssh', verbose_name=_('Protocol'))
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
sudo = models.TextField(default='/sbin/ifconfig', verbose_name=_('Sudo'))
......@@ -205,6 +222,7 @@ class SystemUser(AssetUser):
'name': self.name,
'username': self.username,
'protocol': self.protocol,
'priority': self.priority,
'auto_push': self.auto_push,
}
......
......@@ -115,7 +115,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
class AssetSystemUserSerializer(serializers.ModelSerializer):
class Meta:
model = SystemUser
fields = ('id', 'name', 'username', 'protocol', 'comment')
fields = ('id', 'name', 'username', 'priority', 'protocol', 'comment',)
class SystemUserUpdateAssetsSerializer(serializers.ModelSerializer):
......
......@@ -37,6 +37,7 @@
<h3>{% trans 'Basic' %}</h3>
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.username layout="horizontal" %}
{% bootstrap_field form.priority layout="horizontal" %}
{% bootstrap_field form.protocol layout="horizontal" %}
{% bootstrap_field form.cluster layout="horizontal" %}
......@@ -49,7 +50,6 @@
{{ form.auto_generate_key}}
</div>
</div>
</div>
<div class="auth-fields">
{% bootstrap_field form.private_key_file layout="horizontal" %}
......
......@@ -64,7 +64,9 @@
{% block custom_foot_js %}
<script>
$(document).ready(function () {
$('.select2').select2();
$('.select2').select2({
allowClear: true
});
$("#tags").select2({
tags: true,
maximumSelectionLength: 8 //最多能够选择的个数
......
......@@ -123,7 +123,7 @@ class AdminUserAssetsView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
class AdminUserDeleteView(AdminUserRequiredMixin, DeleteView):
model = AdminUser
template_name = 'assets/delete_confirm.html'
template_name = 'delete_confirm.html'
success_url = reverse_lazy('assets:admin-user-list')
......@@ -9,12 +9,13 @@ import chardet
from io import StringIO
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, FieldDoesNotExist
from django.utils.translation import ugettext_lazy as _
from django.views.generic import TemplateView, ListView, View
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from django.urls import reverse_lazy
from django.views.generic.detail import DetailView, SingleObjectMixin
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect, Http404
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decorator
from django.core.cache import cache
......@@ -22,8 +23,10 @@ from django.utils import timezone
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import get_object_or_404, redirect, reverse
from common.mixins import JSONResponseMixin
from common.utils import get_object_or_none
from common.imexp import ModelExportView
from .. import forms
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
from ..hands import AdminUserRequiredMixin
......@@ -169,7 +172,7 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateView):
class AssetDeleteView(AdminUserRequiredMixin, DeleteView):
model = Asset
template_name = 'assets/delete_confirm.html'
template_name = 'delete_confirm.html'
success_url = reverse_lazy('assets:asset-list')
......@@ -193,46 +196,11 @@ class AssetDetailView(DetailView):
@method_decorator(csrf_exempt, name='dispatch')
class AssetExportView(View):
def get(self, request):
spm = request.GET.get('spm', '')
assets_id_default = [Asset.objects.first().id] if Asset.objects.first() else [1]
assets_id = cache.get(spm, assets_id_default)
fields = [
field for field in Asset._meta.fields
if field.name not in [
'date_created'
]
]
filename = 'assets-{}.csv'.format(
timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S'))
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
response.write(codecs.BOM_UTF8)
assets = Asset.objects.filter(id__in=assets_id)
writer = csv.writer(response, dialect='excel',
quoting=csv.QUOTE_MINIMAL)
header = [field.verbose_name for field in fields]
header.append(_('Asset groups'))
writer.writerow(header)
for asset in assets:
groups = ','.join([group.name for group in asset.groups.all()])
data = [getattr(asset, field.name) for field in fields]
data.append(groups)
writer.writerow(data)
return response
def post(self, request, *args, **kwargs):
try:
assets_id = json.loads(request.body).get('assets_id', [])
except ValueError:
return HttpResponse('Json object not valid', status=400)
spm = uuid.uuid4().hex
cache.set(spm, assets_id, 300)
url = reverse_lazy('assets:asset-export') + '?spm=%s' % spm
return JsonResponse({'redirect': url})
class AssetExportView(ModelExportView):
filename_prefix = 'jumpserver'
redirect_url = reverse_lazy('assets:asset-export')
model = Asset
fields = ('hostname', 'ip')
class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
......
......@@ -97,5 +97,5 @@ class ClusterAssetsView(AdminUserRequiredMixin, DetailView):
class ClusterDeleteView(AdminUserRequiredMixin, DeleteView):
model = Cluster
template_name = 'assets/delete_confirm.html'
template_name = 'delete_confirm.html'
success_url = reverse_lazy('assets:cluster-list')
......@@ -101,6 +101,6 @@ class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView):
class AssetGroupDeleteView(AdminUserRequiredMixin, DeleteView):
template_name = 'assets/delete_confirm.html'
template_name = 'delete_confirm.html'
model = AssetGroup
success_url = reverse_lazy('assets:asset-group-list')
......@@ -99,7 +99,7 @@ class SystemUserDetailView(AdminUserRequiredMixin, DetailView):
class SystemUserDeleteView(AdminUserRequiredMixin, DeleteView):
model = SystemUser
template_name = 'assets/delete_confirm.html'
template_name = 'delete_confirm.html'
success_url = reverse_lazy('assets:system-user-list')
......
This diff is collapsed.
......@@ -1067,13 +1067,13 @@ msgstr "配置"
msgid "Location"
msgstr "位置"
#: assets/templates/assets/delete_confirm.html:6
#: perms/templates/perms/delete_confirm.html:6
#: assets/templates/delete_confirm.html:6
#: perms/templates/delete_confirm.html:6
#: users/templates/users/user_delete_confirm.html:6
msgid "Confirm delete"
msgstr "确认删除"
#: assets/templates/assets/delete_confirm.html:11
#: assets/templates/delete_confirm.html:11
msgid "Are you sure delete"
msgstr "您确定删除吗?"
......
......@@ -19,7 +19,7 @@ from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, \
Asset, AssetGroup
from .models import AssetPermission
from .forms import AssetPermissionForm
from .utils import associate_system_users_and_assets
# from .utils import associate_system_users_and_assets
class AssetPermissionListView(AdminUserRequiredMixin, ListView):
......@@ -87,15 +87,15 @@ class AssetPermissionCreateView(AdminUserRequiredMixin,
'successfully.'.format(url=url, name=self.object.name))
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
# Todo: When create push system user
# def form_valid(self, form):
# assets = form.cleaned_data['assets']
# asset_groups = form.cleaned_data['asset_groups']
# system_users = form.cleaned_data['system_users']
# response = super(AssetPermissionCreateView, self).form_valid(form)
# self.object.created_by = self.request.user.name
# self.object.save()
# return response
class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
......@@ -150,7 +150,7 @@ class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView):
model = AssetPermission
template_name = 'perms/delete_confirm.html'
template_name = 'delete_confirm.html'
success_url = reverse_lazy('perms:asset-permission-list')
......
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% trans 'Confirm delete' %}</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>{% trans 'Are you sure delete' %} <b>{{ object.name }} </b> ?</p>
<input type="submit" value="Confirm" />
</form>
</body>
</html>
\ No newline at end of file
......@@ -2,7 +2,7 @@
{% load i18n %}
{% load static %}
{% load common_tags %}
{% block content_left_head %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
<style>
......@@ -12,6 +12,10 @@
</style>
{% endblock %}
{% block content_left_head %}
123
{% endblock %}
{% block table_search %}
<form id="search_form" method="get" action="" class="pull-right form-inline">
<div class="form-group" id="date">
......@@ -26,7 +30,7 @@
<select class="select2 form-control" name="username">
<option value="">{% trans 'User' %}</option>
{% for u in user_list %}
<option value="{{ u }}" {% if user == u %} selected {% endif %}>{{ u }}</option>
<option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
{% endfor %}
</select>
</div>
......
......@@ -2,7 +2,7 @@
{% load i18n %}
{% load static %}
{% load terminal_tags %}
{% block content_left_head %}
{% block custom_head_css_js %}
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
<style>
#search_btn {
......@@ -11,6 +11,9 @@
</style>
{% endblock %}
{% block content_left_head %}
{% endblock %}
{% block table_search %}
<form id="search_form" method="get" action="" class="pull-right form-inline">
......@@ -26,7 +29,7 @@
<select class="select2 form-control" name="user">
<option value="">{% trans 'User' %}</option>
{% for u in user_list %}
<option value="{{ u }}" {% if u == user %} selected {% endif %}>{{ u }}</option>
<option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
{% endfor %}
</select>
</div>
......@@ -106,10 +109,17 @@
function success() {
window.setTimeout(function () {
window.location.reload()
}, 300)
}, 1000)
}
var success_message = '{% trans "Terminate task send, waiting ..." %}';
var the_url = "{% url 'api-terminal:tasks-list' %}";
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
APIUpdateAttr({
url: the_url,
method: 'POST',
body: JSON.stringify(data),
success: success,
success_message: success_message
});
}
$(document).ready(function() {
$('table').DataTable({
......@@ -118,7 +128,9 @@
"bInfo" : false,
"order": []
});
$('.select2').select2();
$('.select2').select2({
dropdownAutoWidth: true
});
$('#date .input-daterange').datepicker({
dateFormat: 'mm/dd/yy',
keyboardNavigation: false,
......@@ -135,12 +147,6 @@
terminal: terminal_id
};
terminateSession(data)
}).on('click', '#btn_bulk_update', function () {
var data = [];
$('.cbx-term:checked').each(function () {
data.push({proxy_log_id: $(this).attr('value')})
});
terminateSession(data)
})
</script>
{% endblock %}
......
......@@ -2,7 +2,6 @@
{% load i18n static %}
{% block custom_head_css_js %}
{{ block.super }}
<style>
div.dataTables_wrapper div.dataTables_filter,
.dataTables_length {
......@@ -15,9 +14,10 @@
#modal .modal-body { max-height: 200px; }
</style>
{% endblock %}
{% block table_search %}{% endblock %}
{% block table_container %}
{#<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create user" %} </a></div>#}
<table class="table table-striped table-bordered table-hover " id="terminal_list_table" >
<thead>
<tr>
......@@ -40,12 +40,11 @@
</tbody>
</table>
{% include 'terminal/terminal_modal_accept.html' %}
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/jquery.form.min.js' %}"></script>
<script>
$(document).ready(function(){
function initTable() {
var options = {
ele: $('#terminal_list_table'),
buttons: [],
......@@ -100,19 +99,20 @@ $(document).ready(function(){
op_html: $('#actions').html()
};
jumpserver.initDataTable(options);
}
$(document).ready(function(){
initTable();
$('#btn_terminal_accept').click(function () {
var $form = $('#form_terminal_accept');
function success(data, textStatus, jqXHR) {
if (data.success === true) {
window.location.reload()
} else {
$('#modal-error').html(data.msg).css('display', 'block');
}
}).on('click', '#btn-confirm',function () {
var $form = $('#form_terminal_accept');
function success(data, textStatus, jqXHR) {
if (data.success === true) {
window.location.reload()
} else {
$('#modal-error').html(data.msg).css('display', 'block');
}
$form.ajaxSubmit({success: success});
})
}
$form.ajaxSubmit({success: success});
}).on('click', '.btn-del', function(){
var $this = $(this);
var id = $this.data('id');
......@@ -124,8 +124,7 @@ $(document).ready(function(){
var $this = $(this);
var terminal_id = $this.data('id');
var the_url = "{% url 'api-terminal:terminal-detail' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', terminal_id);
var post_url = $('#form_terminal_accept').attr('action').replace('{{ DEFAULT_PK }}', terminal_id);
console.log(post_url);
var post_url = "{% url 'terminal:terminal-accept' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', terminal_id);
$.ajax({
url: the_url,
method: 'GET',
......
......@@ -5,7 +5,7 @@
{% block modal_title%}{% trans "Accept terminal registration" %}{% endblock %}
{% block modal_body %}
{% load bootstrap3 %}
<form action="{% url 'terminal:terminal-accept' pk="{{ DEFAULT_PK }}" %}" method="post" class="form-horizontal" id="form_terminal_accept" enctype="multipart/form-data">
<form action="" method="post" class="form-horizontal" id="form_terminal_accept" enctype="multipart/form-data">
{% csrf_token %}
<p class="alert alert-danger" id="modal-error" style="display: none"></p>
{% bootstrap_field form.name layout="horizontal" %}
......@@ -16,4 +16,4 @@
</form>
{% endblock %}
{% block modal_confirm_id %}btn_terminal_accept{% endblock %}
\ No newline at end of file
{% block modal_confirm_id %}btn-confirm{% endblock %}
\ No newline at end of file
......@@ -10,8 +10,8 @@ from .. import api
app_name = 'terminal'
router = routers.DefaultRouter()
router.register(r'v1/terminal/(?P<terminal>[0-9]+)?/?status', api.StatusViewSet, 'terminal-status')
router.register(r'v1/terminal/(?P<terminal>[0-9]+)?/?sessions', api.SessionViewSet, 'terminal-sessions')
router.register(r'v1/terminal/(?P<terminal>[a-zA-Z0-9\-]{36})?/?status', api.StatusViewSet, 'terminal-status')
router.register(r'v1/terminal/(?P<terminal>a-zA-Z0-9\-]{36})?/?sessions', api.SessionViewSet, 'terminal-sessions')
router.register(r'v1/tasks', api.TaskViewSet, 'tasks')
router.register(r'v1/terminal', api.TerminalViewSet, 'terminal')
router.register(r'v1/command', api.CommandViewSet, 'command')
......
......@@ -70,7 +70,7 @@ class CommandListView(ListView):
'command': self.command,
'date_from': self.date_from_s,
'date_to': self.date_to_s,
'user': self.user,
'username': self.user,
'asset': self.asset,
'system_user': self.system_user,
}
......
......@@ -78,7 +78,7 @@ class SessionListView(AdminUserRequiredMixin, ListView):
'system_user_list': utils.get_system_user_list_from_cache(),
'date_from': self.date_from_s,
'date_to': self.date_to_s,
'user': self.user,
'username': self.user,
'asset': self.asset,
'system_user': self.system_user,
}
......@@ -122,6 +122,7 @@ class SessionOfflineListView(SessionListView):
class SessionDetailView(SingleObjectMixin, ListView):
template_name = 'terminal/session_detail.html'
model = Session
object = None
def get_queryset(self):
self.object = self.get_object()
......
......@@ -62,14 +62,14 @@ class TerminalDetailView(LoginRequiredMixin, DetailView):
class TerminalDeleteView(AdminUserRequiredMixin, DeleteView):
model = Terminal
template_name = 'assets/delete_confirm.html'
template_name = 'delete_confirm.html'
success_url = reverse_lazy('terminal:terminal-list')
class TerminalAcceptView(AdminUserRequiredMixin, JSONResponseMixin, UpdateView):
model = Terminal
form_class = TerminalForm
template_name = 'Terminal/terminal_modal_test.html'
template_name = 'terminal/terminal_modal_accept.html'
def form_valid(self, form):
terminal = form.save()
......
......@@ -49,5 +49,4 @@ class LoginLog(models.Model):
datetime = models.DateTimeField(auto_now_add=True, verbose_name=_('Date login'))
class Meta:
db_table = 'login_log'
ordering = ['-datetime', 'username']
......@@ -38,9 +38,9 @@ class User(AbstractUser):
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone'))
enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP'))
secret_key_otp = models.CharField(max_length=16, blank=True)
# Todo: private_key may be not used
_private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('ssh private key'))
_public_key = models.CharField(max_length=5000, blank=True, verbose_name=_('ssh public key'))
# Todo: Auto generate key, let user download
_private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Private key'))
_public_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Public key'))
comment = models.TextField(max_length=200, blank=True, verbose_name=_('Comment'))
is_first_login = models.BooleanField(default=False)
date_expired = models.DateTimeField(default=date_expired_default, blank=True, null=True, verbose_name=_('Date expired'))
......
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