mirror of https://github.com/jumpserver/jumpserver
perf: 修改翻译
parent
6f37cc4d01
commit
327cdc8604
|
@ -28,7 +28,7 @@ class Migration(migrations.Migration):
|
|||
('org_id',
|
||||
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic perform')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic run')),
|
||||
('interval', models.IntegerField(blank=True, default=24, null=True, verbose_name='Interval')),
|
||||
('crontab', models.CharField(blank=True, max_length=128, null=True, verbose_name='Crontab')),
|
||||
('types', models.JSONField(default=list)),
|
||||
|
|
|
@ -20,7 +20,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic perform')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic run')),
|
||||
('interval', models.IntegerField(blank=True, default=24, null=True, verbose_name='Interval')),
|
||||
('crontab', models.CharField(blank=True, max_length=128, null=True, verbose_name='Crontab')),
|
||||
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
|
||||
|
|
|
@ -24,7 +24,7 @@ class Migration(migrations.Migration):
|
|||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic perform')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic run')),
|
||||
('interval', models.IntegerField(blank=True, default=24, null=True, verbose_name='Interval')),
|
||||
('crontab', models.CharField(blank=True, max_length=128, null=True, verbose_name='Crontab')),
|
||||
('accounts', models.JSONField(default=list, verbose_name='Accounts')),
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:16cedef767e949250b792d7f5921071b001545fc17cff4be093cd5faf5a20176
|
||||
size 2453
|
||||
oid sha256:d25379bd2019d09bc9608414a5516b3d19fac2f5a829f3dd845ffeb194599669
|
||||
size 2535
|
||||
|
|
|
@ -2021,11 +2021,11 @@ msgstr ""
|
|||
|
||||
#: assets/models/platform.py:107 assets/serializers/platform.py:166
|
||||
msgid "Su enabled"
|
||||
msgstr ""
|
||||
msgstr "Switch enabled"
|
||||
|
||||
#: assets/models/platform.py:108 assets/serializers/platform.py:144
|
||||
msgid "Su method"
|
||||
msgstr ""
|
||||
msgstr "Switch method"
|
||||
|
||||
#: assets/models/platform.py:109 assets/serializers/platform.py:147
|
||||
msgid "Custom fields"
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:aa826a4ec69f3ea3fb9250affe699f452857201b8e48065038479b9b88d9bfc1
|
||||
size 167853
|
|
@ -4247,7 +4247,7 @@ msgstr "利用可能なプログラムポータルがありません"
|
|||
|
||||
#: ops/mixin.py:23 ops/mixin.py:104 settings/serializers/auth/ldap.py:66
|
||||
#, fuzzy
|
||||
#| msgid "Periodic perform"
|
||||
#| msgid "Periodic run"
|
||||
msgid "Periodic run"
|
||||
msgstr "定期的なパフォーマンス"
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:da4f0f84c01c061cbab1d2fff69f4cd84edb4bbb5088c83a83789a3149575b8f
|
||||
size 138961
|
|
@ -440,8 +440,8 @@
|
|||
"Expired": "Expiration Date",
|
||||
"Export": "Export",
|
||||
"ExportAll": "Export All",
|
||||
"ExportOnlyFiltered": "Export Search Results Only",
|
||||
"ExportOnlySelectedItems": "Export selected Items Only",
|
||||
"ExportOnlyFiltered": "Export filtered items",
|
||||
"ExportOnlySelectedItems": "Export selected items",
|
||||
"ExportRange": "Export Range",
|
||||
"FC": "Fusion Compute",
|
||||
"Failed": "Failed",
|
||||
|
@ -826,7 +826,7 @@
|
|||
"Receivers": "Receiver",
|
||||
"RecentLogin": "Recent Login",
|
||||
"RecentSession": "Recent sessions",
|
||||
"RecentlyUsed": "Recently Used",
|
||||
"RecentlyUsed": "Recently",
|
||||
"RecipientHelpText": "If both recipient A and B are set, the account's key will be split into two parts",
|
||||
"RecipientServer": "Receiving Server",
|
||||
"Reconnect": "Reconnect",
|
||||
|
|
|
@ -59,7 +59,7 @@ class Migration(migrations.Migration):
|
|||
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
|
||||
('interval', models.IntegerField(blank=True, help_text='Units: seconds', null=True, verbose_name='Interval')),
|
||||
('crontab', models.CharField(blank=True, help_text='5 * * * *', max_length=128, null=True, verbose_name='Crontab')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic perform')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic run')),
|
||||
('callback', models.CharField(blank=True, max_length=128, null=True, verbose_name='Callback')),
|
||||
('is_deleted', models.BooleanField(default=False)),
|
||||
('comment', models.TextField(blank=True, verbose_name='Comment')),
|
||||
|
|
|
@ -60,7 +60,7 @@ class Migration(migrations.Migration):
|
|||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('org_id',
|
||||
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic perform')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic run')),
|
||||
('interval', models.IntegerField(blank=True, default=24, null=True, verbose_name='Interval')),
|
||||
('crontab', models.CharField(blank=True, max_length=128, null=True, verbose_name='Crontab')),
|
||||
('name', models.CharField(max_length=128, null=True, verbose_name='Name')),
|
||||
|
@ -164,7 +164,7 @@ class Migration(migrations.Migration):
|
|||
('id', models.UUIDField(db_index=True, default=uuid.uuid4)),
|
||||
('org_id',
|
||||
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic perform')),
|
||||
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic run')),
|
||||
('interval', models.IntegerField(blank=True, default=24, null=True, verbose_name='Interval')),
|
||||
('crontab', models.CharField(blank=True, max_length=128, null=True, verbose_name='Crontab')),
|
||||
('name', models.CharField(max_length=128, null=True, verbose_name='Name')),
|
||||
|
|
|
@ -22,12 +22,10 @@ class PeriodTaskModelMixin(models.Model):
|
|||
)
|
||||
is_periodic = models.BooleanField(default=False, verbose_name=_("Periodic run"))
|
||||
interval = models.IntegerField(
|
||||
default=24, null=True, blank=True,
|
||||
verbose_name=_("Interval"),
|
||||
default=24, null=True, blank=True, verbose_name=_("Interval"),
|
||||
)
|
||||
crontab = models.CharField(
|
||||
blank=True, max_length=128,
|
||||
verbose_name=_("Crontab"),
|
||||
blank=True, max_length=128, null=True, verbose_name=_("Crontab"),
|
||||
)
|
||||
|
||||
@abc.abstractmethod
|
||||
|
|
|
@ -10,6 +10,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
|
||||
from common.db.models import JMSBaseModel
|
||||
from common.utils import signer, get_logger
|
||||
from .signals import setting_changed
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
@ -84,6 +85,7 @@ class Setting(models.Model):
|
|||
if not item:
|
||||
return
|
||||
item.refresh_setting()
|
||||
setting_changed.send(sender=cls, name=name, item=item)
|
||||
|
||||
def refresh_setting(self):
|
||||
setattr(settings, self.name, self.cleaned_value)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from django.dispatch import Signal
|
||||
|
||||
category_setting_updated = Signal()
|
||||
setting_changed = Signal()
|
||||
|
|
|
@ -31,7 +31,7 @@ from ..signals import (
|
|||
post_user_change_password, post_user_leave_org, pre_user_leave_org
|
||||
)
|
||||
|
||||
__all__ = ['User', 'UserPasswordHistory']
|
||||
__all__ = ['User', 'UserPasswordHistory', ]
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
@ -737,20 +737,25 @@ class JSONFilterMixin:
|
|||
return models.Q(id__in=user_id)
|
||||
|
||||
|
||||
class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterMixin, AbstractUser):
|
||||
class Source(models.TextChoices):
|
||||
local = 'local', _('Local')
|
||||
ldap = 'ldap', 'LDAP/AD'
|
||||
openid = 'openid', 'OpenID'
|
||||
radius = 'radius', 'Radius'
|
||||
cas = 'cas', 'CAS'
|
||||
saml2 = 'saml2', 'SAML2'
|
||||
oauth2 = 'oauth2', 'OAuth2'
|
||||
wecom = 'wecom', _('WeCom')
|
||||
dingtalk = 'dingtalk', _('DingTalk')
|
||||
feishu = 'feishu', _('FeiShu')
|
||||
slack = 'slack', _('Slack')
|
||||
custom = 'custom', 'Custom'
|
||||
class Source(models.TextChoices):
|
||||
local = 'local', _('Local')
|
||||
ldap = 'ldap', 'LDAP/AD'
|
||||
openid = 'openid', 'OpenID'
|
||||
radius = 'radius', 'Radius'
|
||||
cas = 'cas', 'CAS'
|
||||
saml2 = 'saml2', 'SAML2'
|
||||
oauth2 = 'oauth2', 'OAuth2'
|
||||
wecom = 'wecom', _('WeCom')
|
||||
dingtalk = 'dingtalk', _('DingTalk')
|
||||
feishu = 'feishu', _('FeiShu')
|
||||
slack = 'slack', _('Slack')
|
||||
custom = 'custom', 'Custom'
|
||||
|
||||
|
||||
class SourceMixin:
|
||||
source: str
|
||||
_source_choices = []
|
||||
Source = Source
|
||||
|
||||
SOURCE_BACKEND_MAPPING = {
|
||||
Source.local: [
|
||||
|
@ -793,6 +798,61 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterM
|
|||
]
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_sources_enabled(cls):
|
||||
mapper = {
|
||||
cls.Source.local: True,
|
||||
cls.Source.ldap: settings.AUTH_LDAP,
|
||||
cls.Source.openid: settings.AUTH_OPENID,
|
||||
cls.Source.radius: settings.AUTH_RADIUS,
|
||||
cls.Source.cas: settings.AUTH_CAS,
|
||||
cls.Source.saml2: settings.AUTH_SAML2,
|
||||
cls.Source.oauth2: settings.AUTH_OAUTH2,
|
||||
cls.Source.wecom: settings.AUTH_WECOM,
|
||||
cls.Source.feishu: settings.AUTH_FEISHU,
|
||||
cls.Source.slack: settings.AUTH_SLACK,
|
||||
cls.Source.dingtalk: settings.AUTH_DINGTALK,
|
||||
cls.Source.custom: settings.AUTH_CUSTOM
|
||||
}
|
||||
return [str(k) for k, v in mapper.items() if v]
|
||||
|
||||
@property
|
||||
def source_display(self):
|
||||
return self.get_source_display()
|
||||
|
||||
@property
|
||||
def is_local(self):
|
||||
return self.source == self.Source.local.value
|
||||
|
||||
@classmethod
|
||||
def get_source_choices(cls):
|
||||
if cls._source_choices:
|
||||
return cls._source_choices
|
||||
used = cls.objects.values_list('source', flat=True).order_by('source').distinct()
|
||||
enabled_sources = cls.get_sources_enabled()
|
||||
_choices = []
|
||||
for k, v in cls.Source.choices:
|
||||
if k in enabled_sources or k in used:
|
||||
_choices.append((k, v))
|
||||
cls._source_choices = _choices
|
||||
return cls._source_choices
|
||||
|
||||
@classmethod
|
||||
def get_user_allowed_auth_backend_paths(cls, username):
|
||||
if not settings.ONLY_ALLOW_AUTH_FROM_SOURCE or not username:
|
||||
return None
|
||||
user = cls.objects.filter(username=username).first()
|
||||
if not user:
|
||||
return None
|
||||
return user.get_allowed_auth_backend_paths()
|
||||
|
||||
def get_allowed_auth_backend_paths(self):
|
||||
if not settings.ONLY_ALLOW_AUTH_FROM_SOURCE:
|
||||
return None
|
||||
return self.SOURCE_BACKEND_MAPPING.get(self.source, [])
|
||||
|
||||
|
||||
class User(AuthMixin, SourceMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterMixin, AbstractUser):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
username = models.CharField(
|
||||
max_length=128, unique=True, verbose_name=_('Username')
|
||||
|
@ -842,7 +902,6 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterM
|
|||
)
|
||||
created_by = models.CharField(max_length=30, default='', blank=True, verbose_name=_('Created by'))
|
||||
updated_by = models.CharField(max_length=30, default='', blank=True, verbose_name=_('Updated by'))
|
||||
source = models.CharField(max_length=30, default=Source.local, choices=Source.choices, verbose_name=_('Source'))
|
||||
date_password_last_updated = models.DateTimeField(
|
||||
auto_now_add=True, blank=True, null=True,
|
||||
verbose_name=_('Date password last updated')
|
||||
|
@ -850,13 +909,16 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterM
|
|||
need_update_password = models.BooleanField(
|
||||
default=False, verbose_name=_('Need update password')
|
||||
)
|
||||
date_api_key_last_used = models.DateTimeField(null=True, blank=True, verbose_name=_('Date api key used'))
|
||||
date_updated = models.DateTimeField(auto_now=True, verbose_name=_('Date updated'))
|
||||
source = models.CharField(
|
||||
max_length=30, default=Source.local,
|
||||
choices=Source.choices, verbose_name=_('Source')
|
||||
)
|
||||
wecom_id = models.CharField(null=True, default=None, max_length=128, verbose_name=_('WeCom'))
|
||||
dingtalk_id = models.CharField(null=True, default=None, max_length=128, verbose_name=_('DingTalk'))
|
||||
feishu_id = models.CharField(null=True, default=None, max_length=128, verbose_name=_('FeiShu'))
|
||||
slack_id = models.CharField(null=True, default=None, max_length=128, verbose_name=_('Slack'))
|
||||
|
||||
date_api_key_last_used = models.DateTimeField(null=True, blank=True, verbose_name=_('Date api key used'))
|
||||
date_updated = models.DateTimeField(auto_now=True, verbose_name=_('Date updated'))
|
||||
DATE_EXPIRED_WARNING_DAYS = 5
|
||||
|
||||
def __str__(self):
|
||||
|
@ -888,10 +950,6 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterM
|
|||
def get_absolute_url(self):
|
||||
return reverse('users:user-detail', args=(self.id,))
|
||||
|
||||
@property
|
||||
def source_display(self):
|
||||
return self.get_source_display()
|
||||
|
||||
@property
|
||||
def is_expired(self):
|
||||
if self.date_expired and self.date_expired < timezone.now():
|
||||
|
@ -899,6 +957,12 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterM
|
|||
else:
|
||||
return False
|
||||
|
||||
def is_password_authenticate(self):
|
||||
cas = self.Source.cas
|
||||
saml2 = self.Source.saml2
|
||||
oauth2 = self.Source.oauth2
|
||||
return self.source not in [cas, saml2, oauth2]
|
||||
|
||||
@property
|
||||
def expired_remain_days(self):
|
||||
date_remain = self.date_expired - timezone.now()
|
||||
|
@ -917,16 +981,6 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterM
|
|||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_local(self):
|
||||
return self.source == self.Source.local.value
|
||||
|
||||
def is_password_authenticate(self):
|
||||
cas = self.Source.cas
|
||||
saml2 = self.Source.saml2
|
||||
oauth2 = self.Source.oauth2
|
||||
return self.source not in [cas, saml2, oauth2]
|
||||
|
||||
def set_required_attr_if_need(self):
|
||||
if not self.name:
|
||||
self.name = self.username
|
||||
|
@ -985,20 +1039,6 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterM
|
|||
raise PermissionDenied(_('Can not delete admin user'))
|
||||
return super(User, self).delete(using=using, keep_parents=keep_parents)
|
||||
|
||||
@classmethod
|
||||
def get_user_allowed_auth_backend_paths(cls, username):
|
||||
if not settings.ONLY_ALLOW_AUTH_FROM_SOURCE or not username:
|
||||
return None
|
||||
user = cls.objects.filter(username=username).first()
|
||||
if not user:
|
||||
return None
|
||||
return user.get_allowed_auth_backend_paths()
|
||||
|
||||
def get_allowed_auth_backend_paths(self):
|
||||
if not settings.ONLY_ALLOW_AUTH_FROM_SOURCE:
|
||||
return None
|
||||
return self.SOURCE_BACKEND_MAPPING.get(self.source, [])
|
||||
|
||||
class Meta:
|
||||
ordering = ['username']
|
||||
verbose_name = _("User")
|
||||
|
|
|
@ -87,7 +87,7 @@ class UserSerializer(RolesSerializerMixin, ResourceLabelsMixin, CommonBulkModelS
|
|||
default=PasswordStrategy.email,
|
||||
allow_null=True,
|
||||
required=False,
|
||||
label=_("Password strategy"),
|
||||
label=_("Password option"),
|
||||
)
|
||||
mfa_enabled = serializers.BooleanField(read_only=True, label=_("MFA enabled"))
|
||||
mfa_force_enabled = serializers.BooleanField(
|
||||
|
@ -182,6 +182,16 @@ class UserSerializer(RolesSerializerMixin, ResourceLabelsMixin, CommonBulkModelS
|
|||
'mfa_level': {'label': _("MFA level")},
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.set_source_options()
|
||||
|
||||
def set_source_options(self):
|
||||
field = self.fields.get("source")
|
||||
if not field:
|
||||
return
|
||||
field.choices = User.get_source_choices()
|
||||
|
||||
def validate_password(self, password):
|
||||
password_strategy = self.initial_data.get("password_strategy")
|
||||
if self.instance is None and password_strategy != PasswordStrategy.custom:
|
||||
|
|
|
@ -15,9 +15,11 @@ from authentication.backends.oidc.signals import openid_create_or_update_user
|
|||
from authentication.backends.saml2.signals import saml2_create_or_update_user
|
||||
from common.const.crontab import CRONTAB_AT_PM_TWO
|
||||
from common.decorators import on_transaction_commit
|
||||
from common.signals import django_ready
|
||||
from common.utils import get_logger
|
||||
from jumpserver.utils import get_current_request
|
||||
from ops.celery.decorator import register_as_period_task
|
||||
from settings.signals import setting_changed
|
||||
from .models import User, UserPasswordHistory
|
||||
from .signals import post_user_create
|
||||
|
||||
|
@ -173,3 +175,16 @@ def clean_expired_user_session_period():
|
|||
def user_logged_out_callback(sender, request, user, **kwargs):
|
||||
session_key = request.session.session_key
|
||||
UserSession.objects.filter(key=session_key).delete()
|
||||
|
||||
|
||||
@receiver(setting_changed)
|
||||
@on_transaction_commit
|
||||
def on_auth_setting_changed_clear_source_choice(sender, name='', **kwargs):
|
||||
print("Receive setting changed signal: {}".format(name))
|
||||
if name.startswith('AUTH_'):
|
||||
User._source_choices = []
|
||||
|
||||
|
||||
@receiver(django_ready)
|
||||
def on_django_ready_refresh_source(sender, **kwargs):
|
||||
User._source_choices = []
|
||||
|
|
Loading…
Reference in New Issue