class SeriesSerializer(BaseHyperlinkedModelSerializer): web_url = SerializerMethodField() project = ProjectSerializer(read_only=True) submitter = PersonSerializer(read_only=True) mbox = SerializerMethodField() cover_letter = CoverSerializer(read_only=True) patches = PatchSerializer(read_only=True, many=True) def get_web_url(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_absolute_url()) def get_mbox(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_mbox_url()) class Meta: model = Series fields = ('id', 'url', 'web_url', 'project', 'name', 'date', 'submitter', 'version', 'total', 'received_total', 'received_all', 'mbox', 'cover_letter', 'patches') read_only_fields = ('date', 'submitter', 'total', 'received_total', 'received_all', 'mbox', 'cover_letter', 'patches') versioned_fields = { '1.1': ('web_url', ), } extra_kwargs = { 'url': { 'view_name': 'api-series-detail' }, }
class BundleSerializer(BaseHyperlinkedModelSerializer): web_url = SerializerMethodField() project = ProjectSerializer(read_only=True) mbox = SerializerMethodField() owner = UserSerializer(read_only=True) patches = PatchSerializer(many=True, read_only=True) def get_web_url(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_absolute_url()) def get_mbox(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_mbox_url()) class Meta: model = Bundle fields = ('id', 'url', 'web_url', 'project', 'name', 'owner', 'patches', 'public', 'mbox') read_only_fields = ('owner', 'patches', 'mbox') versioned_fields = { '1.1': ('web_url', ), } extra_kwargs = { 'url': { 'view_name': 'api-bundle-detail' }, }
class CoverLetterListSerializer(BaseHyperlinkedModelSerializer): web_url = SerializerMethodField() project = ProjectSerializer(read_only=True) submitter = PersonSerializer(read_only=True) mbox = SerializerMethodField() series = SeriesSerializer(many=True, read_only=True) comments = SerializerMethodField() def get_web_url(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_absolute_url()) def get_mbox(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_mbox_url()) def get_comments(self, cover): return self.context.get('request').build_absolute_uri( reverse('api-cover-comment-list', kwargs={'pk': cover.id})) class Meta: model = CoverLetter fields = ('id', 'url', 'web_url', 'project', 'msgid', 'date', 'name', 'submitter', 'mbox', 'series', 'comments') read_only_fields = fields versioned_fields = { '1.1': ('web_url', 'mbox', 'comments'), } extra_kwargs = { 'url': {'view_name': 'api-cover-detail'}, }
class BundleSerializer(BaseHyperlinkedModelSerializer): web_url = SerializerMethodField() project = ProjectSerializer(read_only=True) mbox = SerializerMethodField() owner = UserSerializer(read_only=True) patches = PatchSerializer(many=True, required=True, style={'base_template': 'input.html'}) def get_web_url(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_absolute_url()) def get_mbox(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_mbox_url()) def create(self, validated_data): patches = validated_data.pop('patches') instance = super(BundleSerializer, self).create(validated_data) instance.overwrite_patches(patches) return instance def update(self, instance, validated_data): patches = validated_data.pop('patches') instance = super(BundleSerializer, self).update(instance, validated_data) instance.overwrite_patches(patches) return instance def validate_patches(self, value): if not len(value): raise ValidationError('Bundles cannot be empty') if len(set([p.project.id for p in value])) > 1: raise ValidationError('Bundle patches must belong to the same ' 'project') return value def validate(self, data): data['project'] = data['patches'][0].project return super(BundleSerializer, self).validate(data) class Meta: model = Bundle fields = ('id', 'url', 'web_url', 'project', 'name', 'owner', 'patches', 'public', 'mbox') read_only_fields = ('project', 'owner', 'mbox') versioned_fields = { '1.1': ('web_url', ), } extra_kwargs = { 'url': { 'view_name': 'api-bundle-detail' }, }
class EventSerializer(ModelSerializer): project = ProjectSerializer(read_only=True) actor = UserSerializer() patch = PatchSerializer(read_only=True) series = SeriesSerializer(read_only=True) cover = CoverLetterSerializer(read_only=True) previous_state = SlugRelatedField(slug_field='slug', read_only=True) current_state = SlugRelatedField(slug_field='slug', read_only=True) previous_delegate = UserSerializer() current_delegate = UserSerializer() created_check = SerializerMethodField() created_check = CheckSerializer() previous_relation = PatchRelationSerializer(read_only=True) current_relation = PatchRelationSerializer(read_only=True) _category_map = { Event.CATEGORY_COVER_CREATED: ['cover'], Event.CATEGORY_PATCH_CREATED: ['patch'], Event.CATEGORY_PATCH_COMPLETED: ['patch', 'series'], Event.CATEGORY_PATCH_STATE_CHANGED: ['patch', 'previous_state', 'current_state'], Event.CATEGORY_PATCH_DELEGATED: ['patch', 'previous_delegate', 'current_delegate'], Event.CATEGORY_PATCH_RELATION_CHANGED: ['patch', 'previous_relation', 'current_relation'], Event.CATEGORY_CHECK_CREATED: ['patch', 'created_check'], Event.CATEGORY_SERIES_CREATED: ['series'], Event.CATEGORY_SERIES_COMPLETED: ['series'], } def to_representation(self, instance): data = super(EventSerializer, self).to_representation(instance) payload = OrderedDict() kept_fields = self._category_map[instance.category] + [ 'id', 'category', 'project', 'date', 'actor'] for field in [x for x in data]: if field not in kept_fields: del data[field] elif field in self._category_map[instance.category]: field_name = 'check' if field == 'created_check' else field payload[field_name] = data.pop(field) data['payload'] = payload return data class Meta: model = Event fields = ('id', 'category', 'project', 'date', 'actor', 'patch', 'series', 'cover', 'previous_state', 'current_state', 'previous_delegate', 'current_delegate', 'created_check', 'previous_relation', 'current_relation',) read_only_fields = fields versioned_fields = { '1.2': ('actor', ), }
class PatchListSerializer(BaseHyperlinkedModelSerializer): web_url = SerializerMethodField() project = ProjectSerializer(read_only=True) state = StateField() submitter = PersonSerializer(read_only=True) delegate = UserSerializer() mbox = SerializerMethodField() series = SeriesSerializer(many=True, read_only=True) comments = SerializerMethodField() check = SerializerMethodField() checks = SerializerMethodField() tags = SerializerMethodField() def get_web_url(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_absolute_url()) def get_mbox(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_mbox_url()) def get_comments(self, patch): return self.context.get('request').build_absolute_uri( reverse('api-patch-comment-list', kwargs={'pk': patch.id})) def get_check(self, instance): return instance.combined_check_state def get_checks(self, instance): return self.context.get('request').build_absolute_uri( reverse('api-check-list', kwargs={'patch_id': instance.id})) def get_tags(self, instance): # TODO(stephenfin): Make tags performant, possibly by reworking the # model return {} class Meta: model = Patch fields = ('id', 'url', 'web_url', 'project', 'msgid', 'date', 'name', 'commit_ref', 'pull_url', 'state', 'archived', 'hash', 'submitter', 'delegate', 'mbox', 'series', 'comments', 'check', 'checks', 'tags') read_only_fields = ('web_url', 'project', 'msgid', 'date', 'name', 'hash', 'submitter', 'mbox', 'series', 'comments', 'check', 'checks', 'tags') versioned_fields = { '1.1': ('comments', 'web_url'), } extra_kwargs = { 'url': { 'view_name': 'api-patch-detail' }, }
class CoverListSerializer(BaseHyperlinkedModelSerializer): web_url = SerializerMethodField() project = ProjectSerializer(read_only=True) submitter = PersonSerializer(read_only=True) mbox = SerializerMethodField() series = SeriesSerializer(read_only=True) comments = SerializerMethodField() def get_web_url(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_absolute_url()) def get_mbox(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_mbox_url()) def get_comments(self, cover): return self.context.get('request').build_absolute_uri( reverse('api-cover-comment-list', kwargs={'cover_id': cover.id}) ) def to_representation(self, instance): # NOTE(stephenfin): This is here to ensure our API looks the same even # after we changed the series-patch relationship from M:N to 1:N. It # will be removed in API v2 data = super(CoverListSerializer, self).to_representation(instance) data['series'] = [data['series']] if data['series'] else [] return data class Meta: model = Cover fields = ( 'id', 'url', 'web_url', 'project', 'msgid', 'list_archive_url', 'date', 'name', 'submitter', 'mbox', 'series', 'comments', ) read_only_fields = fields versioned_fields = { '1.1': ('web_url', 'mbox', 'comments'), '1.2': ('list_archive_url',), } extra_kwargs = { 'url': {'view_name': 'api-cover-detail'}, }
class CoverLetterListSerializer(HyperlinkedModelSerializer): project = ProjectSerializer(read_only=True) submitter = PersonSerializer(read_only=True) mbox = SerializerMethodField() series = SeriesSerializer(many=True, read_only=True) def get_mbox(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_mbox_url()) class Meta: model = CoverLetter fields = ('id', 'url', 'project', 'msgid', 'date', 'name', 'submitter', 'mbox', 'series') read_only_fields = fields extra_kwargs = { 'url': {'view_name': 'api-cover-detail'}, }
class PatchListSerializer(BaseHyperlinkedModelSerializer): web_url = SerializerMethodField() project = ProjectSerializer(read_only=True) state = StateField() submitter = PersonSerializer(read_only=True) delegate = UserSerializer(allow_null=True) mbox = SerializerMethodField() series = SeriesSerializer(read_only=True) comments = SerializerMethodField() check = SerializerMethodField() checks = SerializerMethodField() tags = SerializerMethodField() related = PatchSerializer( source='related.patches', many=True, default=[], style={'base_template': 'input.html'}) def get_web_url(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_absolute_url()) def get_mbox(self, instance): request = self.context.get('request') return request.build_absolute_uri(instance.get_mbox_url()) def get_comments(self, patch): return self.context.get('request').build_absolute_uri( reverse('api-patch-comment-list', kwargs={'pk': patch.id})) def get_check(self, instance): return instance.combined_check_state def get_checks(self, instance): return self.context.get('request').build_absolute_uri( reverse('api-check-list', kwargs={'patch_id': instance.id})) def get_tags(self, instance): # TODO(stephenfin): Make tags performant, possibly by reworking the # model return {} def validate_delegate(self, value): """Check that the delgate is a maintainer of the patch's project.""" if not value: return value if not value.profile.maintainer_projects.only('id').filter( id=self.instance.project.id).exists(): raise ValidationError("User '%s' is not a maintainer for project " "'%s'" % (value, self.instance.project)) return value def to_representation(self, instance): # NOTE(stephenfin): This is here to ensure our API looks the same even # after we changed the series-patch relationship from M:N to 1:N. It # will be removed in API v2 data = super(PatchListSerializer, self).to_representation(instance) data['series'] = [data['series']] if data['series'] else [] # Remove this patch from 'related' if 'related' in data and data['related']: data['related'] = [ x for x in data['related'] if x['id'] != data['id'] ] return data class Meta: model = Patch fields = ('id', 'url', 'web_url', 'project', 'msgid', 'list_archive_url', 'date', 'name', 'commit_ref', 'pull_url', 'state', 'archived', 'hash', 'submitter', 'delegate', 'mbox', 'series', 'comments', 'check', 'checks', 'tags', 'related',) read_only_fields = ('web_url', 'project', 'msgid', 'list_archive_url', 'date', 'name', 'hash', 'submitter', 'mbox', 'series', 'comments', 'check', 'checks', 'tags') versioned_fields = { '1.1': ('comments', 'web_url'), '1.2': ('list_archive_url', 'related',), } extra_kwargs = { 'url': {'view_name': 'api-patch-detail'}, }
class EventSerializer(ModelSerializer): project = ProjectSerializer(read_only=True) actor = UserSerializer() patch = PatchSerializer(read_only=True) series = SeriesSerializer(read_only=True) cover = CoverSerializer(read_only=True) previous_state = SlugRelatedField(slug_field='slug', read_only=True) current_state = SlugRelatedField(slug_field='slug', read_only=True) previous_delegate = UserSerializer() current_delegate = UserSerializer() created_check = SerializerMethodField() created_check = CheckSerializer() previous_relation = SerializerMethodField() current_relation = SerializerMethodField() cover_comment = CoverCommentSerializer() patch_comment = PatchCommentSerializer() # Mapping of event type to fields to include in the response _category_map = { Event.CATEGORY_COVER_CREATED: ['cover'], Event.CATEGORY_PATCH_CREATED: ['patch'], Event.CATEGORY_PATCH_COMPLETED: ['patch', 'series'], Event.CATEGORY_PATCH_STATE_CHANGED: [ 'patch', 'previous_state', 'current_state', ], Event.CATEGORY_PATCH_DELEGATED: [ 'patch', 'previous_delegate', 'current_delegate', ], Event.CATEGORY_PATCH_RELATION_CHANGED: [ 'patch', 'previous_relation', 'current_relation', ], Event.CATEGORY_CHECK_CREATED: ['patch', 'created_check'], Event.CATEGORY_SERIES_CREATED: ['series'], Event.CATEGORY_SERIES_COMPLETED: ['series'], Event.CATEGORY_COVER_COMMENT_CREATED: ['cover', 'cover_comment'], Event.CATEGORY_PATCH_COMMENT_CREATED: ['patch', 'patch_comment'], } # Mapping of database column names to REST API representations _field_name_map = { 'created_check': 'check', 'cover_comment': 'comment', 'patch_comment': 'comment', } def get_previous_relation(self, instance): return None def get_current_relation(self, instance): return None def to_representation(self, instance): data = super(EventSerializer, self).to_representation(instance) payload = OrderedDict() kept_fields = self._category_map[instance.category] + [ 'id', 'category', 'project', 'date', 'actor', ] for field in [x for x in data]: if field not in kept_fields: del data[field] elif field in self._category_map[instance.category]: # remap fields if necessary field_name = self._field_name_map.get(field, field) payload[field_name] = data.pop(field) data['payload'] = payload return data class Meta: model = Event fields = ( 'id', 'category', 'project', 'date', 'actor', 'patch', 'series', 'cover', 'previous_state', 'current_state', 'previous_delegate', 'current_delegate', 'created_check', 'previous_relation', 'current_relation', 'cover_comment', 'patch_comment', ) read_only_fields = fields versioned_fields = { '1.2': ('actor', ), }