Exemple #1
0
def client_func(genericAPIView, user, app, model, func_name, params):
    """云函数, 由客户端直接调用的服务函数"""
    func, options = find_func(app, model, func_name)
    if not func:
        raise exceptions.BusinessException(
            error_code=exceptions.FUNCTION_NOT_FOUNT,
            error_data=f"no such func: {func_name} found",
        )

    if options.get("login_required", False):
        if not user.is_authenticated:
            raise PermissionDenied()

    view_context = {"view": genericAPIView}
    params["view_context"] = view_context

    result = func(user, **params)
    # TODO:考虑函数的返回结果类型。1. 实体,2.实体列表,3.字典,4.无返回,针对不同的结果给客户端反馈
    if isinstance(result, requests.Response):
        return HttpResponse(result, result.headers.get("Content-Type", None))
    if isinstance(result, (list, dict)):
        return success_response(result)
    if isinstance(result, genericAPIView.model):
        serializer = genericAPIView.get_serializer(result)
        return success_response(serializer.data)
    return success_response()
Exemple #2
0
 def _get_menu_from_autobuild(self):
     """根据模型自定义菜单"""
     export_apps = get_export_apps()
     if not export_apps:
         return success_response([])
     try:
         result, id_index = [], 0
         for app_name in export_apps:
             application = apps.get_app_config(app_name)
             for model_item in application.get_models():
                 id_index += 1
                 result.append(
                     {
                         "id": id_index,
                         "name": model_item._meta.verbose_name,
                         "icon": None,
                         "parent": None,
                         "page": "list",
                         "permission": None,
                         "model": f"{app_name}__{model_item._meta.model_name}",
                         "sequence": 0,
                         "menu": [],
                     }
                 )
         return success_response(result)
     except Exception:
         return success_response([])
Exemple #3
0
def manage_func(genericAPIView, user, app, model, func_name, params):
    """云函数, 由客户端直接调用的服务函数"""
    # import ipdb; ipdb.set_trace()
    func, options = find_func(app, model, func_name)
    if not func:
        raise exceptions.BusinessException(
            error_code=exceptions.FUNCTION_NOT_FOUNT,
            error_data=f"no such func: {func_name} found",
        )
    if options.get("login_required", False):
        if not user.is_authenticated:
            raise PermissionDenied()
    if options.get("staff_required", False):
        if not user.is_staff:
            raise PermissionDenied()
    if options.get("superuser_required", False):
        if not user.is_superuser:
            raise PermissionDenied()

    view_context = {"view": genericAPIView}
    params["view_context"] = view_context
    result = func(user, **params)

    # TODO:考虑函数的返回结果类型。1. 实体,2.实体列表,3.字典,4.无返回,针对不同的结果给客户端反馈
    if isinstance(result, requests.Response):
        response = HttpResponse(result,
                                result.headers.get("Content-Type", None))
        if "Content-disposition" in result.headers:
            response["Content-disposition"] = result.headers.get(
                "Content-disposition")
        return response
    if (isinstance(result, list) or isinstance(result, dict)
            or isinstance(result, str) or isinstance(result, bytes)):
        return success_response(result)
    return success_response()
Exemple #4
0
def delete_by_conditon(genericAPIView):
    """按查询条件删除"""
    queryset = genericAPIView.filter_queryset(genericAPIView.get_queryset())
    deleted, rows_count = queryset.delete()
    result = {"deleted": deleted}

    return success_response(result)
Exemple #5
0
def update_sort(genericAPIView, request, data):
    if data.get("dragId") == data.get("hoverId"):
        return
    instance = genericAPIView.model
    admin = genericAPIView.get_bsm_model_admin()
    sort_key = admin.sort_key
    from django.db.models import F, Q

    with transaction.atomic():
        dragItem = instance.objects.filter(id=data["dragId"]).first()
        hoverItem = instance.objects.filter(id=data["hoverId"]).first()
        dragIndex = getattr(dragItem, sort_key)
        hoveIndex = getattr(hoverItem, sort_key)
        isDownward = dragIndex < hoveIndex or (dragIndex == hoveIndex
                                               and dragItem.id < hoverItem.id)
        instance.objects.filter(id=data["dragId"]).update(
            **{
                "parent": hoverItem.parent,
                sort_key: hoveIndex + 1
            })

        instance.objects.filter(
            Q(parent=hoverItem.parent),
            ~Q(id=dragItem.id),
            Q(**{f"{sort_key}__gt": hoveIndex}),
        ).update(**{f"{sort_key}": F(f"{sort_key}") + 2})
        up = Q(id__gt=hoverItem.id) if isDownward else Q(id__gte=hoverItem.id)
        instance.objects.filter(
            Q(parent=hoverItem.parent),
            ~Q(id=dragItem.id),
            Q(**{f"{sort_key}": hoveIndex}),
            up,
        ).update(**{f"{sort_key}": F(f"{sort_key}") + 2})
    return success_response(instance.objects.all().values())
Exemple #6
0
def client_update(genericAPIView, request, partial, set_data):
    """全量更新数据"""
    with transaction.atomic():
        client_user_pip.add_login_user_data(genericAPIView, set_data)
        forward_relation_hand(genericAPIView.model, set_data)

        # partial = kwargs.pop('partial', False)
        instance = genericAPIView.get_object()
        old_instance = copy(instance)

        serializer = genericAPIView.get_validate_form(genericAPIView.action)(
            instance, data=set_data, partial=partial)
        serializer.is_valid(raise_exception=True)
        instance = genericAPIView.perform_update(serializer)

        reverse_relation_hand(genericAPIView.model, set_data, instance)
        instance = genericAPIView.get_queryset().get(pk=instance.pk)

        # with transaction.atomic():
        log.debug(
            "sending Post Update signal with: model: %s, instance: %s",
            genericAPIView.model,
            instance,
        )
        post_bsm_create.send(
            sender=genericAPIView.model,
            instance=instance,
            create=False,
            request=genericAPIView.request,
            old_instance=old_instance,
        )

        serializer = genericAPIView.get_serializer(
            genericAPIView.get_queryset().get(pk=instance.pk))
        return success_response(serializer.data)
Exemple #7
0
    def token(self, request, *args, **kwargs):
        """
        ## 生成对应的上传签名

        **参数放在 query string 中,形式如 ?service=aliyun**

        当前的服务只支持 (aliyun, 阿里云)

        ### Returns

        #### 阿里云的返回数据结构如下:

        ```
        {
            "error_code": "0",
            "error_message": "",
            "result": {
                "accessid": "LTAIudMj4IZMpCCn",
                "host": "speedapi.oss-cn-shanghai.aliyuncs.com",
                "policy": "eyJleHBpcmF0aW9uIjogIjIwMTgV5IiwgIm1lZGlhLyJdXX0=",
                "signature": "9aOOMFzwwVQl0u/sFgdLKRSyeIw=",
                "expire": 1539770693,
                "dir": "media/"
            }
        }
        ```

        #### 腾讯云 COS 返回的数据结构如下
        {
            'startTime': 1592561936
            'expiredTime': 1592561966,
            'expiration': '2020-06-19T10:19:26Z',
            'requestId': '4332ced3-50a7-48fb-a35a-cb9efcec95d9',
            'bucket': 'test-20188932',
            'region': 'ap-guangzhou',
            'credentials': {
                'sessionToken': 'kg1Mg_UmDtAJ3wQA',
                'tmpSecretId': 'AKIDy_RmF9qEg1geYsrJ_UwR4WWYcDGM2iy71R',
                'tmpSecretKey': 'Q5FPMVsD='
            },
        }
        """
        service = request.query_params.get("service",
                                           site_setting["upload_provider"])
        result = {"provider": None}
        if service in ["aliyun", "oss"]:
            result = aliyun.get_token()
            result["provider"] = "oss"
        elif service in ["tencent", "cos"]:
            result = tencent.post_object_token()
            result["provider"] = "cos"
        elif service == "file_storage":
            result = {
                "provider": "file_storage",
                "policy": "",
                "dir": "",
                "host": "/basebone/storage/upload",
            }
        return success_response(result)
Exemple #8
0
    def _get_menu_from_custom(self):
        """从自定义的菜单配置中获取菜单"""
        menu_module = module.get_bsm_global_module(module.BSM_GLOBAL_MODULE_MENU)
        result = getattr(menu_module, module.BSM_GLOBAL_MODULE_MENU_MANAGE, None)

        by_role = getattr(settings, "BSM_MANAGE_MENU_BY_ROLE", False)
        if not by_role:
            return success_response(result["default"])
        else:
            groups = {item.name for item in self.request.user.groups.all()}
            if not groups:
                return success_response([])

            for item in groups:
                if item in result:
                    return success_response(result[item])

        return success_response([])
Exemple #9
0
def manage_create(genericAPIView, request, set_data):
    """
    这里校验表单和序列化类分开创建

    原因:序列化类有可能嵌套
    """
    many = isinstance(set_data, list)
    with transaction.atomic():
        forward_relation_hand(genericAPIView.model, set_data)
        serializer = genericAPIView.get_validate_form(genericAPIView.action)(
            data=set_data,
            context=genericAPIView.get_serializer_context(),
            many=many)
        serializer.is_valid(raise_exception=True)
        instance = genericAPIView.perform_create(serializer)

        if many:
            # 如果是批量插入,则直接返回
            return success_response()

        # 如果有联合查询,单个对象创建后并没有联合查询
        instance = genericAPIView.get_queryset().filter(pk=instance.pk).first()
        serializer = genericAPIView.get_serializer(instance)
        reverse_relation_hand(genericAPIView.model,
                              set_data,
                              instance,
                              detail=False)

        log.debug(
            "sending Post Save signal with: model: %s, instance: %s",
            genericAPIView.model,
            instance,
        )
        post_bsm_create.send(
            sender=genericAPIView.model,
            instance=instance,
            create=True,
            request=genericAPIView.request,
            old_instance=None,
            scope="admin",
        )
    return success_response(serializer.data)
Exemple #10
0
    def get_userinfo(self, request, *args, **kwargs):
        """
        ## 检测是否是否登录

        如果用户已登录,则直接返回此登录用户的数据结构
        """
        serializer = self.get_serializer(request.user)
        result = {}
        result.update(serializer.data)
        result["permissions"] = request.user.get_all_permissions()
        return success_response(result)
Exemple #11
0
 def get_all(self, request, *args, **kargs):
     """获取所有的客户端配置,包括schema, admin"""
     self._load_bsm_admin_module()
     data = {"schemas": get_app_field_schema(), "admins": get_app_admin_config()}
     json_object_schemas, json_array_item_schemas = get_app_json_field_schema()
     json_admin_configs = get_json_field_admin_config(
         json_object_schemas, json_array_item_schemas
     )
     data["schemas"].update(json_object_schemas)
     data["schemas"].update(json_array_item_schemas)
     data["admins"].update(json_admin_configs)
     return success_response(data)
Exemple #12
0
def destroy(genericAPIView, request, scope=""):
    """删除数据"""
    instance = genericAPIView.get_object()
    old_instance = copy(instance)
    genericAPIView.perform_destroy(instance)
    post_bsm_delete.send(
        sender=genericAPIView.model,
        instance=old_instance,
        request=genericAPIView.request,
        scope=scope,
    )
    return success_response()
Exemple #13
0
    def get_chart(self, request, *args, **kwargs):
        log.debug(f"get_chart action: {self.action}")
        from chart.models import Chart
        from django.core.cache import cache

        id = request.data["id"]
        chart = cache.get(f"chart_config:{id}", None)
        log.debug(f"chart get from cache: {chart}")
        if chart is None:
            chart = Chart.objects.prefetch_related(
                "metrics", "dimensions", "chart_filters"
            ).get(id=id)
            cache.set(f"chart_config:{id}", chart, 600)
            log.debug("cached Chart")

        group = {}
        fields = {}
        for dimension in chart.dimensions.all():
            field = {
                "field": dimension.field,
                "displayName": dimension.display_name,
                "expression": dimension.expression,
            }
            if dimension.method:
                field["method"] = dimension.method
            if dimension.name == "groupby":
                group[dimension.name] = field
            if dimension.name == "legend":
                group[dimension.name] = field

        for metric in chart.metrics.all():
            field = {
                "field": metric.field,
                "method": metric.method,
                "expression": metric.expression,
                "displayName": metric.display_name,
                "format": metric.format,
            }
            fields[metric.name] = field
        group_kwargs = self.get_group_data(group)
        filters = [
            {"field": ft.field, "operator": ft.operator, "value": ft.value}
            for ft in chart.chart_filters.all()
        ]
        data = self.group_statistics_data(
            fields,
            group_kwargs,
            sort_keys=chart.sort_keys,
            top_max=chart.top_max,
            filters=filters,
        )
        return success_response(data)
Exemple #14
0
    def batch(self, request, app, model, **kwargs):
        """
        ## 批量操作

        ```python
        {action: 动作, data: 主键的列表}
        ```
        """
        serializer = batch_actions.BatchActionForm(
            data=request.data, context=self.get_serializer_context()
        )
        serializer.is_valid(raise_exception=True)
        serializer.handle()
        return success_response()
Exemple #15
0
def display(genericAPIView, display_fields):
    """查询操作,取名display,避免跟列表list冲突"""
    queryset = genericAPIView.filter_queryset(genericAPIView.get_queryset())

    page = genericAPIView.paginate_queryset(queryset)
    if page is not None:
        """分页查询"""
        serializer = genericAPIView.get_serializer(page, many=True)
        result = filter_display_fields(serializer.data, display_fields)
        response = genericAPIView.get_paginated_response(result)
        result = response.data
    else:
        serializer = genericAPIView.get_serializer(queryset, many=True)
        result = filter_display_fields(serializer.data, display_fields)
    return success_response(result)
Exemple #16
0
    def login(self, request, *args, **kwargs):
        """
        ## 用户登录

        ```
        Params:
            username string 用户名
            password string 用户密码

        Returns:
            object 用户数据结构
        ```
        """
        serializer = forms.LoginForm(
            data=request.data, context=self.get_serializer_context()
        )
        serializer.is_valid(raise_exception=True)

        instance = serializer.save()
        serializer = self.get_serializer(instance)
        return success_response(serializer.data)
Exemple #17
0
def manage_update(genericAPIView, request, partial, set_data):
    """全量更新数据"""
    print("进入全量更新了吗?")
    with transaction.atomic():
        forward_relation_hand(genericAPIView.model, set_data)

        # partial = kwargs.pop('partial', False)
        instance = genericAPIView.get_object()
        old_instance = copy(instance)
        serializer = genericAPIView.get_validate_form(genericAPIView.action)(
            instance,
            data=set_data,
            partial=partial,
            context=genericAPIView.get_serializer_context(),
        )
        serializer.is_valid(raise_exception=True)

        instance = genericAPIView.perform_update(serializer)
        serializer = genericAPIView.get_serializer(instance)

        if getattr(instance, "_prefetched_objects_cache", None):
            instance._prefetched_objects_cache = {}

        reverse_relation_hand(genericAPIView.model, set_data, instance)

    with transaction.atomic():
        log.debug(
            "sending Post Update signal with: model: %s, instance: %s",
            genericAPIView.model,
            instance,
        )
        post_bsm_create.send(
            sender=genericAPIView.model,
            instance=instance,
            create=False,
            old_instance=old_instance,
            request=genericAPIView.request,
            scope="admin",
        )
    return success_response(serializer.data)
Exemple #18
0
def upload(request):
    key, policy, file = (
        request.data["key"],
        request.data["policy"],
        request.data["file"],
    )
    storage_path = site_setting["storage_path"]
    if not storage_path:
        raise BusinessException("storage support not enabled")
    file_path = Path(storage_path).joinpath(key)
    if not is_relative_to(file_path, storage_path):
        raise BusinessException("invalid file key: %s" % key)
    dirname = file_path.parent
    if not dirname.exists():
        dirname.mkdir(parents=True)
    elif not dirname.is_dir():
        raise BusinessException("dir exists: %s" % os.path.dirname(key))
    elif file_path.exists():
        raise BusinessException("file already exists: %s" % key)
    with file_path.open("wb+") as f:
        for chunk in file.chunks():
            f.write(chunk)
    return success_response()
Exemple #19
0
 def _get_menu_from_database(self):
     """从数据库中获取菜单"""
     user = self.request.user
     # permissions = self.request.user.get_all_permissions()
     # permission_filter = (Q(permission=None) | Q(permission='') | Q(permission__in=permissions))
     menus = (
         Menu.objects.prefetch_related("parent").order_by("sequence", "id")
         if user.is_superuser
         else Menu.objects.filter(
             Q(groups__in=self.request.user.groups.all()) | Q(groups__isnull=True)
         )
         .prefetch_related("parent")
         .order_by("sequence", "id")
     )
     fields = {field.name for field in Menu._meta.fields} - {
         "id",
         "parent",
         "permission",
         "name",
     }
     menus_map = {
         menu.id: dict(
             {field: getattr(menu, field) for field in fields},
             **{
                 "name": menu.display_name,
                 "parent_id": menu.parent_id,
                 "children": [],
             },
         )
         for menu in menus
     }
     for _, menu in menus_map.items():
         parent_id = menu["parent_id"]
         if parent_id and parent_id in menus_map:
             menus_map[parent_id]["children"].append(menu)
     menus_data = [m for _, m in menus_map.items() if not m.get("parent_id")]
     return success_response(menus_data)
Exemple #20
0
def client_create(genericAPIView, request, set_data):
    """
    这里校验表单和序列化类分开创建

    原因:序列化类有可能嵌套
    """

    with transaction.atomic():
        client_user_pip.add_login_user_data(genericAPIView, set_data)
        forward_relation_hand(genericAPIView.model, set_data)
        serializer = genericAPIView.get_validate_form(
            genericAPIView.action)(data=set_data)
        serializer.is_valid(raise_exception=True)
        instance = genericAPIView.perform_create(serializer)
        reverse_relation_hand(genericAPIView.model,
                              set_data,
                              instance,
                              detail=False)
        instance = genericAPIView.get_queryset().get(pk=instance.pk)

        # with transaction.atomic():
        log.debug(
            "sending Post Save signal with: model: %s, instance: %s",
            genericAPIView.model,
            instance,
        )
        post_bsm_create.send(
            sender=genericAPIView.model,
            instance=instance,
            create=True,
            request=genericAPIView.request,
            old_instance=None,
        )
        # 如果有联合查询,单个对象创建后并没有联合查询, 所以要多查一次?
        serializer = genericAPIView.get_serializer(
            genericAPIView.get_queryset().get(pk=instance.pk))
        return success_response(serializer.data)
Exemple #21
0
    def get_manage_menu(self, request, *args, **kwargs):
        """获取管理端的菜单配置"""
        if hasattr(settings, "ADMIN_MENUS"):
            group_names = self.request.user.groups.values_list("name", flat=True)
            group_names = set(group_names)

            def map_menus(menus):
                return [
                    {**m, "children": map_menus(m.get("children", []))}
                    for m in menus
                    if "groups" not in m
                    or self.request.user.is_superuser
                    or set(m["groups"]) & group_names
                ]

            return success_response(map_menus(settings.ADMIN_MENUS))

        menutype = request.query_params.get("menutype", "database")
        if menutype == "database":
            return self._get_menu_from_database()
        if menutype == "custom":
            return self._get_menu_from_custom()
        if menutype == "autobuild":
            return self._get_menu_from_autobuild()
Exemple #22
0
 def permissions(self, request, *args, **kwargs):
     """获取当前用户的权限"""
     return success_response(request.user.get_all_permissions())
Exemple #23
0
 def logout(self, request, *args, **kwargs):
     """退出登录"""
     logout(request)
     return success_response()
Exemple #24
0
def move(request, block_id):
    parent = request.data.get("parent", None)
    index = request.data["index"]
    services.move(block_id, parent, index)
    return success_response()
Exemple #25
0
 def get_setting_config(self, request, *args, **kargs):
     settings = get_setting_config()
     return success_response(settings)
Exemple #26
0
    def group_statistics(self, request, *args, **kwargs):
        fields = request.data.get("fields")
        group_kwargs = self.get_group()

        data = self.group_statistics_data(fields, group_kwargs)
        return success_response(data)
Exemple #27
0
    def statistics(self, request, *args, **kwargs):
        """计算统计数据

        请求的数据结构如下:

        {
            key: {
                method: 'count'
                field: 'xxxx',
                verbose_name: '可读名称',
            },
            ...
        }
        """
        log.debug(f"statistics action: {self.action}")
        configs = request.data.get("fields", None)
        if not configs:
            configs = self.basebone_get_statistics_config()
        if not configs:
            return success_response({})

        queryset = self.get_queryset()

        method_map = {"sum": Sum, "count": Count}

        aggregates, relation_aggregates = {}, {}

        relation_fields = [item.name for item in get_all_relation_fields(self.model)]

        for key, value in configs.items():
            if not isinstance(value, dict):
                continue

            method = value.get("method")

            if method not in method_map:
                continue

            field = value.get("field") if value.get("field") else key
            aggregate_param = method_map[value["method"]](field)

            if method == "count":
                aggregate_param = method_map[value["method"]](field, distinct=True)

            condition = Coalesce(aggregate_param, Value(0))

            split_field = field.split("__")[0]
            if split_field in relation_fields:
                relation_aggregates[key] = condition
            else:
                aggregates[key] = condition

        if not aggregates and not relation_aggregates:
            return success_response({})

        result = queryset.aggregate(**aggregates)
        self.basebone_origin_queryset.query.annotations.clear()
        relation_result = self.basebone_origin_queryset.aggregate(**relation_aggregates)

        result.update(relation_result)
        return success_response(result)
Exemple #28
0
def update_by_conditon(genericAPIView, set_fields):
    queryset = genericAPIView.filter_queryset(genericAPIView.get_queryset())
    count = queryset.update(**set_fields)
    result = {"count": count}
    return success_response(result)
Exemple #29
0
def block_view(request, block_id):
    block = Block.objects.get(id=block_id)
    data = None
    if block.component in component_resolver_map:
        data = component_resolver_map[block.component](block)
    return success_response(data)
Exemple #30
0
def retrieve(genericAPIView, display_fields):
    """获取数据详情"""
    instance = genericAPIView.get_object()
    serializer = genericAPIView.get_serializer(instance)
    result = filter_display_fields(serializer.data, display_fields)
    return success_response(result)