Exemplo n.º 1
0
class BaseDistributionSerializer(ModelSerializer):
    """
    The Serializer for the BaseDistribution model.

    The serializer deliberately omits the "remote" field, which is used for
    pull-through caching only. Plugins implementing pull-through caching will
    have to add the field in their derived serializer class like this::

      remote = DetailRelatedField(
          required=False,
          help_text=_('Remote that can be used to fetch content when using pull-through caching.'),
          queryset=models.Remote.objects.all(),
          allow_null=True
      )

    """

    pulp_href = DetailIdentityField(
        view_name_pattern=r"distributions(-.*/.*)-detail", )
    base_path = serializers.CharField(
        help_text=
        _('The base (relative) path component of the published url. Avoid paths that \
                    overlap with other distribution base paths (e.g. "foo" and "foo/bar")'
          ),
        validators=[
            UniqueValidator(queryset=models.BaseDistribution.objects.all())
        ],
    )
    base_url = BaseURLField(
        source="base_path",
        read_only=True,
        help_text=
        _("The URL for accessing the publication as defined by this distribution."
          ),
    )
    content_guard = DetailRelatedField(
        required=False,
        help_text=_("An optional content-guard."),
        view_name_pattern=r"contentguards(-.*/.*)?-detail",
        queryset=models.ContentGuard.objects.all(),
        allow_null=True,
    )
    name = serializers.CharField(
        help_text=_("A unique name. Ex, `rawhide` and `stable`."),
        validators=[
            UniqueValidator(queryset=models.BaseDistribution.objects.all())
        ],
    )

    class Meta:
        abstract = True
        model = models.BaseDistribution
        fields = ModelSerializer.Meta.fields + (
            "base_path",
            "base_url",
            "content_guard",
            "name",
        )

    def _validate_path_overlap(self, path):
        # look for any base paths nested in path
        search = path.split("/")[0]
        q = Q(base_path=search)
        for subdir in path.split("/")[1:]:
            search = "/".join((search, subdir))
            q |= Q(base_path=search)

        # look for any base paths that nest path
        q |= Q(base_path__startswith="{}/".format(path))
        qs = models.BaseDistribution.objects.filter(q)

        if self.instance is not None:
            qs = qs.exclude(pk=self.instance.pk)

        match = qs.first()
        if match:
            raise serializers.ValidationError(
                detail=_("Overlaps with existing distribution '"
                         "{}'").format(match.name))

        return path

    def validate_base_path(self, path):
        self._validate_relative_path(path)
        return self._validate_path_overlap(path)
Exemplo n.º 2
0
class DistributionSerializer(ModelSerializer):
    """
    The Serializer for the Distribution model.

    The serializer deliberately omits the the `publication` and `repository_version` field due to
    plugins typically requiring one or the other but not both.

    To include the ``publication`` field, it is recommended plugins define the field::

      publication = DetailRelatedField(
          required=False,
          help_text=_("Publication to be served"),
          view_name_pattern=r"publications(-.*/.*)?-detail",
          queryset=models.Publication.objects.exclude(complete=False),
          allow_null=True,
      )

    To include the ``repository_version`` field, it is recommended plugins define the field::

      repository_version = RepositoryVersionRelatedField(
          required=False, help_text=_("RepositoryVersion to be served"), allow_null=True
      )

    Additionally, the serializer omits the ``remote`` field, which is used for pull-through caching
    feature and only by plugins which use publications. Plugins implementing a pull-through caching
    should define the field in their derived serializer class like this::

      remote = DetailRelatedField(
          required=False,
          help_text=_('Remote that can be used to fetch content when using pull-through caching.'),
          queryset=models.Remote.objects.all(),
          allow_null=True
      )

    """

    pulp_href = DetailIdentityField(
        view_name_pattern=r"distributions(-.*/.*)-detail")
    pulp_labels = LabelsField(required=False)

    base_path = serializers.CharField(
        help_text=
        _('The base (relative) path component of the published url. Avoid paths that \
                    overlap with other distribution base paths (e.g. "foo" and "foo/bar")'
          ),
        validators=[
            UniqueValidator(queryset=models.Distribution.objects.all())
        ],
    )
    base_url = BaseURLField(
        source="base_path",
        read_only=True,
        help_text=
        _("The URL for accessing the publication as defined by this distribution."
          ),
    )
    content_guard = DetailRelatedField(
        required=False,
        help_text=_("An optional content-guard."),
        view_name_pattern=r"contentguards(-.*/.*)?-detail",
        queryset=models.ContentGuard.objects.all(),
        allow_null=True,
    )
    name = serializers.CharField(
        help_text=_("A unique name. Ex, `rawhide` and `stable`."),
        validators=[
            UniqueValidator(queryset=models.Distribution.objects.all()),
        ],
    )
    repository = DetailRelatedField(
        required=False,
        help_text=_(
            "The latest RepositoryVersion for this Repository will be served."
        ),
        view_name_pattern=r"repositories(-.*/.*)?-detail",
        queryset=models.Repository.objects.all(),
        allow_null=True,
    )

    class Meta:
        abstract = True
        model = models.Distribution
        fields = ModelSerializer.Meta.fields + (
            "base_path",
            "base_url",
            "content_guard",
            "pulp_labels",
            "name",
            "repository",
        )

    def _validate_path_overlap(self, path):
        # look for any base paths nested in path
        search = path.split("/")[0]
        q = Q(base_path=search)
        for subdir in path.split("/")[1:]:
            search = "/".join((search, subdir))
            q |= Q(base_path=search)

        # look for any base paths that nest path
        q |= Q(base_path__startswith="{}/".format(path))
        qs = models.Distribution.objects.filter(q)

        if self.instance is not None:
            qs = qs.exclude(pk=self.instance.pk)

        match = qs.first()
        if match:
            raise serializers.ValidationError(detail=_(
                "Overlaps with existing distribution '{}'").format(match.name))

        return path

    def validate_base_path(self, path):
        self._validate_relative_path(path)
        return self._validate_path_overlap(path)

    def validate(self, data):
        super().validate(data)

        repository_provided = data.get(
            "repository", None) or (self.instance and self.instance.repository)
        repository_version_provided = data.get(
            "repository_version",
            None) or (self.instance and self.instance.repository_version)
        publication_provided = data.get(
            "publication", None) or (self.instance
                                     and self.instance.publication)

        if publication_provided and repository_version_provided:
            raise serializers.ValidationError(
                _("Only one of the attributes 'publication' and 'repository_version' "
                  "may be used simultaneously."))
        elif repository_provided and repository_version_provided:
            raise serializers.ValidationError(
                _("Only one of the attributes 'repository' and 'repository_version' "
                  "may be used simultaneously."))
        # TODO: https://pulp.plan.io/issues/8762

        # elif repository_provided and publication_provided:
        #     raise serializers.ValidationError(
        #         _(
        #             "Only one of the attributes 'repository' and 'publication' "
        #             "may be used simultaneously."
        #         )
        #     )

        return data
Exemplo n.º 3
0
class DistributionSerializer(ModelSerializer, BasePathOverlapMixin):
    """
    The Serializer for the Distribution model.

    The serializer deliberately omits the the `publication` and `repository_version` field due to
    plugins typically requiring one or the other but not both.

    To include the ``publication`` field, it is recommended plugins define the field::

      publication = DetailRelatedField(
          required=False,
          help_text=_("Publication to be served"),
          view_name_pattern=r"publications(-.*/.*)?-detail",
          queryset=models.Publication.objects.exclude(complete=False),
          allow_null=True,
      )

    To include the ``repository_version`` field, it is recommended plugins define the field::

      repository_version = RepositoryVersionRelatedField(
          required=False, help_text=_("RepositoryVersion to be served"), allow_null=True
      )

    Additionally, the serializer omits the ``remote`` field, which is used for pull-through caching
    feature and only by plugins which use publications. Plugins implementing a pull-through caching
    should define the field in their derived serializer class like this::

      remote = DetailRelatedField(
          required=False,
          help_text=_('Remote that can be used to fetch content when using pull-through caching.'),
          queryset=models.Remote.objects.all(),
          allow_null=True
      )

    """

    pulp_href = DetailIdentityField(
        view_name_pattern=r"distributions(-.*/.*)-detail")
    pulp_labels = LabelsField(required=False)

    base_path = serializers.CharField(help_text=_(
        'The base (relative) path component of the published url. Avoid paths that \
                    overlap with other distribution base paths (e.g. "foo" and "foo/bar")'
    ), )
    base_url = BaseURLField(
        source="base_path",
        read_only=True,
        help_text=
        _("The URL for accessing the publication as defined by this distribution."
          ),
    )
    content_guard = DetailRelatedField(
        required=False,
        help_text=_("An optional content-guard."),
        view_name_pattern=r"contentguards(-.*/.*)?-detail",
        queryset=models.ContentGuard.objects.all(),
        allow_null=True,
    )
    name = serializers.CharField(
        help_text=_("A unique name. Ex, `rawhide` and `stable`."),
        validators=[
            UniqueValidator(queryset=models.BaseDistribution.objects.all()),
            UniqueValidator(queryset=models.Distribution.objects.all()),
        ],
    )
    repository = DetailRelatedField(
        required=False,
        help_text=_(
            "The latest RepositoryVersion for this Repository will be served."
        ),
        view_name_pattern=r"repositories(-.*/.*)?-detail",
        queryset=models.Repository.objects.all(),
        allow_null=True,
    )

    class Meta:
        abstract = True
        model = models.BaseDistribution
        fields = ModelSerializer.Meta.fields + (
            "base_path",
            "base_url",
            "content_guard",
            "pulp_labels",
            "name",
            "repository",
        )

    def validate(self, data):
        super().validate(data)

        publication_in_data = "publication" in data
        repository_version_in_data = "repository_version" in data
        publication_in_instance = self.instance.publication if self.instance else None
        repository_version_in_instance = self.instance.repository_version if self.instance else None

        if publication_in_data and repository_version_in_data:
            error = True
        elif publication_in_data and repository_version_in_instance:
            error = True
        elif publication_in_instance and repository_version_in_data:
            error = True
        else:
            error = False

        if error:
            msg = _(
                "Only one of the attributes 'publication' and 'repository_version' may be used "
                "simultaneously.")
            raise serializers.ValidationError(msg)

        return data
Exemplo n.º 4
0
class DistributionSerializer(ModelSerializer):
    _href = serializers.HyperlinkedIdentityField(
        view_name='distributions-detail')
    name = serializers.CharField(
        help_text=_('A unique distribution name. Ex, `rawhide` and `stable`.'),
        validators=[
            validators.MaxLengthValidator(
                models.Distribution._meta.get_field('name').max_length,
                message=_(
                    'Distribution name length must be less than {} characters'
                ).format(
                    models.Distribution._meta.get_field('name').max_length)),
            UniqueValidator(queryset=models.Distribution.objects.all())
        ])
    base_path = serializers.CharField(
        help_text=
        _('The base (relative) path component of the published url. Avoid paths that \
                    overlap with other distribution base paths (e.g. "foo" and "foo/bar")'
          ),
        validators=[
            validators.MaxLengthValidator(
                models.Distribution._meta.get_field('base_path').max_length,
                message=
                _('Distribution base_path length must be less than {} characters'
                  ).format(
                      models.Distribution._meta.get_field(
                          'base_path').max_length)),
            UniqueValidator(queryset=models.Distribution.objects.all()),
        ])
    publisher = DetailRelatedField(
        required=False,
        help_text=_(
            'Publications created by this publisher and repository are automatically'
            'served as defined by this distribution'),
        queryset=models.Publisher.objects.all(),
        allow_null=True)
    publication = serializers.HyperlinkedRelatedField(
        required=False,
        help_text=_(
            'The publication being served as defined by this distribution'),
        queryset=models.Publication.objects.exclude(complete=False),
        view_name='publications-detail',
        allow_null=True)
    repository = serializers.HyperlinkedRelatedField(
        required=False,
        help_text=_(
            'Publications created by this repository and publisher are automatically'
            'served as defined by this distribution'),
        queryset=models.Repository.objects.all(),
        view_name='repositories-detail',
        allow_null=True)
    base_url = BaseURLField(
        source='base_path',
        read_only=True,
        help_text=
        _('The URL for accessing the publication as defined by this distribution.'
          ))

    class Meta:
        model = models.Distribution
        fields = ModelSerializer.Meta.fields + (
            'name',
            'base_path',
            'publisher',
            'publication',
            'base_url',
            'repository',
        )

    def _validate_path_overlap(self, path):
        # look for any base paths nested in path
        search = path.split("/")[0]
        q = Q(base_path=search)
        for subdir in path.split("/")[1:]:
            search = "/".join((search, subdir))
            q |= Q(base_path=search)

        # look for any base paths that nest path
        q |= Q(base_path__startswith='{}/'.format(path))
        qs = models.Distribution.objects.filter(q)

        if self.instance is not None:
            qs = qs.exclude(pk=self.instance.pk)

        match = qs.first()
        if match:
            raise serializers.ValidationError(
                detail=_("Overlaps with existing distribution '"
                         "{}'").format(match.name))

        return path

    def validate_base_path(self, path):
        self._validate_relative_path(path)
        return self._validate_path_overlap(path)

    def validate(self, data):
        super().validate(data)

        if 'publisher' in data:
            publisher = data['publisher']
        elif self.instance:
            publisher = self.instance.publisher
        else:
            publisher = None

        if 'repository' in data:
            repository = data['repository']
        elif self.instance:
            repository = self.instance.repository
        else:
            repository = None

        if publisher and not repository:
            raise serializers.ValidationError({
                'repository':
                _("Repository must be set if "
                  "publisher is set.")
            })
        if repository and not publisher:
            raise serializers.ValidationError({
                'publisher':
                _("Publisher must be set if "
                  "repository is set.")
            })

        return data
Exemplo n.º 5
0
class BaseDistributionSerializer(ModelSerializer, BasePathOverlapMixin):
    """
    The Serializer for the BaseDistribution model.

    The serializer deliberately omits the "remote" field, which is used for
    pull-through caching only. Plugins implementing pull-through caching will
    have to add the field in their derived serializer class like this::

      remote = DetailRelatedField(
          required=False,
          help_text=_('Remote that can be used to fetch content when using pull-through caching.'),
          queryset=models.Remote.objects.all(),
          allow_null=True
      )

    """

    pulp_href = DetailIdentityField(
        view_name_pattern=r"distributions(-.*/.*)-detail")
    pulp_labels = LabelsField(required=False)
    base_path = serializers.CharField(
        help_text=
        _('The base (relative) path component of the published url. Avoid paths that \
                    overlap with other distribution base paths (e.g. "foo" and "foo/bar")'
          ),
        validators=[
            UniqueValidator(queryset=models.BaseDistribution.objects.all())
        ],
    )
    base_url = BaseURLField(
        source="base_path",
        read_only=True,
        help_text=
        _("The URL for accessing the publication as defined by this distribution."
          ),
    )
    content_guard = DetailRelatedField(
        required=False,
        help_text=_("An optional content-guard."),
        view_name_pattern=r"contentguards(-.*/.*)?-detail",
        queryset=models.ContentGuard.objects.all(),
        allow_null=True,
    )
    name = serializers.CharField(
        help_text=_("A unique name. Ex, `rawhide` and `stable`."),
        validators=[
            UniqueValidator(queryset=models.BaseDistribution.objects.all()),
            UniqueValidator(queryset=models.Distribution.objects.all()),
        ],
    )

    def __init__(self, *args, **kwargs):
        """Initialize a BaseDistributionSerializer and emit deprecation warnings"""
        deprecation_logger.warn(
            _("BaseDistributionSerializer is deprecated and could be removed as early as "
              "pulpcore==3.13; use pulpcore.plugin.serializers.DistributionSerializer instead."
              ))
        return super().__init__(*args, **kwargs)

    class Meta:
        abstract = True
        model = models.BaseDistribution
        fields = ModelSerializer.Meta.fields + (
            "base_path",
            "base_url",
            "content_guard",
            "pulp_labels",
            "name",
        )