Commit e8ebc941 authored by ibuler's avatar ibuler

[Update] 修改assets users api

parent f10a7a75
......@@ -40,9 +40,8 @@ class AssetUser(OrgModelMixin):
@property
def private_key_obj(self):
if self._private_key:
key_str = signer.unsign(self._private_key)
return ssh_key_string_to_obj(key_str, password=self.password)
if self.private_key:
return ssh_key_string_to_obj(self.private_key, password=self.password)
else:
return None
......@@ -52,8 +51,7 @@ class AssetUser(OrgModelMixin):
return None
project_dir = settings.PROJECT_DIR
tmp_dir = os.path.join(project_dir, 'tmp')
key_str = signer.unsign(self._private_key)
key_name = '.' + md5(key_str.encode('utf-8')).hexdigest()
key_name = '.' + md5(self.private_key.encode('utf-8')).hexdigest()
key_path = os.path.join(tmp_dir, key_name)
if not os.path.exists(key_path):
self.private_key_obj.write_private_key_file(key_path)
......
......@@ -15,20 +15,20 @@ class AdminUserSerializer(BulkOrgResourceModelSerializer):
"""
管理用户
"""
password = serializers.CharField(
required=False, write_only=True, label=_('Password')
)
class Meta:
list_serializer_class = AdaptedBulkListSerializer
model = AdminUser
fields = [
'id', 'name', 'username', 'password', 'comment',
'connectivity_amount', 'assets_amount',
'id', 'name', 'username', 'password', 'private_key', 'public_key',
'comment', 'connectivity_amount', 'assets_amount',
'date_created', 'date_updated', 'created_by',
]
extra_kwargs = {
'password': {"write_only": True},
'private_key': {"write_only": True},
'public_key': {"write_only": True},
'date_created': {'read_only': True},
'date_updated': {'read_only': True},
'created_by': {'read_only': True},
......
......@@ -29,18 +29,6 @@ class AssetUserSerializer(BulkOrgResourceModelSerializer):
ip = serializers.CharField(read_only=True, label=_("IP"))
connectivity = ConnectivitySerializer(read_only=True, label=_("Connectivity"))
password = serializers.CharField(
max_length=256, allow_blank=True, allow_null=True, write_only=True,
required=False, label=_('Password')
)
public_key = serializers.CharField(
max_length=4096, allow_blank=True, allow_null=True, write_only=True,
required=False, label=_('Public key')
)
private_key = serializers.CharField(
max_length=4096, allow_blank=True, allow_null=True, write_only=True,
required=False, label=_('Private key')
)
backend = serializers.CharField(read_only=True, label=_("Backend"))
class Meta:
......@@ -57,6 +45,9 @@ class AssetUserSerializer(BulkOrgResourceModelSerializer):
]
extra_kwargs = {
'username': {'required': True},
'password': {'write_only': True},
'private_key': {'write_only': True},
'public_key': {'write_only': True},
}
def validate_private_key(self, key):
......@@ -67,17 +58,9 @@ class AssetUserSerializer(BulkOrgResourceModelSerializer):
return key
def create(self, validated_data):
kwargs = {
'name': validated_data.get('username'),
'username': validated_data.get('username'),
'asset': validated_data.get('asset'),
'comment': validated_data.get('comment', ''),
'org_id': validated_data.get('org_id', ''),
'password': validated_data.get('password'),
'public_key': validated_data.get('public_key'),
'private_key': validated_data.get('private_key')
}
instance = AssetUserManager.create(**kwargs)
if not validated_data.get("name") and validated_data.get("username"):
validated_data["name"] = validated_data["username"]
instance = AssetUserManager.create(**validated_data)
return instance
......
......@@ -12,20 +12,20 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer):
"""
系统用户
"""
password = serializers.CharField(
required=False, write_only=True, label=_('Password')
)
class Meta:
model = SystemUser
list_serializer_class = AdaptedBulkListSerializer
fields = [
'id', 'name', 'username', 'login_mode', 'login_mode_display',
'priority', 'protocol', 'auto_push', 'password',
'cmd_filters', 'sudo', 'shell', 'comment', 'nodes', 'assets',
'assets_amount', 'connectivity_amount'
'id', 'name', 'username', 'password', 'public_key', 'private_key',
'login_mode', 'login_mode_display', 'priority', 'protocol',
'auto_push', 'cmd_filters', 'sudo', 'shell', 'comment', 'nodes',
'assets', 'assets_amount', 'connectivity_amount'
]
extra_kwargs = {
'password': {"write_only": True},
'public_key': {"write_only": True},
'private_key': {"write_only": True},
'assets_amount': {'label': _('Asset')},
'connectivity_amount': {'label': _('Connectivity')},
'login_mode_display': {'label': _('Login mode display')},
......
# -*- coding: utf-8 -*-
#
from werkzeug.local import Local
thread_local = Local()
def _find(attr):
return getattr(thread_local, attr, None)
......@@ -3,12 +3,13 @@
import re
from collections import defaultdict
from django.conf import settings
from django.dispatch import receiver
from django.core.signals import request_finished
from django.db import connection
from .utils import get_logger
from .local import thread_local
logger = get_logger(__file__)
pattern = re.compile(r'FROM `(\w+)`')
......@@ -50,6 +51,11 @@ def on_request_finished_logging_db_query(sender, **kwargs):
)
@receiver(request_finished)
def on_request_finished_release_local(sender, **kwargs):
thread_local.__release_local__()
if settings.DEBUG:
request_finished.connect(on_request_finished_logging_db_query)
......
......@@ -176,125 +176,6 @@ def with_cache(func):
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)
def random_string(length):
import string
import random
......
# -*- coding: utf-8 -*-
#
from functools import partial
from common.utils import LocalProxy
try:
from threading import local
except ImportError:
from django.utils._threading_local import local
_thread_locals = local()
from werkzeug.local import LocalProxy
from common.local import thread_local
def set_current_request(request):
setattr(_thread_locals, 'current_request', request)
setattr(thread_local, 'current_request', request)
def _find(attr):
return getattr(_thread_locals, attr, None)
return getattr(thread_local, attr, None)
def get_current_request():
......
# -*- coding: utf-8 -*-
#
from functools import partial
from werkzeug.local import Local
from werkzeug.local import LocalProxy
from common.utils import LocalProxy
from common.local import thread_local
from .models import Organization
_thread_locals = Local()
def get_org_from_request(request):
oid = request.session.get("oid")
if not oid:
......@@ -19,7 +15,7 @@ def get_org_from_request(request):
def set_current_org(org):
setattr(_thread_locals, 'current_org', org)
setattr(thread_local, 'current_org', org.id)
def set_to_default_org():
......@@ -31,17 +27,18 @@ def set_to_root_org():
def _find(attr):
return getattr(_thread_locals, attr, None)
return getattr(thread_local, attr, None)
def get_current_org():
return _find('current_org')
org_id = _find('current_org')
org = Organization.get_instance(org_id)
return org
def get_current_org_id():
org = get_current_org()
org_id = str(org.id) if org.is_real() else ''
org_id = _find('current_org')
return org_id
current_org = LocalProxy(partial(_find, 'current_org'))
current_org = LocalProxy(get_current_org)
......@@ -48,9 +48,10 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
def perform_create(self, serializer):
users = serializer.save()
for user in users:
if current_org and current_org.is_real():
user.orgs.add(current_org.id)
if isinstance(users, User):
users = [users]
if current_org and current_org.is_real():
current_org.users.add(*users)
self.send_created_signal(users)
def get_queryset(self):
......@@ -174,6 +175,7 @@ class UserResetPKApi(generics.UpdateAPIView):
send_reset_ssh_key_mail(user)
# 废弃
class UserUpdatePKApi(generics.UpdateAPIView):
queryset = User.objects.all()
serializer_class = UserPKUpdateSerializer
......@@ -181,7 +183,7 @@ class UserUpdatePKApi(generics.UpdateAPIView):
def perform_update(self, serializer):
user = self.get_object()
user.public_key = serializer.validated_data['_public_key']
user.public_key = serializer.validated_data['public_key']
user.save()
......
......@@ -19,13 +19,16 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
model = User
list_serializer_class = AdaptedBulkListSerializer
fields = [
'id', 'name', 'username', 'email', 'groups', 'groups_display',
'id', 'name', 'username', 'password', 'email', 'public_key',
'groups', 'groups_display',
'role', 'role_display', 'wechat', 'phone', 'otp_level',
'comment', 'source', 'source_display', 'is_valid', 'is_expired',
'is_active', 'created_by', 'is_first_login',
'date_password_last_updated', 'date_expired', 'avatar_url',
]
extra_kwargs = {
'password': {'write_only': True},
'public_key': {'write_only': True},
'groups_display': {'label': _('Groups name')},
'source_display': {'label': _('Source name')},
'is_first_login': {'label': _('Is first login'), 'read_only': True},
......@@ -36,14 +39,37 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
'created_by': {'read_only': True}, 'source': {'read_only': True}
}
@staticmethod
def validate_password(value):
from ..utils import check_password_rules
if not check_password_rules(value):
msg = _('Password does not match security rules')
raise serializers.ValidationError(msg)
return value
@staticmethod
def change_password_to_raw(validated_data):
password = validated_data.pop('password', None)
if password:
validated_data['password_raw'] = password
return validated_data
def create(self, validated_data):
validated_data = self.change_password_to_raw(validated_data)
return super().create(validated_data)
def update(self, instance, validated_data):
validated_data = self.change_password_to_raw(validated_data)
return super().update(instance, validated_data)
class UserPKUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', '_public_key']
fields = ['id', 'public_key']
@staticmethod
def validate__public_key(value):
def validate_public_key(value):
if not validate_ssh_public_key(value):
raise serializers.ValidationError(_('Not a valid ssh public key'))
return value
......
......@@ -217,33 +217,9 @@
{% endblock %}
{% block custom_foot_js %}
<script>
$(document).on('click', '#btn_update_pk', function() {
var $this = $(this);
var pk = $('#txt_pk').val();
var the_url = '{% url "api-users:user-public-key-update" pk=user.id %}';
var body = {'_public_key': pk};
var success = function() {
$('#txt_pk').val('');
var msg = "{% trans 'Successfully updated the SSH public key.' %}";
swal("{% trans 'User SSH public key update' %}", msg, "success");
};
var fail = function() {
var msg = "{% trans 'Failed to update SSH public key.' %}";
swal({
title: "{% trans 'User SSH public key update' %}",
text: msg,
type: "error",
showCancelButton: false,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: true
}, function () {
$('#txt_pk').focus();
}
);
};
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
}).on('click', '.btn-reset-pubkey', function () {
$(document).ready(function () {
})
.on('click', '.btn-reset-pubkey', function () {
var the_url = '{% url "users:user-pubkey-generate" %}';
window.open(the_url, "_blank")
})
......
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