Unverified Commit b156f4ad authored by 老广's avatar 老广 Committed by GitHub

Tmp org (#1579)

* [Update] 添加org api, 升级到django 2.0

* [Update] fix some bug

* [Update] 修改一些bug
parent c816875f
......@@ -2,8 +2,9 @@
#
import random
import time
from rest_framework import generics
from rest_framework import generics, permissions
from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
......@@ -39,9 +40,10 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
queryset = Asset.objects.all()
serializer_class = serializers.AssetSerializer
pagination_class = LimitOffsetPagination
permission_classes = (IsOrgAdminOrAppUser,)
permission_classes = (permissions.AllowAny,)
def get_queryset(self):
time.sleep(3)
queryset = super().get_queryset()\
.prefetch_related('labels', 'nodes')\
.select_related('admin_user')
......
......@@ -2,12 +2,11 @@
from rest_framework_bulk import BulkModelViewSet
from rest_framework.views import APIView, Response
from rest_condition import Or
from django.views.generic.detail import SingleObjectMixin
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 ..utils import test_gateway_connectability
from .. import serializers
......
......@@ -44,7 +44,7 @@ class Gateway(AssetUser):
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
port = models.IntegerField(default=22, verbose_name=_('Port'))
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"))
is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
......
......@@ -35,6 +35,20 @@
.dropdown a:hover {
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>
{% endblock %}
......
......@@ -44,7 +44,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
template_name = 'assets/asset_list.html'
def get_context_data(self, **kwargs):
print(Node.root().name)
Node.root()
context = {
'app': _('Assets'),
'action': _('Asset list'),
......
......@@ -86,7 +86,18 @@ class LDAPTestingAPI(APIView):
class DjangoSettingsAPI(APIView):
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 django.contrib.auth.mixins import UserPassesTestMixin
from django.shortcuts import redirect
from django.http.response import HttpResponseForbidden
from orgs.utils import current_org
......@@ -23,6 +25,18 @@ class IsAppUser(IsValidUser):
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):
"""Allows access only to superuser"""
......@@ -63,3 +77,18 @@ class AdminUserRequiredMixin(UserPassesTestMixin):
self.raise_exception = True
return False
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 = [
url(r'^mail/testing/$', api.MailTestingAPI.as_view(), name='mail-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',
'rest_framework',
'rest_framework_swagger',
'drf_yasg',
'django_filters',
'bootstrap3',
'captcha',
......@@ -230,7 +231,7 @@ LOGGING = {
'level': LOG_LEVEL,
},
'django_auth_ldap': {
'handlers': ['console', 'ansible_logs'],
'handlers': ['console', 'file'],
'level': "INFO",
},
# 'django.db': {
......@@ -294,6 +295,7 @@ REST_FRAMEWORK = {
'common.permissions.IsOrgAdmin',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'users.authentication.AccessKeyAuthentication',
'users.authentication.AccessTokenAuthentication',
'users.authentication.PrivateTokenAuthentication',
......@@ -375,7 +377,7 @@ CACHES = {
'password': CONFIG.REDIS_PASSWORD if CONFIG.REDIS_PASSWORD else '',
'host': CONFIG.REDIS_HOST or '127.0.0.1',
'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
DEFAULT_EXPIRED_YEARS = 70
USER_GUIDE_URL = ""
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'basic': {
'type': 'basic'
}
},
}
\ No newline at end of file
......@@ -9,13 +9,28 @@ from rest_framework.response import Response
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.utils.encoding import iri_to_uri
from rest_framework import permissions
from rest_framework.schemas import get_schema_view
from rest_framework_swagger.renderers import SwaggerUIRenderer, OpenAPIRenderer
# from rest_framework.schemas import get_schema_view
# 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
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>.*)$')
......@@ -85,5 +100,7 @@ urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \
if settings.DEBUG:
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.utils import timezone
from django.db.models import Count
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import redirect
from users.models import User
from assets.models import Asset
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'
session_week = None
......
......@@ -19,6 +19,8 @@ class TaskViewSet(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
permission_classes = (IsOrgAdmin,)
label = None
help_text = ''
class TaskRun(generics.RetrieveAPIView):
......
# -*- 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,)
# -*- coding: utf-8 -*-
#
from threading import local
from django.db import models
from django.shortcuts import redirect
import warnings
......@@ -11,9 +13,6 @@ from .utils import current_org, set_current_org
from .models import Organization
logger = get_logger(__file__)
from threading import local
tl = local()
__all__ = [
......@@ -73,7 +72,7 @@ class OrgModelMixin(models.Model):
class OrgViewGenericMixin:
def dispatch(self, request, *args, **kwargs):
print("Crrent org: {}".format(current_org))
print("Current org: {}".format(current_org))
if not current_org:
return redirect('orgs:switch-a-org')
......@@ -83,6 +82,8 @@ class OrgViewGenericMixin:
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)
......
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 .. import views
from rest_framework.routers import DefaultRouter
from .. import api
app_name = 'orgs'
router = DefaultRouter()
router.register(r'orgs', api.OrgViewSet, 'org')
urlpatterns = [
# url(r'^(?P<pk>[0-9a-zA-Z\-]{36})/$', views.OrgDetailView.as_view(), name='asset-index')
]
\ No newline at end of file
]
urlpatterns += router.urls
......@@ -16,6 +16,8 @@ _thread_locals = local()
def get_org_from_request(request):
oid = request.session.get("oid")
if not oid:
oid = request.META.get("HTTP_X_JMS_ORG")
org = Organization.get_instance(oid)
return org
......
......@@ -250,6 +250,8 @@ function initTree() {
{#$.fn.zTree.init($("#assetTree"), setting);#}
$.fn.zTree.init($("#assetTree"), setting, zNodes);
zTree = $.fn.zTree.getZTreeObj("assetTree");
var root = zTree.getNodes()[0];
zTree.expandNode(root);
{#selectQueryNode();#}
});
}
......
......@@ -250,6 +250,22 @@ function makeLabel(data) {
var jumpserver = {};
jumpserver.checked = false;
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) {
// options = {
// ele *: $('#dataTable_id'),
......@@ -293,21 +309,7 @@ jumpserver.initDataTable = function (options) {
},
columns: options.columns || [],
select: options.select || select,
language: {
search: "搜索",
lengthMenu: "每页 _MENU_",
info: "显示第 _START_ 至 _END_ 项结果; 总共 _TOTAL_ 项",
infoFiltered: "",
infoEmpty: "",
zeroRecords: "没有匹配项",
emptyTable: "没有记录",
paginate: {
first: "«",
previous: "‹",
next: "›",
last: "»"
}
},
language: jumpserver.language,
lengthMenu: [[10, 15, 25, 50, -1], [10, 15, 25, 50, "All"]]
});
table.on('select', function(e, dt, type, indexes) {
......@@ -343,6 +345,16 @@ jumpserver.initDataTable = function (options) {
return table;
};
jumpserver.initStaticTable = function (selector) {
$(selector).DataTable({
"searching": false,
"bInfo": false,
"paging": false,
"order": [],
"language": jumpserver.language
});
};
jumpserver.initServerSideDataTable = function (options) {
// options = {
// ele *: $('#dataTable_id'),
......@@ -374,11 +386,11 @@ jumpserver.initServerSideDataTable = function (options) {
selector: 'td:first-child'
};
var table = ele.DataTable({
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>>',
order: options.order || [],
// 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>>',
// order: options.order || [],
// select: options.select || 'multi',
buttons: [],
// buttons: [],
columnDefs: columnDefs,
serverSide: true,
processing: true,
......@@ -432,21 +444,7 @@ jumpserver.initServerSideDataTable = function (options) {
},
columns: options.columns || [],
select: options.select || select,
language: {
search: "搜索",
lengthMenu: "每页 _MENU_",
info: "显示第 _START_ 至 _END_ 项结果; 总共 _TOTAL_ 项",
infoFiltered: "",
infoEmpty: "",
zeroRecords: "没有匹配项",
emptyTable: "没有记录",
paginate: {
first: "«",
previous: "‹",
next: "›",
last: "»"
}
},
language: jumpserver.language,
lengthMenu: [[10, 15, 25, 50], [10, 15, 25, 50]]
});
table.selected = [];
......
......@@ -64,9 +64,12 @@
<span class="nav-label">{% trans 'Web terminal' %}</span>
</a>
</li>
{% if request.user.is_superuser %}
<li id="terminal"><a href="{% url 'terminal:terminal-list' %}">{% trans 'Terminal' %}</a></li>
{% endif %}
</ul>
</li>
{% if request.user.is_superuser %}
<li id="ops">
<a>
<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>
</ul>
</li>
{% endif %}
<li id="audits">
<a>
<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>#}
{# </ul>#}
{#</li>#}
{% if request.user.is_superuser %}
<li id="settings">
<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>
</a>
</li>
{% endif %}
<script>
$(document).ready(function () {
......
......@@ -150,12 +150,7 @@
});
}
$(document).ready(function() {
$('table').DataTable({
"searching": false,
"paging": false,
"bInfo" : false,
"order": []
});
jumpserver.initStaticTable('table');
$('.select2').select2({
dropdownAutoWidth: true,
width: "auto"
......
......@@ -10,10 +10,10 @@ from .. import api
app_name = 'terminal'
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})?/?sessions', api.SessionViewSet, 'terminal-sessions')
router.register(r'tasks', api.TaskViewSet, 'tasks')
router.register(r'terminal', api.TerminalViewSet, 'terminal')
router.register(r'command', api.CommandViewSet, 'command')
router.register(r'sessions', api.SessionViewSet, 'session')
router.register(r'status', api.StatusViewSet, 'session')
......
......@@ -195,7 +195,7 @@ class User(AbstractUser):
@property
def is_org_admin(self):
if self.is_superuser or self.admin_orgs:
if self.is_superuser or self.admin_orgs.exists():
return True
else:
return False
......@@ -223,7 +223,7 @@ class User(AbstractUser):
self.is_active = True
super().save(*args, **kwargs)
if current_org and current_org.is_real():
self.orgs.add(current_org)
self.orgs.add(current_org.id)
@property
def private_token(self):
......
......@@ -80,12 +80,7 @@
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function() {
$('table').DataTable({
"searching": false,
"bInfo" : false,
"paging": false,
"order": []
});
jumpserver.initStaticTable('table');
$('#date .input-daterange').datepicker({
format: "yyyy-mm-dd",
todayBtn: "linked",
......
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
from django import forms
from django.utils.translation import ugettext as _
from django.urls import reverse_lazy
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.const import create_success_msg, update_success_msg
from orgs.mixins import OrgViewGenericMixin
from ..models import User, UserGroup
from common.permissions import AdminUserRequiredMixin
from ..models import User, UserGroup
from .. import forms
__all__ = ['UserGroupListView', 'UserGroupCreateView', 'UserGroupDetailView',
......@@ -21,7 +19,7 @@ __all__ = ['UserGroupListView', 'UserGroupCreateView', 'UserGroupDetailView',
logger = get_logger(__name__)
class UserGroupListView(AdminUserRequiredMixin, OrgViewGenericMixin, TemplateView):
class UserGroupListView(AdminUserRequiredMixin, TemplateView):
template_name = 'users/user_group_list.html'
def get_context_data(self, **kwargs):
......@@ -33,8 +31,7 @@ class UserGroupListView(AdminUserRequiredMixin, OrgViewGenericMixin, TemplateVie
return super().get_context_data(**kwargs)
class UserGroupCreateView(AdminUserRequiredMixin, OrgViewGenericMixin,
SuccessMessageMixin, CreateView):
class UserGroupCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
model = UserGroup
form_class = forms.UserGroupForm
template_name = 'users/user_group_create_update.html'
......@@ -50,8 +47,7 @@ class UserGroupCreateView(AdminUserRequiredMixin, OrgViewGenericMixin,
return super().get_context_data(**kwargs)
class UserGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin,
OrgViewGenericMixin, UpdateView):
class UserGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
model = UserGroup
form_class = forms.UserGroupForm
template_name = 'users/user_group_create_update.html'
......@@ -71,7 +67,7 @@ class UserGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin,
return super().get_context_data(**kwargs)
class UserGroupDetailView(AdminUserRequiredMixin, OrgViewGenericMixin, DetailView):
class UserGroupDetailView(AdminUserRequiredMixin, DetailView):
model = UserGroup
context_object_name = 'user_group'
template_name = 'users/user_group_detail.html'
......@@ -87,7 +83,7 @@ class UserGroupDetailView(AdminUserRequiredMixin, OrgViewGenericMixin, DetailVie
return super().get_context_data(**kwargs)
class UserGroupGrantedAssetView(AdminUserRequiredMixin, OrgViewGenericMixin, DetailView):
class UserGroupGrantedAssetView(AdminUserRequiredMixin, DetailView):
model = UserGroup
template_name = 'users/user_group_granted_asset.html'
context_object_name = 'user_group'
......
......@@ -308,7 +308,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
file_storage = default_storage
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 super().dispatch(request, *args, **kwargs)
......
......@@ -57,7 +57,7 @@ __all__ = [
logger = get_logger(__name__)
class UserListView(TemplateView):
class UserListView(AdminUserRequiredMixin, TemplateView):
template_name = 'users/user_list.html'
def get_context_data(self, **kwargs):
......
......@@ -14,7 +14,8 @@ coreapi==2.3.3
coreschema==0.0.4
cryptography==2.1.4
decorator==4.1.2
Django==1.11
#Django==1.11
#Django==2.0.7
django-auth-ldap==1.3.0
django-bootstrap3==9.1.0
django-celery-beat==1.1.1
......@@ -24,7 +25,8 @@ django-ranged-response==0.2.0
django-redis-cache==1.7.1
django-rest-swagger==2.1.2
django-simple-captcha==0.5.6
djangorestframework==3.7.3
#djangorestframework==3.7.3
djangorestframework==3.8.2
djangorestframework-bulk==0.2.1
docutils==0.14
ecdsa==0.13
......@@ -69,3 +71,4 @@ sshpubkeys==2.2.0
uritemplate==3.0.0
urllib3==1.22
vine==1.1.4
drf-yasg==1.9.1
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