def setUp(self): self.field = UserField() self.serializer = Serializer(context={ 'request': APIRequestFactory().get('/'), }) self.field.bind('user', self.serializer) self.user = UserFactory()
class TeamMemberSerializer(serializers.Serializer): default_error_messages = { 'user-does-not-exist': "User does not exist: {username}", 'user-already-member': "User is already a team member", 'user-cannot-change-own-role': "User cannot change their own role", } ROLE_CHOICES = ( TeamMember.ROLE_OWNER, TeamMember.ROLE_ADMIN, TeamMember.ROLE_MANAGER, TeamMember.ROLE_CONTRIBUTOR, ) user = UserField() role = serializers.ChoiceField(ROLE_CHOICES) resource_uri = serializers.SerializerMethodField() def create(self, validated_data): try: return self.context['team'].members.create( user=validated_data['user'], role=validated_data['role'], ) except IntegrityError: self.fail('user-already-member') def get_resource_uri(self, member): return reverse('api:team-members-detail', kwargs={ 'team_slug': self.context['team'].slug, 'identifier': 'id$' + member.user.secure_id(), }, request=self.context['request'])
class TeamMemberUpdateSerializer(TeamMemberSerializer): user = UserField(read_only=True) def update(self, instance, validated_data): instance.role = validated_data['role'] instance.save() return instance
class NotesSerializer(serializers.Serializer): user = UserField(read_only=True) created = TimezoneAwareDateTimeField(read_only=True) body = serializers.CharField() def create(self, validated_data): if self.context['editor_notes'] is None: raise PermissionDenied() return self.context['editor_notes'].post(self.context['user'], validated_data['body'])
class ApplicationSerializer(serializers.ModelSerializer): user = UserField(read_only=True) status = MappedChoiceField( Application.STATUSES, default=Application._meta.get_field('status').get_default()) resource_uri = serializers.SerializerMethodField() created = TimezoneAwareDateTimeField(read_only=True) modified = TimezoneAwareDateTimeField(read_only=True) default_error_messages = { 'invalid-status-choice': "Unknown status: {status}", 'not-pending': "Application not pending", } def get_resource_uri(self, application): return reverse('api:team-application-detail', kwargs={ 'team_slug': self.context['team'].slug, 'id': application.id, }, request=self.context['request']) class Meta: model = Application fields = ( 'id', 'status', 'user', 'note', 'created', 'modified', 'resource_uri', ) read_only_fields = ( 'id', 'note', 'created', 'modified', ) def validate_status(self, status): if status not in (Application.STATUS_APPROVED, Application.STATUS_DENIED): self.fail('invalid-status-choice', status=status) return status def update(self, instance, validated_data): if instance.status != Application.STATUS_PENDING: self.fail('not-pending') if validated_data['status'] == Application.STATUS_APPROVED: instance.approve(self.context['user'], 'API') elif validated_data['status'] == Application.STATUS_DENIED: instance.deny(self.context['user'], 'API') return instance
class TeamMemberUpdateSerializer(TeamMemberSerializer): user = UserField(read_only=True) def update(self, instance, validated_data): # don't allow users to change their own role via the API if self.context.get('user') == instance.user: self.fail('user-cannot-change-own-role') else: instance.role = validated_data['role'] instance.save() return instance
class UserFieldTest(TestCase): def setUp(self): self.field = UserField() self.serializer = Serializer(context={ 'request': APIRequestFactory().get('/'), }) self.field.bind('user', self.serializer) self.user = UserFactory() def test_output(self): assert_equal(self.field.to_representation(self.user), user_field_data(self.user)) @test_utils.patch_for_test('api.userlookup.lookup_user') def test_input(self, lookup_user): # Input should be done using the userlookup module. This allows us to # input users using usernames, user ids, or partner ids lookup_user.return_value = self.user assert_equal(self.field.to_internal_value('test-user-id'), self.user) assert_equal(lookup_user.call_args, mock.call('test-user-id')) @test_utils.patch_for_test('api.userlookup.lookup_user') def test_user_not_found(self, lookup_user): # If lookup_user raises a User.DoesNotExist error, we should turn it # into a validation error lookup_user.side_effect = User.DoesNotExist with assert_raises(ValidationError): self.field.to_internal_value('test-user-id')
class MessagesSerializer(serializers.Serializer): user = UserField(required=False) team = serializers.CharField(required=False) subject = serializers.CharField() content = serializers.CharField() default_error_messages = { 'unknown-team': "Unknown team: {team}", 'no-user-or-team': "Must specify either user or team", } def validate_team(self, slug): try: team = Team.objects.get(slug=slug) except Team.DoesNotExist: self.fail('unknown-team', team=slug) if not teams.permissions.can_message_all_members( team, self.context['user']): raise PermissionDenied() return team def validate(self, data): if not ('team' in data or 'user' in data): self.fail('no-user-or-team') return data def recipients(self): if 'user' in self.validated_data: yield self.validated_data['user'] else: qs = self.validated_data['team'].members.select_related('user') for member in qs: yield member.user def create_messages(self): messages = [ Message(user=user, content=self.validated_data['content'], subject=self.validated_data['subject'], message_type='M', author=self.context['user']) for user in self.recipients() if user != self.context['user'] ] Message.objects.bulk_create(messages) if len(messages) == 1: self.context['user'].sent_message()
class ActivitySerializer(serializers.ModelSerializer): type = serializers.SlugField() user = UserField(read_only=True) date = TimezoneAwareDateTimeField(source='created') video = serializers.CharField(source='video.video_id') language = serializers.SerializerMethodField() video_uri = serializers.HyperlinkedRelatedField( source='video', view_name='api:video-detail', lookup_field='video_id', read_only=True) language_uri = serializers.SerializerMethodField() def get_language(self, record): return record.language_code or None def get_language_uri(self, record): if not (record.language_code and record.video): return None return reverse('api:subtitle-language-detail', kwargs={ 'video_id': record.video.video_id, 'language_code': record.language_code, }, request=self.context['request']) def to_representation(self, record): data = super(ActivitySerializer, self).to_representation(record) extra_data_method_name = 'get_{}_extra'.format( record.type.replace('-', '_')) extra_field_method = getattr(self, extra_data_method_name, None) if extra_field_method: data.update(extra_field_method(record)) return data def get_video_url_added_extra(self, record): url_edit = record.get_related_obj() return { 'url': url_edit.new_url, } def get_video_url_edited_extra(self, record): url_edit = record.get_related_obj() return { 'old_url': url_edit.old_url, 'new_url': url_edit.new_url, } def get_video_url_deleted_extra(self, record): url_edit = record.get_related_obj() return { 'url': url_edit.old_url, } def get_video_deleted_extra(self, record): video_deletion = record.get_related_obj() return { 'title': video_deletion.title, } class Meta: model = ActivityRecord fields = ( 'type', 'date', 'user', 'video', 'language', 'video_uri', 'language_uri', )
class SubtitlesSerializer(serializers.Serializer): ORIGIN_CHOICES = [ ('api', _('API')), ('editor', _('Subtitle editor')), ('upload', _('Upload')), ] version_number = serializers.IntegerField(read_only=True) sub_format = SubFormatField(required=False, default='dfxp', initial='dfxp') subtitles = SubtitlesField(required=False) subtitles_url = serializers.URLField(max_length=512, required=False, write_only=True) author = UserField(read_only=True) action = serializers.CharField(required=False, write_only=True, allow_blank=True) is_complete = serializers.NullBooleanField(required=False, write_only=True) origin = serializers.ChoiceField(required=False, write_only=True, default='api', choices=ORIGIN_CHOICES) language = LanguageForSubtitlesSerializer(source='*', read_only=True) title = serializers.CharField(required=False, allow_blank=True) duration = serializers.IntegerField(required=False, write_only=True) description = serializers.CharField(required=False, allow_blank=True) metadata = VideoMetadataSerializer(required=False) video_title = serializers.CharField(source='video.title_display', read_only=True) video_description = serializers.CharField(source='video.description', read_only=True) actions_uri = serializers.SerializerMethodField() notes_uri = serializers.SerializerMethodField() resource_uri = serializers.SerializerMethodField() site_uri = serializers.SerializerMethodField() def __init__(self, *args, **kwargs): super(SubtitlesSerializer, self).__init__(*args, **kwargs) if 'sub_format' in self.fields: for format in self.fields['sub_format'].choices: if not user_can_access_subtitles_format( self.context['user'], format): self.fields['sub_format'].choices.pop(format) def get_actions_uri(self, version): kwargs = { 'video_id': version.video.video_id, 'language_code': version.language_code, } return reverse('api:subtitle-actions', kwargs=kwargs, request=self.context['request']) def get_notes_uri(self, version): kwargs = { 'video_id': version.video.video_id, 'language_code': version.language_code, } return reverse('api:subtitle-notes', kwargs=kwargs, request=self.context['request']) def get_resource_uri(self, version): kwargs = { 'video_id': version.video.video_id, 'language_code': version.language_code, } uri = reverse('api:subtitles', kwargs=kwargs, request=self.context['request']) if self.context['version_number']: uri += '?version_number={}'.format(self.context['version_number']) return uri def get_site_uri(self, version): kwargs = { 'video_id': version.video.video_id, 'lang': version.language_code, 'lang_id': version.subtitle_language_id, 'version_id': version.id, } return reverse('videos:subtitleversion_detail', kwargs=kwargs, request=self.context['request']) def validate(self, data): """ Check that subtitles are provided, either via a string or a URL. """ if ('subtitles' in data) == ('subtitles_url' in data): raise serializers.ValidationError( "Subtitles must be provided either via a string or a URL") return data def validate_origin(self, value): if not value or value == 'api': return ORIGIN_API elif value == 'editor': return ORIGIN_WEB_EDITOR elif value == 'upload': return ORIGIN_UPLOAD else: raise ValidationError('invalid origin value: {}'.format(value)) def to_representation(self, version): data = super(SubtitlesSerializer, self).to_representation(version) # copy a fields to deprecated names data['video'] = data['video_title'] data['version_no'] = data['version_number'] if self.context['allow_language_extra']: extra.video_language.add_data(self.context['request'], data, video=self.context['video'], language=version.subtitle_language) return data def to_internal_value(self, data): # set sub_format from the inputted data. We need this to properly # parse the subtitles param if data.get('sub_format'): self.context['sub_format'] = data['sub_format'] else: self.context['sub_format'] = 'dfxp' return super(SubtitlesSerializer, self).to_internal_value(data) def _process_subtitles_url(self, subtitles_url): value = data_from_url(subtitles_url) if not isinstance(value, basestring): raise serializers.ValidationError("Invalid subtitle data") if isinstance(value, unicode): value = value.encode('utf-8') try: return load_subtitles(self.context['language_code'], value, self.context['sub_format']) except babelsubs.SubtitleParserError, e: logger.warn("Error parsing subtitles ({}/{})".format( self.context['video'].video_id, self.context['language_code']), exc_info=True) raise serializers.ValidationError("Invalid subtitle data")
class MiniSubtitleVersionSerializer(serializers.Serializer): """Serialize a subtitle version for SubtitleLanguageSerializer """ author = UserField(read_only=True) published = serializers.BooleanField(source='is_public') version_no = serializers.IntegerField(source='version_number')
class SubtitlesSerializer(serializers.Serializer): version_number = serializers.IntegerField(read_only=True) sub_format = SubFormatField(required=False, default='dfxp', initial='dfxp') subtitles = SubtitlesField() author = UserField(read_only=True) action = serializers.CharField(required=False, write_only=True, allow_blank=True) is_complete = serializers.NullBooleanField(required=False, write_only=True) from_editor = serializers.BooleanField( required=False, write_only=True, help_text=("Check to flag this version as coming from the " "amara editor.")) language = LanguageForSubtitlesSerializer(source='*', read_only=True) title = serializers.CharField(required=False, allow_blank=True) duration = serializers.IntegerField(required=False, write_only=True) description = serializers.CharField(required=False, allow_blank=True) metadata = VideoMetadataSerializer(required=False) video_title = serializers.CharField(source='video.title_display', read_only=True) video_description = serializers.CharField(source='video.description', read_only=True) actions_uri = serializers.SerializerMethodField() notes_uri = serializers.SerializerMethodField() resource_uri = serializers.SerializerMethodField() site_uri = serializers.SerializerMethodField() def __init__(self, *args, **kwargs): super(SubtitlesSerializer, self).__init__(*args, **kwargs) if 'sub_format' in self.fields: for format in self.fields['sub_format'].choices: if not user_can_access_subtitles_format( self.context['user'], format): self.fields['sub_format'].choices.pop(format) def get_actions_uri(self, version): kwargs = { 'video_id': version.video.video_id, 'language_code': version.language_code, } return reverse('api:subtitle-actions', kwargs=kwargs, request=self.context['request']) def get_notes_uri(self, version): kwargs = { 'video_id': version.video.video_id, 'language_code': version.language_code, } return reverse('api:subtitle-notes', kwargs=kwargs, request=self.context['request']) def get_resource_uri(self, version): kwargs = { 'video_id': version.video.video_id, 'language_code': version.language_code, } uri = reverse('api:subtitles', kwargs=kwargs, request=self.context['request']) if self.context['version_number']: uri += '?version_number={}'.format(self.context['version_number']) return uri def get_site_uri(self, version): kwargs = { 'video_id': version.video.video_id, 'lang': version.language_code, 'lang_id': version.subtitle_language_id, 'version_id': version.id, } return reverse('videos:subtitleversion_detail', kwargs=kwargs, request=self.context['request']) def to_representation(self, version): data = super(SubtitlesSerializer, self).to_representation(version) # copy a fields to deprecated names data['video'] = data['video_title'] data['version_no'] = data['version_number'] if self.context['allow_language_extra']: extra.video_language.add_data(self.context['request'], data, video=self.context['video'], language=version.subtitle_language) return data def to_internal_value(self, data): # set sub_format from the inputted data. We need this to properly # parse the subtitles param if data.get('sub_format'): self.context['sub_format'] = data['sub_format'] else: self.context['sub_format'] = 'dfxp' return super(SubtitlesSerializer, self).to_internal_value(data) def create(self, validated_data): if validated_data.get('from_editor'): origin = ORIGIN_WEB_EDITOR else: origin = ORIGIN_API action = complete = None if 'action' in validated_data: action = validated_data.get("action") elif 'is_complete' in validated_data: complete = validated_data['is_complete'] return pipeline.add_subtitles( self.context['video'], self.context['language_code'], validated_data['subtitles'], action=action, complete=complete, title=validated_data.get('title'), description=validated_data.get('description'), duration=validated_data.get('duration'), metadata=validated_data.get('metadata'), author=self.context['user'], committer=self.context['user'], origin=origin)