From e3aa18ff2d689fc8d15b8e5b991f9887cf67a2d6 Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 20 Jul 2018 17:49:47 +0800 Subject: [PATCH] =?UTF-8?q?[Update]=20=E4=BF=AE=E6=94=B9get=5Fcurrent=5For?= =?UTF-8?q?g=20=E4=B8=BA=20proxy=E5=AF=B9=E8=B1=A1=20current=5Forg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/node.py | 1 - apps/assets/models/node.py | 7 +- apps/assets/templates/assets/asset_list.html | 4 +- apps/assets/views/asset.py | 2 +- apps/common/utils.py | 120 +++++++++++++++++++ apps/jumpserver/views.py | 2 +- apps/orgs/context_processor.py | 4 +- apps/orgs/mixins.py | 15 ++- apps/orgs/models.py | 11 +- apps/orgs/utils.py | 15 ++- apps/perms/forms.py | 3 +- apps/templates/_header_bar.html | 2 +- apps/templates/_left_side_bar.html | 2 +- apps/users/api.py | 3 +- apps/users/forms.py | 6 +- apps/users/models/user.py | 3 +- apps/users/views/login.py | 3 +- apps/users/views/user.py | 2 +- 18 files changed, 171 insertions(+), 34 deletions(-) diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index 178642170..30887ff22 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -22,7 +22,6 @@ from django.utils.translation import ugettext_lazy as _ from django.shortcuts import get_object_or_404 from common.utils import get_logger, get_object_or_none -from orgs.utils import get_current_org from ..hands import IsSuperUser from ..models import Node from ..tasks import update_assets_hardware_info_util, test_asset_connectability_util diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index 43f8d480c..b1aa5cb3d 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -7,7 +7,7 @@ from django.db.models import Q from django.utils.translation import ugettext_lazy as _ from orgs.mixins import OrgModelMixin -from orgs.utils import get_current_org, set_current_org +from orgs.utils import current_org, set_current_org from orgs.models import Organization __all__ = ['Node'] @@ -170,13 +170,12 @@ class Node(OrgModelMixin): @classmethod def create_root_node(cls): with transaction.atomic(): - org = get_current_org() set_current_org(Organization.root()) org_nodes_roots = cls.objects.filter(key__regex=r'^[0-9]+$') org_nodes_roots_keys = org_nodes_roots.values_list('key', flat=True) max_value = max([int(k) for k in org_nodes_roots_keys]) if org_nodes_roots_keys else 0 - set_current_org(org) - root = cls.objects.create(key=max_value+1, value=org.name) + set_current_org(current_org) + root = cls.objects.create(key=max_value+1, value=current_org.name) return root @classmethod diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html index 01c325946..8e9f9d250 100644 --- a/apps/assets/templates/assets/asset_list.html +++ b/apps/assets/templates/assets/asset_list.html @@ -721,9 +721,7 @@ $(document).ready(function(){ return } - var data = { - 'assets': assets_selected - }; + var data = {'assets': assets_selected}; var success = function () { asset_table2.selected = []; asset_table2.ajax.reload() diff --git a/apps/assets/views/asset.py b/apps/assets/views/asset.py index e6d19b75f..ff9462503 100644 --- a/apps/assets/views/asset.py +++ b/apps/assets/views/asset.py @@ -211,7 +211,7 @@ class AssetExportView(View): fields = [ field for field in Asset._meta.fields if field.name not in [ - 'date_created' + 'date_created', 'org_id' ] ] filename = 'assets-{}.csv'.format( diff --git a/apps/common/utils.py b/apps/common/utils.py index deaeb5280..7d4b9af64 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -17,6 +17,7 @@ import threading from io import StringIO import uuid from functools import wraps +import copy import paramiko import sshpubkeys @@ -410,3 +411,122 @@ def with_cache(func): cache[key] = res return res return wrapper + + +class LocalProxy(object): + + """ + Copy from werkzeug.local.LocalProxy + """ + __slots__ = ('__local', '__dict__', '__name__', '__wrapped__') + + def __init__(self, local, name=None): + object.__setattr__(self, '_LocalProxy__local', local) + object.__setattr__(self, '__name__', name) + if callable(local) and not hasattr(local, '__release_local__'): + # "local" is a callable that is not an instance of Local or + # LocalManager: mark it as a wrapped function. + object.__setattr__(self, '__wrapped__', local) + + def _get_current_object(self): + """Return the current object. This is useful if you want the real + object behind the proxy at a time for performance reasons or because + you want to pass the object into a different context. + """ + if not hasattr(self.__local, '__release_local__'): + return self.__local() + try: + return getattr(self.__local, self.__name__) + except AttributeError: + raise RuntimeError('no object bound to %s' % self.__name__) + + @property + def __dict__(self): + try: + return self._get_current_object().__dict__ + except RuntimeError: + raise AttributeError('__dict__') + + def __repr__(self): + try: + obj = self._get_current_object() + except RuntimeError: + return '<%s unbound>' % self.__class__.__name__ + return repr(obj) + + def __bool__(self): + try: + return bool(self._get_current_object()) + except RuntimeError: + return False + + def __dir__(self): + try: + return dir(self._get_current_object()) + except RuntimeError: + return [] + + def __getattr__(self, name): + if name == '__members__': + return dir(self._get_current_object()) + return getattr(self._get_current_object(), name) + + def __setitem__(self, key, value): + self._get_current_object()[key] = value + + def __delitem__(self, key): + del self._get_current_object()[key] + + __setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v) + __delattr__ = lambda x, n: delattr(x._get_current_object(), n) + __str__ = lambda x: str(x._get_current_object()) + __lt__ = lambda x, o: x._get_current_object() < o + __le__ = lambda x, o: x._get_current_object() <= o + __eq__ = lambda x, o: x._get_current_object() == o + __ne__ = lambda x, o: x._get_current_object() != o + __gt__ = lambda x, o: x._get_current_object() > o + __ge__ = lambda x, o: x._get_current_object() >= o + __cmp__ = lambda x, o: cmp(x._get_current_object(), o) # noqa + __hash__ = lambda x: hash(x._get_current_object()) + __call__ = lambda x, *a, **kw: x._get_current_object()(*a, **kw) + __len__ = lambda x: len(x._get_current_object()) + __getitem__ = lambda x, i: x._get_current_object()[i] + __iter__ = lambda x: iter(x._get_current_object()) + __contains__ = lambda x, i: i in x._get_current_object() + __add__ = lambda x, o: x._get_current_object() + o + __sub__ = lambda x, o: x._get_current_object() - o + __mul__ = lambda x, o: x._get_current_object() * o + __floordiv__ = lambda x, o: x._get_current_object() // o + __mod__ = lambda x, o: x._get_current_object() % o + __divmod__ = lambda x, o: x._get_current_object().__divmod__(o) + __pow__ = lambda x, o: x._get_current_object() ** o + __lshift__ = lambda x, o: x._get_current_object() << o + __rshift__ = lambda x, o: x._get_current_object() >> o + __and__ = lambda x, o: x._get_current_object() & o + __xor__ = lambda x, o: x._get_current_object() ^ o + __or__ = lambda x, o: x._get_current_object() | o + __div__ = lambda x, o: x._get_current_object().__div__(o) + __truediv__ = lambda x, o: x._get_current_object().__truediv__(o) + __neg__ = lambda x: -(x._get_current_object()) + __pos__ = lambda x: +(x._get_current_object()) + __abs__ = lambda x: abs(x._get_current_object()) + __invert__ = lambda x: ~(x._get_current_object()) + __complex__ = lambda x: complex(x._get_current_object()) + __int__ = lambda x: int(x._get_current_object()) + __float__ = lambda x: float(x._get_current_object()) + __oct__ = lambda x: oct(x._get_current_object()) + __hex__ = lambda x: hex(x._get_current_object()) + __index__ = lambda x: x._get_current_object().__index__() + __coerce__ = lambda x, o: x._get_current_object().__coerce__(x, o) + __enter__ = lambda x: x._get_current_object().__enter__() + __exit__ = lambda x, *a, **kw: x._get_current_object().__exit__(*a, **kw) + __radd__ = lambda x, o: o + x._get_current_object() + __rsub__ = lambda x, o: o - x._get_current_object() + __rmul__ = lambda x, o: o * x._get_current_object() + __rdiv__ = lambda x, o: o / x._get_current_object() + __rtruediv__ = __rdiv__ + __rfloordiv__ = lambda x, o: o // x._get_current_object() + __rmod__ = lambda x, o: o % x._get_current_object() + __rdivmod__ = lambda x, o: x._get_current_object().__rdivmod__(o) + __copy__ = lambda x: copy.copy(x._get_current_object()) + __deepcopy__ = lambda x, memo: copy.deepcopy(x._get_current_object(), memo) \ No newline at end of file diff --git a/apps/jumpserver/views.py b/apps/jumpserver/views.py index 1ad2bb20f..323f71dd2 100644 --- a/apps/jumpserver/views.py +++ b/apps/jumpserver/views.py @@ -22,7 +22,7 @@ class IndexView(LoginRequiredMixin, OrgViewGenericMixin, TemplateView): session_month_dates_archive = [] def get(self, request, *args, **kwargs): - if not request.user.is_superuser: + if not request.user.is_org_admin: return redirect('assets:user-asset-list') return super(IndexView, self).get(request, *args, **kwargs) diff --git a/apps/orgs/context_processor.py b/apps/orgs/context_processor.py index aa89d3a54..15285c99e 100644 --- a/apps/orgs/context_processor.py +++ b/apps/orgs/context_processor.py @@ -1,14 +1,16 @@ # -*- coding: utf-8 -*- # -from .utils import get_current_org +from .utils import current_org, get_current_org from .models import Organization def org_processor(request): + print('Crernt Org', current_org.name) context = { 'ADMIN_ORGS': Organization.get_user_admin_orgs(request.user), 'CURRENT_ORG': get_current_org(), + 'HAS_ORG_PERM': current_org.can_admin_by(request.user), } return context diff --git a/apps/orgs/mixins.py b/apps/orgs/mixins.py index ec77c4cfd..215518e68 100644 --- a/apps/orgs/mixins.py +++ b/apps/orgs/mixins.py @@ -4,9 +4,10 @@ from django.db import models from django.shortcuts import redirect import warnings from django.forms import ModelForm +from django.http.response import HttpResponseForbidden from common.utils import get_logger -from .utils import get_current_org, set_current_org +from .utils import current_org, set_current_org from .models import Organization logger = get_logger(__file__) @@ -23,7 +24,6 @@ __all__ = [ class OrgManager(models.Manager): def get_queryset(self): - current_org = get_current_org() kwargs = {} if not hasattr(tl, 'times'): tl.times = 0 @@ -44,7 +44,6 @@ class OrgManager(models.Manager): return queryset def all(self): - current_org = get_current_org() if not current_org: msg = 'You can `objects.set_current_org(org).all()` then run it' warnings.warn(msg) @@ -64,7 +63,6 @@ class OrgModelMixin(models.Model): objects = OrgManager() def save(self, *args, **kwargs): - current_org = get_current_org() if current_org and current_org.is_real(): self.org_id = current_org.id return super(OrgModelMixin, self).save(*args, **kwargs) @@ -75,9 +73,16 @@ class OrgModelMixin(models.Model): class OrgViewGenericMixin: def dispatch(self, request, *args, **kwargs): - current_org = get_current_org() + print("Crrent 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() return super().dispatch(request, *args, **kwargs) diff --git a/apps/orgs/models.py b/apps/orgs/models.py index 80cb56e5b..ec94caaf7 100644 --- a/apps/orgs/models.py +++ b/apps/orgs/models.py @@ -60,7 +60,16 @@ class Organization(models.Model): return self.users.all() def get_org_admins(self): - pass + if self.is_real(): + return self.admins.all() + return [] + + def can_admin_by(self, user): + if user.is_superuser: + return True + if user in list(self.get_org_admins()): + return True + return False def is_real(self): return len(str(self.id)) == 36 diff --git a/apps/orgs/utils.py b/apps/orgs/utils.py index 78e3cad1a..3df8c953f 100644 --- a/apps/orgs/utils.py +++ b/apps/orgs/utils.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- # -import re -from django.apps import apps +from functools import partial + +from common.utils import LocalProxy from .models import Organization try: @@ -42,3 +43,13 @@ def set_to_default_org(): def set_to_root_org(): set_current_org(Organization.root()) + + +def _find(attr): + if hasattr(_thread_locals, attr): + return getattr(_thread_locals, attr) + return None + + +current_org = LocalProxy(get_current_org) + diff --git a/apps/perms/forms.py b/apps/perms/forms.py index 6c63982ae..a71b25765 100644 --- a/apps/perms/forms.py +++ b/apps/perms/forms.py @@ -5,7 +5,7 @@ from django import forms from django.utils.translation import ugettext_lazy as _ from orgs.mixins import OrgModelForm -from orgs.utils import get_current_org +from orgs.utils import current_org from .hands import User from .models import AssetPermission @@ -29,7 +29,6 @@ class AssetPermissionForm(OrgModelForm): return users_field = self.fields.get('users') if hasattr(users_field, 'queryset'): - current_org = get_current_org() users_field.queryset = User.objects.filter(orgs=current_org) class Meta: diff --git a/apps/templates/_header_bar.html b/apps/templates/_header_bar.html index ae552fbb6..fc4d50689 100644 --- a/apps/templates/_header_bar.html +++ b/apps/templates/_header_bar.html @@ -35,7 +35,7 @@