Exemple #1
0
class SensitiveWordResource(Resource):
    method_decorators = {
        'get': [mis_permission_required('sensitive-word-get')],
        'put': [mis_permission_required('sensitive-word-put')],
        'delete': [mis_permission_required('sensitive-word-delete')],
    }

    def get(self, target):
        """
        获取敏感词信息
        :param target: 敏感词id
        :return:
        """
        word = SensitiveWord.query.filter_by(id=target).first()
        if not word:
            return {'message': '{} is not exists'.format(target)}, 403

        return marshal(word, SensitiveWordListResource.word_fields)

    def put(self, target):
        """
        修改敏感词信息
        :param target: 敏感词id
        :return:
        """
        args_parser = RequestParser()
        args_parser.add_argument('word', required=True, location='json')
        args_parser.add_argument('weights',
                                 type=inputs.natural,
                                 required=True,
                                 location='json')

        args = args_parser.parse_args()

        word = SensitiveWord.query.filter_by(id=target).first()
        if not word:
            return {'message': '{} is not exists'.format(target)}, 403
        print(word.word, args.word)
        if args.word is not None and args.word != word.word:
            if SensitiveWord.query.filter_by(word=args.word).first():
                return {'message': '{} already exists'.format(args.word)}, 403
            word.word = args.word
        if args.weights:
            word.weights = args.weights
        word.utime = datetime.now()
        db.session.add(word)
        db.session.commit()

        return marshal(word, SensitiveWordListResource.word_fields), 201

    def delete(self, target):
        """
        删除敏感词信息
        :param target: 敏感词id
        """
        SensitiveWord.query.filter_by(id=target).delete(
            synchronize_session=False)
        db.session.commit()
        return {}, 204
Exemple #2
0
class StatisticsSearchTotalResource(Resource):
    """
    搜索统计-总数
    """
    method_decorators = {
        'get': [mis_permission_required('statistics-search-total-get')],
    }

    def get(self):
        # 搜索总用户数
        query = db.session.query(func.sum(StatisticsSearchTotal.user_count))
        search_user_count = int(query.scalar() or 0)

        # 总用户数
        query = User.query
        user_count = int(query.count() or 0)

        # 搜索总数
        query = db.session.query(func.sum(StatisticsSearchTotal.count))
        count = int(query.scalar() or 0)
        return {
            'search_user_count': search_user_count,
            'count': count,
            'user_count': user_count
        }
Exemple #3
0
class ChannelResource(Resource):
    """
    频道
    """
    method_decorators = {
        'put': [mis_permission_required('channel-list-put')],
        'delete': [mis_permission_required('channel-list-delete')],
    }

    def put(self, target):
        """
        修改频道
        """
        json_parser = RequestParser()
        json_parser.add_argument('name', required=True, location='json')
        json_parser.add_argument('is_visible', type=inputs.int_range(0, 1), required=True, location='json')
        json_parser.add_argument('sequence', type=inputs.positive, location='json')
        args = json_parser.parse_args()

        channel = Channel.query.filter_by(id=target).first()
        if not channel:
            return {'message': 'Invalid channel id.'}, 400

        if args.name is not None and args.name != channel.name:
            if Channel.query.filter_by(name=args.name).first():
                return {'message': '{} already exists'.format(args.name)}, 403
            channel.name = args.name
        if args.is_visible is not None:
            channel.is_visible = args.is_visible
        if args.sequence is not None:
            channel.sequence = args.sequence
        db.session.add(channel)
        db.session.commit()

        return marshal(channel, ChannelListResource.channel_fields), 201

    def delete(self, target):
        """
        删除频道
        """
        if Article.query.filter_by(channel_id=target).first():
            return {'message': 'Please delete the article first.'}, 400

        Channel.query.filter_by(id=target).delete(synchronize_session=False)
        return {'message': 'OK'}, 204
Exemple #4
0
class ArticleResource(Resource):
    method_decorators = {
        'get': [mis_permission_required('article-get')],
    }

    def get(self, target):
        # 获取文章完整信息
        article = Article.query.filter_by(id=target).first()
        if not article:
            return {'messaget': 'article is not exits.'}
        ret = marshal(article, ArticleListResource.article_fields)
        ret['content'] = article.content.content
        return ret
Exemple #5
0
class UserResource(Resource):
    """
    单用户管理
    """
    method_decorators = {
        'get': [mis_permission_required('user-get')],
    }

    def get(self, target):
        """
        获取用户信息
        """
        user = User.query.filter_by(id=target).first()
        if not user:
            return {'message': 'Invalid user id.'}, 400
        return marshal(user, UserListResource.user_fields)
Exemple #6
0
class LegalizeResource(Resource):
    method_decorators = {
        'get': [mis_permission_required('legalize-get')],
    }

    def get(self, target):
        """
        用户认证申请记录-详细信息
        """
        legal = LegalizeLog.query.filter_by(id=target).first()
        if not legal:
            return {'message': 'Invalid legalize id.'}, 400
        ret = marshal(legal, LegalizeListResource.legalize_fields)
        if legal.type == LegalizeLog.TYPE.REAL_NAME:
            up = UserProfile.query.filter_by(id=legal.user_id).first()
            ret['user_profile'] = dict(
                user_id=up.id,
                gender=up.gender,
                birthday=up.birthday.strftime('%Y-%m-%d')
                if up.birthday else '',
                real_name=up.real_name,
                id_number=up.id_number,
                id_card_front=up.id_card_front,
                id_card_back=up.id_card_back,
                id_card_handheld=up.id_card_handheld,
                area=up.area,
                company=up.company,
                career=up.career)
        elif legal.type == LegalizeLog.TYPE.QUALIFICATION:
            qa = legal.qualification
            ret['qualification'] = dict(qualification_id=qa.id,
                                        user_id=qa.user_id,
                                        name=qa.name,
                                        id_number=qa.id_number,
                                        industry=qa.industry,
                                        company=qa.company,
                                        position=qa.position,
                                        add_info=qa.add_info,
                                        id_card_front=qa.id_card_front,
                                        id_card_back=qa.id_card_back,
                                        id_card_handheld=qa.id_card_handheld,
                                        qualification_img=qa.qualification_img)
        return ret
Exemple #7
0
class StatisticsReadSourceTotalResource(Resource):
    """
    阅读来源统计-总数
    """
    method_decorators = {
        'get': [mis_permission_required('statistics-read-source-total-get')],
    }

    def get(self):
        srsts = StatisticsReadSourceTotal.query.order_by(StatisticsReadSourceTotal.count.desc()).all()
        ret = {
            'read_sources': [],
            'total_read_count': 0
        }
        for srst in srsts:
            ret['total_read_count'] += srst.count
            ret['read_sources'].append({
                'source': srst.source,
                'source_name': StatisticsReadSourceTotal.SOURCE.source_map[srst.source],
                'count': srst.count,
                'count_20_down': srst.count_20_down,
                'count_20_80': srst.count_20_80,
                'count_80_up': srst.count_80_up,
            })

        return ret


    def post(self):
        for source in StatisticsReadSourceTotal.SOURCE.source_map:
            srst = StatisticsReadSourceTotal.query.filter_by(source=source).first()
            if not srst:
                srst = StatisticsReadSourceTotal(source=source, count=3, count_20_down=1, count_20_80=1, count_80_up=1)

            db.session.add(srst)
            db.session.commit()

        return {}
Exemple #8
0
class StatisticsSalesTotalResource(Resource):
    """
    销售额统计-总数
    """
    method_decorators = {
        'get': [mis_permission_required('statistics-sales-total-get')],
    }

    def get(self):
        """
        地区销售额排行榜
        :return:
        """
        ssts = StatisticsSalesTotal.query.order_by(
            StatisticsSalesTotal.money.desc()).all()
        ret = {'area_sales': [], 'total_money': 0}

        for sst in ssts:
            ret['total_money'] += sst.money
            ret['area_sales'].append(
                dict(area=sst.area,
                     area_name=StatisticsArea.area_map[sst.area],
                     money=sst.money))

        return ret

    def post(self):
        for area in StatisticsArea.area_map:
            import random
            money = random.randint(100, 1000) * 100
            sst = StatisticsSalesTotal.query.filter_by(area=area).first()
            if not sst:
                sst = StatisticsSalesTotal(area=area, money=0)

            sst.money += money
            db.session.add(sst)
            db.session.commit()
        return {}
Exemple #9
0
class ArticleListResource(Resource):
    """
    文章列表管理
    """
    article_fields = {
        'article_id': fields.Integer(attribute='id'),  # 文章id
        'title': fields.String(attribute='title'),  # 文章名称
        'name': fields.String(attribute='user.name'),  # 作者
        'channel_name': fields.String(attribute='channel.name'),  # 所属频道
        'comment_count': fields.Integer(attribute='comment_count'),  # 评论数
        'update_time': fields.DateTime(attribute='ctime',
                                       dt_format='iso8601'),  # 更新时间
        'status': fields.Integer(attribute='status'),  # 状态
    }

    method_decorators = {
        'get': [mis_permission_required('article-list-get')],
        'put': [mis_permission_required('article-list-put')],
    }

    def get(self):
        """
        获取文章列表
        """
        args_parser = RequestParser()
        args_parser.add_argument('page',
                                 type=inputs.positive,
                                 required=False,
                                 location='args')
        args_parser.add_argument('per_page',
                                 type=inputs.int_range(constants.PER_PAGE_MIN,
                                                       constants.PER_PAGE_MAX,
                                                       'per_page'),
                                 required=False,
                                 location='args')
        args_parser.add_argument('title', location='args')
        args_parser.add_argument('channel', location='args')
        args_parser.add_argument('status_list', location='args')
        args_parser.add_argument('begin',
                                 type=parser.date_time,
                                 location='args')
        args_parser.add_argument('end', type=parser.date_time, location='args')
        args_parser.add_argument('order_by', location='args')

        args = args_parser.parse_args()
        page = constants.DEFAULT_PAGE if args.page is None else args.page
        per_page = constants.DEFAULT_PER_PAGE if args.per_page is None else args.per_page

        articles = Article.query
        if args.title is not None:
            articles = articles.filter(
                Article.title.like('%' + args.title + '%'))
        if args.channel is not None:
            channels = Channel.query.filter(
                Channel.name.like('%' + args.channel + '%')).all()
            channel_ids = [i.id for i in channels]
            articles = articles.filter(Article.channel_id.in_(channel_ids))

        if args.status_list is not None:
            try:
                status_list = [int(i) for i in args.status_list.split(',')]
            except:
                return {'message': 'status_list parameter error.'}, 403
            articles = articles.filter(Article.status.in_(status_list))

        if args.begin and args.end and args.end >= args.begin:
            articles = articles.filter(
                Article.ctime.between(args.begin, args.end))

        if args.order_by is not None:
            if args.order_by == 'id':
                articles = articles.order_by(Article.id.asc())
        else:
            articles = articles.order_by(Article.ctime.desc())
        total_count = articles.count()
        articles = articles.offset(per_page * (page - 1)).limit(per_page).all()

        ret = marshal(articles,
                      ArticleListResource.article_fields,
                      envelope='articles')
        ret['total_count'] = total_count

        return ret

    def put(self):
        """
        批量修改文章状态
        :return:
        """
        json_parser = RequestParser()
        json_parser.add_argument('reject_reason', location='json')
        json_parser.add_argument('status',
                                 type=inputs.int_range(1, 6),
                                 required=True,
                                 location='json')
        json_parser.add_argument('article_ids',
                                 action='append',
                                 type=inputs.positive,
                                 required=True,
                                 location='json')
        args = json_parser.parse_args()
        articles = Article.query.filter(Article.id.in_(args.article_ids)).all()
        need_kafka_send_msgs = []
        need_rebuild_es_indexes = []
        for article in articles:
            if args.status == Article.STATUS.BANNED:
                # 封禁
                if article.status != Article.STATUS.APPROVED:
                    return {
                        'message': '"%s" 文章不是审核状态, 不能封禁' % article.title
                    }, 403
            elif args.status == 6:
                # 解封
                if article.status != Article.STATUS.BANNED:
                    return {
                        'message': '"%s" 文章不是封禁状态, 不能解封' % article.title
                    }, 403
                article.status = Article.STATUS.APPROVED
            elif args.status == Article.STATUS.APPROVED:
                # 通过审核
                if article.status != Article.STATUS.UNREVIEWED:
                    return {
                        'message': '"%s" 文章不是待审核状态, 不能通过审核' % article.title
                    }, 403
                article.review_time = datetime.now()
                article.reviewer_id = g.administrator_id

                # 记录需要kafka推送的消息
                need_kafka_send_msgs.append('{},{}'.format(
                    article.channel_id, article.id))
                # 记录需要es添加索引
                need_rebuild_es_indexes.append(article)

            elif args.status == Article.STATUS.FAILED:
                # 审核失败(驳回)
                if article.status != Article.STATUS.UNREVIEWED:
                    return {
                        'message': '"%s" 文章不是待审核状态, 不能驳回' % article.title
                    }, 403
                article.reviewer_id = g.administrator_id
                article.review_time = datetime.now()
                article.reject_reason = args.reject_reason if args.reject_reason else '系统审核'
            elif args.status == Article.STATUS.DELETED:
                # 删除
                article.delete_time = datetime.now()
            else:
                return {'message': '错误的状态操作'}, 403
            article.status = args.status if args.status != 6 else Article.STATUS.APPROVED
            db.session.add(article)
        db.session.commit()

        # 文章通过审核,kafka推送消息给推荐系统
        for msg in need_kafka_send_msgs:
            current_app.kafka_producer.send('new-article', msg.encode())

        # 添加ES索引
        for article in need_rebuild_es_indexes:
            doc = {
                'article_id': article.id,
                'user_id': article.user_id,
                'title': article.title,
                'content': article.content.content,
                'status': article.status,
                'create_time': article.ctime
            }
            try:
                current_app.es.index(index='articles',
                                     doc_type='article',
                                     body=doc,
                                     id=article.id)
            except Exception as e:
                current_app.logger.error(e)

        return {'message': 'OK'}, 201
Exemple #10
0
class LegalizeListResource(Resource):
    """
    用户认证申请记录
    """
    legalize_fields = {
        'legalize_id': fields.Integer(attribute='id'),  # 申请记录id
        'account': fields.String(attribute='user.account'),  # 账号
        'name': fields.String(attribute='user.name'),  # 用户名
        'create_time': fields.DateTime(attribute='ctime',
                                       dt_format='iso8601'),  # 申请认证时间
        'type': fields.Integer(attribute='type'),  # 认证类型
        'status': fields.Integer(attribute='status'),  # 状态
    }

    method_decorators = {
        'get': [mis_permission_required('legalize-list-get')],
        'post': [mis_permission_required('legalize-list-post')],
        'put': [mis_permission_required('legalize-list-put')],
    }

    def get(self):
        """
        获取用户认证申请记录
        """
        args_parser = RequestParser()
        args_parser.add_argument('page',
                                 type=inputs.positive,
                                 required=False,
                                 location='args')
        args_parser.add_argument('per_page',
                                 type=inputs.int_range(constants.PER_PAGE_MIN,
                                                       constants.PER_PAGE_MAX,
                                                       'per_page'),
                                 required=False,
                                 location='args')
        args_parser.add_argument('status',
                                 type=inputs.positive,
                                 location='args')
        args_parser.add_argument('order_by', location='args')

        args = args_parser.parse_args()
        page = constants.DEFAULT_PAGE if args.page is None else args.page
        per_page = constants.DEFAULT_PER_PAGE if args.per_page is None else args.per_page

        legalizes = LegalizeLog.query
        if args.status is not None:
            legalizes = legalizes.filter_by(status=args.status)
        if args.order_by is not None:
            if args.order_by == 'id':
                legalizes = legalizes.order_by(LegalizeLog.id.asc())
            else:
                legalizes = legalizes.order_by(LegalizeLog.utime.desc())
        else:
            legalizes = legalizes.order_by(LegalizeLog.utime.desc())
        total_count = legalizes.count()
        legalizes = legalizes.offset(per_page *
                                     (page - 1)).limit(per_page).all()

        ret = marshal(legalizes,
                      LegalizeListResource.legalize_fields,
                      envelope='legalizes')
        ret['total_count'] = total_count

        return ret

    def post(self):
        """
        *** 测试
        """
        user_id = 8
        # qual = Qualification(user_id=user_id,
        #                      name='wangzq',
        #                      id_number='440982199006091854',
        #                      industry='软件',
        #                      company='cz',
        #                      position='python',
        #                      add_info='nothing',
        #                      id_card_front='id_card_front',
        #                      id_card_back='id_card_back',
        #                      id_card_handheld='id_card_handheld',
        #                      qualification_img='qualification_img',
        #             )
        # db.session.add(qual)
        # db.session.commit()
        legal = LegalizeLog(user_id=user_id,
                            type=LegalizeLog.TYPE.REAL_NAME,
                            status=LegalizeLog.STATUS.PROCESSING)
        db.session.add(legal)
        db.session.commit()

        return marshal(legal, LegalizeListResource.legalize_fields), 201

    def put(self):
        """
        批量通过/驳回
        """
        json_parser = RequestParser()
        json_parser.add_argument('legalize_ids',
                                 action='append',
                                 type=inputs.positive,
                                 required=True,
                                 location='json')
        json_parser.add_argument('status',
                                 type=inputs.int_range(2, 3),
                                 required=True,
                                 location='json')
        json_parser.add_argument('reject_reason', location='json')
        args = json_parser.parse_args()

        legalizes = LegalizeLog.query.filter(
            LegalizeLog.id.in_(args.legalize_ids))
        user_ids = [legal.user_id for legal in legalizes.all()]
        count = legalizes.update({'status': args.status},
                                 synchronize_session=False)
        if args.status == LegalizeLog.STATUS.REJECT:
            legalizes.update(
                {'reject_reason': args.reject_reason or '资料不通过,驳回'},
                synchronize_session=False)
            User.query.filter(User.id.in_(user_ids)).update(
                {'is_media': False}, synchronize_session=False)
        elif args.status == LegalizeLog.STATUS.APPROVED:
            User.query.filter(User.id.in_(user_ids)).update(
                {'is_media': True}, synchronize_session=False)

        db.session.commit()
        return {'count': count}, 201
Exemple #11
0
class UserListResource(Resource):
    """
    用户管理
    """
    user_fields = {
        'user_id': fields.Integer(attribute='id'),  # 用户id
        'account': fields.String(),  # 账号
        'name': fields.String(attribute='name'),  # 用户名
        'email': fields.String(),  # 邮箱
        'mobile': fields.String(attribute='mobile'),  # 手机号
        'last_login': fields.DateTime(attribute='last_login',
                                      dt_format='iso8601'),  # 最后活动时间
        'is_verified': fields.Integer(attribute='is_verified'),  # 是否实名认证
        'is_media': fields.Integer(attribute='is_media'),  # 是否资质认证
        'status': fields.Integer(attribute='status'),  # 状态
    }

    method_decorators = {
        'get': [mis_permission_required('userlist-get')],
        'post': [mis_permission_required('userlist-post')],
        'put': [mis_permission_required('userlist-put')],
    }

    def get(self):
        """
        获取用户列表
        """
        args_parser = RequestParser()
        args_parser.add_argument('page',
                                 type=inputs.positive,
                                 required=False,
                                 location='args')
        args_parser.add_argument('per_page',
                                 type=inputs.int_range(constants.PER_PAGE_MIN,
                                                       constants.PER_PAGE_MAX,
                                                       'per_page'),
                                 required=False,
                                 location='args')
        args_parser.add_argument('keyword', location='args')
        args_parser.add_argument('begin',
                                 type=parser.date_time,
                                 location='args')
        args_parser.add_argument('end', type=parser.date_time, location='args')
        args_parser.add_argument('status',
                                 type=inputs.int_range(0, 1),
                                 location='args')
        args_parser.add_argument('order_by', location='args')

        args = args_parser.parse_args()
        page = constants.DEFAULT_PAGE if args.page is None else args.page
        per_page = constants.DEFAULT_PER_PAGE if args.per_page is None else args.per_page

        users = User.query
        if args.keyword:
            users = users.filter(
                or_(User.mobile.like('%' + args.keyword + '%'),
                    User.account.like('%' + args.keyword + '%')))
        if args.status is not None:
            users = users.filter(User.status == args.status)
        if args.begin and args.end and args.end > args.begin:
            users = users.filter(User.last_login.between(args.begin, args.end))
        if args.order_by is not None:
            if args.order_by == 'id':
                users = users.order_by(User.id.asc())
            else:
                users = users.order_by(User.last_login.desc())
        else:
            users = users.order_by(User.last_login.asc())
        total_count = users.count()
        users = users.offset(per_page * (page - 1)).limit(per_page).all()

        ret = marshal(users, UserListResource.user_fields, envelope='users')
        ret['total_count'] = total_count

        return ret

    def post(self):
        """
        新增用户
        """
        json_parser = RequestParser()
        json_parser.add_argument('account',
                                 type=parser.mis_account,
                                 required=True,
                                 location='json')
        json_parser.add_argument('password',
                                 type=parser.mis_password,
                                 required=True,
                                 location='json')
        json_parser.add_argument('name',
                                 type=inputs.regex(r'^.{1,7}$'),
                                 required=True,
                                 location='json')
        json_parser.add_argument('profile_photo',
                                 type=parser.image_base64,
                                 required=False,
                                 location='json')
        json_parser.add_argument('introduction',
                                 required=False,
                                 location='json')
        json_parser.add_argument('email',
                                 type=parser.email,
                                 required=False,
                                 location='json')
        json_parser.add_argument('mobile',
                                 type=parser.mobile,
                                 required=True,
                                 location='json')
        json_parser.add_argument('gender',
                                 type=inputs.int_range(0, 1),
                                 required=True,
                                 location='json')
        json_parser.add_argument('area', required=False, location='json')
        json_parser.add_argument('company', required=False, location='json')
        json_parser.add_argument('career', required=False, location='json')
        args = json_parser.parse_args()
        if User.query.filter_by(account=args.account).first():
            return {'message': '{} already exists'.format(args.account)}, 403
        if User.query.filter_by(mobile=args.mobile).first():
            return {'message': '{} already exists'.format(args.mobile)}, 403
        user = User(account=args.account,
                    password=generate_password_hash(args.password),
                    name=args.name,
                    introduction=args.introduction,
                    email=args.email,
                    mobile=args.mobile,
                    status=User.STATUS.ENABLE,
                    last_login=datetime.now())
        if args.profile_photo:
            try:
                photo_url = upload_image(args.profile_photo)
                user.profile_photo = photo_url
            except Exception as e:
                current_app.logger.error('upload failed {}'.format(e))
                return {
                    'message': 'Uploading profile photo image failed.'
                }, 507
        db.session.add(user)
        db.session.commit()
        user_profile = UserProfile(id=user.id,
                                   gender=args.gender,
                                   area=args.area,
                                   company=args.company,
                                   career=args.career)
        db.session.add(user_profile)
        db.session.commit()
        return marshal(user, UserListResource.user_fields), 201

    def put(self):
        """
        批量冻结/解冻
        """
        json_parser = RequestParser()
        json_parser.add_argument('user_ids',
                                 action='append',
                                 type=inputs.positive,
                                 required=True,
                                 location='json')
        json_parser.add_argument('status',
                                 type=inputs.int_range(0, 1),
                                 required=True,
                                 location='json')
        args = json_parser.parse_args()

        count = User.query.filter(User.id.in_(args.user_ids)).update(
            {'status': args.status}, synchronize_session=False)
        db.session.commit()
        return {'count': count}, 201
Exemple #12
0
class GroupResource(Resource):
    """
    对指定管理员组管理
    """
    method_decorators = {
        'get': [mis_permission_required('group-get')],
        'put': [mis_permission_required('group-put')],
        'delete': [mis_permission_required('group-delete')],
    }

    def get(self, target):
        """
        获取id=target组的信息
        """
        group = MisAdministratorGroup.query.filter_by(id=target).first()
        if not group:
            return {'message': 'Invalid group id.'}, 400
        ret = marshal(group, GroupListResource.group_fields)
        permission_tree = get_permission_tree(group.id)
        ret['permission_tree'] = permission_tree
        return ret

    def put(self, target):
        """
        修改id=target管理员组信息
        """
        json_parser = RequestParser()
        json_parser.add_argument('name', location='json')
        json_parser.add_argument('remark', location='json')
        json_parser.add_argument('status',
                                 type=inputs.int_range(0, 1),
                                 location='json')
        json_parser.add_argument('permission_ids',
                                 action='append',
                                 type=inputs.positive,
                                 location='json')
        args = json_parser.parse_args()
        print(args)
        group = MisAdministratorGroup.query.filter_by(id=target).first()
        if not group:
            return {'message': 'Invalid group id.'}, 400
        if args.name and args.name != group.name:
            if MisAdministratorGroup.query.filter_by(name=args.name).first():
                return {'message': '{} already exists'.format(args.name)}
            group.name = args.name
        if args.status is not None:
            group.status = args.status
        if args.remark:
            group.remark = args.remark
        if args.permission_ids is not None:
            inc_red_group_permission(group.id, args.permission_ids)
        db.session.add(group)
        db.session.commit()
        return marshal(group, GroupListResource.group_fields), 201

    def delete(self, target):
        """
        删除id=target管理员组信息
        """
        if MisAdministrator.query.filter_by(group_id=target).first():
            return {'message': 'Delete administrator first.'}, 400
        # 删除组权限信息
        MisGroupPermission.query.filter_by(group_id=target).delete(
            synchronize_session=False)
        # 删除组信息
        MisAdministratorGroup.query.filter_by(id=target).delete(
            synchronize_session=False)
        try:
            db.session.commit()
        except:
            db.session.rollback()
            raise

        return {'message': 'OK'}, 204
Exemple #13
0
class GroupListResource(Resource):
    """
    管理员角色/组管理
    """
    method_decorators = {
        'get': [mis_permission_required('group-list-get')],
        'post': [mis_permission_required('group-list-post')],
    }
    group_fields = {
        'group_id': fields.Integer(attribute='id'),
        'name': fields.String(attribute='name'),
        'remark': fields.String(attribute='remark'),
        'status': fields.Integer(attribute='status'),
    }

    def get(self):
        """
        获取所有组
        """
        args_parser = RequestParser()
        args_parser.add_argument('page',
                                 type=inputs.positive,
                                 required=False,
                                 location='args')
        args_parser.add_argument('per_page',
                                 type=inputs.int_range(constants.PER_PAGE_MIN,
                                                       constants.PER_PAGE_MAX,
                                                       'per_page'),
                                 required=False,
                                 location='args')
        args_parser.add_argument('keyword', location='args')
        args_parser.add_argument('order_by', location='args')
        args = args_parser.parse_args()
        page = constants.DEFAULT_PAGE if args.page is None else args.page
        per_page = constants.DEFAULT_PER_PAGE if args.per_page is None else args.per_page

        groups = MisAdministratorGroup.query
        if args.keyword:
            groups = groups.filter(
                MisAdministratorGroup.name.like('%' + args.keyword + '%'))
        if args.order_by is not None:
            if args.order_by == 'id':
                groups = groups.order_by(MisAdministratorGroup.id.asc())
        else:
            groups = groups.order_by(MisAdministratorGroup.utime.desc())
        total_count = groups.count()
        groups = groups.offset(per_page * (page - 1)).limit(per_page).all()

        ret = marshal(groups,
                      GroupListResource.group_fields,
                      envelope='groups')
        ret['total_count'] = total_count
        return ret

    def post(self):
        """
        添加组
        """
        json_parser = RequestParser()
        json_parser.add_argument('name', required=True, location='json')
        json_parser.add_argument('remark', location='json')
        json_parser.add_argument('status',
                                 type=inputs.int_range(0, 1),
                                 location='json')
        json_parser.add_argument('permission_ids',
                                 action='append',
                                 type=inputs.positive,
                                 location='json')
        args = json_parser.parse_args()
        if MisAdministratorGroup.query.filter_by(name=args.name).first():
            return {
                'message': 'Group {} already exists.'.format(args.name)
            }, 403
        group = MisAdministratorGroup(
            name=args.name,
            remark=args.remark if args.remark else '',
            status=args.status if args.status is not None else 1)

        try:
            db.session.add(group)
            db.session.commit()
            print(args.permission_ids)
            if args.permission_ids:
                for index, permission_id in enumerate(args.permission_ids):
                    db.session.add(
                        MisGroupPermission(group_id=group.id,
                                           permission_id=permission_id))
                    print(group.id, permission_id)
                    if (index + 1) % 1000 == 0:
                        db.session.commit()
                db.session.commit()
        except Exception:
            db.session.rollback()
            raise

        return {'group_id': group.id, 'name': args.name}
Exemple #14
0
class StatisticsBasicResource(Resource):
    """
    基本统计
    """
    method_decorators = {
        'get': [mis_permission_required('statistics-basic-get')],
    }

    def _get_size_hour(self, statistics_type, args):
        # 获取粒度为小时的数据
        ret = []
        begin = args.begin
        while begin <= args.end + timedelta(hours=23):
            query = db.session.query(func.sum(StatisticsBasic.count)) \
                .filter(StatisticsBasic.type == statistics_type,
                        and_(StatisticsBasic.date_time >= begin,
                             StatisticsBasic.date_time < begin + timedelta(hours=1))
                        )
            hour_count = int(query.scalar() or 0)
            ret.append(
                dict(date_time=begin.strftime('%Y-%m-%d %H:%M:%S'),
                     count=hour_count))
            begin += timedelta(hours=1)
        return ret

    def _get_size_day(self, statistics_type, args):
        # 获取粒度为天的数据
        ret = []
        begin = args.begin
        while begin <= args.end:
            query = db.session.query(func.sum(StatisticsBasic.count)) \
                .filter(StatisticsBasic.type == statistics_type,
                        and_(StatisticsBasic.date_time >= begin,
                             StatisticsBasic.date_time < begin + timedelta(days=1))
                        )
            day_count = int(query.scalar() or 0)
            ret.append(dict(date=begin.strftime('%Y-%m-%d'), count=day_count))
            begin += timedelta(days=1)
        return ret

    def _get_size_month(self, statistics_type):
        # 获取粒度为月的全年数据
        ret = []
        now = datetime.now()
        month = 1
        while True:
            if month > 12:
                break
            begin = datetime(now.year, month=month, day=1)
            if month == 12:
                end = datetime(now.year + 1, month=1, day=1)
            else:
                end = datetime(now.year, month=month + 1, day=1)
            query = db.session.query(func.sum(StatisticsBasic.count)) \
                .filter(StatisticsBasic.type == statistics_type,
                        and_(StatisticsBasic.date_time >= begin,
                             StatisticsBasic.date_time < end)
                        )
            month_count = int(query.scalar() or 0)
            ret.append(dict(month=month, count=month_count))
            month += 1
        return ret

    def get(self):
        args_parser = RequestParser()
        args_parser.add_argument('type',
                                 type=parser.statistics_type,
                                 required=True,
                                 location='args')
        args_parser.add_argument('size',
                                 type=parser.statistics_size,
                                 location='args')
        args_parser.add_argument('begin', type=parser.date, location='args')
        args_parser.add_argument('end', type=parser.date, location='args')
        args = args_parser.parse_args()
        statistics_type = StatisticsType.type_map[args.type]
        if args.size is not None:
            # 不同粒度的图表数据
            if args.size == 'month':
                return self._get_size_month(statistics_type)
            elif args.size == 'day':
                if not args.begin or not args.end or args.begin > args.end:
                    return {'message': '(begin or end) parameter error.'}, 403
                return self._get_size_day(statistics_type, args)
            elif args.size == 'hour':
                if not args.begin or not args.end or args.begin > args.end:
                    return {'message': '(begin or end) parameter error.'}, 403
                return self._get_size_hour(statistics_type, args)
        else:
            # 获取基本统计数据
            # 1.当天总数 2.周涨/降幅百分比 3.日涨/降幅百分比 4.日平均数 5.总天数 6.总数量

            now = datetime.now()
            today = datetime(year=now.year, month=now.month, day=now.day)

            # 总数
            query = db.session.query(func.sum(StatisticsBasic.count)) \
                .filter(StatisticsBasic.type == statistics_type)
            total_count = int(query.scalar() or 0)

            # 总天数
            first_day = StatisticsBasic.query.order_by(
                StatisticsBasic.date_time.asc()).first()
            total_days = 0
            if first_day is not None:
                total_days = (now - first_day.date_time).days
                if (now -
                        first_day.date_time).seconds > total_days * 3600 * 24:
                    total_days += 1

            # 当天总数
            query = db.session.query(func.sum(StatisticsBasic.count))\
                .filter(StatisticsBasic.type == statistics_type,
                        StatisticsBasic.date_time.between(today, now)
                        )
            day_count = int(query.scalar() or 0)

            # 昨天总数
            yesterday = today - timedelta(days=1)
            query = db.session.query(func.sum(StatisticsBasic.count))\
                .filter(StatisticsBasic.type==statistics_type,
                        and_(StatisticsBasic.date_time >= yesterday,
                             StatisticsBasic.date_time < today)
                        )
            yesterday_count = int(query.scalar() or 0)

            # 上周数量
            lask_week_begin = today - timedelta(days=13)
            lask_week_end = today - timedelta(days=6)
            query = db.session.query(func.sum(StatisticsBasic.count))\
                .filter(StatisticsBasic.type==statistics_type,
                        and_(StatisticsBasic.date_time >= lask_week_begin,
                             StatisticsBasic.date_time < lask_week_end)
                        )
            lask_week_count = int(query.scalar() or 0)

            # 本周数量
            week_begin = lask_week_end
            query = db.session.query(func.sum(StatisticsBasic.count)) \
                .filter(StatisticsBasic.type == statistics_type,
                        and_(StatisticsBasic.date_time >= week_begin,
                             StatisticsBasic.date_time < now)
                        )
            week_count = int(query.scalar() or 0)

            # 周同比
            week_percent = round(
                (week_count - lask_week_count) /
                (lask_week_count if lask_week_count else 1) * 100, 2)
            # 日环比
            day_percent = round(
                (day_count - yesterday_count) /
                (yesterday_count if yesterday_count else 1) * 100, 2)
            # 日均数
            day_average = round(
                total_count / (total_days if total_days else 1), 2)

            ret = dict(day_count=day_count,
                       week_percent=week_percent,
                       day_percent=day_percent,
                       day_average=day_average,
                       total_days=total_days,
                       total_count=total_count)
            return ret
Exemple #15
0
class ChannelListResource(Resource):
    """
    频道列表
    """
    channel_fields = {
        'channel_id': fields.String(attribute='id'),  # 频道ID
        'name': fields.String(attribute='name'),  # 频道名称
        'is_visible': fields.Integer(attribute='is_visible'),  # 状态: 是否可见
    }

    method_decorators = {
        'get': [mis_permission_required('channel-list-get')],
        'post': [mis_permission_required('channel-list-post')],
    }

    def get(self):
        """
        获取所有频道信息
        """
        args_parser = RequestParser()
        args_parser.add_argument('page', type=inputs.positive, required=False, location='args')
        args_parser.add_argument('per_page', type=inputs.int_range(constants.PER_PAGE_MIN,
                                                                   constants.PER_PAGE_MAX,
                                                                   'per_page'),
                                 required=False, location='args')
        args_parser.add_argument('channel_id', location='args')
        args_parser.add_argument('keyword', location='args')
        args_parser.add_argument('is_visible', location='args')
        args_parser.add_argument('order_by', location='args')

        args = args_parser.parse_args()
        page = constants.DEFAULT_PAGE if args.page is None else args.page
        per_page = constants.DEFAULT_PER_PAGE if args.per_page is None else args.per_page

        channels = Channel.query
        if args.channel_id is not None:
            channels = channels.filter_by(channel_id=args.channel_id)
        if args.is_visible is not None:
            channels = channels.filter_by(is_visible=args.is_visible)
        if args.keyword is not None:
            channels = channels.filter(Channel.name.like('%' + args.keyword + '%'))

        if args.order_by is not None:
            if args.order_by == 'id':
                channels = channels.order_by(Channel.id.asc())
        else:
            channels = channels.order_by(Channel.utime.desc())
        total_count = channels.count()
        channels = channels.offset(per_page * (page - 1)).limit(per_page).all()

        ret = marshal(channels, ChannelListResource.channel_fields, envelope='channels')
        for channel in ret['channels']:
            channel['article_count'] = Article.query.filter_by(channel_id=channel['channel_id']).count()
        ret['total_count'] = total_count

        return ret

    def post(self):
        """
        新增频道
        """
        json_parser = RequestParser()
        json_parser.add_argument('name', required=True, location='json')
        json_parser.add_argument('is_visible', type=inputs.int_range(0, 1), required=True, location='json')
        json_parser.add_argument('sequence', type=inputs.positive, location='json')

        args = json_parser.parse_args()
        if Channel.query.filter_by(name=args.name).first():
            return {'message': '{} already exists'.format(args.name)}, 403

        channel = Channel(name=args.name,
                       is_visible=args.is_visible,
                       sequence=args.sequence if args.sequence is not None else 0,
                        )
        db.session.add(channel)
        db.session.commit()

        return marshal(channel, ChannelListResource.channel_fields), 201
Exemple #16
0
class SensitiveWordListResource(Resource):
    """
    敏感词
    """
    word_fields = {
        'id': fields.Integer(attribute='id'),  # 敏感词id
        'word': fields.String(attribute='word'),  # 敏感词
        'weights': fields.Integer(attribute='weights'),  # 权重
        'hold_count': fields.Integer(attribute='hold_count'),  # 拦截次数
        'create_time': fields.DateTime(attribute='ctime',
                                       dt_format='iso8601'),  # 创建时间
        'update_time': fields.DateTime(attribute='utime',
                                       dt_format='iso8601')  # 更新时间
    }

    method_decorators = {
        'get': [mis_permission_required('sensitive-word-list-get')],
        'post': [mis_permission_required('sensitive-word-list-post')],
    }

    def get(self):
        """
        获取敏感词列表
        """
        args_parser = RequestParser()
        args_parser.add_argument('page',
                                 type=inputs.positive,
                                 required=False,
                                 location='args')
        args_parser.add_argument('per_page',
                                 type=inputs.int_range(constants.PER_PAGE_MIN,
                                                       constants.PER_PAGE_MAX,
                                                       'per_page'),
                                 required=False,
                                 location='args')
        args_parser.add_argument('word', location='args')
        args_parser.add_argument('order_by', location='args')

        args = args_parser.parse_args()
        page = constants.DEFAULT_PAGE if args.page is None else args.page
        per_page = constants.DEFAULT_PER_PAGE if args.per_page is None else args.per_page

        words = SensitiveWord.query

        if args.word is not None:
            words = words.filter(SensitiveWord.word.like('%' + args.word +
                                                         '%'))
        if args.order_by is not None:
            if args.order_by == 'id':
                words = words.order_by(SensitiveWord.id.asc())
        else:
            words = words.order_by(SensitiveWord.utime.desc())
        total_count = words.count()
        words = words.offset(per_page * (page - 1)).limit(per_page).all()

        ret = marshal(words,
                      SensitiveWordListResource.word_fields,
                      envelope='words')
        ret['total_count'] = total_count

        return ret

    def post(self):
        """
        添加敏感词
        """
        args_parser = RequestParser()
        args_parser.add_argument('word', required=True, location='json')
        args_parser.add_argument('weights',
                                 type=inputs.natural,
                                 required=True,
                                 location='json')

        args = args_parser.parse_args()
        if SensitiveWord.query.filter_by(word=args.word).first():
            return {'message': '{} already exists'.format(args.word)}, 403
        word = SensitiveWord(word=args.word,
                             weights=args.weights,
                             hold_count=0)
        db.session.add(word)
        db.session.commit()
        return marshal(word, SensitiveWordListResource.word_fields), 201
Exemple #17
0
class AdministratorResource(Resource):
    """
    管理员管理
    """
    method_decorators = {
        'get': [mis_permission_required('administrator-get')],
        'put': [mis_permission_required('administrator-put')],
        'delete': [mis_permission_required('administrator-delete')],
    }

    def get(self, target):
        """
        获取管理员详情
        """
        administrator = MisAdministrator.query.filter_by(id=target).first()
        if not administrator:
            return {'message': 'Invalid administrator id.'}, 400
        return marshal(administrator, AdministratorListResource.administrators_fields)

    def put(self, target):
        """
        修改id=target管理员信息
        """
        json_parser = RequestParser()
        json_parser.add_argument('account', type=parser.mis_account, location='json')
        json_parser.add_argument('password', type=parser.mis_password, location='json')
        json_parser.add_argument('name', location='json')
        json_parser.add_argument('group_id', type=parser.mis_group_id, location='json')
        json_parser.add_argument('status', type=inputs.int_range(0, 1), location='json')

        json_parser.add_argument('email', type=parser.email, location='json')
        json_parser.add_argument('mobile', type=parser.mobile, location='json')
        json_parser.add_argument('current_password', type=parser.mis_password, location='json')

        args = json_parser.parse_args()
        print(args)
        administrator = MisAdministrator.query.filter_by(id=target).first()
        if not administrator:
            return {'message': 'Invalid administrator id.'}, 403

        if args.account and args.account != administrator.account:
            if MisAdministrator.query.filter_by(account=args.account).first():
                return {'message': '{} already exists'.format(args.account)}
            administrator.account = args.account
        if args.password:
            if target == g.administrator_id \
                    and administrator.password != generate_password_hash(args.current_password):
                return {'message': 'Current password error.'}, 403

            administrator.password = generate_password_hash(args.password)
        if args.name:
            administrator.name = args.name
        if args.group_id:
            administrator.group_id = args.group_id
        if args.status is not None:
            administrator.status = args.status
        if args.email:
            administrator.email = args.email
        if args.mobile:
            administrator.mobile = args.mobile

        try:
            db.session.add(administrator)
            db.session.commit()
        except:
            db.session.rollback()
            raise

        return marshal(administrator, AdministratorListResource.administrators_fields), 201

    def delete(self, target):
        """
        删除id=target管理员信息
        """
        MisAdministrator.query.filter_by(id=target).delete(synchronize_session=False)
        db.session.commit()
        return {'message': 'OK'}, 204
Exemple #18
0
class StatisticsSearchResource(Resource):
    """
    搜索统计
    """
    method_decorators = {
        'get': [mis_permission_required('statistics-search-get')],
    }

    def get(self):
        args_parser = RequestParser()
        args_parser.add_argument('page',
                                 type=inputs.positive,
                                 required=False,
                                 location='args')
        args_parser.add_argument('per_page',
                                 type=inputs.int_range(constants.PER_PAGE_MIN,
                                                       constants.PER_PAGE_MAX,
                                                       'per_page'),
                                 required=False,
                                 location='args')
        args = args_parser.parse_args()
        page = constants.DEFAULT_PAGE if args.page is None else args.page
        per_page = constants.DEFAULT_PER_PAGE if args.per_page is None else args.per_page

        ssts = StatisticsSearchTotal.query.order_by(
            StatisticsSearchTotal.count.desc())
        total_count = ssts.count()

        ret = {'keywords': [], 'total_count': total_count}
        ssts = ssts.offset(per_page * (page - 1)).limit(per_page).all()
        for sst in ssts:
            lask_week_count, week_count, week_percent = self._get_week_percent(
                sst.keyword)
            ret['keywords'].append({
                'keyword': sst.keyword,
                'user_count': sst.user_count,
                'week_percent': week_percent,
                # 'lask_week_count': lask_week_count,
                # 'week_count': week_count
            })

        return ret

    # def post(self):
    #     now = datetime.now()
    #     today = datetime(year=now.year, month=now.month, day=now.day)
    #     begin = today - timedelta(days=14)
    #     while begin <= now:
    #         for word in ['java', 'python', 'php']:
    #             import random
    #             count = user_count = 1
    #             ss = StatisticsSearch.query.filter_by(year=begin.year,
    #                                                     month=begin.month,
    #                                                     day=begin.day,
    #                                                     hour=begin.hour,
    #                                                     keyword=word).first()
    #             if not ss:
    #                 ss = StatisticsSearch(year=begin.year,
    #                                     month=begin.month,
    #                                     day=begin.day,
    #                                     hour=begin.hour,
    #                                     keyword=word,
    #                                     count=0,
    #                                     user_count=0,
    #                                     date_time=datetime(year=begin.year,month=begin.month,
    #                                                         day=begin.day,hour=begin.hour))
    #             sst = StatisticsSearchTotal.query.filter_by(keyword=word).first()
    #             if not sst:
    #                 sst = StatisticsSearchTotal(keyword=word, user_count=0, count=0)
    #             ss.count += count
    #             ss.user_count += user_count
    #             sst.count += count
    #             sst.user_count += user_count
    #             db.session.add(ss)
    #             db.session.add(sst)
    #             db.session.commit()
    #         begin += timedelta(hours=1)
    #     return {}

    def _get_week_percent(self, keyword):
        """
        获取搜索关键字的周涨幅
        :param keyword: 搜索关键字
        :return: 周涨幅百分比
        """
        now = datetime.now()
        today = datetime(year=now.year, month=now.month, day=now.day)

        # 上周用户数量
        lask_week_begin = today - timedelta(days=13)
        lask_week_end = today - timedelta(days=6)
        query = db.session.query(func.sum(StatisticsSearch.user_count)) \
            .filter(StatisticsSearch.keyword == keyword,
                    and_(StatisticsSearch.date_time >= lask_week_begin,
                         StatisticsSearch.date_time < lask_week_end)
                    )
        lask_week_count = int(query.scalar() or 0)

        # 本周用户数量
        week_begin = lask_week_end
        query = db.session.query(func.sum(StatisticsSearch.user_count)) \
            .filter(StatisticsSearch.keyword == keyword,
                    and_(StatisticsSearch.date_time >= week_begin,
                         StatisticsSearch.date_time < now)
                    )
        week_count = int(query.scalar() or 0)

        # 周涨幅
        week_percent = round((week_count - lask_week_count) /
                             (lask_week_count if lask_week_count else 1) * 100,
                             2)

        return lask_week_count, week_count, week_percent
Exemple #19
0
class AdministratorListResource(Resource):
    """
    管理员管理
    """
    administrators_fields = {
        'administrator_id': fields.Integer(attribute='id'),
        'account': fields.String(attribute='account'),
        'email': fields.String(attribute='email'),
        'mobile': fields.String(attribute='mobile'),
        'name': fields.String(attribute='name'),
        'group_name': fields.String(attribute='group.name'),
        'group_id': fields.Integer(attribute='group_id'),
        'access_count': fields.Integer(attribute='access_count'),
        'status': fields.Integer(attribute='status'),
        'last_login': fields.Integer(attribute='last_login')
    }
    method_decorators = {
        'get': [mis_permission_required('administrator-list-get')],
        'post': [mis_permission_required('administrator-list-post')],
    }

    def post(self):
        """
        添加管理员
        """
        json_parser = RequestParser()
        json_parser.add_argument('account', type=parser.mis_account, required=True, location='json')
        json_parser.add_argument('password', type=parser.mis_password, required=True, location='json')
        json_parser.add_argument('group_id', type=parser.mis_group_id, required=True, location='json')
        json_parser.add_argument('name', required=True, location='json')
        args = json_parser.parse_args()
        administrator = MisAdministrator.query.filter_by(account=args.account).first()
        if administrator:
            return {'message': '{} already exists'.format(args.account)}, 403

        administrator = MisAdministrator(account=args.account,
                                         password=generate_password_hash(args.password),
                                         name=args.name,
                                         group_id=args.group_id)
        try:
            db.session.add(administrator)
            db.session.commit()
        except Exception:
            db.session.rollback()
            raise

        return {'account': args.account,
                'name': args.name}, 201

    def get(self):
        """
        管理员查询
        """
        args_parser = RequestParser()
        args_parser.add_argument('order_by', location='args')
        args_parser.add_argument('keyword', location='args')
        args_parser.add_argument('status', type=inputs.int_range(0, 1), location='args')
        args_parser.add_argument('page', type=inputs.positive, required=False, location='args')
        args_parser.add_argument('per_page', type=inputs.int_range(constants.PER_PAGE_MIN,
                                                                 constants.PER_PAGE_MAX,
                                                                 'per_page'),
                               required=False, location='args')
        args = args_parser.parse_args()
        page = constants.DEFAULT_PAGE if args.page is None else args.page
        per_page = constants.DEFAULT_PER_PAGE if args.per_page is None else args.per_page

        administrators = MisAdministrator.query
        if args.status is not None:
            administrators = administrators.filter_by(status=args.status)
        if args.keyword:
            administrators = administrators.filter(or_(MisAdministrator.account.like('%' + args.keyword + '%'),
                                                       MisAdministrator.name.like('%' + args.keyword + '%')))
        if args.order_by is not None:
            if args.order_by == 'id':
                administrators = administrators.order_by(MisAdministrator.id.asc())
        else:
            administrators = administrators.order_by(MisAdministrator.utime.desc())
        total_count = administrators.count()
        administrators = administrators.offset(per_page * (page - 1)).limit(per_page).all()

        ret = marshal(administrators, AdministratorListResource.administrators_fields, envelope='administrators')
        ret['total_count'] = total_count
        return ret

    def delete(self):
        """
        批量删除管理员
        """
        json_parser = RequestParser()
        json_parser.add_argument('administrator_ids', action='append', type=inputs.positive, required=True, location='json')
        args = json_parser.parse_args()

        MisAdministrator.query.filter(MisAdministrator.id.in_(args.administrator_ids)).delete(synchronize_session=False)
        db.session.commit()
        return {'message': 'OK'}, 204
Exemple #20
0
class OperationLogListResource(Resource):
    """
    运营日记
    """
    logs_fields = {
        'operation_log_id': fields.Integer(attribute='id'),
        'administrator_id': fields.Integer(attribute='administrator_id'),
        'administrator_name': fields.String(attribute='administrator.name'),
        'ip': fields.String(attribute='ip'),
        'operation': fields.String(attribute='operation'),
        'description': fields.String(attribute='description'),
        'ctime': fields.DateTime(attribute='ctime', dt_format='iso8601'),
    }

    method_decorators = {'get': [mis_permission_required('operationlog-get')]}

    def get(self):
        """
        获取运营日志列表
        """
        args_parser = RequestParser()
        args_parser.add_argument('page',
                                 type=inputs.positive,
                                 required=False,
                                 location='args')
        args_parser.add_argument('per_page',
                                 type=inputs.int_range(constants.PER_PAGE_MIN,
                                                       constants.PER_PAGE_MAX,
                                                       'per_page'),
                                 required=False,
                                 location='args')
        args_parser.add_argument('keyword', location='args')
        args_parser.add_argument('order_by', location='args')
        args_parser.add_argument('begin',
                                 type=parser.date_time,
                                 location='args')
        args_parser.add_argument('end', type=parser.date_time, location='args')
        args = args_parser.parse_args()
        page = constants.DEFAULT_PAGE if args.page is None else args.page
        per_page = constants.DEFAULT_PER_PAGE if args.per_page is None else args.per_page

        logs = MisOperationLog.query
        if args.keyword:
            logs = logs.filter(
                MisOperationLog.operation.like('%' + args.keyword + '%'),
                MisOperationLog.description.like('%' + args.keyword + '%'))
        if args.begin and args.end and args.end > args.begin:
            logs = logs.filter(
                MisOperationLog.ctime.between(args.begin, args.end))
        if args.order_by is not None:
            if args.order_by == 'id':
                logs = logs.order_by(MisOperationLog.id.desc())
        else:
            logs = logs.order_by(MisOperationLog.ctime.desc())
        total_count = logs.count()
        logs = logs.offset(per_page * (page - 1)).limit(per_page).all()

        ret = marshal(logs,
                      OperationLogListResource.logs_fields,
                      envelope='operationlogs')
        ret['total_count'] = total_count
        add_log('查询', '查询: 运营日志')
        return ret