class SubtitleLanguageSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) created = TimezoneAwareDateTimeField(read_only=True) language_code = LanguageCodeField() is_primary_audio_language = serializers.BooleanField(required=False) is_rtl = serializers.BooleanField(read_only=True) is_translation = serializers.SerializerMethodField() original_language_code = serializers.SerializerMethodField() name = serializers.CharField(source='get_language_code_display', read_only=True) title = serializers.CharField(source='get_title', read_only=True) description = serializers.CharField(source='get_description', read_only=True) metadata = VideoMetadataSerializer(required=False, read_only=True) subtitle_count = serializers.IntegerField(read_only=True, source='get_subtitle_count') subtitles_complete = serializers.BooleanField(required=False) versions = MiniSubtitleVersionsField(read_only=True) resource_uri = serializers.SerializerMethodField() default_error_messages = { 'language-exists': _('Language already created: {language_code}'), } class Meta: list_serializer_class = SubtitleLanguageListSerializer def __init__(self, *args, **kwargs): super(SubtitleLanguageSerializer, self).__init__(*args, **kwargs) if self.instance: self.fields['language_code'].read_only = True def get_is_translation(self, language): return compat.subtitlelanguage_is_translation(language) def get_original_language_code(self, language): return compat.subtitlelanguage_original_language_code(language) def get_resource_uri(self, language): kwargs = { 'video_id': language.video.video_id, 'language_code': language.language_code, } return reverse('api:subtitle-language-detail', kwargs=kwargs, request=self.context['request']) def to_representation(self, language): if 'versions' not in self.context: # For the list view, the SubtitleLanguageListSerializer generates # versions, for the detail view we need to generate versions # ourselves _fetch_versions([language], self.context) data = super(SubtitleLanguageSerializer, self).to_representation( language) data['num_versions'] = len(data['versions']) data['is_original'] = data['is_primary_audio_language'] self.add_reviewer_and_approver(data, language) return data def add_reviewer_and_approver(self, data, language): """Add the reviewer/approver fields.""" for version in self.context['versions'][language.id]: reviewer = version.get_reviewed_by() approver = version.get_approved_by() if reviewer: data['reviewer'] = reviewer.username if approver: data['approver'] = approver.username def validate_language_code(self, language_code): if (SubtitleLanguage.objects .filter(video=self.context['video'], language_code=language_code) .exists()): raise serializers.ValidationError("Language already exists") return language_code def create(self, validated_data): language = SubtitleLanguage.objects.create( video=self.context['video'], language_code=validated_data['language_code']) return self.update(language, validated_data) def update(self, language, validated_data): subtitles_complete = validated_data.get( 'subtitles_complete', self.initial_data.get('is_complete', None)) primary_audio_language = validated_data.get( 'is_primary_audio_language', self.initial_data.get('is_original', None)) video = self.context['video'] if subtitles_complete is not None: language.subtitles_complete = subtitles_complete try: language.save() except IntegrityError: self.fail('language-exists', language_code=language.language_code) if primary_audio_language is not None: video.primary_audio_language_code = language.language_code video.save() videos.tasks.video_changed_tasks.delay(video.pk) return language
class VideoSerializer(serializers.Serializer): # Note we could try to use ModelSerializer, but we are so far from the # default implementation that it makes more sense to not inherit. id = serializers.CharField(source='video_id', read_only=True) video_url = serializers.URLField(write_only=True, required=True) video_type = serializers.SerializerMethodField() primary_audio_language_code = LanguageCodeField(required=False, allow_blank=True) original_language = serializers.CharField(source='language', read_only=True) title = serializers.CharField(required=False, allow_blank=True) description = serializers.CharField(required=False, allow_blank=True) duration = serializers.IntegerField(required=False) thumbnail = serializers.URLField(required=False, allow_blank=True) created = TimezoneAwareDateTimeField(read_only=True) team = TeamSerializer(required=False, allow_null=True) project = ProjectSerializer(required=False, allow_null=True) all_urls = serializers.SerializerMethodField() metadata = VideoMetadataSerializer(required=False) languages = VideoLanguageShortSerializer(source='all_subtitle_languages', many=True, read_only=True) activity_uri = serializers.HyperlinkedIdentityField( view_name='api:video-activity', lookup_field='video_id', ) urls_uri = serializers.HyperlinkedIdentityField( view_name='api:video-url-list', lookup_field='video_id', ) subtitle_languages_uri = serializers.HyperlinkedIdentityField( view_name='api:subtitle-language-list', lookup_field='video_id', ) resource_uri = serializers.HyperlinkedIdentityField( view_name='api:video-detail', lookup_field='video_id') default_error_messages = { 'project-without-team': "Can't specify project without team", 'unknown-project': 'Unknown project: {project}', 'video-exists': 'Video already exists for {url}', 'invalid-url': 'Invalid URL: {url}', } class Meta: list_serializer_class = VideoListSerializer def __init__(self, *args, **kwargs): super(VideoSerializer, self).__init__(*args, **kwargs) if self.instance: # video_url should only be sent for creation self.fields['video_url'].read_only = True @property def team_video(self): if self.instance: return self.instance.get_team_video() else: return None def get_all_urls(self, video): video_urls = list(video.get_video_urls()) video_urls.sort(key=lambda vurl: vurl.primary, reverse=True) return [vurl.url for vurl in video_urls] def get_video_type(self, video): types = set() for url in video.get_video_urls(): types.add(url.type) if len(types) == 1: return types.pop() return "" def will_add_video_to_team(self): if not self.team_video: return 'team' in self.validated_data if 'team' in self.validated_data: if self.validated_data['team'] != self.team_video.team: return True if 'project' in self.validated_data: if self.validated_data['project'] != self.team_video.project: return True return False def will_remove_video_from_team(self): if 'team' not in self.validated_data or not self.team_video: return False return self.team_video.team != self.validated_data['team'] def to_internal_value(self, data): self.fixup_data(data) return super(VideoSerializer, self).to_internal_value(data) def validate(self, data): if data.get('project'): if not data.get('team'): self.fail('project-without-team') try: data['project'] = Project.objects.get(team=data['team'], slug=data['project']) except Project.DoesNotExist: self.fail('unknown-project', project=data['project']) return data def fixup_data(self, data): """Alter incoming data to support deprecated behavior.""" for name, value in data.items(): if value == '': # Remove any field has the empty string as its value # This is deprecated behavior form the old API. del data[name] elif name in ('team', 'project') and value == 'null': # Replace "null" with None for team/project data[name] = None def to_representation(self, video): data = super(VideoSerializer, self).to_representation(video) # convert blank language codes to None if video.primary_audio_language_code == '': data['primary_audio_language_code'] = None data['original_language'] = None return data def create(self, validated_data): def setup_video(video, video_url): for key in ('title', 'description', 'duration', 'thumbnail', 'primary_audio_language_code'): if validated_data.get(key): setattr(video, key, validated_data[key]) if validated_data.get('metadata'): video.update_metadata(validated_data['metadata'], commit=False) self._update_team(video, validated_data) try: return Video.add(validated_data['video_url'], self.context['user'], setup_video)[0] except VideoTypeError: self.fail('invalid-url', url=validated_data['video_url']) except Video.UrlAlreadyAdded: self.fail('video-exists', url=validated_data['video_url']) def update(self, video, validated_data): simple_fields = ( 'title', 'description', 'duration', 'thumbnail', 'primary_audio_language_code', ) for field_name in simple_fields: if field_name in validated_data: if field_name == "duration": if not getattr(video, field_name): setattr(video, field_name, validated_data[field_name]) else: setattr(video, field_name, validated_data[field_name]) if validated_data.get('metadata'): video.update_metadata(validated_data['metadata'], commit=True) self._update_team(video, validated_data) video.save() return video def _update_team(self, video, validated_data): if 'team' not in validated_data: return team = validated_data['team'] project = validated_data.get('project') team_video = video.get_team_video() if team is None: if team_video: team_video.delete() video.is_public = True else: if project is None: project = team.default_project if team_video: team_video.move_to(team, project, self.context['user']) else: TeamVideo.objects.create(video=video, team=team, project=project, added_by=self.context['user']) video.is_public = team.is_visible video.clear_team_video_cache()
class VideoSerializer(serializers.Serializer): # Note we could try to use ModelSerializer, but we are so far from the # default implementation that it makes more sense to not inherit. id = serializers.CharField(source='video_id', read_only=True) video_url = serializers.URLField(write_only=True, required=True) primary_audio_language_code = LanguageCodeField(required=False, allow_blank=True) original_language = serializers.CharField(source='language', read_only=True) title = serializers.CharField(required=False, allow_blank=True) description = serializers.CharField(required=False, allow_blank=True) duration = serializers.IntegerField(required=False) thumbnail = serializers.URLField(required=False, allow_blank=True) created = serializers.DateTimeField(read_only=True) team = TeamSerializer(required=False, allow_null=True) project = ProjectSerializer(required=False, allow_null=True) all_urls = serializers.SerializerMethodField() metadata = VideoMetadataSerializer(required=False) languages = VideoLanguageShortSerializer(source='all_subtitle_languages', many=True, read_only=True) resource_uri = serializers.HyperlinkedIdentityField( view_name='api:video-detail', lookup_field='video_id') default_error_messages = { 'project-without-team': "Can't specify project without team", 'unknown-project': 'Unknown project: {project}', 'video-exists': 'Video already exists for {url}', 'invalid-url': 'Invalid URL: {url}', } class Meta: list_serializer_class = VideoListSerializer def __init__(self, *args, **kwargs): super(VideoSerializer, self).__init__(*args, **kwargs) if self.instance: # video_url should only be sent for creation self.fields['video_url'].read_only = True @property def team_video(self): if self.instance: return self.instance.get_team_video() else: return None def get_all_urls(self, video): video_urls = list(video.get_video_urls()) video_urls.sort(key=lambda vurl: vurl.primary, reverse=True) return [vurl.url for vurl in video_urls] def will_add_video_to_team(self): if not self.team_video: return 'team' in self.validated_data if 'team' in self.validated_data: if self.validated_data['team'] != self.team_video.team: return True if 'project' in self.validated_data: if self.validated_data['project'] != self.team_video.project: return True return False def will_remove_video_from_team(self): if 'team' not in self.validated_data or not self.team_video: return False return self.team_video.team != self.validated_data['team'] def to_internal_value(self, data): data = self.fixup_data(data) data = super(VideoSerializer, self).to_internal_value(data) # we have to wait until now because we can't fetch the project until # we know the team if data.get('project'): if not data.get('team'): self.fail('project-without-team') try: data['project'] = Project.objects.get(team=data['team'], slug=data['project']) except Project.DoesNotExist: self.fail('unknown-project', project=data['project']) return data def fixup_data(self, data): """Alter incoming data to support deprecated behavior.""" # iterate over data to build a new dictionary. This is required # because data is a MergeDict, which has issues with deletion. new_data = {} for name, value in data.items(): # Remove any field has the empty string as its value # This is deprecated behavior form the old API. if value == '': continue # Replace "null" with None for team/project if name in ('team', 'project') and value == 'null': value = None new_data[name] = value return new_data def to_representation(self, video): data = super(VideoSerializer, self).to_representation(video) # convert blank language codes to None if video.primary_audio_language_code == '': data['primary_audio_language_code'] = None data['original_language'] = None return data def create(self, validated_data): set_values = {} for key in ('title', 'description', 'duration', 'thumbnail', 'primary_audio_language_code', 'metadata'): if key in validated_data: set_values[key] = validated_data[key] video, created = Video.get_or_create_for_url( validated_data['video_url'], user=self.context['user'], set_values=set_values, ) if video is None: self.fail('invalid-url', url=validated_data['video_url']) if not created: self.fail('video-exists', url=validated_data['video_url']) self._update_team(video, validated_data) return video def update(self, video, validated_data): simple_fields = ( 'title', 'description', 'duration', 'thumbnail', 'primary_audio_language_code', ) for field_name in simple_fields: if field_name in validated_data: setattr(video, field_name, validated_data[field_name]) if validated_data.get('metadata'): video.update_metadata(validated_data['metadata'], commit=True) else: video.save() self._update_team(video, validated_data) return video def _update_team(self, video, validated_data): if 'team' not in validated_data: return team = validated_data['team'] project = validated_data.get('project') team_video = video.get_team_video() if team is None: if team_video: team_video.delete() else: if project is None: project = team.default_project if team_video: team_video.move_to(team, project) else: TeamVideo.objects.create(video=video, team=team, project=project) video.clear_team_video_cache()