[Fixture] 添加用户连接终端

pull/417/head
ibuler 2017-03-31 11:25:25 +08:00
parent 3fa5ce5404
commit 61a481f427
17 changed files with 98 additions and 48 deletions

View File

@ -6,7 +6,7 @@ from django.core.cache import cache
from django.conf import settings from django.conf import settings
from django.utils import timezone from django.utils import timezone
import copy import copy
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView from rest_framework.generics import ListCreateAPIView
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.views import APIView, Response from rest_framework.views import APIView, Response
from rest_framework.permissions import AllowAny from rest_framework.permissions import AllowAny
@ -15,7 +15,8 @@ from rest_framework.decorators import api_view
from .models import Terminal, TerminalHeatbeat from .models import Terminal, TerminalHeatbeat
from .serializers import TerminalSerializer, TerminalHeatbeatSerializer from .serializers import TerminalSerializer, TerminalHeatbeatSerializer
from .hands import IsSuperUserOrAppUser, IsAppUser, User, ProxyLog from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \
IsSuperUserOrAppUserOrUserReadonly
from common.utils import get_object_or_none from common.utils import get_object_or_none
@ -55,7 +56,7 @@ class TerminalRegisterView(ListCreateAPIView):
class TerminalViewSet(viewsets.ModelViewSet): class TerminalViewSet(viewsets.ModelViewSet):
queryset = Terminal.objects.all() queryset = Terminal.objects.all()
serializer_class = TerminalSerializer serializer_class = TerminalSerializer
permission_classes = (IsSuperUserOrAppUser,) permission_classes = (IsSuperUserOrAppUserOrUserReadonly,)
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
return Response({'msg': 'Use register view except that'}, status=404) return Response({'msg': 'Use register view except that'}, status=404)
@ -102,5 +103,4 @@ class TerminateConnectionView(APIView):
tasks[terminal_id] = [{'name': 'kill_proxy', tasks[terminal_id] = [{'name': 'kill_proxy',
'proxy_log_id': proxy_log_id}] 'proxy_log_id': proxy_log_id}]
print(tasks)
return Response({'msg': 'get it'}) return Response({'msg': 'get it'})

View File

@ -2,5 +2,7 @@
# #
from users.models import User from users.models import User
from users.permissions import IsSuperUserOrAppUser, IsAppUser from users.permissions import IsSuperUserOrAppUser, IsAppUser, \
from audits.models import ProxyLog IsSuperUserOrAppUserOrUserReadonly
from audits.models import ProxyLog
from users.utils import AdminUserRequiredMixin

View File

@ -68,19 +68,20 @@ $(document).ready(function(){
} }
}}, }},
{targets: 7, createdCell: function (td, cellData, rowData) { {targets: 7, createdCell: function (td, cellData, rowData) {
console.log(rowData.name);
var update_btn = '<a href="{% url "applications:terminal-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>' var update_btn = '<a href="{% url "applications:terminal-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.replace('99991937', cellData); .replace('99991937', cellData);
var delete_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_delete" data-uid="99991937" data-name="99991938">{% trans "Delete" %}</a>' var delete_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-id="99991937" data-name="99991938">{% trans "Delete" %}</a>'
.replace('99991937', cellData) .replace('99991937', cellData)
.replace('99991938', rowData.name); .replace('99991938', rowData.name);
var accept_btn = '<a class="btn btn-xs btn-primary btn-accept" data-id="99991937">{% trans "Accept" %}</a> ' var accept_btn = '<a class="btn btn-xs btn-primary btn-accept" data-id="99991937">{% trans "Accept" %}</a> '
.replace('99991937', cellData); .replace('99991937', cellData);
var reject_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_delete" data-uid="99991937" data-name="99991938">{% trans "Reject" %}</a>' var reject_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-id="99991937" data-name="99991938">{% trans "Reject" %}</a>'
.replace('99991937', cellData) .replace('99991937', cellData)
.replace('99991938', rowData.name); .replace('99991938', rowData.name);
var connect_btn = '<a href="{% url "applications:terminal-connect" pk=99991937 %}"" class="btn btn-xs btn-warning btn-connect" >{% trans "Connect" %}</a> '
.replace('99991937', cellData);
if (rowData.is_accepted) { if (rowData.is_accepted) {
$(td).html(update_btn + delete_btn) $(td).html(connect_btn + update_btn + delete_btn)
} else { } else {
$(td).html(accept_btn + reject_btn) $(td).html(accept_btn + reject_btn)
} }
@ -105,11 +106,11 @@ $(document).ready(function(){
$form.ajaxSubmit({success: success}); $form.ajaxSubmit({success: success});
}) })
}).on('click', '.btn_delete', function(){ }).on('click', '.btn-del', function(){
var $this = $(this); var $this = $(this);
var uid = $this.data('uid'); var id = $this.data('id');
var name = $(this).data('name'); var name = $(this).data('name');
var the_url = '{% url "api-applications:terminal-detail" pk=99991937 %}'.replace('99991937', uid); var the_url = '{% url "api-applications:terminal-detail" pk=99991937 %}'.replace('99991937', id);
objectDelete($this, name, the_url) objectDelete($this, name, the_url)
}).on('click', '.btn-accept', function () { }).on('click', '.btn-accept', function () {
@ -133,6 +134,10 @@ $(document).ready(function(){
$('#modal_terminal_accept').modal({ $('#modal_terminal_accept').modal({
show: true show: true
}); });
}).on('click', '.btn-connect', function () {
var $this = $(this);
var id = $this.data('id');
console.log(id)
}) })
</script> </script>
{% endblock %} {% endblock %}

View File

@ -9,9 +9,11 @@ from .. import views
app_name = 'applications' app_name = 'applications'
urlpatterns = [ urlpatterns = [
url(r'^terminal$', views.TerminalListView.as_view(), name='terminal-list'), url(r'^terminal/$', views.TerminalListView.as_view(), name='terminal-list'),
url(r'^terminal/(?P<pk>\d+)/$', views.TerminalDetailView.as_view(), url(r'^terminal/(?P<pk>\d+)/$', views.TerminalDetailView.as_view(),
name='terminal-detail'), name='terminal-detail'),
url(r'^terminal/(?P<pk>\d+)/connect/$', views.TerminalConnectView.as_view(),
name='terminal-connect'),
url(r'^terminal/(?P<pk>\d+)/update$', views.TerminalUpdateView.as_view(), url(r'^terminal/(?P<pk>\d+)/update$', views.TerminalUpdateView.as_view(),
name='terminal-update'), name='terminal-update'),
url(r'^terminal/(?P<pk>\d+)/modal/accept$', views.TerminalModelAccept.as_view(), url(r'^terminal/(?P<pk>\d+)/modal/accept$', views.TerminalModelAccept.as_view(),

View File

@ -1,18 +1,19 @@
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
# #
from django.views.generic import ListView, UpdateView, DeleteView, DetailView from django.views.generic import ListView, UpdateView, DeleteView, \
from django.views.generic.edit import BaseUpdateView DetailView, TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.urls import reverse_lazy from django.urls import reverse_lazy, reverse
from .models import Terminal
from users.utils import AdminUserRequiredMixin
from common.mixins import JSONResponseMixin from common.mixins import JSONResponseMixin
from .models import Terminal
from .forms import TerminalForm from .forms import TerminalForm
from .hands import AdminUserRequiredMixin
class TerminalListView(ListView): class TerminalListView(LoginRequiredMixin, ListView):
model = Terminal model = Terminal
template_name = 'applications/terminal_list.html' template_name = 'applications/terminal_list.html'
form_class = TerminalForm form_class = TerminalForm
@ -27,11 +28,11 @@ class TerminalListView(ListView):
return context return context
class TerminalUpdateView(UpdateView): class TerminalUpdateView(AdminUserRequiredMixin, UpdateView):
model = Terminal model = Terminal
form_class = TerminalForm form_class = TerminalForm
template_name = 'applications/terminal_update.html' template_name = 'applications/terminal_update.html'
success_url = reverse_lazy('applications:applications-list') success_url = reverse_lazy('applications:terminal-list')
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(TerminalUpdateView, self).get_context_data(**kwargs) context = super(TerminalUpdateView, self).get_context_data(**kwargs)
@ -39,7 +40,7 @@ class TerminalUpdateView(UpdateView):
return context return context
class TerminalDetailView(DetailView): class TerminalDetailView(LoginRequiredMixin, DetailView):
model = Terminal model = Terminal
template_name = 'applications/terminal_detail.html' template_name = 'applications/terminal_detail.html'
context_object_name = 'terminal' context_object_name = 'terminal'
@ -53,7 +54,7 @@ class TerminalDetailView(DetailView):
return context return context
class TerminalDeleteView(DeleteView): class TerminalDeleteView(AdminUserRequiredMixin, DeleteView):
model = Terminal model = Terminal
template_name = 'assets/delete_confirm.html' template_name = 'assets/delete_confirm.html'
success_url = reverse_lazy('applications:applications-list') success_url = reverse_lazy('applications:applications-list')
@ -88,3 +89,26 @@ class TerminalModelAccept(AdminUserRequiredMixin, JSONResponseMixin, UpdateView)
return self.render_json_response(data) return self.render_json_response(data)
class TerminalConnectView(LoginRequiredMixin, DetailView):
template_name = 'flash_message_standalone.html'
model = Terminal
def get_context_data(self, **kwargs):
if self.object.type == 'Web':
context = {
'title': _('Redirect to web terminal'),
'messages': _('Redirect to web terminal: {}'.format(self.object.url)),
'auto_redirect': True,
'interval': 3,
'redirect_url': self.object.url
}
else:
context = {
'title': _('Connect ssh terminal'),
'messages': _('You should use your ssh client tools '
'connect terminal: {} <br /> <br />'
'{}'.format(self.object.name, self.object.url)),
}
kwargs.update(context)
return super(TerminalConnectView, self).get_context_data(**kwargs)

View File

@ -6,7 +6,7 @@
Other module of this app shouldn't connect with other app. Other module of this app shouldn't connect with other app.
:copyright: (c) 2014-2016 by Jumpserver Team. :copyright: (c) 2014-2017 by Jumpserver Team.
:license: GPL v2, see LICENSE for more details. :license: GPL v2, see LICENSE for more details.
""" """

View File

@ -16,11 +16,13 @@
<div class="panel-options"> <div class="panel-options">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"> <li class="active">
<a href="{% url 'assets:asset-detail' %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset detail' %} </a> <a href="{% url 'assets:asset-detail' pk=asset.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset detail' %} </a>
</li> </li>
{% if user.is_superuser %}
<li class="pull-right"> <li class="pull-right">
<a class="btn btn-outline btn-default" href="{% url 'assets:asset-update' pk=asset.id %}"><i class="fa fa-edit"></i>Update</a> <a class="btn btn-outline btn-default" href="{% url 'assets:asset-update' pk=asset.id %}"><i class="fa fa-edit"></i>Update</a>
</li> </li>
{% endif %}
</ul> </ul>
</div> </div>
<div class="tab-content"> <div class="tab-content">
@ -134,6 +136,7 @@
</div> </div>
</div> </div>
</div> </div>
{% if user.is_superuser %}
<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">
@ -222,6 +225,7 @@
</table> </table>
</div> </div>
</div> </div>
{% endif %}
</div> </div>
</div> </div>
</div> </div>

View File

@ -125,7 +125,7 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateView):
return super(AssetUpdateView, self).form_invalid(form) return super(AssetUpdateView, self).form_invalid(form)
class AssetDeleteView(DeleteView): class AssetDeleteView(AdminUserRequiredMixin, DeleteView):
model = Asset model = Asset
template_name = 'assets/delete_confirm.html' template_name = 'assets/delete_confirm.html'
success_url = reverse_lazy('assets:asset-list') success_url = reverse_lazy('assets:asset-list')

View File

@ -15,7 +15,7 @@
</a> </a>
</li> </li>
<li id="applications"> <li id="applications">
<a href="{% url 'users:user-profile' %}"> <a href="{% url 'applications:terminal-list' %}">
<i class="fa fa-terminal" ></i> <span class="nav-label">{% trans 'Terminal' %}</span><span class="label label-info pull-right"></span> <i class="fa fa-terminal" ></i> <span class="nav-label">{% trans 'Terminal' %}</span><span class="label label-info pull-right"></span>
</a> </a>
</li> </li>

View File

@ -34,7 +34,7 @@
{% if messages %} {% if messages %}
<p> <p>
<div class="alert alert-success" id="messages"> <div class="alert alert-success" id="messages">
{{ messages }} {{ messages|safe }}
</div> </div>
</p> </p>
{% endif %} {% endif %}
@ -52,16 +52,21 @@
Copyright Jumpserver.org Copyright Jumpserver.org
</div> </div>
<div class="col-md-6 text-right"> <div class="col-md-6 text-right">
<small>2014-2016</small> <small>2014-2017</small>
</div> </div>
</div> </div>
</div> </div>
</body> </body>
<script> <script>
var time=5; var time = '{{ interval }}';
if (!time){
time = 5;
} else {
time = parseInt(time);
}
function redirect_page() { function redirect_page() {
if (time >= 0) { if (time >= 0) {
var messages = '{{ messages }} <b>' + time +'</b> ...'; var messages = '{{ messages|safe }} <b>' + time +'</b> ...';
$('#messages').html(messages); $('#messages').html(messages);
time--; time--;
setTimeout(redirect_page, 1000); setTimeout(redirect_page, 1000);

View File

@ -6,7 +6,7 @@
Other module of this app shouldn't connect with other app. Other module of this app shouldn't connect with other app.
:copyright: (c) 2014-2016 by Jumpserver Team. :copyright: (c) 2014-2017 by Jumpserver Team.
:license: GPL v2, see LICENSE for more details. :license: GPL v2, see LICENSE for more details.
""" """

View File

@ -33,7 +33,7 @@ class User(AbstractUser):
email = models.EmailField(max_length=30, unique=True, verbose_name=_('Email')) email = models.EmailField(max_length=30, unique=True, verbose_name=_('Email'))
groups = models.ManyToManyField(UserGroup, related_name='users', blank=True, verbose_name=_('User group')) groups = models.ManyToManyField(UserGroup, related_name='users', blank=True, verbose_name=_('User group'))
role = models.CharField(choices=ROLE_CHOICES, default='User', max_length=10, blank=True, verbose_name=_('Role')) role = models.CharField(choices=ROLE_CHOICES, default='User', max_length=10, blank=True, verbose_name=_('Role'))
avatar = models.ImageField(upload_to="avatar", verbose_name=_('Avatar')) avatar = models.ImageField(upload_to="avatar", null=True, verbose_name=_('Avatar'))
wechat = models.CharField(max_length=30, blank=True, verbose_name=_('Wechat')) wechat = models.CharField(max_length=30, blank=True, verbose_name=_('Wechat'))
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone')) phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone'))
enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP')) enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP'))

View File

@ -12,7 +12,7 @@ class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission):
and request.user.is_valid and request.user.is_valid
class IsAppUser(IsValidUser, permissions.BasePermission): class IsAppUser(IsValidUser):
"""Allows access only to app user """ """Allows access only to app user """
def has_permission(self, request, view): def has_permission(self, request, view):
@ -20,7 +20,7 @@ class IsAppUser(IsValidUser, permissions.BasePermission):
and request.user.is_app and request.user.is_app
class IsSuperUser(IsValidUser, permissions.BasePermission): class IsSuperUser(IsValidUser):
"""Allows access only to superuser""" """Allows access only to superuser"""
def has_permission(self, request, view): def has_permission(self, request, view):
@ -28,7 +28,7 @@ class IsSuperUser(IsValidUser, permissions.BasePermission):
and request.user.is_superuser and request.user.is_superuser
class IsSuperUserOrAppUser(IsValidUser, permissions.BasePermission): class IsSuperUserOrAppUser(IsValidUser):
"""Allows access between superuser and app user""" """Allows access between superuser and app user"""
def has_permission(self, request, view): def has_permission(self, request, view):
@ -36,8 +36,16 @@ class IsSuperUserOrAppUser(IsValidUser, permissions.BasePermission):
and (request.user.is_superuser or request.user.is_app) and (request.user.is_superuser or request.user.is_app)
class IsCurrentUserOrReadOnly(permissions.BasePermission): class IsSuperUserOrAppUserOrUserReadonly(IsSuperUserOrAppUser):
def has_permission(self, request, view):
if IsValidUser.has_permission(self, request, view) \
and request.method in permissions.SAFE_METHODS:
return True
else:
return IsSuperUserOrAppUser.has_permission(self, request, view)
class IsCurrentUserOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj): def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS: if request.method in permissions.SAFE_METHODS:
return True return True

View File

@ -55,7 +55,7 @@
Copyright Jumpserver.org Copyright Jumpserver.org
</div> </div>
<div class="col-md-6 text-right"> <div class="col-md-6 text-right">
<small>© 2014-2016</small> <small>© 2014-2017</small>
</div> </div>
</div> </div>
</div> </div>

View File

@ -78,7 +78,7 @@
Copyright Jumpserver.org Copyright Jumpserver.org
</div> </div>
<div class="col-md-6 text-right"> <div class="col-md-6 text-right">
<small>© 2014-2016</small> <small>© 2014-2017</small>
</div> </div>
</div> </div>
</div> </div>

View File

@ -74,7 +74,7 @@
Copyright Jumpserver.org Copyright Jumpserver.org
</div> </div>
<div class="col-md-6 text-right"> <div class="col-md-6 text-right">
<small>© 2014-2016</small> <small>© 2014-2017</small>
</div> </div>
</div> </div>
</div> </div>

View File

@ -3,18 +3,15 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import base64 import base64
import logging import logging
import os
import re
import uuid import uuid
from paramiko.rsakey import RSAKey
from django.conf import settings from django.conf import settings
from django.contrib.auth.mixins import UserPassesTestMixin from django.contrib.auth.mixins import UserPassesTestMixin
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.core.cache import cache from django.core.cache import cache
from paramiko.rsakey import RSAKey
from common.tasks import send_mail_async from common.tasks import send_mail_async
from common.utils import reverse, get_object_or_none from common.utils import reverse, get_object_or_none
from .models import User from .models import User
@ -30,10 +27,13 @@ logger = logging.getLogger('jumpserver')
class AdminUserRequiredMixin(UserPassesTestMixin): class AdminUserRequiredMixin(UserPassesTestMixin):
login_url = reverse_lazy('users:login')
def test_func(self): def test_func(self):
return self.request.user.is_superuser if not self.request.user.is_authenticated:
return False
elif not self.request.user.is_superuser:
self.raise_exception = True
return False
return True
def user_add_success_next(user): def user_add_success_next(user):