Skip to content

账户生命周期

功能介绍#

账户生命周期,用于处理账户创建,变更,禁用等过程中账户属性相关的逻辑,插件开发者可以根据需要灵活地添加自己的逻辑

实现思路#

  • 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) #

抽象方法,插件加载的入口方法

Source code in arkid/core/extension/account_life.py
def load(self):
    super().load()
    self.listen_event(
        core_event.ACCOUNT_LIFE_PERIODIC_TASK, self.periodic_task_event_handler
    )

periodic_task(self, event, **kwargs) #

抽象方法

Parameters:

Name Type Description Default
event arkid.core.event.Event

生命周期定时任务事件

required
Source code in arkid/core/extension/account_life.py
@abstractmethod
def periodic_task(self, event, **kwargs):
    """
    抽象方法
    Args:
        event (arkid.core.event.Event):  生命周期定时任务事件
    """
    pass

示例#

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) #

抽象方法,插件加载的入口方法

Source code in extension_root/com_longgui_account_life_arkid/__init__.py
def load(self):
    super().load()
    self.register_front_pages(select_user_page)
    self.register_account_life_schema(UserExpirationListSchema, "user_expiration")

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

评论