mirror of https://github.com/jumpserver/jumpserver
Tmp org (#1579)
* [Update] 添加org api, 升级到django 2.0 * [Update] fix some bug * [Update] 修改一些bugpull/1580/head^2
parent
c816875f28
commit
b156f4ad16
|
@ -2,8 +2,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
from rest_framework import generics
|
from rest_framework import generics, permissions
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework_bulk import BulkModelViewSet
|
from rest_framework_bulk import BulkModelViewSet
|
||||||
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
|
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
|
||||||
|
@ -39,9 +40,10 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
|
||||||
queryset = Asset.objects.all()
|
queryset = Asset.objects.all()
|
||||||
serializer_class = serializers.AssetSerializer
|
serializer_class = serializers.AssetSerializer
|
||||||
pagination_class = LimitOffsetPagination
|
pagination_class = LimitOffsetPagination
|
||||||
permission_classes = (IsOrgAdminOrAppUser,)
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
time.sleep(3)
|
||||||
queryset = super().get_queryset()\
|
queryset = super().get_queryset()\
|
||||||
.prefetch_related('labels', 'nodes')\
|
.prefetch_related('labels', 'nodes')\
|
||||||
.select_related('admin_user')
|
.select_related('admin_user')
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
|
|
||||||
from rest_framework_bulk import BulkModelViewSet
|
from rest_framework_bulk import BulkModelViewSet
|
||||||
from rest_framework.views import APIView, Response
|
from rest_framework.views import APIView, Response
|
||||||
from rest_condition import Or
|
|
||||||
|
|
||||||
from django.views.generic.detail import SingleObjectMixin
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from common.permissions import IsOrgAdmin, IsAppUser
|
from common.permissions import IsOrgAdmin, IsAppUser, IsOrgAdminOrAppUser
|
||||||
from ..models import Domain, Gateway
|
from ..models import Domain, Gateway
|
||||||
from ..utils import test_gateway_connectability
|
from ..utils import test_gateway_connectability
|
||||||
from .. import serializers
|
from .. import serializers
|
||||||
|
|
|
@ -44,7 +44,7 @@ class Gateway(AssetUser):
|
||||||
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
|
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
|
||||||
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
||||||
protocol = models.CharField(choices=PROTOCOL_CHOICES, max_length=16, default=SSH_PROTOCOL, verbose_name=_("Protocol"))
|
protocol = models.CharField(choices=PROTOCOL_CHOICES, max_length=16, default=SSH_PROTOCOL, verbose_name=_("Protocol"))
|
||||||
domain = models.ForeignKey(Domain, verbose_name=_("Domain"))
|
domain = models.ForeignKey(Domain, on_delete=models.CASCADE, verbose_name=_("Domain"))
|
||||||
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Comment"))
|
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Comment"))
|
||||||
is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
|
is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,20 @@
|
||||||
.dropdown a:hover {
|
.dropdown a:hover {
|
||||||
background-color: #f1f1f1
|
background-color: #f1f1f1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dataTables_wrapper .dataTables_processing {
|
||||||
|
position: absolute;
|
||||||
|
top: 30%;
|
||||||
|
left: 50%;
|
||||||
|
width: 30%;
|
||||||
|
height: 40px;
|
||||||
|
margin-left: -20%;
|
||||||
|
margin-top: -25px;
|
||||||
|
padding-top: 20px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2em;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -44,7 +44,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
|
||||||
template_name = 'assets/asset_list.html'
|
template_name = 'assets/asset_list.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
print(Node.root().name)
|
Node.root()
|
||||||
context = {
|
context = {
|
||||||
'app': _('Assets'),
|
'app': _('Assets'),
|
||||||
'action': _('Asset list'),
|
'action': _('Asset list'),
|
||||||
|
|
|
@ -86,7 +86,18 @@ class LDAPTestingAPI(APIView):
|
||||||
|
|
||||||
class DjangoSettingsAPI(APIView):
|
class DjangoSettingsAPI(APIView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return Response('Danger, Close now')
|
if not settings.DEBUG:
|
||||||
|
return Response("Not in debug mode")
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
for k, v in settings.__dict__.items():
|
||||||
|
if k and k.isupper():
|
||||||
|
try:
|
||||||
|
json.dumps(v)
|
||||||
|
data[k] = v
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
data[k] = str(v)
|
||||||
|
return Response(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.http.response import HttpResponseForbidden
|
||||||
|
|
||||||
from orgs.utils import current_org
|
from orgs.utils import current_org
|
||||||
|
|
||||||
|
@ -23,6 +25,18 @@ class IsAppUser(IsValidUser):
|
||||||
and request.user.is_app
|
and request.user.is_app
|
||||||
|
|
||||||
|
|
||||||
|
class IsSuperUser(IsValidUser):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return super(IsSuperUser, self).has_permission(request, view) \
|
||||||
|
and request.user.is_superuser
|
||||||
|
|
||||||
|
|
||||||
|
class IsSuperUserOrAppUser(IsSuperUser):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return super(IsSuperUserOrAppUser, self).has_permission(request, view) \
|
||||||
|
and (request.user.is_superuser or request.user.is_app)
|
||||||
|
|
||||||
|
|
||||||
class IsOrgAdmin(IsValidUser):
|
class IsOrgAdmin(IsValidUser):
|
||||||
"""Allows access only to superuser"""
|
"""Allows access only to superuser"""
|
||||||
|
|
||||||
|
@ -63,3 +77,18 @@ class AdminUserRequiredMixin(UserPassesTestMixin):
|
||||||
self.raise_exception = True
|
self.raise_exception = True
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
print("Current org: {}".format(current_org))
|
||||||
|
if not current_org:
|
||||||
|
return redirect('orgs:switch-a-org')
|
||||||
|
|
||||||
|
if not current_org.can_admin_by(request.user):
|
||||||
|
print("{} cannot admin {}".format(request.user, current_org))
|
||||||
|
if request.user.is_org_admin:
|
||||||
|
print("Is org admin")
|
||||||
|
return redirect('orgs:switch-a-org')
|
||||||
|
return HttpResponseForbidden()
|
||||||
|
else:
|
||||||
|
print(current_org.can_admin_by(request.user))
|
||||||
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
|
@ -9,5 +9,5 @@ app_name = 'common'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^mail/testing/$', api.MailTestingAPI.as_view(), name='mail-testing'),
|
url(r'^mail/testing/$', api.MailTestingAPI.as_view(), name='mail-testing'),
|
||||||
url(r'^ldap/testing/$', api.LDAPTestingAPI.as_view(), name='ldap-testing'),
|
url(r'^ldap/testing/$', api.LDAPTestingAPI.as_view(), name='ldap-testing'),
|
||||||
url(r'^django-settings/$', api.DjangoSettingsAPI.as_view(), name='django-settings'),
|
# url(r'^django-settings/$', api.DjangoSettingsAPI.as_view(), name='django-settings'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -66,6 +66,7 @@ INSTALLED_APPS = [
|
||||||
'audits.apps.AuditsConfig',
|
'audits.apps.AuditsConfig',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'rest_framework_swagger',
|
'rest_framework_swagger',
|
||||||
|
'drf_yasg',
|
||||||
'django_filters',
|
'django_filters',
|
||||||
'bootstrap3',
|
'bootstrap3',
|
||||||
'captcha',
|
'captcha',
|
||||||
|
@ -230,7 +231,7 @@ LOGGING = {
|
||||||
'level': LOG_LEVEL,
|
'level': LOG_LEVEL,
|
||||||
},
|
},
|
||||||
'django_auth_ldap': {
|
'django_auth_ldap': {
|
||||||
'handlers': ['console', 'ansible_logs'],
|
'handlers': ['console', 'file'],
|
||||||
'level': "INFO",
|
'level': "INFO",
|
||||||
},
|
},
|
||||||
# 'django.db': {
|
# 'django.db': {
|
||||||
|
@ -294,6 +295,7 @@ REST_FRAMEWORK = {
|
||||||
'common.permissions.IsOrgAdmin',
|
'common.permissions.IsOrgAdmin',
|
||||||
),
|
),
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||||
|
'rest_framework.authentication.BasicAuthentication',
|
||||||
'users.authentication.AccessKeyAuthentication',
|
'users.authentication.AccessKeyAuthentication',
|
||||||
'users.authentication.AccessTokenAuthentication',
|
'users.authentication.AccessTokenAuthentication',
|
||||||
'users.authentication.PrivateTokenAuthentication',
|
'users.authentication.PrivateTokenAuthentication',
|
||||||
|
@ -375,7 +377,7 @@ CACHES = {
|
||||||
'password': CONFIG.REDIS_PASSWORD if CONFIG.REDIS_PASSWORD else '',
|
'password': CONFIG.REDIS_PASSWORD if CONFIG.REDIS_PASSWORD else '',
|
||||||
'host': CONFIG.REDIS_HOST or '127.0.0.1',
|
'host': CONFIG.REDIS_HOST or '127.0.0.1',
|
||||||
'port': CONFIG.REDIS_PORT or 6379,
|
'port': CONFIG.REDIS_PORT or 6379,
|
||||||
'db':CONFIG.REDIS_DB_CACHE or 4,
|
'db': CONFIG.REDIS_DB_CACHE or 4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,3 +427,12 @@ TOKEN_EXPIRATION = CONFIG.TOKEN_EXPIRATION or 3600
|
||||||
DISPLAY_PER_PAGE = CONFIG.DISPLAY_PER_PAGE or 25
|
DISPLAY_PER_PAGE = CONFIG.DISPLAY_PER_PAGE or 25
|
||||||
DEFAULT_EXPIRED_YEARS = 70
|
DEFAULT_EXPIRED_YEARS = 70
|
||||||
USER_GUIDE_URL = ""
|
USER_GUIDE_URL = ""
|
||||||
|
|
||||||
|
|
||||||
|
SWAGGER_SETTINGS = {
|
||||||
|
'SECURITY_DEFINITIONS': {
|
||||||
|
'basic': {
|
||||||
|
'type': 'basic'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
|
@ -9,13 +9,28 @@ from rest_framework.response import Response
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.utils.encoding import iri_to_uri
|
from django.utils.encoding import iri_to_uri
|
||||||
|
from rest_framework import permissions
|
||||||
|
|
||||||
from rest_framework.schemas import get_schema_view
|
# from rest_framework.schemas import get_schema_view
|
||||||
from rest_framework_swagger.renderers import SwaggerUIRenderer, OpenAPIRenderer
|
# from rest_framework_swagger.renderers import SwaggerUIRenderer, OpenAPIRenderer
|
||||||
|
from drf_yasg.views import get_schema_view
|
||||||
|
from drf_yasg import openapi
|
||||||
|
|
||||||
from .views import IndexView, LunaView
|
from .views import IndexView, LunaView
|
||||||
|
|
||||||
schema_view = get_schema_view(title='Users API', renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer])
|
# schema_view = get_schema_view(title='Users API', renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer])
|
||||||
|
schema_view = get_schema_view(
|
||||||
|
openapi.Info(
|
||||||
|
title="Snippets API",
|
||||||
|
default_version='v1',
|
||||||
|
description="Test description",
|
||||||
|
terms_of_service="https://www.google.com/policies/terms/",
|
||||||
|
contact=openapi.Contact(email="contact@snippets.local"),
|
||||||
|
license=openapi.License(name="BSD License"),
|
||||||
|
),
|
||||||
|
public=True,
|
||||||
|
permission_classes=(permissions.AllowAny,),
|
||||||
|
)
|
||||||
api_url_pattern = re.compile(r'^/api/(?P<app>\w+)/(?P<version>\w+)/(?P<extra>.*)$')
|
api_url_pattern = re.compile(r'^/api/(?P<app>\w+)/(?P<version>\w+)/(?P<extra>.*)$')
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,5 +100,7 @@ urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
url(r'^docs/', schema_view, name="docs"),
|
url(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=None), name='schema-json'),
|
||||||
|
url(r'^docs/', schema_view.with_ui('swagger', cache_timeout=None), name="docs"),
|
||||||
|
url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=None), name='redoc'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,16 +4,15 @@ from django.http import HttpResponse
|
||||||
from django.views.generic import TemplateView, View
|
from django.views.generic import TemplateView, View
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from assets.models import Asset
|
from assets.models import Asset
|
||||||
from terminal.models import Session
|
from terminal.models import Session
|
||||||
from orgs.mixins import OrgViewGenericMixin
|
from common.permissions import AdminUserRequiredMixin
|
||||||
|
|
||||||
|
|
||||||
class IndexView(LoginRequiredMixin, OrgViewGenericMixin, TemplateView):
|
class IndexView(AdminUserRequiredMixin, TemplateView):
|
||||||
template_name = 'index.html'
|
template_name = 'index.html'
|
||||||
|
|
||||||
session_week = None
|
session_week = None
|
||||||
|
|
|
@ -19,6 +19,8 @@ class TaskViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Task.objects.all()
|
queryset = Task.objects.all()
|
||||||
serializer_class = TaskSerializer
|
serializer_class = TaskSerializer
|
||||||
permission_classes = (IsOrgAdmin,)
|
permission_classes = (IsOrgAdmin,)
|
||||||
|
label = None
|
||||||
|
help_text = ''
|
||||||
|
|
||||||
|
|
||||||
class TaskRun(generics.RetrieveAPIView):
|
class TaskRun(generics.RetrieveAPIView):
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
||||||
|
from rest_framework import viewsets
|
||||||
|
|
||||||
|
from common.permissions import IsOrgAdminOrAppUser
|
||||||
|
from .models import Organization
|
||||||
|
from .serializers import OrgSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class OrgViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = Organization.objects.all()
|
||||||
|
serializer_class = OrgSerializer
|
||||||
|
permission_classes = (IsOrgAdminOrAppUser,)
|
|
@ -1,5 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
from threading import local
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
import warnings
|
import warnings
|
||||||
|
@ -11,9 +13,6 @@ from .utils import current_org, set_current_org
|
||||||
from .models import Organization
|
from .models import Organization
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
from threading import local
|
|
||||||
|
|
||||||
tl = local()
|
tl = local()
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -73,7 +72,7 @@ class OrgModelMixin(models.Model):
|
||||||
|
|
||||||
class OrgViewGenericMixin:
|
class OrgViewGenericMixin:
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
print("Crrent org: {}".format(current_org))
|
print("Current org: {}".format(current_org))
|
||||||
if not current_org:
|
if not current_org:
|
||||||
return redirect('orgs:switch-a-org')
|
return redirect('orgs:switch-a-org')
|
||||||
|
|
||||||
|
@ -83,6 +82,8 @@ class OrgViewGenericMixin:
|
||||||
print("Is org admin")
|
print("Is org admin")
|
||||||
return redirect('orgs:switch-a-org')
|
return redirect('orgs:switch-a-org')
|
||||||
return HttpResponseForbidden()
|
return HttpResponseForbidden()
|
||||||
|
else:
|
||||||
|
print(current_org.can_admin_by(request.user))
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
from .models import Organization
|
||||||
|
|
||||||
|
|
||||||
|
class OrgSerializer(ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Organization
|
||||||
|
fields = '__all__'
|
||||||
|
read_only_fields = ['id', 'created_by', 'date_created']
|
|
@ -2,10 +2,17 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from .. import views
|
|
||||||
|
from rest_framework.routers import DefaultRouter
|
||||||
|
from .. import api
|
||||||
|
|
||||||
|
|
||||||
app_name = 'orgs'
|
app_name = 'orgs'
|
||||||
|
router = DefaultRouter()
|
||||||
|
router.register(r'orgs', api.OrgViewSet, 'org')
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# url(r'^(?P<pk>[0-9a-zA-Z\-]{36})/$', views.OrgDetailView.as_view(), name='asset-index')
|
]
|
||||||
]
|
|
||||||
|
urlpatterns += router.urls
|
||||||
|
|
|
@ -16,6 +16,8 @@ _thread_locals = local()
|
||||||
|
|
||||||
def get_org_from_request(request):
|
def get_org_from_request(request):
|
||||||
oid = request.session.get("oid")
|
oid = request.session.get("oid")
|
||||||
|
if not oid:
|
||||||
|
oid = request.META.get("HTTP_X_JMS_ORG")
|
||||||
org = Organization.get_instance(oid)
|
org = Organization.get_instance(oid)
|
||||||
return org
|
return org
|
||||||
|
|
||||||
|
|
|
@ -250,6 +250,8 @@ function initTree() {
|
||||||
{#$.fn.zTree.init($("#assetTree"), setting);#}
|
{#$.fn.zTree.init($("#assetTree"), setting);#}
|
||||||
$.fn.zTree.init($("#assetTree"), setting, zNodes);
|
$.fn.zTree.init($("#assetTree"), setting, zNodes);
|
||||||
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
||||||
|
var root = zTree.getNodes()[0];
|
||||||
|
zTree.expandNode(root);
|
||||||
{#selectQueryNode();#}
|
{#selectQueryNode();#}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,6 +250,22 @@ function makeLabel(data) {
|
||||||
var jumpserver = {};
|
var jumpserver = {};
|
||||||
jumpserver.checked = false;
|
jumpserver.checked = false;
|
||||||
jumpserver.selected = {};
|
jumpserver.selected = {};
|
||||||
|
jumpserver.language = {
|
||||||
|
processing: "加载中",
|
||||||
|
search: "搜索",
|
||||||
|
lengthMenu: "每页 _MENU_",
|
||||||
|
info: "显示第 _START_ 至 _END_ 项结果; 总共 _TOTAL_ 项",
|
||||||
|
infoFiltered: "",
|
||||||
|
infoEmpty: "",
|
||||||
|
zeroRecords: "没有匹配项",
|
||||||
|
emptyTable: "没有记录",
|
||||||
|
paginate: {
|
||||||
|
first: "«",
|
||||||
|
previous: "‹",
|
||||||
|
next: "›",
|
||||||
|
last: "»"
|
||||||
|
}
|
||||||
|
};
|
||||||
jumpserver.initDataTable = function (options) {
|
jumpserver.initDataTable = function (options) {
|
||||||
// options = {
|
// options = {
|
||||||
// ele *: $('#dataTable_id'),
|
// ele *: $('#dataTable_id'),
|
||||||
|
@ -293,21 +309,7 @@ jumpserver.initDataTable = function (options) {
|
||||||
},
|
},
|
||||||
columns: options.columns || [],
|
columns: options.columns || [],
|
||||||
select: options.select || select,
|
select: options.select || select,
|
||||||
language: {
|
language: jumpserver.language,
|
||||||
search: "搜索",
|
|
||||||
lengthMenu: "每页 _MENU_",
|
|
||||||
info: "显示第 _START_ 至 _END_ 项结果; 总共 _TOTAL_ 项",
|
|
||||||
infoFiltered: "",
|
|
||||||
infoEmpty: "",
|
|
||||||
zeroRecords: "没有匹配项",
|
|
||||||
emptyTable: "没有记录",
|
|
||||||
paginate: {
|
|
||||||
first: "«",
|
|
||||||
previous: "‹",
|
|
||||||
next: "›",
|
|
||||||
last: "»"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
lengthMenu: [[10, 15, 25, 50, -1], [10, 15, 25, 50, "All"]]
|
lengthMenu: [[10, 15, 25, 50, -1], [10, 15, 25, 50, "All"]]
|
||||||
});
|
});
|
||||||
table.on('select', function(e, dt, type, indexes) {
|
table.on('select', function(e, dt, type, indexes) {
|
||||||
|
@ -343,6 +345,16 @@ jumpserver.initDataTable = function (options) {
|
||||||
return table;
|
return table;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jumpserver.initStaticTable = function (selector) {
|
||||||
|
$(selector).DataTable({
|
||||||
|
"searching": false,
|
||||||
|
"bInfo": false,
|
||||||
|
"paging": false,
|
||||||
|
"order": [],
|
||||||
|
"language": jumpserver.language
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
jumpserver.initServerSideDataTable = function (options) {
|
jumpserver.initServerSideDataTable = function (options) {
|
||||||
// options = {
|
// options = {
|
||||||
// ele *: $('#dataTable_id'),
|
// ele *: $('#dataTable_id'),
|
||||||
|
@ -374,11 +386,11 @@ jumpserver.initServerSideDataTable = function (options) {
|
||||||
selector: 'td:first-child'
|
selector: 'td:first-child'
|
||||||
};
|
};
|
||||||
var table = ele.DataTable({
|
var table = ele.DataTable({
|
||||||
pageLength: options.pageLength || 15,
|
// pageLength: options.pageLength || 15,
|
||||||
dom: options.dom || '<"#uc.pull-left">flt<"row m-t"<"col-md-8"<"#op.col-md-6"><"col-md-6 text-center"i>><"col-md-4"p>>',
|
// dom: options.dom || '<"#uc.pull-left">flt<"row m-t"<"col-md-8"<"#op.col-md-6"><"col-md-6 text-center"i>><"col-md-4"p>>',
|
||||||
order: options.order || [],
|
// order: options.order || [],
|
||||||
// select: options.select || 'multi',
|
// select: options.select || 'multi',
|
||||||
buttons: [],
|
// buttons: [],
|
||||||
columnDefs: columnDefs,
|
columnDefs: columnDefs,
|
||||||
serverSide: true,
|
serverSide: true,
|
||||||
processing: true,
|
processing: true,
|
||||||
|
@ -432,21 +444,7 @@ jumpserver.initServerSideDataTable = function (options) {
|
||||||
},
|
},
|
||||||
columns: options.columns || [],
|
columns: options.columns || [],
|
||||||
select: options.select || select,
|
select: options.select || select,
|
||||||
language: {
|
language: jumpserver.language,
|
||||||
search: "搜索",
|
|
||||||
lengthMenu: "每页 _MENU_",
|
|
||||||
info: "显示第 _START_ 至 _END_ 项结果; 总共 _TOTAL_ 项",
|
|
||||||
infoFiltered: "",
|
|
||||||
infoEmpty: "",
|
|
||||||
zeroRecords: "没有匹配项",
|
|
||||||
emptyTable: "没有记录",
|
|
||||||
paginate: {
|
|
||||||
first: "«",
|
|
||||||
previous: "‹",
|
|
||||||
next: "›",
|
|
||||||
last: "»"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
lengthMenu: [[10, 15, 25, 50], [10, 15, 25, 50]]
|
lengthMenu: [[10, 15, 25, 50], [10, 15, 25, 50]]
|
||||||
});
|
});
|
||||||
table.selected = [];
|
table.selected = [];
|
||||||
|
|
|
@ -64,9 +64,12 @@
|
||||||
<span class="nav-label">{% trans 'Web terminal' %}</span>
|
<span class="nav-label">{% trans 'Web terminal' %}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% if request.user.is_superuser %}
|
||||||
<li id="terminal"><a href="{% url 'terminal:terminal-list' %}">{% trans 'Terminal' %}</a></li>
|
<li id="terminal"><a href="{% url 'terminal:terminal-list' %}">{% trans 'Terminal' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
{% if request.user.is_superuser %}
|
||||||
<li id="ops">
|
<li id="ops">
|
||||||
<a>
|
<a>
|
||||||
<i class="fa fa-coffee" style="width: 14px"></i> <span class="nav-label">{% trans 'Job Center' %}</span><span class="fa arrow"></span>
|
<i class="fa fa-coffee" style="width: 14px"></i> <span class="nav-label">{% trans 'Job Center' %}</span><span class="fa arrow"></span>
|
||||||
|
@ -75,6 +78,7 @@
|
||||||
<li id="task"><a href="{% url 'ops:task-list' %}">{% trans 'Task list' %}</a></li>
|
<li id="task"><a href="{% url 'ops:task-list' %}">{% trans 'Task list' %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
<li id="audits">
|
<li id="audits">
|
||||||
<a>
|
<a>
|
||||||
<i class="fa fa-history" style="width: 14px"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span>
|
<i class="fa fa-history" style="width: 14px"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span>
|
||||||
|
@ -92,11 +96,13 @@
|
||||||
{# <li id="download"><a href="">{% trans 'File download' %}</a></li>#}
|
{# <li id="download"><a href="">{% trans 'File download' %}</a></li>#}
|
||||||
{# </ul>#}
|
{# </ul>#}
|
||||||
{#</li>#}
|
{#</li>#}
|
||||||
|
{% if request.user.is_superuser %}
|
||||||
<li id="settings">
|
<li id="settings">
|
||||||
<a href="{% url 'settings:basic-setting' %}">
|
<a href="{% url 'settings:basic-setting' %}">
|
||||||
<i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span>
|
<i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
|
|
@ -150,12 +150,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('table').DataTable({
|
jumpserver.initStaticTable('table');
|
||||||
"searching": false,
|
|
||||||
"paging": false,
|
|
||||||
"bInfo" : false,
|
|
||||||
"order": []
|
|
||||||
});
|
|
||||||
$('.select2').select2({
|
$('.select2').select2({
|
||||||
dropdownAutoWidth: true,
|
dropdownAutoWidth: true,
|
||||||
width: "auto"
|
width: "auto"
|
||||||
|
|
|
@ -10,10 +10,10 @@ from .. import api
|
||||||
app_name = 'terminal'
|
app_name = 'terminal'
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
|
router.register(r'terminal', api.TerminalViewSet, 'terminal2')
|
||||||
router.register(r'terminal/(?P<terminal>[a-zA-Z0-9\-]{36})?/?status', api.StatusViewSet, 'terminal-status')
|
router.register(r'terminal/(?P<terminal>[a-zA-Z0-9\-]{36})?/?status', api.StatusViewSet, 'terminal-status')
|
||||||
router.register(r'terminal/(?P<terminal>[a-zA-Z0-9\-]{36})?/?sessions', api.SessionViewSet, 'terminal-sessions')
|
router.register(r'terminal/(?P<terminal>[a-zA-Z0-9\-]{36})?/?sessions', api.SessionViewSet, 'terminal-sessions')
|
||||||
router.register(r'tasks', api.TaskViewSet, 'tasks')
|
router.register(r'tasks', api.TaskViewSet, 'tasks')
|
||||||
router.register(r'terminal', api.TerminalViewSet, 'terminal')
|
|
||||||
router.register(r'command', api.CommandViewSet, 'command')
|
router.register(r'command', api.CommandViewSet, 'command')
|
||||||
router.register(r'sessions', api.SessionViewSet, 'session')
|
router.register(r'sessions', api.SessionViewSet, 'session')
|
||||||
router.register(r'status', api.StatusViewSet, 'session')
|
router.register(r'status', api.StatusViewSet, 'session')
|
||||||
|
|
|
@ -195,7 +195,7 @@ class User(AbstractUser):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_org_admin(self):
|
def is_org_admin(self):
|
||||||
if self.is_superuser or self.admin_orgs:
|
if self.is_superuser or self.admin_orgs.exists():
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
@ -223,7 +223,7 @@ class User(AbstractUser):
|
||||||
self.is_active = True
|
self.is_active = True
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
if current_org and current_org.is_real():
|
if current_org and current_org.is_real():
|
||||||
self.orgs.add(current_org)
|
self.orgs.add(current_org.id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def private_token(self):
|
def private_token(self):
|
||||||
|
|
|
@ -80,12 +80,7 @@
|
||||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('table').DataTable({
|
jumpserver.initStaticTable('table');
|
||||||
"searching": false,
|
|
||||||
"bInfo" : false,
|
|
||||||
"paging": false,
|
|
||||||
"order": []
|
|
||||||
});
|
|
||||||
$('#date .input-daterange').datepicker({
|
$('#date .input-daterange').datepicker({
|
||||||
format: "yyyy-mm-dd",
|
format: "yyyy-mm-dd",
|
||||||
todayBtn: "linked",
|
todayBtn: "linked",
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# ~*~ coding: utf-8 ~*~
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from django import forms
|
|
||||||
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
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
|
@ -11,9 +10,8 @@ from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from common.const import create_success_msg, update_success_msg
|
from common.const import create_success_msg, update_success_msg
|
||||||
from orgs.mixins import OrgViewGenericMixin
|
|
||||||
from ..models import User, UserGroup
|
|
||||||
from common.permissions import AdminUserRequiredMixin
|
from common.permissions import AdminUserRequiredMixin
|
||||||
|
from ..models import User, UserGroup
|
||||||
from .. import forms
|
from .. import forms
|
||||||
|
|
||||||
__all__ = ['UserGroupListView', 'UserGroupCreateView', 'UserGroupDetailView',
|
__all__ = ['UserGroupListView', 'UserGroupCreateView', 'UserGroupDetailView',
|
||||||
|
@ -21,7 +19,7 @@ __all__ = ['UserGroupListView', 'UserGroupCreateView', 'UserGroupDetailView',
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class UserGroupListView(AdminUserRequiredMixin, OrgViewGenericMixin, TemplateView):
|
class UserGroupListView(AdminUserRequiredMixin, TemplateView):
|
||||||
template_name = 'users/user_group_list.html'
|
template_name = 'users/user_group_list.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -33,8 +31,7 @@ class UserGroupListView(AdminUserRequiredMixin, OrgViewGenericMixin, TemplateVie
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class UserGroupCreateView(AdminUserRequiredMixin, OrgViewGenericMixin,
|
class UserGroupCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
SuccessMessageMixin, CreateView):
|
|
||||||
model = UserGroup
|
model = UserGroup
|
||||||
form_class = forms.UserGroupForm
|
form_class = forms.UserGroupForm
|
||||||
template_name = 'users/user_group_create_update.html'
|
template_name = 'users/user_group_create_update.html'
|
||||||
|
@ -50,8 +47,7 @@ class UserGroupCreateView(AdminUserRequiredMixin, OrgViewGenericMixin,
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class UserGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin,
|
class UserGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
OrgViewGenericMixin, UpdateView):
|
|
||||||
model = UserGroup
|
model = UserGroup
|
||||||
form_class = forms.UserGroupForm
|
form_class = forms.UserGroupForm
|
||||||
template_name = 'users/user_group_create_update.html'
|
template_name = 'users/user_group_create_update.html'
|
||||||
|
@ -71,7 +67,7 @@ class UserGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin,
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class UserGroupDetailView(AdminUserRequiredMixin, OrgViewGenericMixin, DetailView):
|
class UserGroupDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
model = UserGroup
|
model = UserGroup
|
||||||
context_object_name = 'user_group'
|
context_object_name = 'user_group'
|
||||||
template_name = 'users/user_group_detail.html'
|
template_name = 'users/user_group_detail.html'
|
||||||
|
@ -87,7 +83,7 @@ class UserGroupDetailView(AdminUserRequiredMixin, OrgViewGenericMixin, DetailVie
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class UserGroupGrantedAssetView(AdminUserRequiredMixin, OrgViewGenericMixin, DetailView):
|
class UserGroupGrantedAssetView(AdminUserRequiredMixin, DetailView):
|
||||||
model = UserGroup
|
model = UserGroup
|
||||||
template_name = 'users/user_group_granted_asset.html'
|
template_name = 'users/user_group_granted_asset.html'
|
||||||
context_object_name = 'user_group'
|
context_object_name = 'user_group'
|
||||||
|
|
|
@ -308,7 +308,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
|
||||||
file_storage = default_storage
|
file_storage = default_storage
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if request.user.is_authenticated() and not request.user.is_first_login:
|
if request.user.is_authenticated and not request.user.is_first_login:
|
||||||
return redirect(reverse('index'))
|
return redirect(reverse('index'))
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ __all__ = [
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class UserListView(TemplateView):
|
class UserListView(AdminUserRequiredMixin, TemplateView):
|
||||||
template_name = 'users/user_list.html'
|
template_name = 'users/user_list.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
|
|
@ -14,7 +14,8 @@ coreapi==2.3.3
|
||||||
coreschema==0.0.4
|
coreschema==0.0.4
|
||||||
cryptography==2.1.4
|
cryptography==2.1.4
|
||||||
decorator==4.1.2
|
decorator==4.1.2
|
||||||
Django==1.11
|
#Django==1.11
|
||||||
|
#Django==2.0.7
|
||||||
django-auth-ldap==1.3.0
|
django-auth-ldap==1.3.0
|
||||||
django-bootstrap3==9.1.0
|
django-bootstrap3==9.1.0
|
||||||
django-celery-beat==1.1.1
|
django-celery-beat==1.1.1
|
||||||
|
@ -24,7 +25,8 @@ django-ranged-response==0.2.0
|
||||||
django-redis-cache==1.7.1
|
django-redis-cache==1.7.1
|
||||||
django-rest-swagger==2.1.2
|
django-rest-swagger==2.1.2
|
||||||
django-simple-captcha==0.5.6
|
django-simple-captcha==0.5.6
|
||||||
djangorestframework==3.7.3
|
#djangorestframework==3.7.3
|
||||||
|
djangorestframework==3.8.2
|
||||||
djangorestframework-bulk==0.2.1
|
djangorestframework-bulk==0.2.1
|
||||||
docutils==0.14
|
docutils==0.14
|
||||||
ecdsa==0.13
|
ecdsa==0.13
|
||||||
|
@ -69,3 +71,4 @@ sshpubkeys==2.2.0
|
||||||
uritemplate==3.0.0
|
uritemplate==3.0.0
|
||||||
urllib3==1.22
|
urllib3==1.22
|
||||||
vine==1.1.4
|
vine==1.1.4
|
||||||
|
drf-yasg==1.9.1
|
||||||
|
|
Loading…
Reference in New Issue