账户生命周期
功能介绍#
账户生命周期,用于处理账户创建,变更,禁用等过程中账户属性相关的逻辑,插件开发者可以根据需要灵活地添加自己的逻辑
实现思路#
- ArkID核心提供接口创建和更新生命周期的定时任务: arkid.core.tasks.tasks.account_life_periodic_task
- 定时任务account_life_periodic_task运行时会发送ACCOUNT_LIFE_PERIODIC_TASK事件
- 插件基类中会监听这个事件,在事件处理函数periodic_task_event_handler中调用抽象方法periodic_task
- 具体插件中覆盖抽象方法periodic_task实现具体的逻辑
抽象方法#
基类定义#
arkid.core.extension.account_life.AccountLifeExtension (Extension)
#
Source code in arkid/core/extension/account_life.py
class AccountLifeExtension(Extension):
TYPE = "account_life"
composite_schema_map = {}
created_composite_schema_list = []
composite_key = 'type'
composite_model = TenantExtensionConfig
@property
def type(self):
return AccountLifeExtension.TYPE
def load(self):
super().load()
self.listen_event(
core_event.ACCOUNT_LIFE_PERIODIC_TASK, self.periodic_task_event_handler
)
@abstractmethod
def periodic_task(self, event, **kwargs):
"""
抽象方法
Args:
event (arkid.core.event.Event): 生命周期定时任务事件
"""
pass
def periodic_task_event_handler(self, event, **kwargs):
self.periodic_task(event, **kwargs)
def register_account_life_schema(self, schema, config_type):
self.register_config_schema(schema, self.package + '_' + config_type)
self.register_composite_config_schema(
schema, config_type, exclude=['extension']
)
composite_model (BaseModel)
django-model
#
TenantExtensionConfig(id, is_del, is_active, updated, created, tenant, extension, config, name, type)
Source code in arkid/core/extension/account_life.py
class TenantExtensionConfig(BaseModel):
class Meta(object):
verbose_name = _("插件运行时配置")
verbose_name_plural = _("插件运行时配置")
tenant = models.ForeignKey('core.Tenant', blank=False, on_delete=models.PROTECT, verbose_name=_('租户'))
extension = models.ForeignKey('Extension', blank=False, on_delete=models.PROTECT, verbose_name=_('插件'))
config = models.JSONField(blank=True, default=dict, verbose_name=_('Runtime Config','运行时配置'))
name = models.CharField(max_length=128, default='', verbose_name=_('名称'))
type = models.CharField(max_length=128, default='', verbose_name=_('类型'))
config: JSONField
blank
django-field
#
Runtime Config
created: DateTimeField
blank
django-field
nullable
#
创建时间
extension: ForeignKey
django-field
#
插件
id: UUIDField
django-field
#
ID
is_active: BooleanField
django-field
#
是否可用
is_del: BooleanField
django-field
#
是否删除
name: CharField
django-field
#
名称
tenant: ForeignKey
django-field
#
租户
type: CharField
django-field
#
类型
updated: DateTimeField
blank
django-field
nullable
#
更新时间
load(self)
#
periodic_task(self, event, **kwargs)
#
示例#
extension_root.com_longgui_account_life_arkid.AccountLifeArkIDExtension (AccountLifeExtension)
#
Source code in extension_root/com_longgui_account_life_arkid/__init__.py
class AccountLifeArkIDExtension(AccountLifeExtension):
def load(self):
super().load()
self.register_front_pages(select_user_page)
self.register_account_life_schema(UserExpirationListSchema, "user_expiration")
def create_tenant_config(self, tenant, config, name, type):
"""
创建生命周期配置,手工解决expiration_time类型为datetime不能json序列化的问题
"""
config_created = TenantExtensionConfig()
config_created.tenant = tenant
config_created.extension = Extension.active_objects.get(package=self.package)
config_created.config = json.loads(config.json())
config_created.name = name
config_created.type = type
config_created.save()
return config_created
def update_tenant_config(self, id, config, name, type):
"""
更新生命周期配置,手工解决expiration_time类型为datetime不能json序列化的问题
"""
tenantextensionconfig = TenantExtensionConfig.valid_objects.filter(
id=id
).first()
tenantextensionconfig.config = json.loads(config.json())
tenantextensionconfig.name = name
tenantextensionconfig.type = type
tenantextensionconfig.save()
return tenantextensionconfig
def periodic_task(self, event, **kwargs):
"""
遍历所有插件配置,如果配置中用户对应的过期时间小于当前时间,则禁用用户
Args:
event (arkid.core.event.Event): 生命周期定时任务事件
"""
logger.info("Doing account life arkid priodic task...")
configs = self.get_tenant_configs(event.tenant)
for cfg in configs:
for item in cfg.config:
user_id = item.get('user').get('id')
user = User.objects.get(id=user_id)
expiration_time = timezone.datetime.strptime(
item.get('expiration_time'), '%Y-%m-%dT%H:%M:%S'
)
logger.info(f"expiration_time: {expiration_time}/now: {datetime.now()}")
if expiration_time <= datetime.now():
user.offline()
create_tenant_config(self, tenant, config, name, type)
#
创建生命周期配置,手工解决expiration_time类型为datetime不能json序列化的问题
Source code in extension_root/com_longgui_account_life_arkid/__init__.py
def create_tenant_config(self, tenant, config, name, type):
"""
创建生命周期配置,手工解决expiration_time类型为datetime不能json序列化的问题
"""
config_created = TenantExtensionConfig()
config_created.tenant = tenant
config_created.extension = Extension.active_objects.get(package=self.package)
config_created.config = json.loads(config.json())
config_created.name = name
config_created.type = type
config_created.save()
return config_created
load(self)
#
periodic_task(self, event, **kwargs)
#
遍历所有插件配置,如果配置中用户对应的过期时间小于当前时间,则禁用用户
Parameters:
Name | Type | Description | Default |
---|---|---|---|
event |
arkid.core.event.Event |
生命周期定时任务事件 |
required |
Source code in extension_root/com_longgui_account_life_arkid/__init__.py
def periodic_task(self, event, **kwargs):
"""
遍历所有插件配置,如果配置中用户对应的过期时间小于当前时间,则禁用用户
Args:
event (arkid.core.event.Event): 生命周期定时任务事件
"""
logger.info("Doing account life arkid priodic task...")
configs = self.get_tenant_configs(event.tenant)
for cfg in configs:
for item in cfg.config:
user_id = item.get('user').get('id')
user = User.objects.get(id=user_id)
expiration_time = timezone.datetime.strptime(
item.get('expiration_time'), '%Y-%m-%dT%H:%M:%S'
)
logger.info(f"expiration_time: {expiration_time}/now: {datetime.now()}")
if expiration_time <= datetime.now():
user.offline()
update_tenant_config(self, id, config, name, type)
#
更新生命周期配置,手工解决expiration_time类型为datetime不能json序列化的问题
Source code in extension_root/com_longgui_account_life_arkid/__init__.py
def update_tenant_config(self, id, config, name, type):
"""
更新生命周期配置,手工解决expiration_time类型为datetime不能json序列化的问题
"""
tenantextensionconfig = TenantExtensionConfig.valid_objects.filter(
id=id
).first()
tenantextensionconfig.config = json.loads(config.json())
tenantextensionconfig.name = name
tenantextensionconfig.type = type
tenantextensionconfig.save()
return tenantextensionconfig