Пример #1
0
class AdminAbnormalOrdersView(AdminBaseView):
    """后台-订单-获取异常订单列表"""
    pagination_class = StandardResultsSetPagination

    @AdminBaseView.permission_required(
        [AdminBaseView.staff_permissions.ADMIN_ORDER])
    @use_args(
        {
            "order_types":
            StrToList(
                required=False,
                missing=[OrderType.GROUPON],
                validate=[validate.ContainsOnly([OrderType.GROUPON])],
                comment="订单类型筛选 1: 普通订单, 5: 拼团订单",
            ),
            "order_pay_types":
            StrToList(
                required=False,
                missing=[OrderPayType.ON_DELIVERY, OrderPayType.WEIXIN_JSAPI],
                validate=[
                    validate.ContainsOnly(
                        [OrderPayType.WEIXIN_JSAPI, OrderPayType.ON_DELIVERY])
                ],
                comment="订单支付方式筛选 1: 微信支付, 2: 货到付款",
            ),
            "order_delivery_methods":
            StrToList(
                required=False,
                missing=[
                    DeliveryType.StaffDelivery, DeliveryType.ExpressDelivery
                ],
                validate=[
                    validate.ContainsOnly([
                        DeliveryType.ExpressDelivery,
                        DeliveryType.StaffDelivery
                    ])
                ],
                comment="订单配送方式筛选 1: 送货上门, 2: 自提",
            ),
            "order_status":
            StrToList(
                required=False,
                missing=[OrderStatus.REFUND_FAIL],
                validate=[validate.ContainsOnly([OrderStatus.REFUND_FAIL])],
                comment="订单状态筛选 6: 退款失败",
            ),
            "order_num":
            fields.String(comment="订单号搜索,与其他条件互斥"),
        },
        location="query")
    def get(self, request, args):
        orders = list_shop_abnormal_orders(self.current_shop.id, **args)
        orders = self._get_paginated_data(orders, AdminOrderSerializer)
        return self.send_success(data_list=orders)
Пример #2
0
class FilterPublishersSchema(FilterSchema):
    sort_by = fields.Str(validate=sort_one_of(
        ['id', 'name', 'airtime', 'comment', 'created_at', 'updated_at']),
                         missing='created_at')
    query = fields.Str(validate=validate.Length(min=3, max=100), missing=None)
    query_fields = fields.List(fields.Str(),
                               validate=validate.ContainsOnly(
                                   ['name', 'comment']),
                               missing=['name', 'comment'])
Пример #3
0
class AdminProductGroupsView(AdminBaseView):
    """后台-货品-批量更新货品分组"""

    @AdminBaseView.permission_required([AdminBaseView.staff_permissions.ADMIN_PRODUCT])
    @use_args(
        {
            "product_ids": fields.List(
                fields.Integer(required=True),
                required=True,
                validate=[validate.Length(1)],
                comment="货品ID列表",
            ),
            "group_id": fields.Integer(required=True, comment="货品分组ID"),
        },
        location="json"
    )
    def put(self, request, args):
        shop = self.current_shop
        group_id = args.get("group_id")
        product_ids = args.pop("product_ids")
        # 校验分组是否存在
        product_group = get_product_group_by_shop_id_and_id(shop.id, group_id)
        if not product_group:
            return self.send_fail(error_text="货品分组不存在")
        # 获取货品,更新货品信息
        update_product_product_group_by_ids(product_ids, group_id)
        return self.send_success()

    @AdminBaseView.permission_required([AdminBaseView.staff_permissions.ADMIN_PRODUCT])
    @use_args(
        {
            "status": StrToList(
                required=False,
                missing=[ProductStatus.ON, ProductStatus.OFF],
                validate=[
                    validate.ContainsOnly(
                        [ProductStatus.ON, ProductStatus.OFF]
                    )
                ],
                comment="货品状态,上架/下架",
            )
        },
        location="query"
    )
    def get(self, request, args):
        shop = self.current_shop
        product_group_with_count = list_product_group_with_product_count(shop.id, **args)
        serializer = AdminProductGroupSerializer(product_group_with_count, many=True)
        return self.send_success(data_list=serializer.data)
Пример #4
0
class MallOrdersView(MallBaseView):
    """商城-订单列表"""
    pagination_class = StandardResultsSetPagination

    @use_args(
        {
            "order_status":
            StrToList(
                required=False,
                missing=[],
                validate=[
                    validate.ContainsOnly([
                        OrderStatus.CANCELED,
                        OrderStatus.UNPAID,
                        OrderStatus.PAID,
                        OrderStatus.CONFIRMED,
                        OrderStatus.FINISHED,
                        OrderStatus.REFUNDED,
                        OrderStatus.REFUND_FAIL,
                        OrderStatus.WAITTING,
                    ])
                ],
                comment="订单状态列表",
            ),
        },
        location="query",
    )
    def get(self, reuqest, args, shop_code):
        self._set_current_shop(reuqest, shop_code)
        user_id = self.current_user.id
        shop_id = self.current_shop.id
        customer = get_customer_by_user_id_and_shop_id_interface(
            user_id, shop_id)
        # 不是客户在这个店肯定没单
        if not customer:
            return self.send_success(data_list=[])
        order_list = list_customer_order_by_customer_ids(
            [customer.id], args.get('order_status'))
        order_list = self._get_paginated_data(order_list, MallOrdersSerializer)
        return self.send_success(data_list=order_list)
Пример #5
0
class AdminGrouponAttendsView(AdminBaseView):
    """后台-玩法-拼团-参与拼团列表"""
    pagination_class = StandardResultsSetPagination

    @AdminBaseView.permission_required(
        [AdminBaseView.staff_permissions.ADMIN_PROMOTION])
    @use_args(
        {
            "groupon_id":
            fields.Integer(required=True, comment="拼团id"),
            "groupon_attend_status":
            StrToList(
                required=False,
                missing=[
                    GrouponAttendStatus.WAITTING,
                    GrouponAttendStatus.SUCCEEDED,
                    GrouponAttendStatus.FAILED,
                ],
                validate=validate.ContainsOnly([
                    GrouponAttendStatus.WAITTING,
                    GrouponAttendStatus.SUCCEEDED,
                    GrouponAttendStatus.FAILED,
                ]),
                comment="拼团参与状态,1:拼团中 2:已成团 3:已失败",
            ),
        },
        location="query")
    def get(self, request, args):
        success, groupon = get_shop_groupon_by_id(self.current_shop.id,
                                                  args.pop("groupon_id"))
        if not success:
            return self.send_fail(error_text=groupon)
        groupon_attends = list_groupon_attends_by_groupon(
            groupon, args["groupon_attend_status"])
        groupon_attends = self._get_paginated_data(
            groupon_attends, AdminGrouponAttendSerializer)
        return self.send_success(data_list=groupon_attends)
Пример #6
0
class GrampsObjectResource(GrampsObjectResourceHelper, Resource):
    """Resource for a single object."""

    @use_args(
        {
            "backlinks": fields.Boolean(missing=False),
            "extend": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(
                    choices=[
                        "all",
                        "citation_list",
                        "event_ref_list",
                        "family_list",
                        "note_list",
                        "parent_family_list",
                        "person_ref_list",
                        "primary_parent_family",
                        "place",
                        "source_handle",
                        "father_handle",
                        "mother_handle",
                        "media_list",
                        "reporef_list",
                        "tag_list",
                        "backlinks",
                        "child_ref_list",
                    ]
                ),
            ),
            "formats": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1))
            ),
            "format_options": fields.Str(validate=validate.Length(min=1)),
            "keys": fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "locale": fields.Str(missing=None, validate=validate.Length(min=1, max=5)),
            "profile": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(
                    choices=[
                        "all",
                        "self",
                        "families",
                        "events",
                        "age",
                        "span",
                        "ratings",
                        "references",
                    ]
                ),
            ),
            "skipkeys": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1))
            ),
            "soundex": fields.Boolean(missing=False),
            "strip": fields.Boolean(missing=False),
        },
        location="query",
    )
    def get(self, args: Dict, handle: str) -> Response:
        """Get the object."""
        try:
            obj = self.get_object_from_handle(handle)
        except HandleError:
            abort(404)
        locale = get_locale_for_language(args["locale"], default=True)
        get_etag = hash_object(obj)
        return self.response(
            200, self.full_object(obj, args, locale=locale), args, etag=get_etag
        )

    def delete(self, handle: str) -> Response:
        """Delete the object."""
        require_permissions([PERM_DEL_OBJ])
        try:
            obj = self.get_object_from_handle(handle)
        except HandleError:
            abort(404)
        get_etag = hash_object(obj)
        for etag in request.if_match:
            if etag != get_etag:
                abort(412)
        trans_dict = delete_object(
            self.db_handle_writable, handle, self.gramps_class_name
        )
        # update search index
        indexer: SearchIndexer = current_app.config["SEARCH_INDEXER"]
        with indexer.get_writer(overwrite=False, use_async=True) as writer:
            indexer.delete_object(writer, handle)
        return self.response(200, trans_dict, total_items=len(trans_dict))

    def put(self, handle: str) -> Response:
        """Modify an existing object."""
        require_permissions([PERM_EDIT_OBJ])
        try:
            obj_old = self.get_object_from_handle(handle)
        except HandleError:
            abort(404)
        get_etag = hash_object(obj_old)
        for etag in request.if_match:
            if etag != get_etag:
                abort(412)
        obj = self._parse_object()
        if not obj:
            abort(400)
        db_handle = self.db_handle_writable
        with DbTxn("Edit object", db_handle) as trans:
            try:
                update_object(db_handle, obj, trans)
            except ValueError:
                abort(400)
            trans_dict = transaction_to_json(trans)
        # update search index
        indexer: SearchIndexer = current_app.config["SEARCH_INDEXER"]
        with indexer.get_writer(overwrite=False, use_async=True) as writer:
            for _trans_dict in trans_dict:
                handle = _trans_dict["handle"]
                class_name = _trans_dict["_class"]
                indexer.add_or_update_object(writer, handle, db_handle, class_name)
        return self.response(200, trans_dict, total_items=len(trans_dict))
Пример #7
0
class AdminProductsView(AdminBaseView):
    """后台-货品-获取货品列表&批量修改货品(上架,下架)&批量删除货品"""
    pagination_class = StandardResultsSetPagination

    @AdminBaseView.permission_required([AdminBaseView.staff_permissions.ADMIN_PRODUCT])
    @use_args(
        {
            "keyword": fields.String(required=False, missing="", comment="货品关键字"),
            "group_id": fields.Integer(required=True, comment="分组ID"),
            "page": fields.Integer(required=False, missing=1, comment="页码"),
            "status": StrToList(
                required=False,
                missing=[ProductStatus.ON, ProductStatus.OFF],
                validate=[validate.ContainsOnly([ProductStatus.ON, ProductStatus.OFF])],
                comment="货品状态,上架、下架",
            ),
            "promotion_types": StrToList(
                required=False,
                missing=[],
                validate=[
                    validate.ContainsOnly({PromotionType.NORMAL, PromotionType.GROUPON})
                ],
                comment="货品营销类型",
            ),
        },
        location="query"
    )
    def get(self, request, args):
        page = args.pop("page")
        shop = self.current_shop
        product_list = list_product_by_filter(shop.id, **args)
        # page为-1时不分页
        if page < 0:
            product_list = {"results": AdminProductsSerializer(product_list, many=True).data}
        else:
            product_list = self._get_paginated_data(product_list, AdminProductsSerializer)
        return self.send_success(data_list=product_list)

    @AdminBaseView.permission_required([AdminBaseView.staff_permissions.ADMIN_PRODUCT])
    @use_args(
        {
            "product_ids": fields.List(
                fields.Integer(required=True),
                required=True,
                validate=[validate.Length(1)],
                commet="货品ID列表",
            ),
            "operation_type": fields.Integer(
                required=False,
                missing=1,
                validate=[validate.OneOf(
                    [ProductOperationType.ON, ProductOperationType.OFF]
                )],
                comment="操作类型,1:上架,2:下架"
            )
        },
        location="json"
    )
    def put(self, request, args):
        operation_type = args.get("operation_type")
        product_ids = args.get("product_ids")
        product_list = list_product_by_ids(self.current_shop.id, product_ids)
        product_ids = [pl.id for pl in product_list]
        product_ids_set = list_alive_groupon_by_product_ids_interface(product_ids)
        product_name_list = update_products_status(
            product_list, operation_type, product_ids_set
        )
        if product_name_list:
            if operation_type == ProductOperationType.ON:
                log_operate_type = ProductLogType.ON_PRODUCT
            else:
                log_operate_type = ProductLogType.OFF_PRODUCT
            log_info = {
                "shop_id": self.current_shop.id,
                "operator_id": self.current_user.id,
                "operate_type": log_operate_type,
                "operate_content": "、".join(product_name_list),
            }
            create_product_log_interface(log_info)
        return self.send_success()

    @AdminBaseView.permission_required([AdminBaseView.staff_permissions.ADMIN_PRODUCT])
    @use_args(
        {
            "product_ids": fields.List(
                fields.Integer(required=True),
                required=True,
                validate=[validate.Length(1)],
                commet="货品ID列表",
            )
        },
        location="json",
    )
    def delete(self, request, args):
        product_ids = args.get("product_ids")
        product_list = list_product_by_ids(self.current_shop.id, product_ids)
        product_ids = [pl.id for pl in product_list]
        product_ids_set = list_alive_groupon_by_product_ids_interface(product_ids)
        product_name_list = delete_product_by_ids_and_shop_id(product_list, product_ids_set)
        # 记录日志
        if product_name_list:
            log_info = {
                "shop_id": self.current_shop.id,
                "operator_id": self.current_user.id,
                "operate_type": ProductLogType.DELETE_PRODUCT,
                "operate_content": "、".join(product_name_list),
            }
            create_product_log_interface(log_info)
        return self.send_success()
Пример #8
0
class SearchResource(GrampsJSONEncoder, ProtectedResource):
    """Fulltext search resource."""

    @property
    def db_handle(self) -> DbReadBase:
        """Get the database instance."""
        return get_db_handle()

    def get_object_from_handle(
        self, handle: str, class_name: str, args: Dict, locale: GrampsLocale
    ) -> GrampsObject:
        """Get the object given a Gramps handle."""
        query_method = self.db_handle.method("get_%s_from_handle", class_name)
        obj = query_method(handle)
        if "profile" in args:
            if class_name == "person":
                obj.profile = get_person_profile_for_object(
                    self.db_handle, obj, args["profile"], locale=locale
                )
            elif class_name == "family":
                obj.profile = get_family_profile_for_object(
                    self.db_handle, obj, args["profile"], locale=locale
                )
            elif class_name == "event":
                obj.profile = get_event_profile_for_object(
                    self.db_handle, obj, args["profile"], locale=locale
                )
            elif class_name == "citation":
                obj.profile = get_citation_profile_for_object(
                    self.db_handle, obj, args["profile"], locale=locale
                )
            elif class_name == "place":
                obj.profile = get_place_profile_for_object(
                    self.db_handle, obj, locale=locale
                )
            elif class_name == "media":
                obj.profile = get_media_profile_for_object(
                    self.db_handle, obj, args["profile"], locale=locale
                )

        return obj

    @use_args(
        {
            "locale": fields.Str(missing=None, validate=validate.Length(min=1, max=5)),
            "query": fields.Str(required=True, validate=validate.Length(min=1)),
            "page": fields.Int(missing=1, validate=validate.Range(min=1)),
            "pagesize": fields.Int(missing=20, validate=validate.Range(min=1)),
            "sort": fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "profile": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(
                    choices=["all", "self", "families", "events", "age", "span"]
                ),
            ),
            "strip": fields.Boolean(missing=False),
        },
        location="query",
    )
    def get(self, args: Dict):
        """Get search result."""
        searcher = current_app.config["SEARCH_INDEXER"]
        total, hits = searcher.search(
            query=args["query"],
            page=args["page"],
            pagesize=args["pagesize"],
            # search in private records if allowed to
            include_private=has_permissions([PERM_VIEW_PRIVATE]),
            sort=args.get("sort"),
        )
        if hits:
            locale = get_locale_for_language(args["locale"], default=True)
            for hit in hits:
                try:
                    hit["object"] = self.get_object_from_handle(
                        handle=hit["handle"],
                        class_name=hit["object_type"],
                        args=args,
                        locale=locale,
                    )
                except HandleError:
                    pass
            # filter out hits without object (i.e. if handle failed)
            hits = [hit for hit in hits if "object" in hit]
        return self.response(200, payload=hits or [], args=args, total_items=total)
Пример #9
0
class GrampsObjectsResource(GrampsObjectResourceHelper, Resource):
    """Resource for multiple objects."""

    @use_args(
        {
            "backlinks": fields.Boolean(missing=False),
            "dates": fields.Str(
                missing=None,
                validate=validate.Regexp(
                    r"^([0-9]+|\*)/([1-9]|1[0-2]|\*)/([1-9]|1[0-9]|2[0-9]|3[0-1]|\*)$|"
                    r"^-[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])$|"
                    r"^[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])-$|"
                    r"^[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])-"
                    r"[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])$"
                ),
            ),
            "extend": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(
                    choices=[
                        "all",
                        "citation_list",
                        "event_ref_list",
                        "family_list",
                        "note_list",
                        "parent_family_list",
                        "person_ref_list",
                        "primary_parent_family",
                        "place",
                        "source_handle",
                        "father_handle",
                        "mother_handle",
                        "media_list",
                        "reporef_list",
                        "tag_list",
                        "backlinks",
                        "child_ref_list",
                    ]
                ),
            ),
            "filter": fields.Str(validate=validate.Length(min=1)),
            "formats": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1))
            ),
            "format_options": fields.Str(validate=validate.Length(min=1)),
            "gramps_id": fields.Str(validate=validate.Length(min=1)),
            "keys": fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "locale": fields.Str(missing=None, validate=validate.Length(min=1, max=5)),
            "page": fields.Integer(missing=0, validate=validate.Range(min=1)),
            "pagesize": fields.Integer(missing=20, validate=validate.Range(min=1)),
            "profile": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(
                    choices=[
                        "all",
                        "self",
                        "families",
                        "events",
                        "age",
                        "span",
                        "ratings",
                        "references",
                    ]
                ),
            ),
            "rules": fields.Str(validate=validate.Length(min=1)),
            "skipkeys": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1))
            ),
            "sort": fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "soundex": fields.Boolean(missing=False),
            "strip": fields.Boolean(missing=False),
        },
        location="query",
    )
    def get(self, args: Dict) -> Response:
        """Get all objects."""
        locale = get_locale_for_language(args["locale"], default=True)
        if "gramps_id" in args:
            obj = self.get_object_from_gramps_id(args["gramps_id"])
            if obj is None:
                abort(404)
            return self.response(
                200, [self.full_object(obj, args, locale=locale)], args, total_items=1
            )

        query_method = self.db_handle.method("get_%s_handles", self.gramps_class_name)
        if self.gramps_class_name in ["Event", "Repository", "Note"]:
            handles = query_method()
        else:
            handles = query_method(sort_handles=True, locale=locale)

        if "filter" in args or "rules" in args:
            handles = apply_filter(
                self.db_handle, args, self.gramps_class_name, handles
            )

        if args["dates"]:
            handles = self.match_dates(handles, args["dates"])

        if "sort" in args:
            handles = self.sort_objects(handles, args["sort"], locale=locale)

        total_items = len(handles)

        if args["page"] > 0:
            offset = (args["page"] - 1) * args["pagesize"]
            handles = handles[offset : offset + args["pagesize"]]

        query_method = self.db_handle.method(
            "get_%s_from_handle", self.gramps_class_name
        )
        return self.response(
            200,
            [
                self.full_object(query_method(handle), args, locale=locale)
                for handle in handles
            ],
            args,
            total_items=total_items,
        )
Пример #10
0
class GrampsObjectResource(GrampsObjectResourceHelper, Resource):
    """Resource for a single object."""

    @use_args(
        {
            "backlinks": fields.Boolean(missing=False),
            "extend": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(
                    choices=[
                        "all",
                        "citation_list",
                        "event_ref_list",
                        "family_list",
                        "note_list",
                        "parent_family_list",
                        "person_ref_list",
                        "primary_parent_family",
                        "place",
                        "source_handle",
                        "father_handle",
                        "mother_handle",
                        "media_list",
                        "reporef_list",
                        "tag_list",
                        "backlinks",
                        "child_ref_list",
                    ]
                ),
            ),
            "formats": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1))
            ),
            "format_options": fields.Str(validate=validate.Length(min=1)),
            "keys": fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "locale": fields.Str(missing=None, validate=validate.Length(min=1, max=5)),
            "profile": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(
                    choices=[
                        "all",
                        "self",
                        "families",
                        "events",
                        "age",
                        "span",
                        "ratings",
                        "references",
                    ]
                ),
            ),
            "skipkeys": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1))
            ),
            "soundex": fields.Boolean(missing=False),
            "strip": fields.Boolean(missing=False),
        },
        location="query",
    )
    def get(self, args: Dict, handle: str) -> Response:
        """Get the object."""
        try:
            obj = self.get_object_from_handle(handle)
        except HandleError:
            abort(404)
        locale = get_locale_for_language(args["locale"], default=True)
        return self.response(200, self.full_object(obj, args, locale=locale), args)
Пример #11
0
class GrampsObjectsResource(GrampsObjectResourceHelper, Resource):
    """Resource for multiple objects."""

    @use_args(
        {
            "backlinks": fields.Boolean(missing=False),
            "dates": fields.Str(
                missing=None,
                validate=validate.Regexp(
                    r"^([0-9]+|\*)/([1-9]|1[0-2]|\*)/([1-9]|1[0-9]|2[0-9]|3[0-1]|\*)$|"
                    r"^-[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])$|"
                    r"^[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])-$|"
                    r"^[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])-"
                    r"[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])$"
                ),
            ),
            "extend": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(
                    choices=[
                        "all",
                        "citation_list",
                        "event_ref_list",
                        "family_list",
                        "note_list",
                        "parent_family_list",
                        "person_ref_list",
                        "primary_parent_family",
                        "place",
                        "source_handle",
                        "father_handle",
                        "mother_handle",
                        "media_list",
                        "reporef_list",
                        "tag_list",
                        "backlinks",
                        "child_ref_list",
                    ]
                ),
            ),
            "filter": fields.Str(validate=validate.Length(min=1)),
            "formats": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1))
            ),
            "format_options": fields.Str(validate=validate.Length(min=1)),
            "gramps_id": fields.Str(validate=validate.Length(min=1)),
            "keys": fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "locale": fields.Str(missing=None, validate=validate.Length(min=1, max=5)),
            "page": fields.Integer(missing=0, validate=validate.Range(min=1)),
            "pagesize": fields.Integer(missing=20, validate=validate.Range(min=1)),
            "profile": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(
                    choices=[
                        "all",
                        "self",
                        "families",
                        "events",
                        "age",
                        "span",
                        "ratings",
                        "references",
                    ]
                ),
            ),
            "rules": fields.Str(validate=validate.Length(min=1)),
            "skipkeys": fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1))
            ),
            "sort": fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "soundex": fields.Boolean(missing=False),
            "strip": fields.Boolean(missing=False),
            "filemissing": fields.Boolean(missing=False),
        },
        location="query",
    )
    def get(self, args: Dict) -> Response:
        """Get all objects."""
        locale = get_locale_for_language(args["locale"], default=True)
        if "gramps_id" in args:
            obj = self.get_object_from_gramps_id(args["gramps_id"])
            if obj is None:
                abort(404)
            return self.response(
                200, [self.full_object(obj, args, locale=locale)], args, total_items=1
            )

        query_method = self.db_handle.method("get_%s_handles", self.gramps_class_name)
        if self.gramps_class_name in ["Event", "Repository", "Note"]:
            handles = query_method()
        else:
            handles = query_method(sort_handles=True, locale=locale)

        if "filter" in args or "rules" in args:
            handles = apply_filter(
                self.db_handle, args, self.gramps_class_name, handles
            )

        if self.gramps_class_name == "Media" and args.get("filemissing"):
            handles = get_missing_media_file_handles(self.db_handle, handles)

        if args["dates"]:
            handles = self.match_dates(handles, args["dates"])

        if "sort" in args:
            handles = self.sort_objects(handles, args["sort"], locale=locale)

        total_items = len(handles)

        if args["page"] > 0:
            offset = (args["page"] - 1) * args["pagesize"]
            handles = handles[offset : offset + args["pagesize"]]

        query_method = self.db_handle.method(
            "get_%s_from_handle", self.gramps_class_name
        )
        return self.response(
            200,
            [
                self.full_object(query_method(handle), args, locale=locale)
                for handle in handles
            ],
            args,
            total_items=total_items,
        )

    def post(self) -> Response:
        """Post a new object."""
        require_permissions([PERM_ADD_OBJ])
        obj = self._parse_object()
        if not obj:
            abort(400)
        db_handle = self.db_handle_writable
        with DbTxn("Add objects", db_handle) as trans:
            try:
                add_object(db_handle, obj, trans, fail_if_exists=True)
            except ValueError:
                abort(400)
            trans_dict = transaction_to_json(trans)
        # update search index
        indexer: SearchIndexer = current_app.config["SEARCH_INDEXER"]
        with indexer.get_writer(overwrite=False, use_async=True) as writer:
            for _trans_dict in trans_dict:
                handle = _trans_dict["handle"]
                class_name = _trans_dict["_class"]
                indexer.add_or_update_object(writer, handle, db_handle, class_name)
        return self.response(201, trans_dict, total_items=len(trans_dict))
Пример #12
0
class AdminOrdersView(AdminBaseView):
    """后台-订单-获取订单列表"""
    pagination_class = StandardResultsSetPagination

    @AdminBaseView.permission_required(
        [AdminBaseView.staff_permissions.ADMIN_ORDER])
    @use_args(
        {
            "order_types":
            StrToList(
                required=False,
                missing=[OrderType.NORMAL, OrderType.GROUPON],
                validate=[
                    validate.ContainsOnly(
                        [OrderType.NORMAL, OrderType.GROUPON])
                ],
                comment="订单类型筛选 1: 普通订单, 5: 拼团订单",
            ),
            "order_pay_types":
            StrToList(
                required=False,
                missing=[OrderPayType.WEIXIN_JSAPI, OrderPayType.ON_DELIVERY],
                validate=[
                    validate.ContainsOnly(
                        [OrderPayType.WEIXIN_JSAPI, OrderPayType.ON_DELIVERY])
                ],
                comment="订单支付方式筛选 1: 微信支付, 2: 货到付款",
            ),
            "order_delivery_methods":
            StrToList(
                required=False,
                missing=[
                    OrderDeliveryMethod.HOME_DELIVERY,
                    OrderDeliveryMethod.CUSTOMER_PICK,
                ],
                validate=[
                    validate.ContainsOnly([
                        OrderDeliveryMethod.HOME_DELIVERY,
                        OrderDeliveryMethod.CUSTOMER_PICK,
                    ])
                ],
                comment="订单配送方式筛选 1: 送货上门, 2: 自提",
            ),
            "order_status":
            StrToList(
                required=False,
                missing=[
                    OrderStatus.PAID,
                    OrderStatus.CONFIRMED,
                    OrderStatus.FINISHED,
                    OrderStatus.REFUNDED,
                ],
                validate=[
                    validate.ContainsOnly([
                        OrderStatus.PAID,
                        OrderStatus.CONFIRMED,
                        OrderStatus.FINISHED,
                        OrderStatus.REFUNDED,
                    ])
                ],
                comment="订单状态筛选 2: 未处理 3: 处理中 4: 已完成 5: 已退款",
            ),
            "num":
            fields.String(
                required=False, data_key="order_num", comment="订单号搜索,与其他条件互斥"),
        },
        location="query")
    def get(self, request, args):
        shop_id = self.current_shop.id
        order_list = list_shop_orders(shop_id, **args)
        order_list = self._get_paginated_data(order_list,
                                              AdminOrdersSerializer)
        return self.send_success(data_list=order_list)
Пример #13
0
class TimelineFamiliesResource(ProtectedResource, GrampsJSONEncoder):
    """Families timeline resource."""
    @use_args(
        {
            "dates":
            fields.Str(
                missing=None,
                validate=validate.Regexp(
                    r"^-[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])$|"
                    r"^[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])-$|"
                    r"^[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])-"
                    r"[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])$"),
            ),
            "discard_empty":
            fields.Boolean(missing=True),
            "event_classes":
            fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(choices=EVENT_CATEGORIES),
            ),
            "events":
            fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "filter":
            fields.Str(validate=validate.Length(min=1)),
            "keys":
            fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "handles":
            fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "locale":
            fields.Str(missing=None, validate=validate.Length(min=1, max=5)),
            "page":
            fields.Integer(missing=0, validate=validate.Range(min=1)),
            "pagesize":
            fields.Integer(missing=20, validate=validate.Range(min=1)),
            "ratings":
            fields.Boolean(missing=False),
            "rules":
            fields.Str(validate=validate.Length(min=1)),
            "skipkeys":
            fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "strip":
            fields.Boolean(missing=False),
        },
        location="query",
    )
    def get(self, args: Dict):
        """Get consolidated list of events in timeline for a list of families."""
        db_handle = get_db_handle()
        locale = get_locale_for_language(args["locale"], default=True)
        events = prepare_events(args)
        try:
            timeline = Timeline(
                db_handle,
                dates=args["dates"],
                events=events,
                ratings=args["ratings"],
                discard_empty=args["discard_empty"],
                locale=locale,
            )
        except ValueError:
            abort(422)

        if "handles" in args:
            handles = args["handles"]
        else:
            handles = db_handle.get_family_handles(sort_handles=True,
                                                   locale=locale)

        try:
            if "filter" in args or "rules" in args:
                handles = apply_filter(db_handle, args, "Family", handles)

            for handle in handles:
                timeline.add_family(handle)
        except HandleError:
            abort(404)

        payload = timeline.profile(page=args["page"],
                                   pagesize=args["pagesize"])
        return self.response(200,
                             payload,
                             args,
                             total_items=len(timeline.timeline))
Пример #14
0
class PersonTimelineResource(ProtectedResource, GrampsJSONEncoder):
    """Person timeline resource."""
    @use_args(
        {
            "ancestors":
            fields.Integer(missing=1, validate=validate.Range(min=1, max=5)),
            "dates":
            fields.Str(
                missing=None,
                validate=validate.Regexp(
                    r"^-[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])$|"
                    r"^[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])-$|"
                    r"^[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])-"
                    r"[0-9]+/([1-9]|1[0-2])/([1-9]|1[0-9]|2[0-9]|3[0-1])$"),
            ),
            "discard_empty":
            fields.Boolean(missing=True),
            "event_classes":
            fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(choices=EVENT_CATEGORIES),
            ),
            "events":
            fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "first":
            fields.Boolean(missing=True),
            "keys":
            fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "last":
            fields.Boolean(missing=True),
            "locale":
            fields.Str(missing=None),
            "offspring":
            fields.Integer(missing=1, validate=validate.Range(min=1, max=5)),
            "omit_anchor":
            fields.Boolean(missing=True),
            "page":
            fields.Integer(missing=0, validate=validate.Range(min=1)),
            "pagesize":
            fields.Integer(missing=20, validate=validate.Range(min=1)),
            "precision":
            fields.Integer(missing=1, validate=validate.Range(min=1, max=3)),
            "ratings":
            fields.Boolean(missing=False),
            "relative_event_classes":
            fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(choices=EVENT_CATEGORIES),
            ),
            "relative_events":
            fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)), ),
            "relatives":
            fields.DelimitedList(
                fields.Str(validate=validate.Length(min=1)),
                validate=validate.ContainsOnly(choices=RELATIVES),
            ),
            "skipkeys":
            fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
            "strip":
            fields.Boolean(missing=False),
        },
        location="query",
    )
    def get(self, args: Dict, handle: str):
        """Get list of events in timeline for a person."""
        locale = get_locale_for_language(args["locale"], default=True)
        events = prepare_events(args)
        relatives = []
        if "relatives" in args:
            relatives = args["relatives"]
        relative_events = []
        if "relative_events" in args:
            relative_events = args["relative_events"]
        if "relative_event_classes" in args:
            relative_events = relative_events + args["relative_event_classes"]
        try:
            timeline = Timeline(
                get_db_handle(),
                dates=args["dates"],
                events=events,
                ratings=args["ratings"],
                relatives=relatives,
                relative_events=relative_events,
                discard_empty=args["discard_empty"],
                omit_anchor=args["omit_anchor"],
                precision=args["precision"],
                locale=locale,
            )
            timeline.add_person(
                Handle(handle),
                anchor=True,
                start=args["first"],
                end=args["last"],
                ancestors=args["ancestors"],
                offspring=args["offspring"],
            )
        except ValueError:
            abort(422)
        except HandleError:
            abort(404)

        payload = timeline.profile(page=args["page"],
                                   pagesize=args["pagesize"])
        return self.response(200,
                             payload,
                             args,
                             total_items=len(timeline.timeline))
Пример #15
0
class AdminLogsView(AdminBaseView):
    """后台-员工-操作日志"""
    @AdminBaseView.permission_required(
        [AdminBaseView.staff_permissions.ADMIN_STAFF])
    @use_args(
        {
            "operator_ids":
            fields.Function(
                deserialize=lambda x: x.replace(" ", "").split(","),
                missing=[],
                comment="操作人ID",
            ),
            "operate_module_ids":
            StrToList(
                missing=[],
                validate=[
                    validate.ContainsOnly(list(all_module_dict.values()))
                ],
                comment="模块ID",
            ),
        },
        location="query")
    def get(self, request, args):
        args["operate_module_ids"] = [
            int(_) for _ in args.get("operate_module_ids")
        ]
        # django时区问题
        args["end_date"] = make_aware(datetime.datetime.today() +
                                      datetime.timedelta(1))
        args["from_date"] = make_aware(datetime.datetime.today() -
                                       datetime.timedelta(90))
        shop_id = self.current_shop.id
        # 查询单个还是多个
        operate_module_ids = args.pop("operate_module_ids")
        # 查单个
        if len(operate_module_ids) == 1:
            module_id = operate_module_ids[0]
            log_list = list_one_module_log_by_filter(shop_id, module_id,
                                                     **args)
            module_id_2_log_list = {module_id: log_list}
        # 查询多个
        else:
            module_id_2_log_list = dict_more_modules_log_by_filter(
                shop_id, operate_module_ids, **args)
        """
        module_2_log_list = {
            1: [log, log ...],
            2: [log, log ...],
            ...
        }
        """
        # 封装数据
        module_id_2_name = {v: k.lower() for k, v in all_module_dict.items()}
        all_log_list = []
        for module_id, log_list_query in module_id_2_log_list.items():
            def_name = "format_{}_data".format(module_id_2_name.get(module_id))
            log_list = getattr(self, def_name)(log_list_query)
            all_log_list.extend(log_list)

        all_log_list = sorted(all_log_list,
                              key=lambda x: x["operate_time"],
                              reverse=True)
        return self.send_success(data_list=all_log_list)

    def format_order_data(self, log_list_query):
        """封装订单日志数据"""
        for log in log_list_query:
            if log.operate_type in [
                    OrderLogType.HOME_DELIVERY_AMOUNT,
                    OrderLogType.HOME_MINIMUM_FREE_AMOUNT,
                    OrderLogType.HOME_MINIMUM_ORDER_AMOUNT,
                    OrderLogType.PICK_MINIMUM_FREE_AMOUNT,
                    OrderLogType.PICK_SERVICE_AMOUNT,
            ]:
                log.old_value = log.operate_content.split("|")[0]
                log.new_value = log.operate_content.split("|")[1]
                log.operate_content = ""
        order_log_serializer = OrderLogSerializer(log_list_query, many=True)
        log_list = order_log_serializer.data
        return log_list

    def format_config_data(self, log_list_query):
        """封装设置日志数据"""
        log_list = ConfigLogSerializer(log_list_query, many=True).data
        return log_list

    def format_product_data(self, log_list_query):
        """封装货品日志数据"""
        log_list = ProductLogSerializer(log_list_query, many=True).data
        return log_list

    def format_promotion_data(self, log_list_query):
        """封装货品日志数据"""
        log_list = PromotionLogSerializer(log_list_query, many=True).data
        return log_list
Пример #16
0
class AdminCustomerOrdersView(AdminBaseView):
    """后台-客户-历史订单查询"""
    pagination_class = StandardResultsSetPagination

    @AdminBaseView.permission_required(
        [AdminBaseView.staff_permissions.ADMIN_CUSTOMER])
    @use_args(
        {
            "customer_id":
            fields.Integer(
                required=True, validate=[validate.Range(1)], comment="客户ID"),
            "order_types":
            StrToList(
                required=False,
                missing=[],
                validate=[
                    validate.ContainsOnly(
                        [OrderType.NORMAL, OrderType.GROUPON])
                ],
                comment="订单类型, 1: 普通订单, 5: 拼团订单",
            ),
            "order_pay_types":
            StrToList(
                required=False,
                missing=[],
                validate=[
                    validate.ContainsOnly(
                        [OrderPayType.WEIXIN_JSAPI, OrderPayType.ON_DELIVERY])
                ],
                comment="订单支付类型, 1: 微信支付, 2: 货到付款",
            ),
            "order_delivery_methods":
            StrToList(
                required=False,
                missing=[],
                validate=[
                    validate.ContainsOnly([
                        OrderDeliveryMethod.HOME_DELIVERY,
                        OrderDeliveryMethod.CUSTOMER_PICK,
                    ])
                ],
                comment="配送类型, 1: 送货上门, 2: 自提",
            ),
            "order_status":
            StrToList(
                required=False,
                missing=[
                    OrderStatus.PAID,
                    OrderStatus.CONFIRMED,
                    OrderStatus.FINISHED,
                    OrderStatus.REFUNDED,
                ],
                validate=[
                    validate.ContainsOnly([
                        OrderStatus.PAID,
                        OrderStatus.CONFIRMED,
                        OrderStatus.FINISHED,
                        OrderStatus.REFUNDED,
                    ])
                ],
                comment="订单状态, 2: 未处理, 3: 处理中, 4: 已完成, 5: 已退款",
            ),
        },
        location="query")
    def get(self, request, args):
        args["shop_id"] = self.current_shop.id
        order_list = list_customer_orders_interface(**args)
        order_list = self._get_paginated_data(order_list,
                                              AdminOrdersSerializer)
        return self.send_success(data_list=order_list)
Пример #17
0
        fields.Int(
            required=False, missing=0, validate=[validate.Range(min=0, max=1)])
    },
    location="query")
def get_random(length, specials, digits):
    return generate_password(length, specials, digits)


# Homework 3. Bitcoin rate function
@app.route("/bitcoin_rate")
@use_kwargs(
    {
        "currency":
        fields.Str(required=False,
                   missing="USD",
                   validate=[validate.ContainsOnly(string.ascii_uppercase)])
    },
    location="query")
def get_bitcoin_rate(currency):
    return bitcoin_request(currency)


# Homework 2. Reading CSV file function
@app.route("/avr_data")
def avr_data():
    height_lst, weight_lst = [], []
    with open("hw.csv", newline="") as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            height_lst.append(float(row[' "Height(Inches)"']))
            weight_lst.append(float(row[' "Weight(Pounds)"']))