Exemple #1
0
    def delete_object(self, obj, view_kwargs):
        """Delete an object through sqlalchemy

        :param DeclarativeMeta item: an item from sqlalchemy
        :param dict view_kwargs: kwargs from the resource view
        """
        if obj is None:
            url_field = getattr(self, "url_field", "id")
            filter_value = view_kwargs[url_field]
            raise ObjectNotFound(
                f"{self.model.__name__}: {filter_value} not found",
                source={"parameter": url_field})

        self.before_delete_object(obj, view_kwargs)

        for i_plugins in self.resource.plugins:
            try:
                i_plugins.data_layer_delete_object_clean_data(
                    obj=obj, view_kwargs=view_kwargs, self_json_api=self)
            except PluginMethodNotImplementedError:
                pass

        self.session.delete(obj)
        try:
            self.session.commit()
        except JsonApiException as e:
            self.session.rollback()
            raise e
        except Exception as e:
            self.session.rollback()
            raise JsonApiException("Delete object error: " + str(e))

        self.after_delete_object(obj, view_kwargs)
Exemple #2
0
    def update_object(self, obj, data, view_kwargs):
        """Update an object through sqlalchemy

        :param DeclarativeMeta obj: an object from sqlalchemy
        :param dict data: the data validated by marshmallow
        :param dict view_kwargs: kwargs from the resource view
        :return boolean: True if object have changed else False
        """
        if obj is None:
            url_field = getattr(self, "url_field", "id")
            filter_value = view_kwargs[url_field]
            raise ObjectNotFound(
                f"{self.model.__name__}: {filter_value} not found",
                source={"parameter": url_field})

        self.before_update_object(obj, data, view_kwargs)

        relationship_fields = get_relationships(self.resource.schema,
                                                model_field=True)
        nested_fields = get_nested_fields(self.resource.schema,
                                          model_field=True)

        join_fields = relationship_fields + nested_fields

        for i_plugins in self.resource.plugins:
            try:
                data = i_plugins.data_layer_update_object_clean_data(
                    data=data,
                    obj=obj,
                    view_kwargs=view_kwargs,
                    join_fields=join_fields,
                    self_json_api=self,
                )
            except PluginMethodNotImplementedError:
                pass

        for key, value in data.items():
            if hasattr(obj, key) and key not in join_fields:
                setattr(obj, key, value)

        self.apply_relationships(data, obj)
        self.apply_nested_fields(data, obj)

        try:
            self.session.commit()
        except JsonApiException as e:
            self.session.rollback()
            raise e
        except Exception as e:
            self.session.rollback()
            orig_e = getattr(e, "orig", object)
            message = getattr(orig_e, "args", [])
            message = message[0] if message else None
            e = message if message else e
            raise JsonApiException("Update object error: " + str(e),
                                   source={"pointer": "/data"})

        self.after_update_object(obj, data, view_kwargs)
Exemple #3
0
 def query(self, view_kwargs):
     query_ = self.session.query(Computer)
     if view_kwargs.get('id') is not None:
         try:
             self.session.query(Person).filter_by(id=view_kwargs['id']).one()
         except NoResultFound:
             raise ObjectNotFound({'parameter': 'id'}, "Person: {} not found".format(view_kwargs['id']))
         else:
             query_ = query_.join(Person).filter(Person.id == view_kwargs['id'])
     return query_
Exemple #4
0
    def event_update_avatar(self, *args, id: int = None, **view_kwargs):
        # language=YAML
        """
        ---
        summary: Update user's avatar
        tags:
        - User
        parameters:
        - in: path
          name: id
          required: True
          type: integer
          format: int32
          description: "user's id"
        requestBody:
          content:
            multipart/form-data:
              schema:
                type: object
                properties:
                  new_avatar:
                    type: string
                    format: binary
        consumes:
        - multipart/form-data
        responses:
          201:
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    avatar_url:
                      type: string
                      example: "uploads/avatar.gif"
        """
        avatar = request.files.get("new_avatar")
        if not avatar:
            raise BadRequest(
                "avatar file is required! please fill `new_avatar` form field")

        user = User.query.filter_by(id=id).one_or_none()
        if user is None:
            raise ObjectNotFound(
                "User #{} not found".format(id),
                source={"parameter": "id"},
            )

        filename = avatar.filename
        avatar_path = str(UPLOADS_DIR / filename)
        avatar.save(avatar_path)
        user.avatar_path = str(UPLOADS_DIR_NAME / filename)
        db.session.commit()
        return {"avatar_url": user.avatar_path}, 201
Exemple #5
0
 def before_get_object(self, view_kwargs):
     if view_kwargs.get('computer_id') is not None:
         try:
             computer = self.session.query(Computer).filter_by(id=view_kwargs['computer_id']).one()
         except NoResultFound:
             raise ObjectNotFound({'parameter': 'computer_id'},
                                  "Computer: {} not found".format(view_kwargs['computer_id']))
         else:
             if computer.person is not None:
                 view_kwargs['id'] = computer.person.id
             else:
                 view_kwargs['id'] = None
Exemple #6
0
    def get_relationship(self, relationship_field, related_type_,
                         related_id_field, view_kwargs):
        """Get a relationship

        :param str relationship_field: the model attribute used for relationship
        :param str related_type_: the related resource type
        :param str related_id_field: the identifier field of the related model
        :param dict view_kwargs: kwargs from the resource view
        :return tuple: the object and related object(s)
        """
        self.before_get_relationship(relationship_field, related_type_,
                                     related_id_field, view_kwargs)

        obj = self.get_object(view_kwargs)

        if obj is None:
            url_field = getattr(self, "url_field", "id")
            filter_value = view_kwargs[url_field]
            raise ObjectNotFound(
                f"{self.model.__name__}: {filter_value} not found",
                source={"parameter": url_field})

        if not hasattr(obj, relationship_field):
            raise RelationNotFound(
                f"{obj.__class__.__name__} has no attribute {relationship_field}"
            )

        related_objects = getattr(obj, relationship_field)

        if related_objects is None:
            return obj, related_objects

        self.after_get_relationship(
            obj,
            related_objects,
            relationship_field,
            related_type_,
            related_id_field,
            view_kwargs,
        )

        if isinstance(related_objects, InstrumentedList):
            return obj, [{
                "type": related_type_,
                "id": getattr(obj_, related_id_field)
            } for obj_ in related_objects]
        else:
            return obj, {
                "type": related_type_,
                "id": getattr(related_objects, related_id_field)
            }
Exemple #7
0
    def get(self, *args, **kwargs):
        """Get object details"""
        self.before_get(args, kwargs)

        qs = self.qs_manager_class(request.args, self.schema)

        obj = self.get_object(kwargs, qs)

        if obj is None:
            url_field = getattr(self._data_layer, "url_field", "id")
            value = f" '{kwargs.get(url_field)}'" if kwargs.get(
                url_field) else ""
            raise ObjectNotFound(
                f"{self.data_layer['model'].__name__}{value} not found.")

        self.before_marshmallow(args, kwargs)

        schema = compute_schema(self.schema,
                                getattr(self, "get_schema_kwargs", dict()), qs,
                                qs.include)

        for i_plugins in self.plugins:
            try:
                i_plugins.after_init_schema_in_resource_detail_get(
                    *args,
                    schema=schema,
                    model=self.data_layer["model"],
                    **kwargs)
            except PluginMethodNotImplementedError:
                pass

        result = schema.dump(obj)

        final_result = self.after_get(result)

        return final_result
Exemple #8
0
    def delete_relationship(self, json_data, relationship_field,
                            related_id_field, view_kwargs):
        """Delete a relationship

        :param dict json_data: the request params
        :param str relationship_field: the model attribute used for relationship
        :param str related_id_field: the identifier field of the related model
        :param dict view_kwargs: kwargs from the resource view
        """
        self.before_delete_relationship(json_data, relationship_field,
                                        related_id_field, view_kwargs)

        obj = self.get_object(view_kwargs)

        if obj is None:
            url_field = getattr(self, "url_field", "id")
            filter_value = view_kwargs[url_field]
            raise ObjectNotFound(
                f"{self.model.__name__}: {filter_value} not found",
                source={"parameter": url_field})

        if not hasattr(obj, relationship_field):
            raise RelationNotFound(
                f"{obj.__class__.__name__} has no attribute {relationship_field}"
            )

        related_model = getattr(obj.__class__,
                                relationship_field).property.mapper.class_

        updated = False

        if isinstance(json_data["data"], list):
            obj_ids = {
                str(getattr(obj__, related_id_field))
                for obj__ in getattr(obj, relationship_field)
            }

            for obj_ in json_data["data"]:
                if obj_["id"] in obj_ids:
                    getattr(obj, relationship_field).remove(
                        self.get_related_object(related_model,
                                                related_id_field, obj_))
                    updated = True
        else:
            setattr(obj, relationship_field, None)
            updated = True

        try:
            self.session.commit()
        except JsonApiException as e:
            self.session.rollback()
            raise e
        except Exception as e:
            self.session.rollback()
            raise JsonApiException("Delete relationship error: " + str(e))

        self.after_delete_relationship(obj, updated, json_data,
                                       relationship_field, related_id_field,
                                       view_kwargs)

        return obj, updated
Exemple #9
0
    def update_relationship(self, json_data, relationship_field,
                            related_id_field, view_kwargs):
        """Update a relationship

        :param dict json_data: the request params
        :param str relationship_field: the model attribute used for relationship
        :param str related_id_field: the identifier field of the related model
        :param dict view_kwargs: kwargs from the resource view
        :return boolean: True if relationship have changed else False
        """
        self.before_update_relationship(json_data, relationship_field,
                                        related_id_field, view_kwargs)

        obj = self.get_object(view_kwargs)

        if obj is None:
            url_field = getattr(self, "url_field", "id")
            filter_value = view_kwargs[url_field]
            raise ObjectNotFound(
                f"{self.model.__name__}: {filter_value} not found",
                source={"parameter": url_field})

        if not hasattr(obj, relationship_field):
            raise RelationNotFound(
                f"{obj.__class__.__name__} has no attribute {relationship_field}"
            )

        related_model = getattr(obj.__class__,
                                relationship_field).property.mapper.class_

        updated = False

        if isinstance(json_data["data"], list):
            related_objects = []

            for obj_ in json_data["data"]:
                related_objects.append(
                    self.get_related_object(related_model, related_id_field,
                                            obj_))

            obj_ids = {
                getattr(obj__, related_id_field)
                for obj__ in getattr(obj, relationship_field)
            }
            new_obj_ids = {
                getattr(related_object, related_id_field)
                for related_object in related_objects
            }
            if obj_ids != new_obj_ids:
                setattr(obj, relationship_field, related_objects)
                updated = True

        else:
            related_object = None

            if json_data["data"] is not None:
                related_object = self.get_related_object(
                    related_model, related_id_field, json_data["data"])

            obj_id = getattr(getattr(obj, relationship_field),
                             related_id_field, None)
            new_obj_id = getattr(related_object, related_id_field, None)
            if obj_id != new_obj_id:
                setattr(obj, relationship_field, related_object)
                updated = True

        try:
            self.session.commit()
        except JsonApiException as e:
            self.session.rollback()
            raise e
        except Exception as e:
            self.session.rollback()
            raise JsonApiException("Update relationship error: " + str(e))

        self.after_update_relationship(obj, updated, json_data,
                                       relationship_field, related_id_field,
                                       view_kwargs)

        return obj, updated