Пример #1
0
def update_category(public_id: int, data: dict):
    """
    HTTP `PUT`/`PATCH` route for update a single category resource.

    Args:
        public_id (int): Public ID of the updatable category
        data (CategoryModel.SCHEMA): New category data to update

    Raises:
        ManagerGetError: When the category with the `public_id` was not found.
        ManagerUpdateError: When something went wrong during the update.

    Returns:
        UpdateSingleResponse: With update result of the new updated category.
    """
    category_manager: CategoryManager = CategoryManager(
        database_manager=current_app.database_manager)
    try:
        category = CategoryModel.from_data(data=data)
        category_manager.update(public_id=PublicID(public_id),
                                category=CategoryModel.to_json(category))
        api_response = UpdateSingleResponse(result=data,
                                            url=request.url,
                                            model=CategoryModel.MODEL)
    except ManagerGetError as err:
        return abort(404, err.message)
    except ManagerUpdateError as err:
        return abort(400, err.message)

    return api_response.make_response()
Пример #2
0
def delete_category(public_id: int):
    """
    HTTP `DELETE` route for delete a single category resource.

    Args:
        public_id (int): Public ID of the deletable category

    Raises:
        ManagerGetError: When the category with the `public_id` was not found.
        ManagerDeleteError: When something went wrong during the deletion.

    Returns:
        DeleteSingleResponse: Delete result with the deleted category as data.
    """
    category_manager: CategoryManager = CategoryManager(
        database_manager=current_app.database_manager)
    try:
        deleted_category = category_manager.delete(
            public_id=PublicID(public_id))
        api_response = DeleteSingleResponse(
            raw=CategoryModel.to_json(deleted_category),
            model=CategoryModel.MODEL)
    except ManagerGetError as err:
        return abort(404, err.message)
    except ManagerDeleteError as err:
        return abort(404, err.message)
    return api_response.make_response()
Пример #3
0
    def count(
            self,
            filter: Union[List[dict], dict],
            user: UserModel = None,
            permission: AccessControlPermission = None
    ) -> Union[Query, Pipeline]:
        """
        Count the number of documents in the stages
        Args:
            filter: filter requirement
            user: request user
            permission: acl permission

        Returns:
            Query with count stages.
        """
        self.clear()
        self.query = Pipeline([])

        if isinstance(filter, dict):
            self.query.append(self.match_(filter))
        elif isinstance(filter, list):
            for pipe in filter:
                self.query.append(pipe)

        if user and permission:
            self.query += (AccessControlQueryBuilder().build(
                group_id=PublicID(user.group_id), permission=permission))

        self.query.append(self.count_('total'))
        return self.query
Пример #4
0
def update_group(public_id: int, data: dict):
    """
    HTTP `PUT`/`PATCH` route for update a single group resource.

    Args:
        public_id (int): Public ID of the updatable group.
        data (UserGroupModel.SCHEMA): New group data to update.

    Raises:
        ManagerGetError: When the group with the `public_id` was not found.
        ManagerUpdateError: When something went wrong during the update.

    Returns:
        UpdateSingleResponse: With update result of the new updated group.
    """
    group_manager: GroupManager = GroupManager(database_manager=current_app.database_manager,
                                               right_manager=RightManager(rights))
    try:
        group = UserGroupModel.from_data(data=data, rights=RightManager(rights).rights)
        group_dict = UserGroupModel.to_dict(group)
        group_dict['rights'] = [right.get('name') for right in group_dict.get('rights', [])]
        group_manager.update(public_id=PublicID(public_id), group=group_dict)
        api_response = UpdateSingleResponse(result=group_dict, url=request.url,
                                            model=UserGroupModel.MODEL)
    except ManagerGetError as err:
        return abort(404, err.message)
    except ManagerUpdateError as err:
        return abort(400, err.message)
    return api_response.make_response()
Пример #5
0
def change_user_password(public_id: int):
    """
    HTTP `PATCH` route for updating a single user password.

    Args:
        public_id (int): Public ID of the user.

    Raises:
        ManagerGetError: When the user with the `public_id` was not found.
        ManagerUpdateError: When something went wrong during the updated.

    Returns:
        UpdateSingleResponse: User with new password
    """
    user_manager: UserManager = UserManager(
        database_manager=current_app.database_manager)
    security_manager: SecurityManager = SecurityManager(
        database_manager=current_app.database_manager)
    try:
        user = user_manager.get(public_id=public_id)
        password = security_manager.generate_hmac(request.json.get('password'))
        user.password = password
        user_manager.update(public_id=PublicID(public_id), user=user)
        api_response = UpdateSingleResponse(result=UserModel.to_dict(user),
                                            url=request.url,
                                            model=UserModel.MODEL)
    except ManagerGetError as err:
        return abort(404, err.message)
    except ManagerUpdateError as err:
        return abort(400, err.message)

    return api_response.make_response()
Пример #6
0
def delete_user(public_id: int):
    """
    HTTP `DELETE` route for delete a single user resource.

    Args:
        public_id (int): Public ID of the user.

    Raises:
        ManagerGetError: When the user with the `public_id` was not found.
        ManagerDeleteError: When something went wrong during the deletion.

    Returns:
        DeleteSingleResponse: Delete result with the deleted user as data.
    """
    user_manager: UserManager = UserManager(
        database_manager=current_app.database_manager)
    try:
        deleted_group = user_manager.delete(public_id=PublicID(public_id))
        api_response = DeleteSingleResponse(
            raw=UserModel.to_dict(deleted_group), model=UserModel.MODEL)
    except ManagerGetError as err:
        return abort(404, err.message)
    except ManagerDeleteError as err:
        return abort(404, err.message)
    return api_response.make_response()
Пример #7
0
def update_user(public_id: int, data: dict):
    """
    HTTP `PUT`/`PATCH` route for update a single user resource.

    Args:
        public_id (int): Public ID of the updatable user.
        data (UserModel.SCHEMA): New user data to update.

    Raises:
        ManagerGetError: When the user with the `public_id` was not found.
        ManagerUpdateError: When something went wrong during the update.

    Returns:
        UpdateSingleResponse: With update result of the new updated user.
    """
    user_manager: UserManager = UserManager(
        database_manager=current_app.database_manager)
    try:
        user = UserModel.from_data(data=data)
        user_manager.update(public_id=PublicID(public_id), user=user)
        api_response = UpdateSingleResponse(result=UserModel.to_dict(user),
                                            url=request.url,
                                            model=UserModel.MODEL)
    except ManagerGetError as err:
        return abort(404, err.message)
    except ManagerUpdateError as err:
        return abort(400, err.message)
    return api_response.make_response()
Пример #8
0
def delete_group(public_id: int, params: GroupDeletionParameters):
    """
    HTTP `DELETE` route for delete a single group resource.

    Args:
        public_id (int): Public ID of the user.
        params (GroupDeletionParameters): Optional action parameters for handling users when the group \
                                          is going to be deleted.

    Notes:
        Based on the params attribute. Users can be moved or deleted.

    Raises:
        ManagerGetError: When the group with the `public_id` was not found.
        ManagerDeleteError: When something went wrong during the deletion.

    Returns:
        DeleteSingleResponse: Delete result with the deleted group as data.
    """
    group_manager: GroupManager = GroupManager(database_manager=current_app.database_manager,
                                               right_manager=RightManager(rights))
    user_manager: UserManager = UserManager(database_manager=current_app.database_manager)

    # Check of action is set
    if params.action:
        users_in_group: List[UserModel] = user_manager.get_many(Query({'group_id': public_id}))
        if len(users_in_group) > 0:
            if params.action == GroupDeleteMode.MOVE.value:
                if params.group_id:
                    for user in users_in_group:
                        user.group_id = int(params.group_id)
                        try:
                            user_manager.update(user.public_id, user)
                        except ManagerUpdateError as err:
                            return abort(400,
                                         f'Could not move user: {user.public_id} to group: {params.group_id} | '
                                         f'Error: {err.message}')

            if params.action == GroupDeleteMode.DELETE.value:
                for user in users_in_group:
                    try:
                        user_manager.delete(user.public_id)
                    except ManagerDeleteError as err:
                        return abort(400, f'Could not delete user: {user.public_id} | Error: {err.message}')

    try:
        deleted_group = group_manager.delete(public_id=PublicID(public_id))
        api_response = DeleteSingleResponse(raw=UserGroupModel.to_dict(deleted_group), model=UserGroupModel.MODEL)
    except ManagerGetError as err:
        return abort(404, err.message)
    except ManagerDeleteError as err:
        return abort(404, err.message)
    return api_response.make_response()
Пример #9
0
    def build(self, filter: Union[List[dict], dict], limit: int, skip: int, sort: str, order: int,
              user: UserModel = None, permission: AccessControlPermission = None, *args, **kwargs) -> \
            Union[Query, Pipeline]:
        """
        Converts the parameters from the call to a mongodb aggregation pipeline
        Args:
            filter: dict or list of dict query/queries which the elements have to match.
            limit: max number of documents to return.
            skip: number of documents to skip first.
            sort: sort field
            order: sort order
            user: request user
            permission: AccessControlPermission
            *args:
            **kwargs:

        Returns:
            The `LogQueryBuilder` query pipeline with the parameter contents.
        """
        self.clear()
        self.query = Pipeline([])

        if isinstance(filter, dict):
            self.query.append(self.match_(filter))
        elif isinstance(filter, list):
            for pipe in filter:
                self.query.append(pipe)

        if user and permission:
            self.query += (LookedAccessControlQueryBuilder().build(
                group_id=PublicID(user.group_id), permission=permission))

        if limit == 0:
            results_query = [self.skip_(limit)]
        else:
            results_query = [self.skip_(skip), self.limit_(limit)]

        self.query.append(self.sort_(sort=sort, order=order))

        self.query.append(
            self.facet_({
                'meta': [self.count_('total')],
                'results': results_query
            }))
        return self.query
Пример #10
0
def delete_link(public_id: int, request_user: UserModel):
    link_manager = ObjectLinkManager(
        database_manager=current_app.database_manager)
    try:
        deleted_type = link_manager.delete(
            public_id=PublicID(public_id),
            user=request_user,
            permission=AccessControlPermission.DELETE)
        api_response = DeleteSingleResponse(
            raw=ObjectLinkModel.to_json(deleted_type),
            model=ObjectLinkModel.MODEL)
    except ManagerGetError as err:
        return abort(404, err.message)
    except ManagerDeleteError as err:
        return abort(400, err.message)
    except AccessDeniedError as err:
        return abort(403, err.message)
    return api_response.make_response()
Пример #11
0
def delete_type(public_id: int):
    """
    HTTP `DELETE` route for delete a single type resource.

    Args:
        public_id (int): Public ID of the deletable type

    Raises:
        ManagerGetError: When the type with the `public_id` was not found.
        ManagerDeleteError: When something went wrong during the deletion.

    Notes:
        Deleting the type will also delete all objects in this type!

    Returns:
        DeleteSingleResponse: Delete result with the deleted type as data.
    """
    type_manager = TypeManager(database_manager=current_app.database_manager)
    from cmdb.framework.cmdb_object_manager import CmdbObjectManager
    deprecated_object_manager = CmdbObjectManager(
        database_manager=current_app.database_manager)

    try:
        objects_ids = [
            object_.get_public_id() for object_ in
            deprecated_object_manager.get_objects_by_type(public_id)
        ]
        deprecated_object_manager.delete_many_objects({'type_id': public_id},
                                                      objects_ids, None)
        deleted_type = type_manager.delete(public_id=PublicID(public_id))
        api_response = DeleteSingleResponse(
            raw=TypeModel.to_json(deleted_type), model=TypeModel.MODEL)
    except ManagerGetError as err:
        return abort(404, err.message)
    except ManagerDeleteError as err:
        return abort(400, err.message)
    except Exception as err:
        return abort(400, str(err))
    return api_response.make_response()
Пример #12
0
    def build(self,
              search_term,
              user: UserModel = None,
              permission: AccessControlPermission = None,
              active_flag: bool = False,
              *args,
              **kwargs) -> Pipeline:
        """Build a pipeline query out of search search term"""

        regex = self.regex_('fields.value', f'{search_term}', 'ims')
        pipe_and = self.and_(
            [regex, {
                'active': {
                    "$eq": True
                }
            } if active_flag else {}])
        pipe_match = self.match_(pipe_and)

        # load reference fields in runtime.
        self.pipeline = SearchReferencesPipelineBuilder().build()

        # permission builds
        if user and permission:
            self.pipeline = [
                *self.pipeline, *(AccessControlQueryBuilder().build(
                    group_id=PublicID(user.group_id), permission=permission))
            ]
        self.add_pipe(pipe_match)
        self.add_pipe(
            {'$group': {
                "_id": {
                    'active': '$active'
                },
                'count': {
                    '$sum': 1
                }
            }})
        self.add_pipe({
            '$group': {
                '_id': 0,
                'levels': {
                    '$push': {
                        '_id': '$_id.active',
                        'count': '$count'
                    }
                },
                'total': {
                    '$sum': '$count'
                }
            }
        })
        self.add_pipe({'$unwind': '$levels'})
        self.add_pipe({'$sort': {"levels._id": -1}})
        self.add_pipe({
            '$group': {
                '_id': 0,
                'levels': {
                    '$push': {
                        'count': "$levels.count"
                    }
                },
                "total": {
                    '$avg': '$total'
                }
            }
        })
        self.add_pipe({
            '$project': {
                'total': "$total",
                'active': {
                    '$arrayElemAt': ["$levels", 0]
                },
                'inactive': {
                    '$arrayElemAt': ["$levels", 1]
                }
            }
        })
        self.add_pipe({
            '$project': {
                '_id': 0,
                'active': {
                    '$cond': [{
                        '$ifNull': ["$active", False]
                    }, '$active.count', 0]
                },
                'inactive': {
                    '$cond': [{
                        '$ifNull': ['$inactive', False]
                    }, '$inactive.count', 0]
                },
                'total': '$total'
            }
        })

        return self.pipeline
Пример #13
0
    def build(self,
              params: List[SearchParam],
              obj_manager: CmdbObjectManager = None,
              user: UserModel = None,
              permission: AccessControlPermission = None,
              active_flag: bool = False,
              *args,
              **kwargs) -> Pipeline:
        """Build a pipeline query out of frontend params"""
        # clear pipeline
        self.clear()

        # load reference fields in runtime.
        self.pipeline = SearchReferencesPipelineBuilder().build()

        # fetch only active objects
        if active_flag:
            self.add_pipe(self.match_({'active': {"$eq": True}}))

        # text builds
        text_params = [
            _ for _ in params
            if _.search_form == 'text' or _.search_form == 'regex'
        ]
        for param in text_params:
            regex = self.regex_('fields.value', param.search_text, 'ims')
            self.add_pipe(self.match_(regex))

        # type builds
        disjunction_query = []
        type_params = [_ for _ in params if _.search_form == 'type']
        for param in type_params:
            if param.settings and len(param.settings.get('types', [])) > 0:
                type_id_in = self.in_('type_id', param.settings['types'])
                if param.disjunction:
                    disjunction_query.append(type_id_in)
                else:
                    self.add_pipe(self.match_(type_id_in))
        if len(disjunction_query) > 0:
            self.add_pipe(self.match_(self.or_(disjunction_query)))

        # category builds
        category_params = [_ for _ in params if _.search_form == 'category']
        for param in category_params:
            if param.settings and len(param.settings.get('categories',
                                                         [])) > 0:
                categories = obj_manager.get_categories_by(
                    **self.regex_('label', param.search_text))
                for curr_category in categories:
                    type_id_in = self.in_('type_id', curr_category.types)
                    self.add_pipe(self.match_(type_id_in))

        # public builds
        id_params = [_ for _ in params if _.search_form == 'publicID']
        for param in id_params:
            self.add_pipe(self.match_({'public_id': int(param.search_text)}))

        # permission builds
        if user and permission:
            self.pipeline = [
                *self.pipeline, *(AccessControlQueryBuilder().build(
                    group_id=PublicID(user.group_id), permission=permission))
            ]
        return self.pipeline
Пример #14
0
    def build(self, filter: Union[List[dict], dict], limit: int, skip: int, sort: str, order: int,
              user: UserModel = None, permission: AccessControlPermission = None, *args, **kwargs) -> \
            Union[Query, Pipeline]:
        """
        Converts the parameters from the call to a mongodb aggregation pipeline
        Args:
            filter: dict or list of dict query/queries which the elements have to match.
            limit: max number of documents to return.
            skip: number of documents to skip first.
            sort: sort field
            order: sort order
            user: request user
            permission: AccessControlPermission
            *args:
            **kwargs:

        Returns:
            The `FrameworkQueryBuilder` query pipeline with the parameter contents.
        """
        self.clear()
        loading_dep_preset = [
            self.lookup_(_from='framework.types',
                         _local='type_id',
                         _foreign='public_id',
                         _as='type'),
            self.unwind_({'path': '$type'}),
            self.match_({'type': {
                '$ne': None
            }}),
            self.lookup_(_from='management.users',
                         _local='author_id',
                         _foreign='public_id',
                         _as='author'),
            self.unwind_({
                'path': '$author',
                'preserveNullAndEmptyArrays': True
            }),
            self.lookup_(_from='management.users',
                         _local='editor_id',
                         _foreign='public_id',
                         _as='editor'),
            self.unwind_({
                'path': '$editor',
                'preserveNullAndEmptyArrays': True
            }),
        ]
        self.query = Pipeline(loading_dep_preset)

        if isinstance(filter, dict):
            self.query.append(self.match_(filter))
        elif isinstance(filter, list):
            for pipe in filter:
                self.query.append(pipe)

        if user and permission:
            self.query += (AccessControlQueryBuilder().build(
                group_id=PublicID(user.group_id), permission=permission))

        if limit == 0:
            results_query = [self.skip_(limit)]
        else:
            results_query = [self.skip_(skip), self.limit_(limit)]

        # TODO: Remove nasty quick hack
        if sort.startswith('fields'):
            sort_value = sort[7:]
            self.query.append({
                '$addFields': {
                    'order': {
                        '$filter': {
                            'input': '$fields',
                            'as': 'fields',
                            'cond': {
                                '$eq': ['$$fields.name', sort_value]
                            }
                        }
                    }
                }
            })
            self.query.append({'$sort': {'order': order}})
        else:
            self.query.append(self.sort_(sort=sort, order=order))

        self.query += results_query
        return self.query