Ejemplo n.º 1
0
class AdminLoginLog(db.Document):
    """ 管理员登录日志 """

    TYPE = db.choices(LOGIN='******', LOGOUT='退出登录', ERROR='登录认证失败')

    user = db.ReferenceField('AdminUser', verbose_name='用户')
    log_type = db.StringField(choices=TYPE.CHOICES, verbose_name='类型')
    useragent = db.StringField(verbose_name='用户代理(UA)')
    ip = db.StringField(max_length=20, verbose_name='IP')
    created_at = db.DateTimeField(default=datetime.now, verbose_name='创建时间')

    @staticmethod
    def log(user, log_type, **kwargs):
        ua = kwargs.get('ua', get_useragent())
        ip = kwargs.get('ip', get_ip())
        AdminLoginLog(user=user, log_type=log_type, useragent=ua, ip=ip).save()

    @staticmethod
    def login(user):
        AdminLoginLog.log(user, AdminLoginLog.TYPE.LOGIN)

    @staticmethod
    def logout(user):
        AdminLoginLog.log(user, AdminLoginLog.TYPE.LOGOUT)

    @staticmethod
    def error(user):
        AdminLoginLog.log(user, AdminLoginLog.TYPE.ERROR)
Ejemplo n.º 2
0
class View(db.Document):
    """ 视图 """

    TYPE = db.choices(DEFAULT='默认', MODEL='模型', CATEGORY='分类')

    name = db.StringField(max_length=128, verbose_name='名称')
    label = db.StringField(max_length=128, verbose_name='标签')
    view_type = db.StringField(default=TYPE.DEFAULT,
                               choices=TYPE.CHOICES,
                               verbose_name='类型')
    # model = db.ReferenceField('Model', verbose_name='模型')
    menu_icon = db.StringField(max_length=128, verbose_name='图标')
    page_size = db.IntField(default=50, verbose_name='每页记录数')
    can_create = db.BooleanField(default=True, verbose_name='允许创建')
    can_edit = db.BooleanField(default=True, verbose_name='允许编辑')
    can_delete = db.BooleanField(default=True, verbose_name='允许删除')
    can_view_details = db.BooleanField(default=False, verbose_name='允许查看详情')
    can_export = db.BooleanField(default=False, verbose_name='允许导出')
    # column_list = db.ListField(db.StringField(), verbose_name='显示列表字段')
    # column_exclude_list = db.ListField(db.StringField(), verbose_name='隐藏列表字段')
    column_center_list = db.ListField(db.StringField(), verbose_name='居中列表')
    created_at = db.DateTimeField(default=datetime.now, verbose_name='创建时间')
    updated_at = db.DateTimeField(default=datetime.now, verbose_name='更新时间')

    def __repr__(self):
        return '<View {name!r}>'.format(name=self.name)

    def __unicode__(self):
        return self.name

    def process(self, admin, view):
        pass
Ejemplo n.º 3
0
class Image(db.Document):
    """ 图片 """
    key = db.StringField(max_length=128, verbose_name='键名')
    name = db.StringField(max_length=128, verbose_name='图片名称')
    image = db.XImageField(verbose_name='图片')
    # image = db.StringField(verbose_name='图片名称')
    created_at = db.DateTimeField(default=datetime.now, verbose_name='创建时间')
    updated_at = db.DateTimeField(default=datetime.now, verbose_name='更新时间')

    def __unicode__(self):
        return '%s-%s' % (self.key, self.name)
Ejemplo n.º 4
0
class File(db.Document):
    """ 文件 """
    key = db.StringField(max_length=128, verbose_name='键名')
    name = db.StringField(max_length=128, verbose_name='文件名称')
    file = db.XFileField(max_size=20 * 1024 * 1024, verbose_name='文件')
    created_at = db.DateTimeField(default=datetime.now, verbose_name='创建时间')
    updated_at = db.DateTimeField(default=datetime.now, verbose_name='更新时间')

    meta = dict(allow_inheritance=True, )

    def __unicode__(self):
        return '%s-%s' % (self.key, self.name)
Ejemplo n.º 5
0
class AdminUser(db.Document):
    """ 管理员 """

    uid = db.StringField(max_length=50, verbose_name='UID')
    username = db.StringField(max_length=50, verbose_name='用户名')
    password = db.StringField(max_length=128, verbose_name='密码')
    group = db.ReferenceField('AdminGroup', verbose_name='管理组')
    is_root = db.BooleanField(default=False, verbose_name='是否超级管理员')
    active = db.BooleanField(default=True, verbose_name='是否激活')
    freezed_at = db.DateTimeField(verbose_name='冻结时间')
    logined_at = db.DateTimeField(default=datetime.now, verbose_name='登录时间')
    updated_at = db.DateTimeField(default=datetime.now, verbose_name='更新时间')
    created_at = db.DateTimeField(default=datetime.now, verbose_name='创建时间')

    meta = dict(
        ordering=['-created_at'],
    )

    def __unicode__(self):
        return self.username

    def __repr__(self):
        return '<AdminUser {username!r}>'.format(username=self.username)

    @property
    def is_authenticated(self):
        """ 是否登录 """
        return True

    @property
    def is_active(self):
        """ 是否激活 """
        return self.active

    @property
    def is_anonymous(self):
        """ 是否游客 """
        return False

    def get_id(self):
        return str(self.username)

    def hash_password(self, password):
        """ hash算法加密密码 """
        # 在python3中,你需要使用在generate_password_hash()上使用decode('utf-8')方法
        self.password = bcrypt.generate_password_hash(password).decode('utf-8')

    def verify_password(self, password):
        """ 验证密码 """
        return bcrypt.check_password_hash(self.password, password)
Ejemplo n.º 6
0
class AdminGroup(db.Document):
    """ 管理组 """
    name = db.StringField(max_length=50, verbose_name='组名')
    power = db.ListField(db.ReferenceField('View'), verbose_name='使用权限')
    can_create = db.ListField(db.ReferenceField('View'), verbose_name='创建权限')
    can_edit = db.ListField(db.ReferenceField('View'), verbose_name='编辑权限')
    can_delete = db.ListField(db.ReferenceField('View'), verbose_name='删除权限')
    updated_at = db.DateTimeField(default=datetime.now, verbose_name='更新时间')
    created_at = db.DateTimeField(default=datetime.now, verbose_name='创建时间')

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return '<AdminGroup {name!r}>'.format(name=self.name)

    @cached_property
    def power_list(self):
        return [x.name for x in self.power]

    @cached_property
    def can_create_list(self):
        return [x.name for x in self.can_create]

    @cached_property
    def can_edit_list(self):
        return [x.name for x in self.can_edit]

    @cached_property
    def can_delete_list(self):
        return [x.name for x in self.can_delete]
Ejemplo n.º 7
0
class AdminChangeLog(db.Document):
    """ 管理员操作日志 """

    TYPE = db.choices(CREATE='创建', EDIT='编辑', DELETE='删除')

    user = db.ReferenceField('AdminUser', verbose_name='用户')
    log_type = db.StringField(choices=TYPE.CHOICES, verbose_name='类型')
    model = db.StringField(verbose_name='模块')
    before_data = db.StringField(verbose_name='操作前数据')
    after_data = db.StringField(verbose_name='操作后数据')
    useragent = db.StringField(verbose_name='用户代理(UA)')
    ip = db.StringField(max_length=20, verbose_name='IP')
    created_at = db.DateTimeField(default=datetime.now, verbose_name='创建时间')

    @staticmethod
    def log(user, log_type, model, before_data, after_data, **kwargs):
        ua = kwargs.get('ua', get_useragent())
        ip = kwargs.get('ip', get_ip())
        AdminChangeLog(user=user,
                       log_type=log_type,
                       model=model,
                       before_data=before_data,
                       after_data=after_data,
                       useragent=ua,
                       ip=ip).save()

    @staticmethod
    def change_data(user, model, **kwargs):
        """ 变更数据 """
        before = dict(id=model.id)
        after = dict(id=model.id)
        if kwargs.get('form'):
            try:
                for k, v in kwargs.get('form').data.items():
                    if v != model[k]:
                        before[k] = model[k]
                        after[k] = v
            except:
                pass
        else:
            before = model.to_mongo()
        if kwargs.get('log_type') == AdminChangeLog.TYPE.DELETE:
            after = ''
        AdminChangeLog.log(
            user=user,
            log_type=kwargs.get('log_type'),
            model=model.__class__.__name__,
            before_data=str(before),
            after_data=str(after),
        )

    @staticmethod
    def ajax_change(user, model, **kwargs):
        before_data = dict(id=kwargs.get('id'))
        after_data = dict(id=kwargs.get('id'))
        key = kwargs.get('key')
        before_data[key] = kwargs.get('before_data')
        after_data[key] = kwargs.get('after_data')

        AdminChangeLog.log(
            user=user,
            model=model.__name__,
            before_data=str(before_data),
            after_data=str(after_data),
            log_type=AdminChangeLog.TYPE.EDIT,
        )
Ejemplo n.º 8
0
class Item(db.Document):
    """ 选项 """
    MENU_ICON = 'gear'

    TYPE = db.choices(INT='整数', FLOAT='浮点数', STRING='字符串', BOOLEAN='布尔值')

    name = db.StringField(max_length=40, verbose_name='名称')
    key = db.StringField(max_length=40, verbose_name='键名')
    data_type = db.StringField(default=TYPE.INT,
                               choices=TYPE.CHOICES,
                               verbose_name='类型')
    value = db.DynamicField(verbose_name='值')
    created_at = db.DateTimeField(default=datetime.now, verbose_name='创建时间')
    updated_at = db.DateTimeField(default=datetime.now, verbose_name='更新时间')

    meta = dict(
        indexes=['key', '-created_at'],
        ordering=['-created_at'],
    )

    @staticmethod
    # @cache.memoize(timeout=5)
    def get(key, value=0, name=None):
        """ 取值(整型/浮点型) """
        item = Item.objects(key=key).first()
        if item:
            try:
                if item.data_type == Item.TYPE.INT:
                    return int(item.value)
                if item.data_type == Item.TYPE.FLOAT:
                    return float(item.value)
            except ValueError as e:
                return 0
        data_type = Item.TYPE.FLOAT if type(value) is float else Item.TYPE.INT
        Item(key=key, data_type=data_type, value=value, name=name).save()
        return value

    @staticmethod
    def set(key, value=0, name=None):
        """ 设置值(整型/浮点型) """
        item = Item.objects(key=key).first()
        if not item:
            item = Item(key=key)
        if name is not None:
            item.name = name
        item.data_type = Item.TYPE.FLOAT if type(
            value) is float else Item.TYPE.INT
        item.value = value
        item.updated_at = datetime.now()
        item.save()

    @staticmethod
    def inc(key, start=0, value=1, name=None):
        """ 递增,步长为num, 默认递增1; 不存在则创建 """
        params = dict(inc__value=value, set__updated_at=datetime.now())
        if name is not None:
            params['set__name'] = name
        item = Item.objects(key=key).modify(**params)
        if not item:
            params = dict(key=key,
                          data_type=Item.TYPE.INT,
                          value=start + value)
            if name is not None:
                params['name'] = name
            Item(**params).save()
            return start + value
        else:
            return item.value + value

    @staticmethod
    # @cache.memoize(timeout=5)
    def text(key, value='', name=None):
        """ 取值(字符串) """
        item = Item.objects(key=key).first()
        if item:
            return str(item.value)
        Item(key=key, data_type=Item.TYPE.STRING, value=value,
             name=name).save()
        return value

    @staticmethod
    def set_text(key, value='', name=None):
        """ 设置值(字符串) """
        item = Item.objects(key=key).first()
        if not item:
            item = Item(key=key)
        if name is not None:
            item.name = name
        item.data_type = Item.TYPE.STRING
        item.value = value
        item.updated_at = datetime.now()
        item.save()

    @staticmethod
    # @cache.memoize(timeout=5)
    def bool(key, value=False, name=None):
        """ 取值(布尔类型) """
        item = Item.objects(key=key).first()
        if item:
            return True if item.value in ['true', 'True', True] else False
        Item(key=key, data_type=Item.TYPE.BOOLEAN, value=value,
             name=name).save()
        return value

    @staticmethod
    def set_bool(key, value=False, name=None):
        """ 设置值(布尔类型) """
        item = Item.objects(key=key).first()
        if not item:
            item = Item(key=key)
        if name is not None:
            item.name = name
        item.data_type = Item.TYPE.BOOLEAN
        item.value = value
        item.updated_at = datetime.now()
        item.save()
        return True if value in ['true', 'True', True] else False

    @staticmethod
    def choice(key, value='', name=None, sep='|', coerce=str):
        return coerce(random.choice(Item.text(key, value, name).split(sep)))

    @staticmethod
    def list(key, value='', name=None, sep='|', coerce=int):
        return [coerce(x) for x in Item.text(key, value, name).split(sep)]

    @staticmethod
    def group(key, value='', name=None, sep='|', sub='-', coerce=int):
        texts = Item.text(key, value, name).split(sep)
        return [[coerce(y) for y in x.split(sub)] for x in texts]

    @staticmethod
    def hour(key, value='', name=None, sep='|', sub='-', default=None):
        h = datetime.now().hour
        for x in Item.group(key, value, name, sep, sub):
            if x[0] <= h <= x[1]:
                return x
        return default

    @staticmethod
    def time(key, value='', name=None):
        format_str = "%Y-%m-%d %H:%M:%S"
        value = Item.text(key, datetime.now().strftime(format_str), name)
        try:
            value = datetime.strptime(value, format_str)
        except:
            pass
        return value
Ejemplo n.º 9
0
class StatsLog(db.Document):
    """ 统计日志 """
    MENU_ICON = 'bar-chart'

    TYPE = db.choices(INT='整数', FLOAT='浮点数', STRING='字符串', BOOLEAN='布尔值')

    name = db.StringField(max_length=40, verbose_name='名称')
    key = db.StringField(max_length=128, verbose_name='键名')
    uid = db.StringField(max_length=128, verbose_name='用户ID')
    xid = db.StringField(max_length=128, verbose_name='其他ID')
    data_type = db.StringField(default=TYPE.INT,
                               choices=TYPE.CHOICES,
                               verbose_name='类型')
    label = db.StringField(max_length=128, verbose_name='标签')
    day = db.StringField(max_length=20, verbose_name='日期')
    hour = db.IntField(default=0, verbose_name='小时')
    value = db.DynamicField(verbose_name='值')
    created_at = db.DateTimeField(default=datetime.now, verbose_name='创建时间')
    updated_at = db.DateTimeField(default=datetime.now, verbose_name='更新时间')

    meta = dict(
        indexes=[
            'key',
            '-created_at',
            '-updated_at',
            ('key', 'uid'),
            ('key', 'day', 'hour'),
            ('key', 'uid', 'xid', 'label', 'day', 'hour'),
        ],
        ordering=['-created_at'],
    )

    @staticmethod
    def get(key,
            uid='',
            xid='',
            label='',
            day=lambda: today(),
            hour=-1,
            value=0,
            name=None,
            save=True):
        """ 取值(整型/浮点型) """
        if callable(day):
            day = day()
        day = str(day)[:10]
        log = StatsLog.objects(key=key,
                               uid=uid,
                               xid=xid,
                               label=label,
                               day=day,
                               hour=hour).first()
        if log:
            if name is not None:
                log.name = name
                log.save()
            try:
                if log.data_type == StatsLog.TYPE.INT:
                    return int(log.value)
                if log.data_type == StatsLog.TYPE.FLOAT:
                    return float(log.value)
            except ValueError as e:
                return 0
        if save:
            data_type = StatsLog.TYPE.FLOAT if type(
                value) is float else StatsLog.TYPE.INT
            StatsLog(key=key,
                     data_type=data_type,
                     uid=uid,
                     xid=xid,
                     label=label,
                     day=day,
                     hour=hour,
                     value=value,
                     name=name).save()
            return value
        return None

    @staticmethod
    def set(key,
            uid='',
            xid='',
            label='',
            day=lambda: today(),
            hour=-1,
            value=0,
            name=None,
            save=True):
        """ 设置值(整型/浮点型) """
        if callable(day):
            day = day()
        day = str(day)[:10]

        data_type = StatsLog.TYPE.FLOAT if type(
            value) is float else StatsLog.TYPE.INT
        params = dict(set__value=value,
                      set__data_type=data_type,
                      set__updated_at=datetime.now())
        if name is not None:
            params['set__name'] = name
        log = StatsLog.objects(key=key,
                               uid=uid,
                               xid=xid,
                               label=label,
                               day=day,
                               hour=hour).modify(**params)
        if log:
            return value
        if save:
            StatsLog(key=key,
                     data_type=data_type,
                     uid=uid,
                     xid=xid,
                     label=label,
                     day=day,
                     hour=hour,
                     value=value,
                     name=name).save()
            return value
        return None

    @staticmethod
    def inc(key,
            uid='',
            xid='',
            label='',
            day=lambda: today(),
            hour=-1,
            start=0,
            value=1,
            name=None,
            save=True):
        """ 递增(整型/浮点型) """
        if callable(day):
            day = day()
        day = str(day)[:10]

        data_type = StatsLog.TYPE.FLOAT if type(
            value) is float else StatsLog.TYPE.INT
        params = dict(inc__value=value,
                      set__data_type=data_type,
                      set__updated_at=datetime.now())
        if name is not None:
            params['set__name'] = name
        log = StatsLog.objects(key=key,
                               uid=uid,
                               xid=xid,
                               label=label,
                               day=day,
                               hour=hour).modify(**params)
        if log:
            return log.value + value
        if save:
            StatsLog(key=key,
                     data_type=data_type,
                     uid=uid,
                     xid=xid,
                     label=label,
                     day=day,
                     hour=hour,
                     value=start + value,
                     name=name).save()
            return start + value
        return None

    @staticmethod
    def text(key,
             uid='',
             xid='',
             label='',
             day=lambda: today(),
             hour=-1,
             value='',
             name=None,
             save=True):
        """ 取值(字符串) """
        if callable(day):
            day = day()
        day = str(day)[:10]
        log = StatsLog.objects(key=key,
                               uid=uid,
                               xid=xid,
                               label=label,
                               day=day,
                               hour=hour).first()
        if log:
            if name is not None:
                log.name = name
                log.save()
            return log.value
        if save:
            StatsLog(key=key,
                     data_type=StatsLog.TYPE.STRING,
                     uid=uid,
                     xid=xid,
                     label=label,
                     day=day,
                     hour=hour,
                     value=value,
                     name=name).save()
            return value
        return None

    @staticmethod
    def set_text(key,
                 uid='',
                 xid='',
                 label='',
                 day=lambda: today(),
                 hour=-1,
                 value='',
                 name=None,
                 save=True):
        """ 设置值(字符串) """
        if callable(day):
            day = day()
        day = str(day)[:10]

        params = dict(set__value=value, set__updated_at=datetime.now())
        if name is not None:
            params['set__name'] = name
        log = StatsLog.objects(key=key,
                               uid=uid,
                               xid=xid,
                               label=label,
                               day=day,
                               hour=hour).modify(**params)
        if log:
            return value
        if save:
            StatsLog(key=key,
                     data_type=StatsLog.TYPE.STRING,
                     uid=uid,
                     xid=xid,
                     label=label,
                     day=day,
                     hour=hour,
                     value=value,
                     name=name).save()
            return value
        return None

    @staticmethod
    def bool(key,
             uid='',
             xid='',
             label='',
             day=lambda: today(),
             hour=-1,
             value=False,
             name=None,
             save=True):
        """ 取值(布尔值) """
        if type(value) is not bool:
            raise ValueError('The type of value is not bool.')
        if callable(day):
            day = day()
        day = str(day)[:10]

        log = StatsLog.objects(key=key,
                               uid=uid,
                               xid=xid,
                               label=label,
                               day=day,
                               hour=hour).first()
        if log:
            if name is not None:
                log.name = name
                log.save()
            return True if log.value in ['true', 'True', True] else False
        if save:
            StatsLog(key=key,
                     data_type=StatsLog.TYPE.BOOLEAN,
                     uid=uid,
                     xid=xid,
                     label=label,
                     day=day,
                     hour=hour,
                     value=value,
                     name=name).save()
            return value
        return None

    @staticmethod
    def set_bool(key,
                 uid='',
                 xid='',
                 label='',
                 day=lambda: today(),
                 hour=-1,
                 value=False,
                 name=None,
                 save=True):
        """ 设置值(布尔值) """
        if type(value) is not bool:
            raise ValueError('The type of value is not bool.')
        if callable(day):
            day = day()
        day = str(day)[:10]

        params = dict(set__value=value, set__updated_at=datetime.now())
        if name is not None:
            params['set__name'] = name
        log = StatsLog.objects(key=key,
                               uid=uid,
                               xid=xid,
                               label=label,
                               day=day,
                               hour=hour).modify(**params)
        if log:
            return value
        if save:
            StatsLog(key=key,
                     data_type=StatsLog.TYPE.BOOLEAN,
                     uid=uid,
                     xid=xid,
                     label=label,
                     day=day,
                     hour=hour,
                     value=value,
                     name=name).save()
            return value
        return None

    @staticmethod
    def xget(key,
             uid='',
             xid='',
             label='',
             day='',
             hour=-1,
             value=0,
             name=None,
             save=True):
        """ 取值 """
        return StatsLog.get(key, uid, xid, label, day, hour, value, name, save)

    @staticmethod
    def xset(key,
             uid='',
             xid='',
             label='',
             day='',
             hour=-1,
             value=0,
             name=None,
             save=True):
        """ 设置值 """
        return StatsLog.set(key, uid, xid, label, day, hour, value, name, save)

    @staticmethod
    def xinc(key,
             uid='',
             xid='',
             label='',
             day='',
             hour=-1,
             start=0,
             value=1,
             name=None,
             save=True):
        """ 递增 """
        return StatsLog.inc(key, uid, xid, label, day, hour, start, value,
                            name, save)

    @staticmethod
    def xtext(key,
              uid='',
              xid='',
              label='',
              day='',
              hour=-1,
              value='',
              name=None,
              save=True):
        """ 取值(字符串) """
        return StatsLog.text(key, uid, xid, label, day, hour, value, name,
                             save)

    @staticmethod
    def xset_text(key,
                  uid='',
                  xid='',
                  label='',
                  day='',
                  hour=-1,
                  value='',
                  name=None,
                  save=True):
        """ 设置值(字符串) """
        return StatsLog.set_text(key, uid, xid, label, day, hour, value, name,
                                 save)

    @staticmethod
    def xbool(key,
              uid='',
              xid='',
              label='',
              day='',
              hour=-1,
              value=False,
              name=None,
              save=True):
        """ 取值(布尔值) """
        return StatsLog.bool(key, uid, xid, label, day, hour, value, name,
                             save)

    @staticmethod
    def xset_bool(key,
                  uid='',
                  xid='',
                  label='',
                  day='',
                  hour=-1,
                  value=False,
                  name=None,
                  save=True):
        """ 设置值(布尔值) """
        return StatsLog.set_bool(key, uid, xid, label, day, hour, value, name,
                                 save)

    @staticmethod
    def choice(key,
               uid='',
               xid='',
               label='',
               day=lambda: today(),
               hour=-1,
               value='',
               name=None,
               save=True,
               sep='|',
               coerce=str):
        return coerce(
            random.choice(
                StatsLog.text(key,
                              uid=uid,
                              xid=xid,
                              label=label,
                              day=day,
                              hour=hour,
                              value=value,
                              name=name,
                              save=save).split(sep)))

    @staticmethod
    def xchoice(key,
                uid='',
                xid='',
                label='',
                day='',
                hour=-1,
                value='',
                name=None,
                save=True,
                sep='|',
                coerce=str):
        return coerce(
            random.choice(
                StatsLog.xtext(key,
                               uid=uid,
                               xid=xid,
                               label=label,
                               day=day,
                               hour=hour,
                               value=value,
                               name=name,
                               save=save).split(sep)))

    @staticmethod
    def list(key,
             uid='',
             xid='',
             label='',
             day=lambda: today(),
             hour=-1,
             value='',
             name=None,
             save=True,
             sep='|',
             coerce=int):
        """ 将特定格式的字符串转为一维数组 """
        """ 例如, 字符串格式为'1|2|3|4', 返回的是[1, 2, 3, 4] """
        text = StatsLog.text(key,
                             uid=uid,
                             xid=xid,
                             label=label,
                             day=day,
                             hour=hour,
                             value=value,
                             name=name,
                             save=save)
        if not text:
            return None
        texts = text.split(sep)
        return [coerce(x) for x in texts]

    @staticmethod
    def xlist(key,
              uid='',
              xid='',
              label='',
              day='',
              hour=-1,
              value='',
              name=None,
              save=True,
              sep='|',
              coerce=int):
        """ 将特定格式的字符串转为一维数组 """
        """ 例如, 字符串格式为'1|2|3|4', 返回的是[1, 2, 3, 4] """
        text = StatsLog.xtext(key,
                              uid=uid,
                              xid=xid,
                              label=label,
                              day=day,
                              hour=hour,
                              value=value,
                              name=name,
                              save=save)
        if not text:
            return None
        texts = text.split(sep)
        return [coerce(x) for x in texts]

    @staticmethod
    def group(key,
              uid='',
              xid='',
              label='',
              day=lambda: today(),
              hour=-1,
              value='',
              name=None,
              save=True,
              sep='|',
              sub='-',
              coerce=int):
        """ 将特定格式的字符串转为二维数组 """
        """ 例如, 字符串格式为'1-3|4-9|10-32|64-128', 
            返回的是[[1, 3], [4, 9], [10, 32], [64, 128]]
        """
        text = StatsLog.text(key,
                             uid=uid,
                             xid=xid,
                             label=label,
                             day=day,
                             hour=hour,
                             value=value,
                             name=name,
                             save=save)
        if not text:
            return None
        texts = text.split(sep)
        return [[coerce(y) for y in x.split(sub)] for x in texts]

    @staticmethod
    def xgroup(key,
               uid='',
               xid='',
               label='',
               day='',
               hour=-1,
               value='',
               name=None,
               save=True,
               sep='|',
               sub='-',
               coerce=int):
        """ 将特定格式的字符串转为二维数组 """
        """ 例如, 字符串格式为'1-3|4-9|10-32|64-128', 
            返回的是[[1, 3], [4, 9], [10, 32], [64, 128]]
        """
        text = StatsLog.xtext(key,
                              uid=uid,
                              xid=xid,
                              label=label,
                              day=day,
                              hour=hour,
                              value=value,
                              name=name,
                              save=save)
        texts = text.split(sep)
        return [[coerce(y) for y in x.split(sub)] for x in texts]

    @staticmethod
    def hour_range(key,
                   uid='',
                   xid='',
                   label='',
                   day=lambda: today(),
                   hour=-1,
                   value='',
                   name=None,
                   save=True,
                   sep='|',
                   sub='-',
                   default=None):
        """ 获取当前时间整点所在的整点区间 """
        """ 例如, 当前时间的整点是10点, value为'3-8|9-14|15-23', 则10在区间[9, 14]之间,
                返回的值是[9, 14]
        """
        groups = StatsLog.group(key,
                                uid=uid,
                                xid=xid,
                                label=label,
                                day=day,
                                hour=hour,
                                value=value,
                                name=name,
                                save=save,
                                sep=sep,
                                sub=sub)
        if not groups:
            return None
        h = datetime.now().hour
        for x in groups:
            if x[0] <= h <= x[1]:
                return x
        return default

    @staticmethod
    def xhour_range(key,
                    uid='',
                    xid='',
                    label='',
                    day='',
                    hour=-1,
                    value='',
                    name=None,
                    save=True,
                    sep='|',
                    sub='-',
                    default=None):
        """ 获取当前时间整点所在的整点区间 """
        """ 例如, 当前时间的整点是10点, value为'3-8|9-14|15-23', 则10在区间[9, 14]之间,
                返回的值是[9, 14]
        """
        groups = StatsLog.xgroup(key,
                                 uid=uid,
                                 xid=xid,
                                 label=label,
                                 day=day,
                                 hour=hour,
                                 value=value,
                                 name=name,
                                 save=save,
                                 sep=sep,
                                 sub=sub)
        if not groups:
            return None
        h = datetime.now().hour
        for x in groups:
            if x[0] <= h <= x[1]:
                return x
        return default