Merge pull request #1698 from jumpserver/dev

Dev
pull/2638/head
老广 2018-08-15 23:53:49 -05:00 committed by GitHub
commit a2aa923abe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 177 additions and 73 deletions

View File

@ -48,7 +48,7 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
return return
node = get_object_or_404(Node, id=node_id) node = get_object_or_404(Node, id=node_id)
show_current_asset = self.request.query_params.get("show_current_asset") show_current_asset = self.request.query_params.get("show_current_asset") in ('1', 'true')
if node.is_root(): if node.is_root():
if show_current_asset: if show_current_asset:

View File

@ -36,6 +36,10 @@ class DomainForm(forms.ModelForm):
class GatewayForm(PasswordAndKeyAuthForm, OrgModelForm): class GatewayForm(PasswordAndKeyAuthForm, OrgModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
password_field = self.fields.get('password')
password_field.help_text = _('Password should not contain special characters')
def save(self, commit=True): def save(self, commit=True):
# Because we define custom field, so we need rewrite :method: `save` # Because we define custom field, so we need rewrite :method: `save`

View File

@ -6,8 +6,10 @@ import uuid
import logging import logging
import random import random
from functools import reduce from functools import reduce
from collections import defaultdict
from django.db import models from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache from django.core.cache import cache
@ -100,6 +102,7 @@ class Asset(OrgModelMixin):
verbose_name=_('CPU model')) verbose_name=_('CPU model'))
cpu_count = models.IntegerField(null=True, verbose_name=_('CPU count')) cpu_count = models.IntegerField(null=True, verbose_name=_('CPU count'))
cpu_cores = models.IntegerField(null=True, verbose_name=_('CPU cores')) cpu_cores = models.IntegerField(null=True, verbose_name=_('CPU cores'))
cpu_vcpus = models.IntegerField(null=True, verbose_name=_('CPU vcpus'))
memory = models.CharField(max_length=64, null=True, blank=True, memory = models.CharField(max_length=64, null=True, blank=True,
verbose_name=_('Memory')) verbose_name=_('Memory'))
disk_total = models.CharField(max_length=1024, null=True, blank=True, disk_total = models.CharField(max_length=1024, null=True, blank=True,
@ -161,17 +164,25 @@ class Asset(OrgModelMixin):
nodes = list(reduce(lambda x, y: set(x) | set(y), nodes)) nodes = list(reduce(lambda x, y: set(x) | set(y), nodes))
return nodes return nodes
@property @classmethod
def org_name(self): def get_queryset_by_fullname_list(cls, fullname_list):
from orgs.models import Organization org_fullname_map = defaultdict(list)
org = Organization.get_instance(self.org_id) for fullname in fullname_list:
return org.name hostname, org = cls.split_fullname(fullname)
org_fullname_map[org].append(hostname)
filter_arg = Q()
for org, hosts in org_fullname_map.items():
if org.is_real():
filter_arg |= Q(hostname__in=hosts, org_id=org.id)
else:
filter_arg |= Q(Q(org_id__isnull=True) | Q(org_id=''), hostname__in=hosts)
return Asset.objects.filter(filter_arg)
@property @property
def hardware_info(self): def hardware_info(self):
if self.cpu_count: if self.cpu_count:
return '{} Core {} {}'.format( return '{} Core {} {}'.format(
self.cpu_count * self.cpu_cores, self.cpu_vcpus or self.cpu_count * self.cpu_cores,
self.memory, self.disk_total self.memory, self.disk_total
) )
else: else:

View File

@ -35,4 +35,4 @@ class Label(OrgModelMixin):
class Meta: class Meta:
db_table = "assets_label" db_table = "assets_label"
unique_together = [('name', 'value')] unique_together = [('name', 'value', 'org_id')]

View File

@ -44,7 +44,7 @@ def set_assets_hardware_info(result, **kwargs):
logger.error("Get asset info failed: {}".format(hostname)) logger.error("Get asset info failed: {}".format(hostname))
continue continue
asset = get_object_or_none(Asset, hostname=hostname) asset = Asset.objects.get_object_by_fullname(hostname)
if not asset: if not asset:
continue continue
@ -60,6 +60,7 @@ def set_assets_hardware_info(result, **kwargs):
___cpu_model = ___cpu_model[:64] ___cpu_model = ___cpu_model[:64]
___cpu_count = info.get('ansible_processor_count', 0) ___cpu_count = info.get('ansible_processor_count', 0)
___cpu_cores = info.get('ansible_processor_cores', None) or len(info.get('ansible_processor', [])) ___cpu_cores = info.get('ansible_processor_cores', None) or len(info.get('ansible_processor', []))
___cpu_vcpus = info.get('ansible_processor_vcpus', 0)
___memory = '%s %s' % capacity_convert('{} MB'.format(info.get('ansible_memtotal_mb'))) ___memory = '%s %s' % capacity_convert('{} MB'.format(info.get('ansible_memtotal_mb')))
disk_info = {} disk_info = {}
for dev, dev_info in info.get('ansible_devices', {}).items(): for dev, dev_info in info.get('ansible_devices', {}).items():
@ -95,7 +96,7 @@ def update_assets_hardware_info_util(assets, task_name=None):
# task_name = _("Update some assets hardware info") # task_name = _("Update some assets hardware info")
task_name = _("更新资产硬件信息") task_name = _("更新资产硬件信息")
tasks = const.UPDATE_ASSETS_HARDWARE_TASKS tasks = const.UPDATE_ASSETS_HARDWARE_TASKS
hostname_list = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] hostname_list = [asset.fullname for asset in assets if asset.is_active and asset.is_unixlike()]
if not hostname_list: if not hostname_list:
logger.info("Not hosts get, may be asset is not active or not unixlike platform") logger.info("Not hosts get, may be asset is not active or not unixlike platform")
return {} return {}
@ -134,7 +135,7 @@ def update_assets_hardware_info_period():
# task_name = _("Update assets hardware info period") # task_name = _("Update assets hardware info period")
task_name = _("定期更新资产硬件信息") task_name = _("定期更新资产硬件信息")
hostname_list = [ hostname_list = [
asset.hostname for asset in Asset.objects.all() asset.fullname for asset in Asset.objects.all()
if asset.is_active and asset.is_unixlike() if asset.is_active and asset.is_unixlike()
] ]
tasks = const.UPDATE_ASSETS_HARDWARE_TASKS tasks = const.UPDATE_ASSETS_HARDWARE_TASKS
@ -181,7 +182,7 @@ def test_admin_user_connectability_util(admin_user, task_name):
from ops.utils import update_or_create_ansible_task from ops.utils import update_or_create_ansible_task
assets = admin_user.get_related_assets() assets = admin_user.get_related_assets()
hosts = [asset.hostname for asset in assets hosts = [asset.fullname for asset in assets
if asset.is_active and asset.is_unixlike()] if asset.is_active and asset.is_unixlike()]
if not hosts: if not hosts:
return return
@ -228,7 +229,7 @@ def test_asset_connectability_util(assets, task_name=None):
if task_name is None: if task_name is None:
# task_name = _("Test assets connectability") # task_name = _("Test assets connectability")
task_name = _("测试资产可连接性") task_name = _("测试资产可连接性")
hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] hosts = [asset.fullname for asset in assets if asset.is_active and asset.is_unixlike()]
if not hosts: if not hosts:
logger.info("No hosts, passed") logger.info("No hosts, passed")
return {} return {}
@ -280,7 +281,7 @@ def test_system_user_connectability_util(system_user, task_name):
""" """
from ops.utils import update_or_create_ansible_task from ops.utils import update_or_create_ansible_task
assets = system_user.get_assets() assets = system_user.get_assets()
hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] hosts = [asset.fullname for asset in assets if asset.is_active and asset.is_unixlike()]
tasks = const.TEST_SYSTEM_USER_CONN_TASKS tasks = const.TEST_SYSTEM_USER_CONN_TASKS
if not hosts: if not hosts:
logger.info("No hosts, passed") logger.info("No hosts, passed")
@ -378,7 +379,7 @@ def push_system_user_util(system_users, assets, task_name):
logger.info("Not tasks, passed") logger.info("Not tasks, passed")
return {} return {}
hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] hosts = [asset.fullname for asset in assets if asset.is_active and asset.is_unixlike()]
if not hosts: if not hosts:
logger.info("Not hosts, passed") logger.info("Not hosts, passed")
return {} return {}

View File

@ -451,10 +451,11 @@ $(document).ready(function(){
$.each(rows, function (index, obj) { $.each(rows, function (index, obj) {
assets.push(obj.id) assets.push(obj.id)
}); });
var _node_id = current_node ? current_node : null;
$.ajax({ $.ajax({
url: "{% url "assets:asset-export" %}", url: "{% url "assets:asset-export" %}",
method: 'POST', method: 'POST',
data: JSON.stringify({assets_id: assets, node_id: current_node.node_id}), data: JSON.stringify({assets_id: assets, node_id: _node_id}),
dataType: "json", dataType: "json",
success: function (data, textStatus) { success: function (data, textStatus) {
window.open(data.redirect) window.open(data.redirect)

View File

@ -12,7 +12,7 @@
{% block form %} {% block form %}
<form action="" method="post" class="form-horizontal"> <form action="" method="post" class="form-horizontal">
{% if form.no_field_errors %} {% if form.non_field_errors %}
<div class="alert alert-danger"> <div class="alert alert-danger">
{{ form.non_field_errors }} {{ form.non_field_errors }}
</div> </div>

View File

@ -12,8 +12,8 @@ def get_assets_by_id_list(id_list):
return Asset.objects.filter(id__in=id_list) return Asset.objects.filter(id__in=id_list)
def get_assets_by_hostname_list(hostname_list): def get_assets_by_fullname_list(hostname_list):
return Asset.objects.filter(hostname__in=hostname_list) return Asset.objects.get_queryset_by_fullname_list(hostname_list)
def get_system_user_by_name(name): def get_system_user_by_name(name):

View File

@ -214,13 +214,13 @@ class AssetExportView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
try: try:
assets_id = json.loads(request.body).get('assets_id', []) assets_id = json.loads(request.body).get('assets_id', [])
assets_node_id = json.loads(request.body).get('node_id', None) node_id = json.loads(request.body).get('node_id', None)
except ValueError: except ValueError:
return HttpResponse('Json object not valid', status=400) return HttpResponse('Json object not valid', status=400)
if not assets_id and assets_node_id: if not assets_id:
assets_node = get_object_or_none(Node, id=assets_node_id) node = get_object_or_none(Node, id=node_id) if node_id else Node.root()
assets = assets_node.get_all_assets() assets = node.get_all_assets()
for asset in assets: for asset in assets:
assets_id.append(asset.id) assets_id.append(asset.id)

Binary file not shown.

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-13 15:01+0800\n" "POT-Creation-Date: 2018-08-15 15:14+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n" "Language-Team: Jumpserver team<ibuler@qq.com>\n"
@ -103,7 +103,7 @@ msgid "Port"
msgstr "端口" msgstr "端口"
#: assets/forms/domain.py:15 assets/forms/label.py:13 #: assets/forms/domain.py:15 assets/forms/label.py:13
#: assets/models/asset.py:231 assets/templates/assets/admin_user_list.html:25 #: assets/models/asset.py:232 assets/templates/assets/admin_user_list.html:25
#: assets/templates/assets/domain_detail.html:60 #: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:23 #: assets/templates/assets/domain_list.html:23
#: assets/templates/assets/label_list.html:16 #: assets/templates/assets/label_list.html:16
@ -123,7 +123,11 @@ msgstr "端口"
msgid "Asset" msgid "Asset"
msgstr "资产" msgstr "资产"
#: assets/forms/domain.py:55 assets/forms/user.py:79 assets/forms/user.py:139 #: assets/forms/domain.py:42
msgid "Password should not contain special characters"
msgstr "密码不能包含特殊字符"
#: assets/forms/domain.py:59 assets/forms/user.py:79 assets/forms/user.py:139
#: assets/models/base.py:22 assets/models/cluster.py:18 #: assets/models/base.py:22 assets/models/cluster.py:18
#: assets/models/domain.py:18 assets/models/group.py:20 #: assets/models/domain.py:18 assets/models/group.py:20
#: assets/models/label.py:18 assets/templates/assets/admin_user_detail.html:56 #: assets/models/label.py:18 assets/templates/assets/admin_user_detail.html:56
@ -156,7 +160,7 @@ msgstr "资产"
msgid "Name" msgid "Name"
msgstr "名称" msgstr "名称"
#: assets/forms/domain.py:56 assets/forms/user.py:80 assets/forms/user.py:140 #: assets/forms/domain.py:60 assets/forms/user.py:80 assets/forms/user.py:140
#: assets/models/base.py:23 assets/templates/assets/admin_user_detail.html:60 #: assets/models/base.py:23 assets/templates/assets/admin_user_detail.html:60
#: assets/templates/assets/admin_user_list.html:24 #: assets/templates/assets/admin_user_list.html:24
#: assets/templates/assets/domain_gateway_list.html:60 #: assets/templates/assets/domain_gateway_list.html:60
@ -303,42 +307,48 @@ msgstr "CPU数量"
msgid "CPU cores" msgid "CPU cores"
msgstr "CPU核数" msgstr "CPU核数"
#: assets/models/asset.py:104 assets/templates/assets/asset_detail.html:89 #: assets/models/asset.py:103
#, fuzzy
#| msgid "CPU count"
msgid "CPU vcpus"
msgstr "CPU数量"
#: assets/models/asset.py:105 assets/templates/assets/asset_detail.html:89
msgid "Memory" msgid "Memory"
msgstr "内存" msgstr "内存"
#: assets/models/asset.py:106 #: assets/models/asset.py:107
msgid "Disk total" msgid "Disk total"
msgstr "硬盘大小" msgstr "硬盘大小"
#: assets/models/asset.py:108 #: assets/models/asset.py:109
msgid "Disk info" msgid "Disk info"
msgstr "硬盘信息" msgstr "硬盘信息"
#: assets/models/asset.py:111 assets/templates/assets/asset_detail.html:101 #: assets/models/asset.py:112 assets/templates/assets/asset_detail.html:101
#: assets/templates/assets/user_asset_list.html:166 #: assets/templates/assets/user_asset_list.html:166
msgid "OS" msgid "OS"
msgstr "操作系统" msgstr "操作系统"
#: assets/models/asset.py:113 #: assets/models/asset.py:114
msgid "OS version" msgid "OS version"
msgstr "系统版本" msgstr "系统版本"
#: assets/models/asset.py:115 #: assets/models/asset.py:116
msgid "OS arch" msgid "OS arch"
msgstr "系统架构" msgstr "系统架构"
#: assets/models/asset.py:117 #: assets/models/asset.py:118
msgid "Hostname raw" msgid "Hostname raw"
msgstr "主机名原始" msgstr "主机名原始"
#: assets/models/asset.py:121 assets/templates/assets/asset_create.html:34 #: assets/models/asset.py:122 assets/templates/assets/asset_create.html:34
#: assets/templates/assets/asset_detail.html:220 #: assets/templates/assets/asset_detail.html:220
#: assets/templates/assets/asset_update.html:39 templates/_nav.html:27 #: assets/templates/assets/asset_update.html:39 templates/_nav.html:27
msgid "Labels" msgid "Labels"
msgstr "标签管理" msgstr "标签管理"
#: assets/models/asset.py:123 assets/models/base.py:30 #: assets/models/asset.py:124 assets/models/base.py:30
#: assets/models/cluster.py:28 assets/models/group.py:21 #: assets/models/cluster.py:28 assets/models/group.py:21
#: assets/templates/assets/admin_user_detail.html:68 #: assets/templates/assets/admin_user_detail.html:68
#: assets/templates/assets/asset_detail.html:117 #: assets/templates/assets/asset_detail.html:117
@ -350,7 +360,7 @@ msgstr "标签管理"
msgid "Created by" msgid "Created by"
msgstr "创建者" msgstr "创建者"
#: assets/models/asset.py:126 assets/models/cluster.py:26 #: assets/models/asset.py:127 assets/models/cluster.py:26
#: assets/models/domain.py:21 assets/models/group.py:22 #: assets/models/domain.py:21 assets/models/group.py:22
#: assets/models/label.py:24 assets/templates/assets/admin_user_detail.html:64 #: assets/models/label.py:24 assets/templates/assets/admin_user_detail.html:64
#: assets/templates/assets/domain_detail.html:68 #: assets/templates/assets/domain_detail.html:68
@ -364,7 +374,7 @@ msgstr "创建者"
msgid "Date created" msgid "Date created"
msgstr "创建日期" msgstr "创建日期"
#: assets/models/asset.py:128 assets/models/base.py:27 #: assets/models/asset.py:129 assets/models/base.py:27
#: assets/models/cluster.py:29 assets/models/domain.py:19 #: assets/models/cluster.py:29 assets/models/domain.py:19
#: assets/models/domain.py:48 assets/models/group.py:23 #: assets/models/domain.py:48 assets/models/group.py:23
#: assets/models/label.py:22 assets/templates/assets/admin_user_detail.html:72 #: assets/models/label.py:22 assets/templates/assets/admin_user_detail.html:72
@ -474,7 +484,7 @@ msgstr "默认资产组"
msgid "User" msgid "User"
msgstr "用户" msgstr "用户"
#: assets/models/label.py:19 assets/models/node.py:19 #: assets/models/label.py:19 assets/models/node.py:20
#: assets/templates/assets/label_list.html:15 common/models.py:27 #: assets/templates/assets/label_list.html:15 common/models.py:27
msgid "Value" msgid "Value"
msgstr "值" msgstr "值"
@ -483,7 +493,7 @@ msgstr "值"
msgid "Category" msgid "Category"
msgstr "分类" msgstr "分类"
#: assets/models/node.py:18 #: assets/models/node.py:19
msgid "Key" msgid "Key"
msgstr "" msgstr ""
@ -557,35 +567,35 @@ msgstr "系统用户"
msgid "%(value)s is not an even number" msgid "%(value)s is not an even number"
msgstr "%(value)s is not an even number" msgstr "%(value)s is not an even number"
#: assets/tasks.py:96 assets/tasks.py:116 #: assets/tasks.py:97 assets/tasks.py:117
msgid "更新资产硬件信息" msgid "更新资产硬件信息"
msgstr "" msgstr ""
#: assets/tasks.py:135 #: assets/tasks.py:136
msgid "定期更新资产硬件信息" msgid "定期更新资产硬件信息"
msgstr "" msgstr ""
#: assets/tasks.py:213 #: assets/tasks.py:214
msgid "定期测试管理账号可连接性: {}" msgid "定期测试管理账号可连接性: {}"
msgstr "" msgstr ""
#: assets/tasks.py:220 #: assets/tasks.py:221
msgid "测试管理行号可连接性: {}" msgid "测试管理行号可连接性: {}"
msgstr "" msgstr ""
#: assets/tasks.py:230 #: assets/tasks.py:231
msgid "测试资产可连接性" msgid "测试资产可连接性"
msgstr "" msgstr ""
#: assets/tasks.py:300 #: assets/tasks.py:301
msgid "Test system user connectability: {}" msgid "Test system user connectability: {}"
msgstr "测试系统用户可连接性: {}" msgstr "测试系统用户可连接性: {}"
#: assets/tasks.py:316 #: assets/tasks.py:317
msgid "定期测试系统用户可连接性: {}" msgid "定期测试系统用户可连接性: {}"
msgstr "" msgstr ""
#: assets/tasks.py:401 #: assets/tasks.py:402
msgid "推送系统用户到入资产: {}" msgid "推送系统用户到入资产: {}"
msgstr "" msgstr ""
@ -850,7 +860,7 @@ msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:200 #: assets/templates/assets/asset_detail.html:200
#: assets/templates/assets/asset_list.html:630 #: assets/templates/assets/asset_list.html:631
#: assets/templates/assets/system_user_detail.html:195 #: assets/templates/assets/system_user_detail.html:195
#: assets/templates/assets/system_user_list.html:139 templates/_modal.html:22 #: assets/templates/assets/system_user_list.html:139 templates/_modal.html:22
#: terminal/templates/terminal/session_detail.html:108 #: terminal/templates/terminal/session_detail.html:108
@ -1052,7 +1062,7 @@ msgstr "重命名成功"
msgid "Rename failed, do not change the root node name" msgid "Rename failed, do not change the root node name"
msgstr "重命名失败,不可以更改根节点名称" msgstr "重命名失败,不可以更改根节点名称"
#: assets/templates/assets/asset_list.html:625 #: assets/templates/assets/asset_list.html:626
#: assets/templates/assets/system_user_list.html:134 #: assets/templates/assets/system_user_list.html:134
#: users/templates/users/user_detail.html:369 #: users/templates/users/user_detail.html:369
#: users/templates/users/user_detail.html:394 #: users/templates/users/user_detail.html:394
@ -1063,20 +1073,20 @@ msgstr "重命名失败,不可以更改根节点名称"
msgid "Are you sure?" msgid "Are you sure?"
msgstr "你确认吗?" msgstr "你确认吗?"
#: assets/templates/assets/asset_list.html:626 #: assets/templates/assets/asset_list.html:627
msgid "This will delete the selected assets !!!" msgid "This will delete the selected assets !!!"
msgstr "删除选择资产" msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:634 #: assets/templates/assets/asset_list.html:635
msgid "Asset Deleted." msgid "Asset Deleted."
msgstr "已被删除" msgstr "已被删除"
#: assets/templates/assets/asset_list.html:635 #: assets/templates/assets/asset_list.html:636
#: assets/templates/assets/asset_list.html:640 #: assets/templates/assets/asset_list.html:641
msgid "Asset Delete" msgid "Asset Delete"
msgstr "删除" msgstr "删除"
#: assets/templates/assets/asset_list.html:639 #: assets/templates/assets/asset_list.html:640
msgid "Asset Deleting failed." msgid "Asset Deleting failed."
msgstr "删除失败" msgstr "删除失败"

View File

@ -2,7 +2,7 @@
# #
from .ansible.inventory import BaseInventory from .ansible.inventory import BaseInventory
from assets.utils import get_assets_by_hostname_list, get_system_user_by_name from assets.utils import get_assets_by_fullname_list, get_system_user_by_name
__all__ = [ __all__ = [
'JMSInventory' 'JMSInventory'
@ -44,7 +44,7 @@ class JMSInventory(BaseInventory):
super().__init__(host_list=host_list) super().__init__(host_list=host_list)
def get_jms_assets(self): def get_jms_assets(self):
assets = get_assets_by_hostname_list(self.hostname_list) assets = get_assets_by_fullname_list(self.hostname_list)
return assets return assets
def convert_to_ansible(self, asset, run_as_admin=False): def convert_to_ansible(self, asset, run_as_admin=False):

View File

@ -8,7 +8,7 @@ from django.shortcuts import redirect
from django.forms import ModelForm from django.forms import ModelForm
from django.http.response import HttpResponseForbidden from django.http.response import HttpResponseForbidden
from common.utils import get_logger from common.utils import get_logger, is_uuid
from .utils import current_org, set_current_org, set_to_root_org from .utils import current_org, set_current_org, set_to_root_org
from .models import Organization from .models import Organization
@ -39,6 +39,25 @@ class OrgManager(models.Manager):
tl.times += 1 tl.times += 1
return queryset return queryset
def filter_by_fullname(self, fullname, field=None):
ori_org = current_org
value, org = self.model.split_fullname(fullname)
set_current_org(org)
if not field:
if hasattr(self.model, 'name'):
field = 'name'
elif hasattr(self.model, 'hostname'):
field = 'hostname'
queryset = self.get_queryset().filter(**{field: value})
set_current_org(ori_org)
return queryset
def get_object_by_fullname(self, fullname, field=None):
queryset = self.filter_by_fullname(fullname, field=field)
if len(queryset) == 1:
return queryset[0]
return None
def all(self): def all(self):
if not current_org: if not current_org:
msg = 'You can `objects.set_current_org(org).all()` then run it' msg = 'You can `objects.set_current_org(org).all()` then run it'
@ -57,11 +76,50 @@ class OrgModelMixin(models.Model):
org_id = models.CharField(max_length=36, null=True, blank=True, default=None) org_id = models.CharField(max_length=36, null=True, blank=True, default=None)
objects = OrgManager() objects = OrgManager()
sep = '@'
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if current_org and current_org.is_real(): if current_org and current_org.is_real():
self.org_id = current_org.id self.org_id = current_org.id
return super().save(*args, **kwargs) return super().save(*args, **kwargs)
@classmethod
def split_fullname(cls, fullname, sep=None):
if not sep:
sep = cls.sep
index = fullname.rfind(sep)
if index == -1:
value = fullname
org = Organization.default()
else:
value = fullname[:index]
org = Organization.get_instance(fullname[index + 1:])
return value, org
@property
def org(self):
from orgs.models import Organization
org = Organization.get_instance(self.org_id)
return org
@property
def org_name(self):
return self.org.name
@property
def fullname(self, attr=None):
name = ''
if attr and hasattr(self, attr):
name = getattr(self, attr)
elif hasattr(self, 'name'):
name = self.name
elif hasattr(self, 'hostname'):
name = self.hostname
if self.org.is_real():
return name + self.sep + self.org_name
else:
return name
class Meta: class Meta:
abstract = True abstract = True

View File

@ -4,6 +4,8 @@ from django.db import models
from django.core.cache import cache from django.core.cache import cache
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common.utils import is_uuid
class Organization(models.Model): class Organization(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
@ -15,19 +17,23 @@ class Organization(models.Model):
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment')) comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
CACHE_PREFIX = 'JMS_ORG_{}' CACHE_PREFIX = 'JMS_ORG_{}'
ROOT_ID = 'ROOT' ROOT_ID_NAME = 'ROOT'
DEFAULT_ID = 'DEFAULT' DEFAULT_ID_NAME = 'DEFAULT'
def __str__(self): def __str__(self):
return self.name return self.name
def set_to_cache(self): def set_to_cache(self):
key = self.CACHE_PREFIX.format(self.id) key_id = self.CACHE_PREFIX.format(self.id)
cache.set(key, self, 3600) key_name = self.CACHE_PREFIX.format(self.name)
cache.set(key_id, self, 3600)
cache.set(key_name, self, 3600)
def expire_cache(self): def expire_cache(self):
key = self.CACHE_PREFIX.format(self.id) key_id = self.CACHE_PREFIX.format(self.id)
cache.set(key, self, 1) key_name = self.CACHE_PREFIX.format(self.name)
cache.delete(key_id)
cache.delete(key_name)
@classmethod @classmethod
def get_instance_from_cache(cls, oid): def get_instance_from_cache(cls, oid):
@ -35,18 +41,23 @@ class Organization(models.Model):
return cache.get(key, None) return cache.get(key, None)
@classmethod @classmethod
def get_instance(cls, oid, default=True): def get_instance(cls, id_or_name, default=True):
cached = cls.get_instance_from_cache(oid) cached = cls.get_instance_from_cache(id_or_name)
if cached: if cached:
return cached return cached
if oid == cls.DEFAULT_ID: if not id_or_name:
return cls.default() if default else None
elif id_or_name == cls.DEFAULT_ID_NAME:
return cls.default() return cls.default()
elif oid == cls.ROOT_ID: elif id_or_name == cls.ROOT_ID_NAME:
return cls.root() return cls.root()
try: try:
org = cls.objects.get(id=oid) if is_uuid(id_or_name):
org = cls.objects.get(id=id_or_name)
else:
org = cls.objects.get(name=id_or_name)
org.set_to_cache() org.set_to_cache()
except cls.DoesNotExist: except cls.DoesNotExist:
org = cls.default() if default else None org = cls.default() if default else None
@ -56,6 +67,8 @@ class Organization(models.Model):
from users.models import User from users.models import User
if self.is_default(): if self.is_default():
users = User.objects.filter(orgs__isnull=True) users = User.objects.filter(orgs__isnull=True)
elif not self.is_real():
users = User.objects.all()
else: else:
users = self.users.all() users = self.users.all()
users = users.exclude(role=User.ROLE_APP) users = users.exclude(role=User.ROLE_APP)
@ -90,14 +103,20 @@ class Organization(models.Model):
@classmethod @classmethod
def default(cls): def default(cls):
return cls(id=cls.DEFAULT_ID, name="Default") return cls(id=cls.DEFAULT_ID_NAME, name=cls.DEFAULT_ID_NAME)
@classmethod @classmethod
def root(cls): def root(cls):
return cls(id=cls.ROOT_ID, name='Root') return cls(id=cls.ROOT_ID_NAME, name=cls.ROOT_ID_NAME)
def is_default(self): def is_root(self):
if self.id is self.DEFAULT_ID: if self.id is self.ROOT_ID_NAME:
return True
else:
return False
def is_default(self):
if self.id is self.DEFAULT_ID_NAME:
return True return True
else: else:
return False return False