def already_added_message(self, video): if video == self.cleaned_data.get('video'): return _('Video URL already added to this video') if video.can_user_see(self.user): link = mark_safe('<a href="{}">{}</a>'.format( video.get_absolute_url(), ugettext('view video'))) return fmt( _('Video URL already added to a different video (%(link)s)'), link=link) else: return _('Video URL already added to a different video')
def test_n_minutes_ago(self): for n in range(2, 60): when = self.now - timedelta(minutes=n) expected = fmt(self.expected_string_past, count=n, unit='minutes') self.assertEqual(due_date("", when), expected) when = self.now - timedelta(minutes=30, seconds=30) expected = fmt(self.expected_string_past, count=31, unit='minutes') self.assertEqual(due_date("", when), expected) when = self.now - timedelta(minutes=30, seconds=31) expected = fmt(self.expected_string_past, count=31, unit='minutes') self.assertEqual(due_date("", when), expected) when = self.now - timedelta(minutes=30, seconds=29) expected = fmt(self.expected_string_past, count=30, unit='minutes') self.assertEqual(due_date("", when), expected) when = self.now - timedelta(seconds=60) expected = fmt(self.expected_string_past, count=1, unit='minute') self.assertEqual(due_date("", when), expected)
def send_role_changed_message(member, old_member_info): team = member.team context = { 'team': team, 'member': member, 'old_role_name': old_member_info.role_name, 'new_role_name': member.get_role_name(), 'team_name': unicode(team), 'custom_message': team.get_message_for_role(member.role), 'management_url': team.new_workflow.management_page_default(member.user), 'was_a_project_or_language_manager': old_member_info.project_or_language_manager, 'languages_managed': member.get_languages_managed(), 'projects_managed': member.get_projects_managed(), } if was_promotion(member, old_member_info): subject = fmt(_('You have been promoted on the %(team)s team'), team=unicode(team)) else: subject = fmt(_('Your role has been changed on the %(team)s team'), team=unicode(team)) notify_users(Notifications.ROLE_CHANGED, [member.user], subject, 'messages/team-role-changed.html', context)
def elapsed_time(when): """ Format the amount of time that has passed Args: when (datetime/timedelta): time to display. If this is a datetime, then we will display the time between now and it. If it's a timedelta, then we use that directly """ if isinstance(when, timedelta): delta = when dt = now() - timedelta else: delta = now() - when dt = when if delta.days < 0: return _('now') elif delta.days < 1: if delta.seconds < 60: return _('now') elif delta.seconds < 60 * 60: minutes = int(round(delta.seconds / 60.0)) return fmt(ungettext(u'%(count)s minute ago', u'%(count)s minutes ago', minutes), count=minutes) else: hours = int(round(delta.seconds / 60.0 / 60.0)) return fmt(ungettext(u'%(count)s hours ago', u'%(count)s hours ago', hours), count=hours) elif delta.days < 7: days = int(round(delta.days + delta.seconds / SECONDS_IN_A_DAY)) return fmt(ungettext('%(count)s day ago', '%(count)s days ago', days), count=days) else: return date(dt)
def clean(self, value): try: team = self.team except AttributeError: raise AssertionError("team not set") try: members_qs = team.members.all().select_related('user') return members_qs.get(user__username=value) except TeamMember.DoesNotExist: raise forms.ValidationError( fmt(_(u'%(username)s is not a member of the team'), username=value))
def test_n_hours_ago(self): when = self.now - timedelta(minutes=60) expected = fmt(self.expected_string_past, count=1, unit='hour') self.assertEqual(due_date("", when), expected) for n in range(2, 24): when = self.now - timedelta(hours=n) expected = fmt(self.expected_string_past, count=n, unit='hours') self.assertEqual(due_date("", when), expected) when = self.now - timedelta(hours=23, minutes=30) + timedelta(seconds=1) expected = fmt(self.expected_string_past, count=23, unit='hours') self.assertEqual(due_date("", when), expected) when = self.now - timedelta(hours=23, minutes=30, seconds=1) expected = fmt(self.expected_string_past, count=24, unit='hours') self.assertEqual(due_date("", when), expected) when = self.now - timedelta(hours=23, minutes=30) expected = fmt(self.expected_string_past, count=24, unit='hours') self.assertEqual(due_date("", when), expected)
class VideoURLField(forms.URLField): """Field for inputting URLs for videos. This field checks that we can lookup a VideoType for the URL. If successful, we return the VideoType as the cleaned data. """ def clean(self, video_url): if not video_url: if self.required: raise forms.ValidationError(self.error_messages['required']) return None try: video_type = video_type_registrar.video_type_for_url(video_url) except VideoTypeError, e: raise forms.ValidationError(e) if not video_type: contact_link = fmt(_('<a href="mailto:%(email)s">Contact us</a>'), email=settings.FEEDBACK_EMAIL) for d in video_type_registrar.domains: if d in video_url: raise forms.ValidationError( mark_safe( fmt(_( u"Please try again with a link to a video page. " "%(contact_link)s if there's a problem."), contact_link=contact_link))) raise forms.ValidationError( mark_safe( fmt(_( u"You must link to a video on a compatible site " "(like YouTube) or directly to a video file that works " "with HTML5 browsers. For example: " "http://mysite.com/myvideo.ogg or " "http://mysite.com/myipadvideo.m4v " "%(contact_link)s if there's a problem"), contact_link=contact_link))) return video_type
def check_can_edit(self): if self.workflow.user_can_edit_subtitles(self.user, self.language_code): return True learn_more_link = u'<a href="{}">{}</a>'.format( u'http://support.amara.org/solution/articles/212109-why-do-i-see-a-message-saying-that-i-am-not-permitted-to-edit-subtitles', _(u'Learn more')) messages.error(self.request, fmt(_('Sorry, you do not have permission to edit ' 'these subtitles. (%(learn_more_link)s)'), learn_more_link=learn_more_link)) return False
def _verify_translation_subtitle_counts(self, from_language_code): if from_language_code and hasattr(self, '_parsed_subtitles'): from_count = len(self.from_sv.get_subtitles()) current_count = len(self._parsed_subtitles.get_subtitles()) if current_count > from_count: raise forms.ValidationError( fmt(_(u"Sorry, we couldn't upload your file because " u"the number of lines in your translation " u"(%(translation_lines)s) doesn't match the " u"original (%(source_lines)s)."), translation_lines=current_count, source_lines=from_count))
def setup_video(video, video_url): video.is_public = team.videos_public() if video_item.get('title'): video.title = video_item['title'] if video_item.get('description'): video.description = video_item['description'] if video_item.get('language'): language = video_item['language'].lower() if language in SUPPORTED_LANGUAGE_CODES: video.primary_audio_language_code = language else: messages.append( fmt(_( u"Badly formated language for %(url)s: %(language)s, ignoring it." ), url=video_url, language=video_item['language'])) if video_item.get('duration') and not video.duration: try: video.duration = int(video_item['duration']) except: messages.append( fmt(_( u"Badly formated duration for %(url)s: %(duration)s, ignoring it." ), url=video_url, duration=video_item['duration'])) if video_item.get('project'): project, created = Project.objects.get_or_create( team=team, slug=pan_slugify(video_item['project']), defaults={'name': video_item['project']}) else: project = team.default_project team_video = TeamVideo.objects.create(video=video, team=team, project=project, added_by=user)
def clean_video_url(self): video_url = self.cleaned_data['video_url'] if video_url: try: video_type = video_type_registrar.video_type_for_url(video_url) except VideoTypeError, e: raise forms.ValidationError(e) if not video_type: contact_link = fmt( _('<a href="mailto:%(email)s">Contact us</a>'), email=settings.FEEDBACK_EMAIL) for d in video_type_registrar.domains: if d in video_url: raise forms.ValidationError( mark_safe( fmt(_( u"Please try again with a link to a video page. " "%(contact_link)s if there's a problem."), contact_link=contact_link))) raise forms.ValidationError( mark_safe( fmt(_( u"You must link to a video on a compatible site " "(like YouTube) or directly to a video file that works " "with HTML5 browsers. For example: " "http://mysite.com/myvideo.ogg or " "http://mysite.com/myipadvideo.m4v " "%(contact_link)s if there's a problem"), contact_link=contact_link))) else: self._video_type = video_type # we need to use the cannonical url as the user provided might need # redirection (i.e. youtu.be/fdaf/), and django's validator will # choke on redirection (urllib2 for python2.6), see https://unisubs.sifterapp.com/projects/12298/issues/427646/comments video_url = video_type.convert_to_video_url()
def progress_bar(label, current, total, css_class='teal'): if total > 0: percent = '{}%'.format(100.0 * float(current) / float(total)) else: percent = '0%' percent_label = fmt(_(u'%(percent)s complete'), percent=percent) return format_html( '<div class="progressBar teal">' '<div class="progressBar-progress" role="progressbar" style="width: {};">' '<span class="sr-only">{}</span></div></div>' '<p class="progressBar-label teal">{} ' '<span class="progressBar-percentage">{}</span></p>', percent, percent_label, unicode(label), percent_label)
def setup_import_team(self): # Setup the import team field. The choices are: # - None to disable import # - Any valid sync team # - The account team it self # - The current import_team label_template = _('Import Videos into %(team)s') choices = [('', _("Disable Video Import"))] choices.append((self.account.team.id, fmt(label_template, team=self.account.team.name))) choices.extend( (team_id, fmt(label_template, team=team_name)) for team_id, team_name in self.fields['sync_teams'].choices) if (self.account.import_team_id and self.account.import_team_id not in [c[0] for c in choices]): choices.append((self.account.import_team_id, fmt(label_template, team=self.account.import_team.name))) self.fields['import_team'].choices = choices self.fields['import_team'].initial = self.account.import_team_id
def clean_draft(self): data = self.cleaned_data['draft'] if data.size > SUBTITLE_FILESIZE_LIMIT_KB * 1024: raise forms.ValidationError( fmt(_(u'File size must be less than %(size)s kb.'), size=SUBTITLE_FILESIZE_LIMIT_KB)) parts = data.name.rsplit('.', 1) self.extension = parts[-1].lower() if self.extension not in SUBTITLE_FILE_FORMATS: raise forms.ValidationError( fmt(_(u'Unsupported format. Please upload one of ' u'the following: %(formats)s'), formats=", ".join(SUBTITLE_FILE_FORMATS))) text = data.read() encoding = chardet.detect(text)['encoding'] if not encoding: raise forms.ValidationError(_(u'Can not detect file encoding')) # For xml based formats we can't just convert to unicode, as the parser # will complain that the string encoding doesn't match the encoding # declaration in the xml file if it's not utf-8. is_xml = self.extension in ('dfxp', 'ttml', 'xml') decoded = force_unicode(text, encoding) if not is_xml else text try: # we don't know the language code yet, since we are early in the # clean process. Set it to blank for now and we'll set it to the # correct value in save() self._parsed_subtitles = load_subtitles('', decoded, self.extension) except TypeError, e: raise forms.ValidationError(e)
def format_changes(self): """Get a list of changes to display to the user Returns: List of strings to displa to the user, for example: - Videos public changed to true - 13 miscellaneous settings changed """ rv = [] misc_count = 0 for name, value in self.get_changes().items(): if name in self.SETTINGS_CHANGE_LABELS: rv.append(fmt(ugettext(u'%(setting)s changed to %(value)s'), setting=self.SETTINGS_CHANGE_LABELS[name], value=self.format_value(name, value))) else: misc_count += 1 if misc_count: rv.append(fmt(ungettext( u'%(count)s miscellaneous setting changed', u'%(count)s miscellaneous settings changed', misc_count), count=misc_count)) return rv
def clean_subtitles(self): subtitles = self.cleaned_data['subtitles'] if subtitles.size > KB_SIZELIMIT * 1024: raise forms.ValidationError(fmt( _(u'File size should be less %(size)s kb'), size=KB_SIZELIMIT)) parts = subtitles.name.split('.') extension = parts[-1].lower() if extension not in babelsubs.get_available_formats(): raise forms.ValidationError( fmt(_(u'Incorrect format. ' u'Upload one of the following: %(formats)s.'), formats=", ".join(babelsubs.get_available_formats()))) text = subtitles.read() encoding = chardet.detect(text)['encoding'] if not encoding: raise forms.ValidationError(_(u'Can not detect file encoding')) try: parser = babelsubs.parsers.discover(extension) subtitle_set = parser('en', force_unicode(text, encoding)) except babelsubs.SubtitleParserError: raise forms.ValidationError(_(u'Incorrect subtitles format')) subtitles.seek(0) return subtitles
class CreateVideoUrlForm(forms.ModelForm): def __init__(self, user, *args, **kwargs): self.user = user super(CreateVideoUrlForm, self).__init__(*args, **kwargs) self.fields['video'].widget = forms.HiddenInput() class Meta: model = VideoUrl fields = ('url', 'video') def clean_url(self): url = self.cleaned_data['url'] try: video_type = video_type_registrar.video_type_for_url(url) video_url = video_type.video_url(video_type) if video_type.requires_url_exists and not url_exists(video_url) : raise forms.ValidationError(_(u'This URL appears to be a broken link.')) except VideoTypeError, e: raise forms.ValidationError(e) if not video_type: contact_link = fmt( _('<a href="mailto:%(email)s">contact us</a>'), email=settings.FEEDBACK_EMAIL) raise forms.ValidationError(mark_safe(fmt( _(u"""Amara does not support that website or video format. If you'd like to us to add support for a new site or format, or if you think there's been some mistake, %(contact_link)s!"""), contact_link=contact_link))) self._video_type = video_type return video_type.convert_to_video_url()
def team_invitation_sent(invite_pk): from messages.models import Message from teams.models import Invite, Setting, TeamMember invite = Invite.objects.get(pk=invite_pk) if not team_sends_notification( invite.team, 'block_invitation_sent_message') or not invite.user.is_active: return False # does this team have a custom message for this? team_default_message = None messages = Setting.objects.messages().filter(team=invite.team) if messages.exists(): data = {} for m in messages: data[m.get_key_display()] = m.data mapping = { TeamMember.ROLE_ADMIN: data['messages_admin'], TeamMember.ROLE_MANAGER: data['messages_manager'], TeamMember.ROLE_CONTRIBUTOR: data['messages_invite'], } team_default_message = mapping.get(invite.role, None) context = { 'invite': invite, 'role': invite.role, "user": invite.user, "inviter": invite.author, "team": invite.team, "invite_pk": invite_pk, 'note': invite.note, 'custom_message': team_default_message, 'url_base': get_url_base(), } title = fmt(ugettext(u"You've been invited to team %(team)s on Amara"), team=invite.team.name) if invite.user.notify_by_message: body = render_to_string("messages/team-you-have-been-invited.txt", context) msg = Message() msg.message_type = 'S' msg.subject = title msg.user = invite.user msg.object = invite msg.author = invite.author msg.content = body msg.save() template_name = 'messages/email/team-you-have-been-invited.html' return send_templated_email(invite.user, title, template_name, context)
def assign_task_for_editor(video, language_code, user): team_video = video.get_team_video() if team_video is None: return None task_set = team_video.task_set.incomplete().filter(language=language_code) tasks = list(task_set[:1]) if tasks: task = tasks[0] if task.assignee is None and can_assign_task(task, user): task.assignee = user task.set_expiration() task.save() if task.assignee != user: return fmt(_("Another user is currently performing " "the %(task_type)s task for these subtitles"), task_type=task.get_type_display())
def team_member_promoted(team_pk, user_pk, new_role): if getattr(settings, "MESSAGES_DISABLED", False): return from messages.models import Message from teams.models import Setting, TeamMember, Team user = User.objects.get(pk=user_pk) team = Team.objects.get(pk=team_pk) team_default_message = None messages = Setting.objects.messages().filter(team=team) if messages.exists(): data = {} for m in messages: data[m.get_key_display()] = m.data mapping = { TeamMember.ROLE_ADMIN: data['messages_admin'], TeamMember.ROLE_MANAGER: data['messages_manager'], } team_default_message = mapping.get(new_role, None) if new_role == TeamMember.ROLE_ADMIN: role_label = "Admin" elif new_role == TeamMember.ROLE_MANAGER: role_label = "Manager" context = { 'role': role_label, "user": user, "team": team, 'custom_message': team_default_message, 'url_base': get_url_base(), } title = fmt(ugettext(u"You are now a(n) %(role)s for the %(team)s team!"), role=role_label, team=team.name) body = render_to_string("messages/team-member-promoted.txt", context) msg = Message(user=user, subject=title, content=body, message_type=SYSTEM_NOTIFICATION) msg.save() send_new_message_notification.delay(msg.id) if user.notify_by_email: template_name = 'messages/email/team-member-promoted.html' send_templated_email(user, title, template_name, context)
def send_invitation_message(invite): if not team_sends_notification(invite.team,'block_invitation_sent_message'): return False context = { 'invite': invite, 'role': invite.role, "user":invite.user, "inviter":invite.author, "team": invite.team, 'note': invite.note, 'custom_message': invite.team.get_message('messages_invite'), } title = fmt(_(u"You've been invited to the %(team)s team"), team=unicode(invite.team)) notify_users(Notifications.TEAM_INVITATION, [invite.user], title, 'messages/team-invitation.html', context)
def member_search(request, team, qs): query = request.GET.get('query') if query: members_qs = (qs.filter( user__username__icontains=query).select_related('user')) else: members_qs = TeamMember.objects.none() data = [{ 'value': member.user.username, 'label': fmt(_('%(username)s (%(full_name)s)'), username=member.user.username, full_name=unicode(member.user)), } for member in members_qs] return HttpResponse(json.dumps(data), mimetype='application/json')
def _add_share_panel_context_for_video(context, video): page_url = reverse('videos:video', kwargs={'video_id': video.video_id}) abs_page_url = "http://{0}{1}".format(domain(), page_url) if video.latest_version() is not None: msg = _(u"Just found a version of this video with subtitles") else: msg = _("Check out this video and help make subtitles") email_message = _( u"Hey-- check out this video %(video_title)s and help make subtitles: %(url)s" ) email_message = fmt(email_message, video_title=_share_video_title(video), url=abs_page_url) _add_share_panel_context(context, _make_facebook_url(abs_page_url, msg), _make_twitter_url(abs_page_url, msg), {'video_url': video.get_video_url()}, _make_email_url(email_message), abs_page_url)
def application_sent(application_pk): if getattr(settings, "MESSAGES_DISABLED", False): return from messages.models import Message from teams.models import Application, TeamMember application = Application.objects.get(pk=application_pk) if not team_sends_notification(application.team, 'block_application_sent_message'): return False notifiable = TeamMember.objects.filter( team=application.team, user__is_active=True, role__in=[TeamMember.ROLE_ADMIN, TeamMember.ROLE_OWNER]) for m in notifiable: template_name = "messages/application-sent.txt" context = { "application": application, "applicant": application.user, "url_base": get_url_base(), "team": application.team, "note": application.note, "user": m.user, } body = render_to_string(template_name, context) subject = fmt(ugettext(u'%(user)s is applying for team %(team)s'), user=application.user, team=application.team.name) if m.user.notify_by_message: msg = Message() msg.message_type = 'S' msg.subject = subject msg.content = body msg.user = m.user msg.object = application.team msg.author = application.user msg.save() send_templated_email(m.user, subject, "messages/email/application-sent-email.html", context) return True
def autocomplete_user_view(request, queryset, limit=10): query = request.GET.get('query') # put exact matches first users = list(queryset.filter(username=query)) limit -= len(users) # add non-exact matches next users.extend( queryset.filter( Q(username__icontains=query) | Q(first_name__icontains=query) | Q(last_name__icontains=query) | Q(full_name__icontains=query)).exclude(username=query)[:limit]) data = [{ 'value': user.username, 'label': fmt(_('%(username)s (%(full_name)s)'), username=user.username, full_name=unicode(user)), } for user in users] return HttpResponse(json.dumps(data), mimetype='application/json')
def _verify_no_translation_conflict(self, subtitle_language, from_language_code): existing_from_language = subtitle_language.get_translation_source_language() existing_from_language_code = ( existing_from_language and existing_from_language.language_code) or '' # If the user said this is a translation, but the language already # exists and *isn't* a translation, fail. if from_language_code: language_is_not_a_translation = (not existing_from_language_code) if language_is_not_a_translation and subtitle_language.get_tip(): raise forms.ValidationError(_( u"The language already exists and is not a translation.")) # If it's marked as a translation from a different language, don't # allow that until our UI can handle showing different reference # languages elif existing_from_language_code and existing_from_language_code != from_language_code: raise forms.ValidationError(fmt( _(u"The language already exists as a " u"translation from %(source_lang)s."), source_lang=existing_from_language.get_language_code_display()))
def share_panel_context_for_video(video): page_url = reverse('videos:video', kwargs={'video_id':video.video_id}) abs_page_url = "{}://{}{}".format(settings.DEFAULT_PROTOCOL, settings.HOSTNAME, page_url) if video.latest_version() is not None: msg = _(u"Just found a version of this video with subtitles") else: msg = _("Check out this video and help make subtitles") email_message = _(u"Hey-- check out this video %(video_title)s and help make subtitles: %(url)s") email_message = fmt(email_message, video_title=video.title_display(), url=abs_page_url) return share_panel_context( make_facebook_url(abs_page_url, msg), make_twitter_url(abs_page_url, msg), { 'video_url': video.get_video_url() }, abs_page_url )
def set_original_language(request, video_id): """ We only allow if a video is own a team, or the video owner is the logged in user """ video = get_object_or_404(Video, video_id=video_id) if not (can_edit_video(video.get_team_video(), request.user) or video.user == request.user): return HttpResponseForbidden("Can't touch this.") form = ChangeVideoOriginalLanguageForm(request.POST or None, initial={ 'language_code': video.primary_audio_language_code }) if request.method == "POST" and form.is_valid(): video.primary_audio_language_code = form.cleaned_data['language_code'] video.save() messages.success(request, fmt( _(u'The language for %(video)s has been changed'), video=video)) return HttpResponseRedirect(reverse("videos:set_original_language", args=(video_id,))) return render(request, "videos/set-original-language.html", { "video": video, 'form': form })
def clean_txtfile(self): f = self.cleaned_data['txtfile'] if f.name.split('.')[-1] != 'txt': raise forms.ValidationError(_('File should have txt format')) if f.size > KB_SIZELIMIT * 1024: raise forms.ValidationError(fmt( _(u'File size should be less %(size)s kb'), size=KB_SIZELIMIT)) text = f.read() encoding = chardet.detect(text)['encoding'] if not encoding: raise forms.ValidationError(_(u'Can not detect file encoding')) try: self.file_text = force_unicode(text, encoding) except DjangoUnicodeDecodeError: raise forms.ValidationError(_(u'Can\'t encode file. It should have utf8 encoding.')) f.seek(0) return f
def handle_callback(request, redirect_uri): """Handle the youtube oauth callback. :param request: djongo Request object :redirect_uri: same URI as as passed to request_token_url() :returns: OAuthCallbackData object """ code = request.GET.get('code') error = request.GET.get('error') state = request.GET.get('state') if error is not None: raise OAuthError(fmt(_('Youtube error: %(error)s'), error=error)) if code is None: logger.warn("handle_callback: no authorization code (%s)" % request.GET) raise OAuthError(_('Error while linking. Please try again.')) if state is not None: state = json.loads(state) # exchange the auth code for refresh/access tokens response = _oauth_token_post(code=code, grant_type='authorization_code', redirect_uri=redirect_uri) # decode the id_token. We can skip verification since we used HTTPS to # connect to google response_data = response.json() token_data = jwt.decode(response_data['id_token'], verify=False) return OAuthCallbackData( response_data.get('refresh_token'), response_data['access_token'], "", token_data['sub'], state, )