[Change] Rename applications -> terminal

This commit is contained in:
ibuler
2017-12-01 17:28:47 +08:00
parent 19051d36dc
commit 61a8d95f46
37 changed files with 51 additions and 50 deletions

View File

@@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@@ -1,219 +0,0 @@
# -*- coding: utf-8 -*-
#
import base64
from collections import OrderedDict
import copy
import logging
import tarfile
import os
from rest_framework import viewsets, serializers
from rest_framework.views import APIView, Response
from rest_framework.permissions import AllowAny
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.conf import settings
from common.utils import get_object_or_none
from .models import Terminal, TerminalStatus, TerminalSession, TerminalTask
from .serializers import TerminalSerializer, TerminalStatusSerializer, \
TerminalSessionSerializer, TerminalTaskSerializer
from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \
IsSuperUserOrAppUserOrUserReadonly
from .backends import get_command_store, get_replay_store, SessionCommandSerializer
logger = logging.getLogger(__file__)
class TerminalViewSet(viewsets.ModelViewSet):
queryset = Terminal.objects.filter(is_deleted=False)
serializer_class = TerminalSerializer
permission_classes = (IsSuperUserOrAppUserOrUserReadonly,)
def create(self, request, *args, **kwargs):
name = request.data.get('name')
remote_ip = request.META.get('REMOTE_ADDR')
x_real_ip = request.META.get('X-Real-IP')
remote_addr = x_real_ip or remote_ip
terminal = get_object_or_none(Terminal, name=name)
if terminal:
msg = 'Terminal name %s already used' % name
return Response({'msg': msg}, status=409)
serializer = self.serializer_class(data={
'name': name, 'remote_addr': remote_addr
})
if serializer.is_valid():
terminal = serializer.save()
app_user, access_key = terminal.create_app_user()
data = OrderedDict()
data['terminal'] = copy.deepcopy(serializer.data)
data['user'] = app_user.to_json()
data['access_key'] = {'id': access_key.id,
'secret': access_key.secret}
return Response(data, status=201)
else:
data = serializer.errors
return Response(data, status=400)
def get_permissions(self):
if self.action == "create":
self.permission_classes = (AllowAny,)
return super().get_permissions()
class TerminalStatusViewSet(viewsets.ModelViewSet):
queryset = TerminalStatus.objects.all()
serializer_class = TerminalStatusSerializer
permission_classes = (IsSuperUserOrAppUser,)
session_serializer_class = TerminalSessionSerializer
def create(self, request, *args, **kwargs):
self.handle_sessions()
return super().create(request, *args, **kwargs)
def handle_sessions(self):
sessions_active = []
for session_data in self.request.data.get("sessions", []):
session_data["terminal"] = self.request.user.terminal.id
_id = session_data["id"]
session = get_object_or_none(TerminalSession, id=_id)
if session:
serializer = TerminalSessionSerializer(data=session_data,
instance=session)
else:
serializer = TerminalSessionSerializer(data=session_data)
if serializer.is_valid():
serializer.save()
else:
logger.error("session serializer is not valid {}".format(
serializer.errors))
if not session_data["is_finished"]:
sessions_active.append(session_data["id"])
sessions_in_db_active = TerminalSession.objects.filter(
is_finished=False, terminal=self.request.user.terminal.id
)
for session in sessions_in_db_active:
if str(session.id) not in sessions_active:
session.is_finished = True
session.date_end = timezone.now()
session.save()
def get_queryset(self):
terminal_id = self.kwargs.get("terminal", None)
if terminal_id:
terminal = get_object_or_404(Terminal, id=terminal_id)
self.queryset = terminal.terminalstatus_set.all()
return self.queryset
def perform_create(self, serializer):
serializer.validated_data["terminal"] = self.request.user.terminal
return super().perform_create(serializer)
def get_permissions(self):
if self.action == "create":
self.permission_classes = (IsAppUser,)
return super().get_permissions()
class TerminalSessionViewSet(viewsets.ModelViewSet):
queryset = TerminalSession.objects.all()
serializers_class = TerminalSessionSerializer
permission_classes = (IsSuperUserOrAppUser,)
def get_queryset(self):
terminal_id = self.kwargs.get("terminal", None)
if terminal_id:
terminal = get_object_or_404(Terminal, id=terminal_id)
self.queryset = terminal.terminalstatus_set.all()
return self.queryset
class TerminalTaskViewSet(viewsets.ModelViewSet):
queryset = TerminalTask.objects.all()
serializer_class = TerminalTaskSerializer
permission_classes = (IsSuperUserOrAppUser,)
def get_queryset(self):
terminal_id = self.kwargs.get("terminal", None)
if terminal_id:
terminal = get_object_or_404(Terminal, id=terminal_id)
self.queryset = terminal.terminalstatus_set.all()
if hasattr(self.request.user, "terminal"):
terminal = self.request.user.terminal
self.queryset = terminal.terminalstatus_set.all()
return self.queryset
class SessionReplayAPI(APIView):
permission_classes = (IsSuperUserOrAppUser,)
def post(self, request, **kwargs):
session_id = kwargs.get("pk", None)
session = get_object_or_404(TerminalSession, id=session_id)
record_dir = settings.CONFIG.SESSION_RECORDE_DIR
date = session.date_start.strftime("%Y-%m-%d")
record_dir = os.path.join(record_dir, date, str(session.id))
record_filename = os.path.join(record_dir, "replay.tar.gz2")
if not os.path.isdir(record_dir):
try:
os.makedirs(record_dir)
except FileExistsError:
pass
archive_stream = request.data.get("archive")
if not archive_stream:
return Response("None file upload", status=400)
with open(record_filename, 'wb') as f:
for chunk in archive_stream.chunks():
f.write(chunk)
session.has_replay = True
session.save()
return Response({"session_id": session.id}, status=201)
class SessionCommandViewSet(viewsets.ViewSet):
"""接受app发送来的command log, 格式如下
{
"user": "admin",
"asset": "localhost",
"system_user": "web",
"session": "xxxxxx",
"input": "whoami",
"output": "d2hvbWFp", # base64.b64encode(s)
"timestamp": 1485238673.0
}
"""
command_store = get_command_store()
serializer_class = SessionCommandSerializer
permission_classes = (IsSuperUserOrAppUser,)
def get_queryset(self):
self.command_store.all()
def create(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, many=True)
if serializer.is_valid():
ok = self.command_store.bulk_save(serializer.validated_data)
if ok:
return Response("ok", status=201)
else:
return Response("save error", status=500)
else:
print(serializer.errors)
return Response({"msg": "Not valid: {}".format(serializer.errors)}, status=401)
def list(self, request, *args, **kwargs):
queryset = list(self.command_store.all())
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)

View File

@@ -1,7 +0,0 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class ApplicationsConfig(AppConfig):
name = 'applications'

View File

@@ -1,17 +0,0 @@
from importlib import import_module
from django.conf import settings
from .command.serializers import SessionCommandSerializer
def get_command_store():
command_engine = import_module(settings.COMMAND_STORE_BACKEND)
command_store = command_engine.CommandStore()
return command_store
def get_replay_store():
replay_engine = import_module(settings.RECORD_STORE_BACKEND)
replay_store = replay_engine.RecordStore()
return replay_store

View File

@@ -1,22 +0,0 @@
# coding: utf-8
import abc
class CommandBase(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def save(self, command):
pass
@abc.abstractmethod
def bulk_save(self, commands):
pass
@abc.abstractmethod
def filter(self, date_from=None, date_to=None, user=None,
asset=None, system_user=None, command=None, session=None):
pass

View File

@@ -1,70 +0,0 @@
# ~*~ coding: utf-8 ~*~
import datetime
from django.utils import timezone
from .base import CommandBase
class CommandStore(CommandBase):
def __init__(self):
from applications.models import SessionCommand
self.model = SessionCommand
def save(self, command):
"""
保存命令到数据库
"""
self.model.objects.create(
user=command["user"], asset=command["asset"],
system_user=command["system_user"], input=command["input"],
output=command["output"], session=command["session"],
timestamp=command["timestamp"]
)
def bulk_save(self, commands):
"""
批量保存命令到数据库, command的顺序和save中一致
"""
_commands = []
for c in commands:
_commands.append(self.model(
user=c["user"], asset=c["asset"], system_user=c["system_user"],
input=c["input"], output=c["output"], session=c["session"],
timestamp=c["timestamp"]
))
return self.model.objects.bulk_create(_commands)
def filter(self, date_from=None, date_to=None, user=None,
asset=None, system_user=None, _input=None, session=None):
filter_kwargs = {}
if date_from:
filter_kwargs['timestamp__gte'] = int(date_from.timestamp())
else:
week_ago = timezone.now() - datetime.timedelta(days=7)
filter_kwargs['timestamp__gte'] = int(week_ago.timestamp())
if date_to:
filter_kwargs['timestamp__lte'] = int(date_to.timestamp())
else:
filter_kwargs['timestamp__lte'] = int(timezone.now().timestamp())
if user:
filter_kwargs['user'] = user
if asset:
filter_kwargs['asset'] = asset
if system_user:
filter_kwargs['system_user'] = system_user
if _input:
filter_kwargs['input__icontains'] = _input
if session:
filter_kwargs['session'] = session
queryset = self.model.objects.filter(**filter_kwargs)
return queryset
def all(self):
"""返回所有数据"""
return self.model.objects.iterator()

View File

@@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
#
import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
class AbstractSessionCommand(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
user = models.CharField(max_length=64, verbose_name=_("User"))
asset = models.CharField(max_length=128, verbose_name=_("Asset"))
system_user = models.CharField(max_length=64, verbose_name=_("System user"))
input = models.CharField(max_length=128, db_index=True, verbose_name=_("Input"))
output = models.CharField(max_length=1024, verbose_name=_("Output"))
session = models.CharField(max_length=36, db_index=True, verbose_name=_("Session"))
timestamp = models.IntegerField(db_index=True)
class Meta:
abstract = True
def __str__(self):
return self.input

View File

@@ -1,16 +0,0 @@
# ~*~ coding: utf-8 ~*~
from rest_framework import serializers
class SessionCommandSerializer(serializers.Serializer):
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
id = serializers.UUIDField(read_only=True)
user = serializers.CharField(max_length=64)
asset = serializers.CharField(max_length=128)
system_user = serializers.CharField(max_length=64)
input = serializers.CharField(max_length=128)
output = serializers.CharField(max_length=1024)
session = serializers.CharField(max_length=36)
timestamp = serializers.IntegerField()

View File

@@ -1,2 +0,0 @@
# ~*~ coding: utf-8 ~*~

View File

@@ -1,14 +0,0 @@
# coding: utf-8
import abc
class RecordBase(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def save(self, proxy_log_id, output, timestamp):
pass
@abc.abstractmethod
def filter(self, date_from_ts=None, proxy_log_id=None):
pass

View File

@@ -1,31 +0,0 @@
# ~*~ coding: utf-8 ~*~
from .base import RecordBase
from audits.models import RecordLog
class RecordStore(RecordBase):
model = RecordLog
queryset = []
def save(self, proxy_log_id, output, timestamp):
return self.model.objects.create(
proxy_log_id=proxy_log_id, output=output, timestamp=timestamp
)
def filter(self, date_from_ts=None, proxy_log_id=''):
filter_kwargs = {}
if date_from_ts:
filter_kwargs['timestamp__gte'] = date_from_ts
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.all()

View File

@@ -1,20 +0,0 @@
# ~*~ coding: utf-8 ~*~
import base64
from rest_framework import serializers
from audits.models import RecordLog
from audits.backends import record_store
class RecordSerializer(serializers.ModelSerializer):
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
class Meta:
model = RecordLog
fields = '__all__'
def create(self, validated_data):
try:
output = validated_data['output']
validated_data['output'] = base64.b64decode(output)
except IndexError:
pass
return record_store.save(**dict(validated_data))

View File

@@ -1,21 +0,0 @@
# ~*~ coding: utf-8 ~*~
#
from django import forms
from django.utils.translation import ugettext_lazy as _
from .models import Terminal
class TerminalForm(forms.ModelForm):
class Meta:
model = Terminal
fields = ['name', 'remote_addr', 'ssh_port', 'http_port', 'comment']
help_texts = {
'remote_addr': _('A unique addr of every terminal, user browser can arrive it'),
'ssh_port': _("Coco ssh listen port"),
'http_port': _("Coco http/ws listen port"),
}
widgets = {
'name': forms.TextInput(attrs={'readonly': 'readonly'})
}

View File

@@ -1,8 +0,0 @@
# -*- coding: utf-8 -*-
#
from users.models import User
from users.permissions import IsSuperUserOrAppUser, IsAppUser, \
IsSuperUserOrAppUserOrUserReadonly
from audits.models import ProxyLog
from users.utils import AdminUserRequiredMixin

View File

@@ -1,119 +0,0 @@
from __future__ import unicode_literals
import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
from users.models import User
from .backends.command.models import AbstractSessionCommand
class Terminal(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=32, unique=True, verbose_name=_('Name'))
remote_addr = models.CharField(max_length=128, verbose_name=_('Remote Address'))
ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222)
http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000)
user = models.OneToOneField(User, related_name='terminal', verbose_name='Application User', null=True, on_delete=models.CASCADE)
is_accepted = models.BooleanField(default=False, verbose_name='Is Accepted')
is_deleted = models.BooleanField(default=False)
date_created = models.DateTimeField(auto_now_add=True)
comment = models.TextField(blank=True, verbose_name=_('Comment'))
@property
def is_active(self):
if self.user and self.user.is_active:
return True
return False
@is_active.setter
def is_active(self, active):
if self.user:
self.user.is_active = active
self.user.save()
def create_app_user(self):
user, access_key = User.create_app_user(name=self.name, comment=self.comment)
self.user = user
self.save()
return user, access_key
def delete(self, using=None, keep_parents=False):
if self.user:
self.user.delete()
self.is_deleted = True
self.save()
return
def __str__(self):
status = "Active"
if not self.is_accepted:
status = "NotAccept"
elif self.is_deleted:
status = "Deleted"
elif not self.is_active:
status = "Disable"
return '%s: %s' % (self.name, status)
class Meta:
ordering = ('is_accepted',)
class TerminalStatus(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
session_online = models.IntegerField(verbose_name=_("Session Online"), default=0)
cpu_used = models.FloatField(verbose_name=_("CPU Usage"))
memory_used = models.FloatField(verbose_name=_("Memory Used"))
connections = models.IntegerField(verbose_name=_("Connections"))
threads = models.IntegerField(verbose_name=_("Threads"))
boot_time = models.FloatField(verbose_name=_("Boot Time"))
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'terminal_status'
class TerminalSession(models.Model):
LOGIN_FROM_CHOICES = (
('ST', 'SSH Terminal'),
('WT', 'Web Terminal'),
)
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
user = models.CharField(max_length=128, verbose_name=_("User"))
asset = models.CharField(max_length=1024, verbose_name=_("Asset"))
system_user = models.CharField(max_length=128, verbose_name=_("System User"))
login_from = models.CharField(max_length=2, choices=LOGIN_FROM_CHOICES, default="ST")
is_finished = models.BooleanField(default=False)
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
terminal = models.UUIDField(null=True, verbose_name=_("Terminal"))
date_start = models.DateTimeField(verbose_name=_("Date Start"))
date_end = models.DateTimeField(verbose_name=_("Date End"), null=True)
class Meta:
db_table = "terminal_session"
def __str__(self):
return "{0.id} of {0.user} to {0.asset}".format(self)
class TerminalTask(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, verbose_name=_("Name"))
args = models.CharField(max_length=1024, verbose_name=_("Task Args"))
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.CASCADE)
is_finished = models.BooleanField(default=False)
date_created = models.DateTimeField(auto_now_add=True)
date_finished = models.DateTimeField(null=True)
class Meta:
db_table = "terminal_task"
class SessionCommand(AbstractSessionCommand):
class Meta:
db_table = "session_command"

View File

@@ -1,51 +0,0 @@
# -*- coding: utf-8 -*-
#
from django.utils import timezone
from rest_framework import serializers
from .models import Terminal, TerminalStatus, TerminalSession, TerminalTask
from .hands import ProxyLog
class TerminalSerializer(serializers.ModelSerializer):
session_connected = serializers.SerializerMethodField()
is_alive = serializers.SerializerMethodField()
class Meta:
model = Terminal
fields = ['id', 'name', 'remote_addr', 'http_port', 'ssh_port',
'comment', 'is_accepted', 'session_connected', 'is_alive']
@staticmethod
def get_session_connected(obj):
return TerminalSession.objects.filter(terminal=obj.id, is_finished=False)
@staticmethod
def get_is_alive(obj):
log = obj.terminalstatus_set.last()
if log and timezone.now() - log.date_created < timezone.timedelta(seconds=600):
return True
else:
return False
class TerminalSessionSerializer(serializers.ModelSerializer):
class Meta:
model = TerminalSession
fields = '__all__'
class TerminalStatusSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = TerminalStatus
class TerminalTaskSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = TerminalTask

View File

@@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
#
from celery import shared_task
# Todo: 定期清理上报history
@shared_task
def clean_terminal_history():
pass

View File

@@ -1,77 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active">
<a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Terminal detail' %} </a>
</li>
<li class="pull-right">
<a class="btn btn-outline btn-default" href="{% url 'applications:terminal-update' pk=terminal.id %}"><i class="fa fa-edit"></i>Update</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ terminal.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td width="20%">{% trans 'Name' %}:</td>
<td><b>{{ terminal.name }}</b></td>
</tr>
<tr>
<td>{% trans 'Remote address' %}:</td>
<td><b>{{ terminal.remote_addr }}</b></td>
</tr>
<tr>
<td>{% trans 'URL to login' %}:</td>
<td><b>{{ terminal.url }}</b></td>
</tr>
<tr>
<td>{% trans 'Terminal type' %}:</td>
<td><b>{{ terminal.get_type_display }}</b></td>
</tr>
<tr>
<td>{% trans 'Date created' %}:</td>
<td><b>{{ terminal.date_created }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ asset.comment }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,149 +0,0 @@
{% extends '_base_list.html' %}
{% load i18n static %}
{% block custom_head_css_js %}
{{ block.super }}
<style>
div.dataTables_wrapper div.dataTables_filter,
.dataTables_length {
float: right !important;
}
div.dataTables_wrapper div.dataTables_filter {
margin-left: 15px;
}
#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>
<th class="text-center">
<div class="checkbox checkbox-default">
<input type="checkbox" class="ipt_check_all">
</div>
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Addr' %}</th>
<th class="text-center">{% trans 'SSH port' %}</th>
<th class="text-center">{% trans 'Http port' %}</th>
<th class="text-center">{% trans 'Sessions' %}</th>
<th class="text-center">{% trans 'Active' %}</th>
<th class="text-center">{% trans 'Alive' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
{% include 'applications/terminal_modal_accept.html' %}
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/jquery.form.min.js' %}"></script>
<script>
$(document).ready(function(){
var options = {
ele: $('#terminal_list_table'),
buttons: [],
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "applications:terminal-detail" pk=99991937 %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('99991937', rowData.id));
}},
{targets: 6, createdCell: function (td, cellData) {
if (!cellData) {
$(td).html('<i class="fa fa-times text-danger"></i>')
} else {
$(td).html('<i class="fa fa-check text-navy"></i>')
}
}},
{targets: 7, createdCell: function (td, cellData) {
if (!cellData) {
$(td).html('<i class="fa fa-circle text-danger"></i>')
} else {
$(td).html('<i class="fa fa-circle text-navy"></i>')
}
}},
{targets: 8, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "applications:terminal-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.replace('99991937', cellData);
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('99991938', rowData.name);
var accept_btn = '<a class="btn btn-xs btn-primary btn-accept" data-id="99991937">{% trans "Accept" %}</a> '
.replace('99991937', cellData);
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('99991938', rowData.name);
var connect_btn = '<a href="" class="btn btn-xs btn-warning btn-connect" >{% trans "Connect" %}</a> '
.replace('99991937', cellData);
if (rowData.is_accepted) {
{% if user.is_superuser %}
$(td).html(connect_btn + update_btn + delete_btn);
{% else %}
$(td).html(connect_btn);
{% endif %}
} else {
{% if user.is_superuser %}
$(td).html(accept_btn + reject_btn);
{% endif %}
}
}}
],
ajax_url: '{% url "api-applications:terminal-list" %}',
columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" }, {data: "ssh_port"}, {data: "http_port"},
{data: "session_connected"}, {data: "is_accepted" }, {data: 'is_alive'}, {data: "id"}],
op_html: $('#actions').html()
};
jumpserver.initDataTable(options);
$('#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');
}
}
$form.ajaxSubmit({success: success});
})
}).on('click', '.btn-del', function(){
var $this = $(this);
var id = $this.data('id');
var name = $(this).data('name');
var the_url = '{% url "api-applications:terminal-detail" pk=99991937 %}'.replace('99991937', id);
objectDelete($this, name, the_url)
}).on('click', '.btn-accept', function () {
var $this = $(this);
var terminal_id = $this.data('id');
var the_url = "{% url 'api-applications:terminal-detail' pk=99991937 %}".replace('99991937', terminal_id);
var post_url = $('#form_terminal_accept').attr('action').replace('99991937', terminal_id);
console.log(post_url);
$.ajax({
url: the_url,
method: 'GET',
success: function (data) {
$('#id_name').val(data.name);
$('#id_remote_addr').val(data.remote_addr);
$('#id_url').val(data.url);
$('#id_comment').val(data.comment);
$('#form_terminal_accept').attr('action', post_url)
}
});
$('#modal_terminal_accept').modal({
show: true
});
}).on('click', '.btn-connect', function () {
var $this = $(this);
var id = $this.data('id');
console.log(id)
})
</script>
{% endblock %}

View File

@@ -1,19 +0,0 @@
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}modal_terminal_accept{% endblock %}
{% block modal_class %}modal-lg{% endblock %}
{% block modal_title%}{% trans "Accept terminal registration" %}{% endblock %}
{% block modal_body %}
{% load bootstrap3 %}
<form action="{% url 'applications:terminal-modal-accept' pk="99991937" %}" 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" %}
{% bootstrap_field form.remote_addr layout="horizontal" %}
{% bootstrap_field form.ssh_port layout="horizontal" %}
{% bootstrap_field form.http_port layout="horizontal" %}
{% bootstrap_field form.comment layout="horizontal" %}
</form>
{% endblock %}
{% block modal_confirm_id %}btn_terminal_accept{% endblock %}

View File

@@ -1,5 +0,0 @@
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>

View File

@@ -1,72 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load bootstrap3 %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>{{ action }}</h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %}
<h3>{% trans 'Info' %}</h3>
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.remote_addr layout="horizontal" %}
{% bootstrap_field form.ssh_port layout="horizontal" %}
{% bootstrap_field form.http_port layout="horizontal" %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3>
{% bootstrap_field form.comment layout="horizontal" %}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function () {
$('.select2').select2();
$('.input-group.date').datepicker({
format: "yyyy-mm-dd",
todayBtn: "linked",
keyboardNavigation: false,
forceParse: false,
calendarWeeks: true,
autoclose: true
});
})
</script>
{% endblock %}

View File

@@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -1 +0,0 @@

View File

@@ -1,22 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
from django.conf.urls import url
from rest_framework import routers
from .. import api
app_name = 'applications'
router = routers.DefaultRouter()
router.register(r'v1/terminal/(?P<terminal>[0-9]+)?/?status', api.TerminalStatusViewSet, 'terminal-status')
router.register(r'v1/terminal/(?P<terminal>[0-9]+)?/?sessions', api.TerminalSessionViewSet, 'terminal-sessions')
router.register(r'v1/terminal', api.TerminalViewSet, 'terminal')
router.register(r'v1/command', api.SessionCommandViewSet, 'command')
urlpatterns = [
url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-_]+)/replay/$', api.SessionReplayAPI.as_view(), name='session-replay'),
]
urlpatterns += router.urls

View File

@@ -1,21 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
from django.conf.urls import url
from .. import views
app_name = 'applications'
urlpatterns = [
url(r'^terminal/$', views.TerminalListView.as_view(), name='terminal-list'),
url(r'^terminal/(?P<pk>[0-9a-zA-Z\-]+)/$', views.TerminalDetailView.as_view(),
name='terminal-detail'),
url(r'^terminal/(?P<pk>[0-9a-zA-Z\-]+)/connect/$', views.TerminalConnectView.as_view(),
name='terminal-connect'),
url(r'^terminal/(?P<pk>[0-9a-zA-Z\-]+)/update$', views.TerminalUpdateView.as_view(),
name='terminal-update'),
url(r'^terminal/(?P<pk>[0-9a-zA-Z\-]+)/modal/accept$', views.TerminalModelAccept.as_view(),
name='terminal-modal-accept'),
]

View File

@@ -1,110 +0,0 @@
# ~*~ coding: utf-8 ~*~
#
from django.views.generic import ListView, UpdateView, DeleteView, \
DetailView, TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.translation import ugettext as _
from django.urls import reverse_lazy, reverse
from common.mixins import JSONResponseMixin
from .models import Terminal
from .forms import TerminalForm
from .hands import AdminUserRequiredMixin
class TerminalListView(LoginRequiredMixin, ListView):
model = Terminal
template_name = 'applications/terminal_list.html'
form_class = TerminalForm
def get_context_data(self, **kwargs):
context = super(TerminalListView, self).get_context_data(**kwargs)
context.update({
'app': _('Terminal'),
'action': _('Terminal list'),
'form': self.form_class()
})
return context
class TerminalUpdateView(AdminUserRequiredMixin, UpdateView):
model = Terminal
form_class = TerminalForm
template_name = 'applications/terminal_update.html'
success_url = reverse_lazy('applications:terminal-list')
def get_context_data(self, **kwargs):
context = super(TerminalUpdateView, self).get_context_data(**kwargs)
context.update({'app': _('Applications'), 'action': _('Update terminal')})
return context
class TerminalDetailView(LoginRequiredMixin, DetailView):
model = Terminal
template_name = 'applications/terminal_detail.html'
context_object_name = 'terminal'
def get_context_data(self, **kwargs):
context = super(TerminalDetailView, self).get_context_data(**kwargs)
context.update({
'app': _('Applications'),
'action': _('Terminal detail')
})
return context
class TerminalDeleteView(AdminUserRequiredMixin, DeleteView):
model = Terminal
template_name = 'assets/delete_confirm.html'
success_url = reverse_lazy('applications:applications-list')
class TerminalModelAccept(AdminUserRequiredMixin, JSONResponseMixin, UpdateView):
model = Terminal
form_class = TerminalForm
template_name = 'applications/terminal_modal_test.html'
def form_valid(self, form):
terminal = form.save()
terminal.is_accepted = True
terminal.is_active = True
terminal.save()
data = {
'success': True,
'msg': 'success'
}
return self.render_json_response(data)
def form_invalid(self, form):
data = {
'success': False,
'msg': str(form.errors),
}
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') + 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)),
'redirect_url': reverse('applications:terminal-list')
}
kwargs.update(context)
return super(TerminalConnectView, self).get_context_data(**kwargs)