mirror of https://github.com/jumpserver/jumpserver
Merge branch 'dev' into pr@dev@license
commit
28d6f2f9ef
|
@ -133,11 +133,13 @@ class AccountRiskViewSet(OrgBulkModelViewSet):
|
||||||
s.validated_data, ("asset", "username", "action", "risk")
|
s.validated_data, ("asset", "username", "action", "risk")
|
||||||
)
|
)
|
||||||
handler = RiskHandler(asset=asset, username=username, request=self.request)
|
handler = RiskHandler(asset=asset, username=username, request=self.request)
|
||||||
data = handler.handle(act, risk)
|
|
||||||
if not data:
|
try:
|
||||||
return Response(data={"message": "Success"})
|
risk = handler.handle(act, risk)
|
||||||
s = serializers.AccountRiskSerializer(instance=data)
|
s = serializers.AccountRiskSerializer(instance=risk)
|
||||||
return Response(data=s.data)
|
return Response(data=s.data)
|
||||||
|
except Exception as e:
|
||||||
|
return Response(status=400, data=str(e))
|
||||||
|
|
||||||
|
|
||||||
class CheckAccountEngineViewSet(JMSModelViewSet):
|
class CheckAccountEngineViewSet(JMSModelViewSet):
|
||||||
|
|
|
@ -155,6 +155,19 @@ class AnalyseAccountRisk:
|
||||||
def _update_risk(self, account):
|
def _update_risk(self, account):
|
||||||
return account
|
return account
|
||||||
|
|
||||||
|
def lost_accounts(self, asset, lost_users):
|
||||||
|
if not self.check_risk:
|
||||||
|
return
|
||||||
|
for user in lost_users:
|
||||||
|
self._create_risk(
|
||||||
|
dict(
|
||||||
|
asset_id=str(asset.id),
|
||||||
|
username=user,
|
||||||
|
risk=RiskChoice.account_deleted,
|
||||||
|
details=[{"datetime": self.now.isoformat()}],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def analyse_risk(self, asset, ga, d, sys_found):
|
def analyse_risk(self, asset, ga, d, sys_found):
|
||||||
if not self.check_risk:
|
if not self.check_risk:
|
||||||
return
|
return
|
||||||
|
@ -289,6 +302,8 @@ class GatherAccountsManager(AccountBasePlaybookManager):
|
||||||
"username": username,
|
"username": username,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
risk_analyser = AnalyseAccountRisk(self.check_risk)
|
||||||
|
risk_analyser.lost_accounts(asset, lost_users)
|
||||||
|
|
||||||
# 收集的账号 比 账号列表多的, 有可能是账号中删掉了, 但这时候状态已经是 confirm 了
|
# 收集的账号 比 账号列表多的, 有可能是账号中删掉了, 但这时候状态已经是 confirm 了
|
||||||
# 标识状态为 待处理, 让管理员去确认
|
# 标识状态为 待处理, 让管理员去确认
|
||||||
|
|
|
@ -139,6 +139,7 @@ class Migration(migrations.Migration):
|
||||||
choices=[
|
choices=[
|
||||||
("long_time_no_login", "Long time no login"),
|
("long_time_no_login", "Long time no login"),
|
||||||
("new_found", "New found"),
|
("new_found", "New found"),
|
||||||
|
("account_deleted", "Account deleted"),
|
||||||
("groups_changed", "Groups change"),
|
("groups_changed", "Groups change"),
|
||||||
("sudoers_changed", "Sudo changed"),
|
("sudoers_changed", "Sudo changed"),
|
||||||
("authorized_keys_changed", "Authorized keys changed"),
|
("authorized_keys_changed", "Authorized keys changed"),
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
from itertools import islice
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import TextChoices
|
from django.db.models import TextChoices
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from itertools import islice
|
|
||||||
|
|
||||||
from common.const import ConfirmOrIgnore
|
from common.const import ConfirmOrIgnore
|
||||||
from common.db.models import JMSBaseModel
|
from common.db.models import JMSBaseModel
|
||||||
|
@ -41,6 +42,7 @@ class RiskChoice(TextChoices):
|
||||||
# 依赖自动发现的
|
# 依赖自动发现的
|
||||||
long_time_no_login = 'long_time_no_login', _('Long time no login') # 好久没登录的账号, 禁用、删除
|
long_time_no_login = 'long_time_no_login', _('Long time no login') # 好久没登录的账号, 禁用、删除
|
||||||
new_found = 'new_found', _('New found') # 未被纳管的账号, 纳管, 删除, 禁用
|
new_found = 'new_found', _('New found') # 未被纳管的账号, 纳管, 删除, 禁用
|
||||||
|
account_deleted = 'account_deleted', _('Account deleted') # 账号被删除, 纳管, 删除, 禁用
|
||||||
group_changed = 'groups_changed', _('Groups change') # 组变更, 确认
|
group_changed = 'groups_changed', _('Groups change') # 组变更, 确认
|
||||||
sudo_changed = 'sudoers_changed', _('Sudo changed') # sudo 变更, 确认
|
sudo_changed = 'sudoers_changed', _('Sudo changed') # sudo 变更, 确认
|
||||||
authorized_keys_changed = 'authorized_keys_changed', _('Authorized keys changed') # authorized_keys 变更, 确认
|
authorized_keys_changed = 'authorized_keys_changed', _('Authorized keys changed') # authorized_keys 变更, 确认
|
||||||
|
|
|
@ -8,7 +8,7 @@ from accounts.models import (
|
||||||
AccountRisk,
|
AccountRisk,
|
||||||
SecretType,
|
SecretType,
|
||||||
AutomationExecution,
|
AutomationExecution,
|
||||||
RiskChoice
|
RiskChoice, Account
|
||||||
)
|
)
|
||||||
from common.const import ConfirmOrIgnore
|
from common.const import ConfirmOrIgnore
|
||||||
from common.utils import random_string
|
from common.utils import random_string
|
||||||
|
@ -19,10 +19,11 @@ TYPE_CHOICES = [
|
||||||
("close", _("Close")),
|
("close", _("Close")),
|
||||||
("disable_remote", _("Disable remote")),
|
("disable_remote", _("Disable remote")),
|
||||||
("delete_remote", _("Delete remote")),
|
("delete_remote", _("Delete remote")),
|
||||||
|
("delete_account", _("Delete account")),
|
||||||
("delete_both", _("Delete remote")),
|
("delete_both", _("Delete remote")),
|
||||||
("add_account", _("Add account")),
|
("add_account", _("Add account")),
|
||||||
("change_password_add", _("Change password and Add")),
|
("change_password_add", _("Change password and Add")),
|
||||||
("change_password", _("Change password"))
|
("change_password", _("Change password")),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +74,10 @@ class RiskHandler:
|
||||||
def handle_reopen(self):
|
def handle_reopen(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def handle_delete_account(self):
|
||||||
|
Account.objects.filter(asset=self.asset, username=self.username).delete()
|
||||||
|
GatheredAccount.objects.filter(asset=self.asset, username=self.username).delete()
|
||||||
|
|
||||||
def handle_close(self):
|
def handle_close(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -113,6 +118,15 @@ class RiskHandler:
|
||||||
def handle_delete_remote(self):
|
def handle_delete_remote(self):
|
||||||
self._handle_delete(delete="remote")
|
self._handle_delete(delete="remote")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def start_execution(execution):
|
||||||
|
execution.save()
|
||||||
|
execution.start()
|
||||||
|
|
||||||
|
if execution.status != "success":
|
||||||
|
msg = _("Execution failed: {}").format(execution.status)
|
||||||
|
raise ValidationError(msg)
|
||||||
|
|
||||||
def _handle_delete(self, delete="both"):
|
def _handle_delete(self, delete="both"):
|
||||||
asset = self.asset
|
asset = self.asset
|
||||||
execution = AutomationExecution()
|
execution = AutomationExecution()
|
||||||
|
@ -124,9 +138,7 @@ class RiskHandler:
|
||||||
"delete": delete,
|
"delete": delete,
|
||||||
"risk": self.risk
|
"risk": self.risk
|
||||||
}
|
}
|
||||||
execution.save()
|
self.start_execution(execution)
|
||||||
execution.start()
|
|
||||||
return execution.summary
|
|
||||||
|
|
||||||
def handle_delete_both(self):
|
def handle_delete_both(self):
|
||||||
self._handle_delete(delete="both")
|
self._handle_delete(delete="both")
|
||||||
|
@ -134,7 +146,11 @@ class RiskHandler:
|
||||||
def handle_change_password(self):
|
def handle_change_password(self):
|
||||||
asset = self.asset
|
asset = self.asset
|
||||||
execution = AutomationExecution()
|
execution = AutomationExecution()
|
||||||
account = self.asset.accounts.get(username=self.username)
|
account = self.asset.accounts.filter(username=self.username, secret_type=SecretType.PASSWORD).first()
|
||||||
|
|
||||||
|
if not account:
|
||||||
|
raise ValidationError("Account not found")
|
||||||
|
|
||||||
execution.snapshot = {
|
execution.snapshot = {
|
||||||
"assets": [str(asset.id)],
|
"assets": [str(asset.id)],
|
||||||
"accounts": [str(account.id)],
|
"accounts": [str(account.id)],
|
||||||
|
@ -143,9 +159,7 @@ class RiskHandler:
|
||||||
"secret_strategy": "random",
|
"secret_strategy": "random",
|
||||||
"name": "Change account password: {}@{}".format(self.username, asset.name),
|
"name": "Change account password: {}@{}".format(self.username, asset.name),
|
||||||
}
|
}
|
||||||
execution.save()
|
self.start_execution(execution)
|
||||||
execution.start()
|
|
||||||
return execution.summary
|
|
||||||
|
|
||||||
def handle_change_password_add(self):
|
def handle_change_password_add(self):
|
||||||
asset = self.asset
|
asset = self.asset
|
||||||
|
@ -174,10 +188,10 @@ class RiskHandler:
|
||||||
'check_conn_after_change': True,
|
'check_conn_after_change': True,
|
||||||
"name": "Push account password: {}@{}".format(self.username, asset.name),
|
"name": "Push account password: {}@{}".format(self.username, asset.name),
|
||||||
}
|
}
|
||||||
execution.save()
|
self.start_execution(execution)
|
||||||
execution.start()
|
|
||||||
|
|
||||||
GatheredAccount.objects.filter(asset=self.asset, username=self.username).update(
|
(
|
||||||
present=True
|
GatheredAccount.objects
|
||||||
|
.filter(asset=self.asset, username=self.username)
|
||||||
|
.update(present=True)
|
||||||
)
|
)
|
||||||
return execution.summary
|
|
||||||
|
|
|
@ -106,11 +106,9 @@ class CommandFilterACL(UserAssetAccountBaseACL):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def create_command_review_ticket(self, run_command, session, cmd_filter_acl, org_id):
|
def create_command_review_ticket(self, run_command, session, cmd_filter_acl, org_id):
|
||||||
from tickets.const import TicketType
|
|
||||||
from tickets.models import ApplyCommandTicket
|
from tickets.models import ApplyCommandTicket
|
||||||
data = {
|
data = {
|
||||||
'title': _('Command confirm') + ' ({})'.format(session.user),
|
'title': _('Command confirm') + ' ({})'.format(session.user),
|
||||||
'type': TicketType.command_confirm,
|
|
||||||
'applicant': session.user_obj,
|
'applicant': session.user_obj,
|
||||||
'apply_run_user_id': session.user_id,
|
'apply_run_user_id': session.user_id,
|
||||||
'apply_run_asset': str(session.asset),
|
'apply_run_asset': str(session.asset),
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
{% include '_head_css_js.html' %}
|
{% include '_head_css_js.html' %}
|
||||||
<link href="{% static "css/jumpserver.css" %}" rel="stylesheet">
|
<link href="{% static "css/jumpserver.css" %}" rel="stylesheet">
|
||||||
<script src="{% static "js/jumpserver.js" %}?_=9"></script>
|
<script src="{% static "js/jumpserver.js" %}?_=9"></script>
|
||||||
|
<style>
|
||||||
|
.btn-sm i {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -20,19 +25,18 @@
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="ibox-content">
|
<div class="ibox-content">
|
||||||
<div>
|
<div>
|
||||||
<img src="{{ INTERFACE.logo_logout }}" style="margin: auto" width="82" height="82">
|
<img src="{{ INTERFACE.logo_logout }}" style="margin: auto" width="62" height="62" alt="logo">
|
||||||
<h2 style="display: inline">
|
<h2 style="display: inline">
|
||||||
{{ INTERFACE.login_title }}
|
{{ INTERFACE.login_title }}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p></p>
|
|
||||||
<div class="alert alert-success info-messages">
|
<div class="alert alert-success info-messages">
|
||||||
{{ msg|safe }}
|
{{ msg|safe }}
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-danger error-messages" style="display: none">
|
<div class="alert alert-danger error-messages" style="display: none"></div>
|
||||||
</div>
|
|
||||||
<div class="progress progress-bar-default progress-striped active">
|
<div class="progress progress-bar-default progress-striped active">
|
||||||
<div aria-valuemax="3600" aria-valuemin="0" aria-valuenow="43" role="progressbar" class="progress-bar">
|
<div aria-valuemax="3600" aria-valuemin="0" aria-valuenow="43" role="progressbar"
|
||||||
|
class="progress-bar">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -84,7 +88,8 @@ function doRequestAuth() {
|
||||||
},
|
},
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
if (!data.error && data.msg === 'ok') {
|
if (!data.error && data.msg === 'ok') {
|
||||||
window.onbeforeunload = function(){};
|
window.onbeforeunload = function () {
|
||||||
|
};
|
||||||
window.location = "{% url 'authentication:login-guard' %}"
|
window.location = "{% url 'authentication:login-guard' %}"
|
||||||
} else if (data.error !== "login_confirm_wait") {
|
} else if (data.error !== "login_confirm_wait") {
|
||||||
if (!errorMsgShow) {
|
if (!errorMsgShow) {
|
||||||
|
@ -105,6 +110,7 @@ function doRequestAuth() {
|
||||||
flash_message: false, // 是否显示flash消息
|
flash_message: false, // 是否显示flash消息
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function initClipboard() {
|
function initClipboard() {
|
||||||
var clipboard = new Clipboard('.btn-copy', {
|
var clipboard = new Clipboard('.btn-copy', {
|
||||||
text: function (trigger) {
|
text: function (trigger) {
|
||||||
|
@ -138,8 +144,10 @@ function cancelTicket() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelCloseConfirm() {
|
function cancelCloseConfirm() {
|
||||||
window.onbeforeunload = function() {};
|
window.onbeforeunload = function () {
|
||||||
window.onunload = function(){};
|
};
|
||||||
|
window.onunload = function () {
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCloseConfirm() {
|
function setCloseConfirm() {
|
||||||
|
|
|
@ -12,15 +12,10 @@ class CeleryBaseService(BaseService):
|
||||||
@property
|
@property
|
||||||
def cmd(self):
|
def cmd(self):
|
||||||
print('\n- Start Celery as Distributed Task Queue: {}'.format(self.queue.capitalize()))
|
print('\n- Start Celery as Distributed Task Queue: {}'.format(self.queue.capitalize()))
|
||||||
ansible_config_path = os.path.join(settings.APPS_DIR, 'libs', 'ansible', 'ansible.cfg')
|
os.environ.setdefault('PYTHONPATH', settings.APPS_DIR)
|
||||||
ansible_modules_path = os.path.join(settings.APPS_DIR, 'libs', 'ansible', 'modules')
|
|
||||||
os.environ.setdefault('LC_ALL', 'en_US.UTF-8')
|
os.environ.setdefault('LC_ALL', 'en_US.UTF-8')
|
||||||
os.environ.setdefault('LANG', 'en_US.UTF-8')
|
os.environ.setdefault('LANG', 'en_US.UTF-8')
|
||||||
os.environ.setdefault('PYTHONOPTIMIZE', '1')
|
os.environ.setdefault('PYTHONOPTIMIZE', '1')
|
||||||
os.environ.setdefault('ANSIBLE_FORCE_COLOR', 'True')
|
|
||||||
os.environ.setdefault('ANSIBLE_CONFIG', ansible_config_path)
|
|
||||||
os.environ.setdefault('ANSIBLE_LIBRARY', ansible_modules_path)
|
|
||||||
os.environ.setdefault('PYTHONPATH', settings.APPS_DIR)
|
|
||||||
|
|
||||||
if os.getuid() == 0:
|
if os.getuid() == 0:
|
||||||
os.environ.setdefault('C_FORCE_ROOT', '1')
|
os.environ.setdefault('C_FORCE_ROOT', '1')
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1523,5 +1523,7 @@
|
||||||
"IpGroup": "IP group",
|
"IpGroup": "IP group",
|
||||||
"PublicIP": "Public IP",
|
"PublicIP": "Public IP",
|
||||||
"PrivateIP": "Private IP",
|
"PrivateIP": "Private IP",
|
||||||
"ExecuteAfterSaving": "Execute after saving"
|
"ExecuteAfterSaving": "Execute after saving",
|
||||||
|
"PleaseEnterReason": "Please enter a reason",
|
||||||
|
"Processing": "Processing"
|
||||||
}
|
}
|
|
@ -914,7 +914,7 @@
|
||||||
"PasswordAndSSHKey": "认证设置",
|
"PasswordAndSSHKey": "认证设置",
|
||||||
"PasswordChangeLog": "改密日志",
|
"PasswordChangeLog": "改密日志",
|
||||||
"PasswordError": "密码错误",
|
"PasswordError": "密码错误",
|
||||||
"PasswordExpired": "密码过期了",
|
"PasswordExpired": "密码已过期",
|
||||||
"PasswordPlaceholder": "请输入密码",
|
"PasswordPlaceholder": "请输入密码",
|
||||||
"PasswordRecord": "密码记录",
|
"PasswordRecord": "密码记录",
|
||||||
"PasswordRule": "密码规则",
|
"PasswordRule": "密码规则",
|
||||||
|
@ -1525,5 +1525,7 @@
|
||||||
"IpGroup": "IP 组",
|
"IpGroup": "IP 组",
|
||||||
"PublicIP": "公有 IP",
|
"PublicIP": "公有 IP",
|
||||||
"PrivateIP": "私有 IP",
|
"PrivateIP": "私有 IP",
|
||||||
"ExecuteAfterSaving": "保存后执行"
|
"ExecuteAfterSaving": "保存后执行",
|
||||||
|
"PleaseEnterReason": "请输入原因",
|
||||||
|
"Processing": "处理中"
|
||||||
}
|
}
|
|
@ -1,11 +1,23 @@
|
||||||
from ops.ansible.cleaner import WorkPostRunCleaner, cleanup_post_run
|
import os
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from ops.ansible.cleaner import WorkPostRunCleaner
|
||||||
|
|
||||||
|
|
||||||
class BaseRunner(WorkPostRunCleaner):
|
class BaseRunner(WorkPostRunCleaner):
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.runner_params = kwargs
|
self.runner_params = kwargs
|
||||||
self.clean_workspace = kwargs.pop("clean_workspace", True)
|
self.clean_workspace = kwargs.pop("clean_workspace", True)
|
||||||
|
self.setup_env()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setup_env():
|
||||||
|
ansible_config_path = os.path.join(settings.APPS_DIR, 'libs', 'ansible', 'ansible.cfg')
|
||||||
|
ansible_modules_path = os.path.join(settings.APPS_DIR, 'libs', 'ansible', 'modules')
|
||||||
|
os.environ.setdefault('ANSIBLE_FORCE_COLOR', 'True')
|
||||||
|
os.environ.setdefault('ANSIBLE_CONFIG', ansible_config_path)
|
||||||
|
os.environ.setdefault('ANSIBLE_LIBRARY', ansible_modules_path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def kill_precess(cls, pid):
|
def kill_precess(cls, pid):
|
||||||
|
|
|
@ -8,9 +8,6 @@ __all__ = ['AnsibleNativeRunner']
|
||||||
|
|
||||||
|
|
||||||
class AnsibleNativeRunner(BaseRunner):
|
class AnsibleNativeRunner(BaseRunner):
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def kill_precess(cls, pid):
|
def kill_precess(cls, pid):
|
||||||
return kill_ansible_ssh_process(pid)
|
return kill_ansible_ssh_process(pid)
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from perms.const import ActionChoices
|
from perms.const import ActionChoices
|
||||||
|
from tickets.const import TicketType
|
||||||
from .general import Ticket
|
from .general import Ticket
|
||||||
|
|
||||||
__all__ = ['ApplyAssetTicket']
|
__all__ = ['ApplyAssetTicket']
|
||||||
|
@ -19,6 +20,8 @@ class ApplyAssetTicket(Ticket):
|
||||||
apply_date_start = models.DateTimeField(verbose_name=_('Date start'), null=True)
|
apply_date_start = models.DateTimeField(verbose_name=_('Date start'), null=True)
|
||||||
apply_date_expired = models.DateTimeField(verbose_name=_('Date expired'), null=True)
|
apply_date_expired = models.DateTimeField(verbose_name=_('Date expired'), null=True)
|
||||||
|
|
||||||
|
TICKET_TYPE = TicketType.apply_asset
|
||||||
|
|
||||||
def get_apply_actions_display(self):
|
def get_apply_actions_display(self):
|
||||||
return ActionChoices.display(self.apply_actions)
|
return ActionChoices.display(self.apply_actions)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .general import Ticket
|
from .general import Ticket
|
||||||
|
from ...const import TicketType
|
||||||
|
|
||||||
|
|
||||||
class ApplyCommandTicket(Ticket):
|
class ApplyCommandTicket(Ticket):
|
||||||
|
@ -19,5 +20,7 @@ class ApplyCommandTicket(Ticket):
|
||||||
null=True, verbose_name=_('Command filter acl')
|
null=True, verbose_name=_('Command filter acl')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
TICKET_TYPE = TicketType.command_confirm
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Apply Command Ticket')
|
verbose_name = _('Apply Command Ticket')
|
||||||
|
|
|
@ -303,6 +303,8 @@ class Ticket(StatusMixin, JMSBaseModel):
|
||||||
max_length=36, blank=True, default='', verbose_name=_('Organization'), db_index=True
|
max_length=36, blank=True, default='', verbose_name=_('Organization'), db_index=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
TICKET_TYPE = TicketType.general
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('-date_created',)
|
ordering = ('-date_created',)
|
||||||
verbose_name = _('Ticket')
|
verbose_name = _('Ticket')
|
||||||
|
@ -313,11 +315,23 @@ class Ticket(StatusMixin, JMSBaseModel):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '{}({})'.format(self.title, self.applicant)
|
return '{}({})'.format(self.title, self.applicant)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
self.type = self.TICKET_TYPE
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def spec_ticket(self):
|
def spec_ticket(self):
|
||||||
attr = self.type.replace('_', '') + 'ticket'
|
attr = self.type.replace('_', '') + 'ticket'
|
||||||
return getattr(self, attr)
|
return getattr(self, attr)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, value):
|
||||||
|
self.title = value
|
||||||
|
|
||||||
# TODO 先单独处理一下
|
# TODO 先单独处理一下
|
||||||
@property
|
@property
|
||||||
def org_name(self):
|
def org_name(self):
|
||||||
|
|
|
@ -5,6 +5,8 @@ from .general import Ticket
|
||||||
|
|
||||||
__all__ = ['ApplyLoginAssetTicket']
|
__all__ = ['ApplyLoginAssetTicket']
|
||||||
|
|
||||||
|
from ...const import TicketType
|
||||||
|
|
||||||
|
|
||||||
class ApplyLoginAssetTicket(Ticket):
|
class ApplyLoginAssetTicket(Ticket):
|
||||||
apply_login_user = models.ForeignKey(
|
apply_login_user = models.ForeignKey(
|
||||||
|
@ -17,6 +19,8 @@ class ApplyLoginAssetTicket(Ticket):
|
||||||
max_length=128, default='', verbose_name=_('Login account')
|
max_length=128, default='', verbose_name=_('Login account')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
TICKET_TYPE = TicketType.login_asset_confirm
|
||||||
|
|
||||||
def activate_connection_token_if_need(self):
|
def activate_connection_token_if_need(self):
|
||||||
if not self.connection_token:
|
if not self.connection_token:
|
||||||
return
|
return
|
||||||
|
|
|
@ -5,11 +5,15 @@ from .general import Ticket
|
||||||
|
|
||||||
__all__ = ['ApplyLoginTicket']
|
__all__ = ['ApplyLoginTicket']
|
||||||
|
|
||||||
|
from ...const import TicketType
|
||||||
|
|
||||||
|
|
||||||
class ApplyLoginTicket(Ticket):
|
class ApplyLoginTicket(Ticket):
|
||||||
apply_login_ip = models.GenericIPAddressField(verbose_name=_('Login IP'), null=True)
|
apply_login_ip = models.GenericIPAddressField(verbose_name=_('Login IP'), null=True)
|
||||||
apply_login_city = models.CharField(max_length=64, verbose_name=_('Login city'), null=True)
|
apply_login_city = models.CharField(max_length=64, verbose_name=_('Login city'), null=True)
|
||||||
apply_login_datetime = models.DateTimeField(verbose_name=_('Login Date'), null=True)
|
apply_login_datetime = models.DateTimeField(verbose_name=_('Login Date'), null=True)
|
||||||
|
|
||||||
|
TICKET_TYPE = TicketType.login_confirm
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Apply Login Ticket')
|
verbose_name = _('Apply Login Ticket')
|
||||||
|
|
|
@ -25,8 +25,9 @@ class TicketSerializer(OrgResourceModelSerializerMixin):
|
||||||
fields_mini = ['id', 'title']
|
fields_mini = ['id', 'title']
|
||||||
fields_small = fields_mini + ['org_id', 'comment']
|
fields_small = fields_mini + ['org_id', 'comment']
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
'serial_num', 'process_map', 'approval_step', 'type', 'state', 'applicant',
|
'serial_num', 'process_map', 'approval_step', 'type',
|
||||||
'status', 'date_created', 'date_updated', 'org_name', 'rel_snapshot'
|
'state', 'applicant', 'status', 'date_created',
|
||||||
|
'date_updated', 'org_name', 'rel_snapshot'
|
||||||
]
|
]
|
||||||
fields = fields_small + read_only_fields
|
fields = fields_small + read_only_fields
|
||||||
extra_kwargs = {}
|
extra_kwargs = {}
|
||||||
|
|
|
@ -137,8 +137,8 @@ class AuthMixin:
|
||||||
if self.can_update_ssh_key():
|
if self.can_update_ssh_key():
|
||||||
from authentication.models import SSHKey
|
from authentication.models import SSHKey
|
||||||
SSHKey.objects.create(
|
SSHKey.objects.create(
|
||||||
public_key=public_key, private_key=private_key, user=self, name=kwargs.get('name'),
|
public_key=public_key, private_key=private_key, user=self, name=kwargs.get('name', ''),
|
||||||
comment=kwargs.get('comment'), is_active=kwargs.get('is_active')
|
comment=kwargs.get('comment', ''), is_active=kwargs.get('is_active')
|
||||||
)
|
)
|
||||||
post_user_change_password.send(self.__class__, user=self)
|
post_user_change_password.send(self.__class__, user=self)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue