def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if not check_rate_limit(request): messages.error( request, _('Too many messages sent, please try again later!') ) elif form.is_valid(): mail_admins_contact( request, '%(subject)s', CONTACT_TEMPLATE, form.cleaned_data, form.cleaned_data['email'], ) return redirect('home') else: initial = get_initial_contact(request) if request.GET.get('t') in CONTACT_SUBJECTS: initial['subject'] = CONTACT_SUBJECTS[request.GET['t']] form = ContactForm(initial=initial) return render( request, 'accounts/contact.html', { 'form': form, 'title': _('Contact'), } )
def change_access(request, project): obj = get_project(request, project) if not request.user.has_perm('billing:project.permissions', obj): raise PermissionDenied() form = ProjectAccessForm(request.POST, instance=obj) if not form.is_valid(): for error in form.errors: for message in form.errors[error]: messages.error(request, message) else: form.save() Change.objects.create( project=obj, action=Change.ACTION_ACCESS_EDIT, user=request.user, details={'access_control': obj.access_control}, ) messages.success( request, _('Project access control has been changed.') ) return redirect( 'manage-access', project=obj.slug, )
def post(self, request, **kwargs): component = self.get_component() if not request.user.has_perm('screenshot.add', component): raise PermissionDenied() self._add_form = ScreenshotForm(request.POST, request.FILES) if self._add_form.is_valid(): obj = Screenshot.objects.create( component=component, user=request.user, **self._add_form.cleaned_data ) request.user.profile.uploaded += 1 request.user.profile.save(update_fields=['uploaded']) try_add_source(request, obj) messages.success( request, _( 'Screenshot has been uploaded, ' 'you can now assign it to source strings.' ) ) return redirect(obj) messages.error( request, _('Failed to upload screenshot, please fix errors below.') ) return self.get(request, **kwargs)
def auto_translation(request, project, subproject, lang): translation = get_translation(request, project, subproject, lang) project = translation.subproject.project if not can_automatic_translation(request.user, project): raise PermissionDenied() autoform = AutoForm(translation, request.user, request.POST) if translation.subproject.locked or not autoform.is_valid(): messages.error(request, _('Failed to process form!')) return redirect(translation) updated = auto_translate( request.user, translation, autoform.cleaned_data['subproject'], autoform.cleaned_data['inconsistent'], autoform.cleaned_data['overwrite'] ) import_message( request, updated, _('Automatic translation completed, no strings were updated.'), ungettext( 'Automatic translation completed, %d string was updated.', 'Automatic translation completed, %d strings were updated.', updated ) ) return redirect(translation)
def save_zen(request, project, subproject, lang): """Save handler for zen mode.""" translation = get_translation(request, project, subproject, lang) user_locked = translation.is_user_locked(request.user) form = TranslationForm( request.user.profile, translation, None, request.POST ) if not can_translate(request.user, translation): messages.error( request, _('You don\'t have privileges to save translations!') ) elif not form.is_valid(): messages.error(request, _('Failed to save translation!')) elif not user_locked: unit = form.cleaned_data['unit'] perform_translation(unit, form, request) return render( request, 'zen-response.html', {}, )
def change_component(request, project, component): obj = get_component(request, project, component) if not request.user.has_perm('component.edit', obj): raise Http404() if request.method == 'POST': form = ComponentSettingsForm(request.POST, instance=obj) if form.is_valid(): form.save() messages.success(request, _('Settings saved')) return redirect( 'settings', project=obj.project.slug, component=obj.slug ) else: messages.error( request, _('Invalid settings, please check the form for errors!') ) else: form = ComponentSettingsForm(instance=obj) return render( request, 'component-settings.html', { 'project': obj.project, 'object': obj, 'form': form, } )
def reset_password_set(request): """Perform actual password reset.""" user = User.objects.get(pk=request.session['perform_reset']) if user.has_usable_password(): request.session.flush() request.session.set_expiry(None) messages.error( request, _('Password reset has been already completed!') ) return redirect('login') if request.method == 'POST': form = SetPasswordForm(user, request.POST) if form.is_valid(): request.session.set_expiry(None) form.save(request, delete_session=True) return redirect('login') else: form = SetPasswordForm(user) return render( request, 'accounts/reset.html', { 'title': _('Password reset'), 'form': form, 'captcha_form': None, 'second_stage': True, } )
def handle_merge(translation, request, next_unit_url): """Handle unit merging.""" mergeform = MergeForm(translation, request.GET) if not mergeform.is_valid(): messages.error(request, _('Invalid merge request!')) return None unit = mergeform.cleaned_data['unit'] merged = mergeform.cleaned_data['merge_unit'] if not request.user.has_perm('unit.edit', unit): messages.error( request, _('Insufficient privileges for saving translations.') ) return None # Store unit saved = unit.translate(request, merged.target, merged.state) # Update stats if there was change if saved: request.user.profile.translated += 1 request.user.profile.save() # Redirect to next entry return HttpResponseRedirect(next_unit_url)
def add_user(request, project): """Add user to a project.""" obj, form = check_user_form(request, project, True) if form is not None: try: user = form.cleaned_data['user'] obj.add_user(user) Change.objects.create( project=obj, action=Change.ACTION_ADD_USER, user=request.user, details={'username': user.username}, ) messages.success( request, _('User has been added to this project.') ) except Group.DoesNotExist: messages.error( request, _('Failed to find group to add a user!') ) return redirect( 'manage-access', project=obj.slug, )
def post(self, request, **kwargs): component = self.get_component(kwargs) if not can_add_screenshot(request.user, component.project): raise PermissionDenied() self._add_form = ScreenshotForm(request.POST, request.FILES) if self._add_form.is_valid(): obj = Screenshot.objects.create( component=component, **self._add_form.cleaned_data ) try_add_source(request, obj) messages.success( request, _( 'Screenshot has been uploaded, ' 'you can now assign it to source strings.' ) ) return redirect(obj) else: messages.error( request, _('Failed to upload screenshot, please fix errors below.') ) return self.get(request, **kwargs)
def handle_translate(request, translation, this_unit_url, next_unit_url): """Save translation or suggestion to database and backend.""" # Antispam protection antispam = AntispamForm(request.POST) if not antispam.is_valid(): # Silently redirect to next entry return HttpResponseRedirect(next_unit_url) form = TranslationForm( request.user, translation, None, request.POST ) if not form.is_valid(): show_form_errors(request, form) return None unit = form.cleaned_data['unit'] go_next = True if 'suggest' in request.POST: go_next = perform_suggestion(unit, form, request) elif not request.user.has_perm('unit.edit', unit): messages.error( request, _('Insufficient privileges for saving translations.') ) else: go_next = perform_translation(unit, form, request) # Redirect to next entry if go_next: return HttpResponseRedirect(next_unit_url) return HttpResponseRedirect(this_unit_url)
def comment(request, pk): """Add new comment.""" unit = get_object_or_404(Unit, pk=pk) request.user.check_access(unit.translation.component.project) if not request.user.has_perm('comment.add', unit.translation): raise PermissionDenied() form = CommentForm(request.POST) if form.is_valid(): if form.cleaned_data['scope'] == 'global': lang = None else: lang = unit.translation.language Comment.objects.add( unit, request.user, lang, form.cleaned_data['comment'] ) messages.success(request, _('Posted new comment')) else: messages.error(request, _('Failed to add comment!')) return redirect_next(request.POST.get('next'), unit)
def delete_user(request, project): """Remove user from a project.""" obj, form = check_user_form(request, project, True) if form is not None: owners = User.objects.all_admins(obj) user = form.cleaned_data['user'] is_owner = owners.filter(pk=user.pk).exists() if is_owner and owners.count() <= 1: messages.error(request, _('You can not remove last owner!')) else: obj.remove_user(user) Change.objects.create( project=obj, action=Change.ACTION_REMOVE_USER, user=request.user, details={'username': user.username}, ) messages.success( request, _('User has been removed from this project.') ) return redirect( 'manage-access', project=obj.slug, )
def mail_admins_contact(request, subject, message, context, sender, to): """Send a message to the admins, as defined by the ADMINS setting.""" LOGGER.info( 'contact form from %s', sender, ) if not to and settings.ADMINS: to = [a[1] for a in settings.ADMINS] elif not settings.ADMINS: messages.error( request, _('Message could not be sent to administrator!') ) LOGGER.error( 'ADMINS not configured, can not send message!' ) return mail = EmailMultiAlternatives( '{0}{1}'.format(settings.EMAIL_SUBJECT_PREFIX, subject % context), message % context, to=to, headers={'Reply-To': sender}, ) mail.send(fail_silently=False) messages.success( request, _('Message has been sent to administrator.') )
def rate_wrap(request, *args, **kwargs): if request.method == 'POST': session = request.session now = time() k_timeout = '{}_timeout'.format(scope) k_attempts = '{}_attempts'.format(scope) # Reset expired counter if (k_timeout in session and k_attempts in session and session[k_timeout] <= now): session[k_attempts] = 0 # Get current attempts attempts = session.get(k_attempts, 0) # Did we hit the limit? if attempts >= get_rate_setting(scope, 'ATTEMPTS'): # Rotate session token rotate_token(request) # Logout user if request.user.is_authenticated: logout(request) messages.error( request, _('Too many attempts, you have been logged out!') ) return redirect('login') session[k_attempts] = attempts + 1 if k_timeout not in session: window = get_rate_setting(scope, 'WINDOW') session[k_timeout] = now + window return function(request, *args, **kwargs)
def perform_translation(unit, form, request): """Handle translation and stores it to a backend.""" # Remember old checks oldchecks = set( unit.active_checks().values_list('check', flat=True) ) # Run AutoFixes on user input if not unit.translation.is_template: new_target, fixups = fix_target(form.cleaned_data['target'], unit) else: new_target = form.cleaned_data['target'] fixups = [] # Save saved = unit.translate( request, new_target, form.cleaned_data['state'] ) # Should we skip to next entry if not saved: revert_rate_limit('translate', request) return True # Warn about applied fixups if fixups: messages.info( request, _('Following fixups were applied to translation: %s') % ', '.join([force_text(f) for f in fixups]) ) # Get new set of checks newchecks = set( unit.active_checks().values_list('check', flat=True) ) # Did we introduce any new failures? if saved and newchecks > oldchecks: # Show message to user messages.error( request, _( 'The translation has been saved, however there ' 'are some newly failing checks: {0}' ).format( ', '.join( [force_text(CHECKS[check].name) for check in newchecks] ) ) ) # Stay on same entry return False return True
def new_language(request, project, component): obj = get_component(request, project, component) form_class = get_new_language_form(request, obj) can_add = obj.can_add_new_language(request) if request.method == 'POST': form = form_class(obj, request.POST) if form.is_valid(): langs = form.cleaned_data['lang'] kwargs = { 'user': request.user, 'author': request.user, 'component': obj, 'details': {}, } for language in Language.objects.filter(code__in=langs): kwargs['details']['language'] = language.code if can_add: obj.add_new_language(language, request) Change.objects.create( action=Change.ACTION_ADDED_LANGUAGE, **kwargs ) elif obj.new_lang == 'contact': Change.objects.create( action=Change.ACTION_REQUESTED_LANGUAGE, **kwargs ) messages.success( request, _( "A request for a new translation has been " "sent to the project's maintainers." ) ) return redirect(obj) messages.error( request, _('Please fix errors in the form.') ) else: form = form_class(obj) return render( request, 'new-language.html', { 'object': obj, 'project': obj.project, 'form': form, 'can_add': can_add, } )
def rate_wrap(request, *args, **kwargs): attempts = request.session.get('auth_attempts', 0) if (request.method == 'POST' and attempts >= settings.AUTH_MAX_ATTEMPTS): logout(request) messages.error( request, _('Too many authentication attempts!') ) return redirect('login') return function(request, *args, **kwargs)
def _get_queryset_language(self): """Filtering by language""" if self.translation is None and 'lang' in self.request.GET: try: self.language = Language.objects.get( code=self.request.GET['lang'] ) except Language.DoesNotExist: messages.error( self.request, _('Failed to find matching language!') )
def _get_queryset_user(self): """Filtering by user""" if 'user' in self.request.GET: try: self.user = User.objects.get( username=self.request.GET['user'] ) except User.DoesNotExist: messages.error( self.request, _('Failed to find matching user!') )
def handle_dismiss(request): try: error = ConfigurationError.objects.get( pk=int(request.POST['pk']) ) if 'ignore' in request.POST: error.ignored = True error.save(update_fields=['ignored']) else: error.delete() except (ValueError, KeyError, ConfigurationError.DoesNotExist): messages.error(request, _('Failed to dismiss configuration error!')) return redirect('admin:performance')
def show_form_errors(request, form): """Show all form errors as a message.""" for error in form.non_field_errors(): messages.error(request, error) for field in form: for error in field.errors: messages.error( request, _('Error in parameter %(field)s: %(error)s') % { 'field': field.name, 'error': error } )
def perform_translation(unit, form, request): """Handle translation and stores it to a backend.""" # Remember old checks oldchecks = set( unit.active_checks().values_list('check', flat=True) ) # Run AutoFixes on user input if not unit.translation.is_template(): new_target, fixups = fix_target(form.cleaned_data['target'], unit) else: new_target = form.cleaned_data['target'] fixups = [] # Save saved = unit.translate( request, new_target, form.cleaned_data['fuzzy'] ) # Warn about applied fixups if len(fixups) > 0: messages.info( request, _('Following fixups were applied to translation: %s') % ', '.join([force_text(f) for f in fixups]) ) # Get new set of checks newchecks = set( unit.active_checks().values_list('check', flat=True) ) # Did we introduce any new failures? if saved and newchecks > oldchecks: # Show message to user messages.error( request, _( 'Some checks have failed on your translation: {0}' ).format( ', '.join( [force_text(CHECKS[check].name) for check in newchecks] ) ) ) # Stay on same entry return False return True
def edit_check_flags(request, pk): """Change source string check flags.""" source = get_object_or_404(Source, pk=pk) if not can_edit_flags(request.user, source.subproject.project): raise PermissionDenied() form = CheckFlagsForm(request.POST) if form.is_valid(): source.check_flags = form.cleaned_data['flags'] source.save() else: messages.error(request, _('Failed to change check flags!')) return redirect_next(request.POST.get('next'), source.get_absolute_url())
def edit_priority(request, pk): """Change source string priority.""" source = get_object_or_404(Source, pk=pk) if not can_edit_priority(request.user, source.subproject.project): raise PermissionDenied() form = PriorityForm(request.POST) if form.is_valid(): source.priority = form.cleaned_data['priority'] source.save() else: messages.error(request, _('Failed to change a priority!')) return redirect_next(request.POST.get('next'), source.get_absolute_url())
def rate_wrap(request, *args, **kwargs): attempts = request.session.get('auth_attempts', 0) if request.method == 'POST': if attempts >= settings.AUTH_MAX_ATTEMPTS: rotate_token(request) if request.user.is_authenticated: logout(request) messages.error( request, _('Too many attempts, you have been logged out!') ) return redirect('login') request.session['auth_attempts'] = attempts + 1 return function(request, *args, **kwargs)
def form_valid(self, form): if not check_perm(self.request.user, 'memory.edit', self.objects): raise PermissionDenied() try: TranslationMemory.import_file( self.request, form.cleaned_data['file'], **self.objects ) messages.success( self.request, _('File processed, the entries will appear shortly.') ) except MemoryImportError as error: messages.error(self.request, force_text(error)) return super(UploadView, self).form_valid(form)
def edit_context(request, pk): """Change source string context.""" source = get_object_or_404(Source, pk=pk) if not request.user.has_perm('source.edit', source.component): raise PermissionDenied() form = ContextForm(request.POST) if form.is_valid(): source.context = form.cleaned_data['context'] source.save() else: messages.error(request, _('Failed to change a context!')) return redirect_next(request.POST.get('next'), source.get_absolute_url())
def perform_suggestion(unit, form, request): """Handle suggesion saving.""" if form.cleaned_data['target'][0] == '': messages.error(request, _('Your suggestion is empty!')) # Stay on same entry return False if not request.user.has_perm('suggestion.add', unit.translation): # Need privilege to add messages.error( request, _('You don\'t have privileges to add suggestions!') ) # Stay on same entry return False if not request.user.is_authenticated: # Spam check if is_spam('\n'.join(form.cleaned_data['target']), request): messages.error( request, _('Your suggestion has been identified as spam!') ) return False # Create the suggestion result = Suggestion.objects.add( unit, join_plural(form.cleaned_data['target']), request, request.user.has_perm('suggestion.vote', unit) ) if not result: messages.error(request, _('Your suggestion already exists!')) return result
def execute_locked(request, obj, message, call, *args, **kwargs): """Helper function to catch possible lock exception.""" try: result = call(*args, **kwargs) # With False the call is supposed to show errors on its own if result is None or result: messages.success(request, message) except Timeout as error: messages.error( request, _('Failed to lock the repository, another operation is in progress.') ) report_error(error, request) return redirect_param(obj, '#repository')
def trial(request): """Form for hosting request.""" if not settings.OFFER_HOSTING: return redirect("home") plan = request.POST.get("plan", "enterprise") # Avoid frequent requests for a trial for same user if plan != "libre" and request.user.auditlog_set.filter( activity="trial").exists(): messages.error( request, _("Seems you've already requested a trial period recently. " "Please contact us with your inquiry so we can find the " "best solution for you."), ) return redirect(reverse("contact") + "?t=trial") if request.method == "POST": from weblate.billing.models import Billing, Plan AuditLog.objects.create(request.user, request, "trial") billing = Billing.objects.create( plan=Plan.objects.get(slug=plan), state=Billing.STATE_TRIAL, expiry=timezone.now() + timedelta(days=14), ) billing.owners.add(request.user) messages.info( request, _("Your trial period is now up and running; " "create your translation project and start Weblating!"), ) return redirect(reverse("create-project") + f"?billing={billing.pk}") return render(request, "accounts/trial.html", {"title": _("Gratis trial")})
def change_project(request, project): obj = get_project(request, project) if not request.user.has_perm("project.edit", obj): raise Http404() if request.method == "POST": settings_form = ProjectSettingsForm(request, request.POST, instance=obj) if settings_form.is_valid(): settings_form.save() messages.success(request, _("Settings saved")) return redirect("settings", project=obj.slug) else: messages.error( request, _("Invalid settings, please check the form for errors!") ) else: settings_form = ProjectSettingsForm(request, instance=obj) return render( request, "project-settings.html", {"object": obj, "form": settings_form}, )
def change_component(request, project, component): obj = get_component(request, project, component) if not request.user.has_perm("component.edit", obj): raise Http404() if request.method == "POST": form = ComponentSettingsForm(request, request.POST, instance=obj) if form.is_valid(): form.save() messages.success(request, _("Settings saved")) return redirect("settings", project=obj.project.slug, component=obj.slug) else: messages.error( request, _("Invalid settings, please check the form for errors!") ) # Get a fresh copy of object, otherwise it will use unsaved changes # from the failed form obj = Component.objects.get(pk=obj.pk) else: form = ComponentSettingsForm(request, instance=obj) if obj.repo_needs_merge(): messages.warning( request, _( "The repository is outdated, you might not get " "expected results until you update it." ), ) return render( request, "component-settings.html", {"project": obj.project, "object": obj, "form": form}, )
def mail_admins_contact(request, subject, message, context, sender, to): """Send a message to the admins, as defined by the ADMINS setting.""" LOGGER.info( 'contact form from %s', sender, ) if not to and settings.ADMINS: to = [a[1] for a in settings.ADMINS] elif not settings.ADMINS: messages.error(request, _('Message could not be sent to administrator!')) LOGGER.error('ADMINS not configured, can not send message!') return mail = EmailMultiAlternatives( '{0}{1}'.format(settings.EMAIL_SUBJECT_PREFIX, subject % context), message % context, to=to, headers={'Reply-To': sender}, ) mail.send(fail_silently=False) messages.success(request, _('Message has been sent to administrator.'))
def reset_password_set(request): """Perform actual password reset.""" user = User.objects.get(pk=request.session['perform_reset']) if user.has_usable_password(): request.session.flush() request.session.set_expiry(None) messages.error(request, _('Password reset has been already completed!')) return redirect('login') if request.method == 'POST': form = SetPasswordForm(user, request.POST) if form.is_valid(): request.session.set_expiry(None) form.save(request, delete_session=True) return redirect('login') else: form = SetPasswordForm(user) return render( request, 'accounts/reset.html', { 'title': _('Password reset'), 'form': form, 'captcha_form': None, 'second_stage': True, })
def invite_user(request, project): """Invite user to a project.""" obj, form = check_user_form(request, project, True, form_class=InviteUserForm) if form is not None: try: user = form.save() obj.add_user(user) Change.objects.create( project=obj, action=Change.ACTION_INVITE_USER, user=request.user, details={'username': user.username}, ) send_invitation(request, obj, user) messages.success(request, _('User has been invited to this project.')) except Group.DoesNotExist: messages.error(request, _('Failed to find group to add a user!')) return redirect('manage-access', project=obj.slug)
def change_access(request, project): obj = get_project(request, project) if not request.user.has_perm('billing:project.permissions', obj): raise PermissionDenied() form = ProjectAccessForm(request.POST, instance=obj) if not form.is_valid(): for error in form.errors: for message in form.errors[error]: messages.error(request, message) else: form.save() Change.objects.create( project=obj, action=Change.ACTION_ACCESS_EDIT, user=request.user, details={'access_control': obj.access_control}, ) messages.success(request, _('Project access control has been changed.')) return redirect('manage-access', project=obj.slug)
def comment(request, pk): """Add new comment.""" scope = unit = get_object_or_404(Unit, pk=pk) component = unit.translation.component if not request.user.has_perm("comment.add", unit.translation): raise PermissionDenied() form = CommentForm(component.project, request.POST) if form.is_valid(): # Is this source or target comment? if form.cleaned_data["scope"] in ("global", "report"): scope = unit.source_unit # Create comment object Comment.objects.add(scope, request, form.cleaned_data["comment"]) # Add review label/flag if form.cleaned_data["scope"] == "report": if component.has_template(): if scope.translated and not scope.readonly: scope.translate( request.user, scope.target, STATE_FUZZY, change_action=Change.ACTION_MARKED_EDIT, ) else: label = component.project.label_set.get_or_create( name=gettext_noop("Source needs review"), defaults={"color": "red"})[0] scope.labels.add(label) messages.success(request, _("Posted new comment")) else: messages.error(request, _("Failed to add comment!")) return redirect_next(request.POST.get("next"), unit)
def tools(request): emailform = TestMailForm(initial={'email': request.user.email}) if request.method == 'POST': if 'email' in request.POST: emailform = TestMailForm(request.POST) if emailform.is_valid(): try: send_test_mail(**emailform.cleaned_data) messages.success(request, _('Test e-mail sent.')) except Exception as error: report_error(error, request) messages.error(request, _('Could not send test e-mail: %s') % error) return render( request, "manage/tools.html", { 'menu_items': MENU, 'menu_page': 'tools', 'email_form': emailform }, )
def handle_translate(request, unit, this_unit_url, next_unit_url): """Save translation or suggestion to database and backend.""" form = TranslationForm(request.user, unit, request.POST) if not form.is_valid(): show_form_errors(request, form) return None go_next = True if "suggest" in request.POST: go_next = perform_suggestion(unit, form, request) elif not request.user.has_perm("unit.edit", unit): if request.user.has_perm("unit.flag", unit): update_explanation(unit, form) else: messages.error( request, _("Insufficient privileges for saving translations.")) else: go_next = perform_translation(unit, form, request) # Redirect to next entry if "save-stay" not in request.POST and go_next: return HttpResponseRedirect(next_unit_url) return HttpResponseRedirect(this_unit_url)
def add_host_key(request, host, port=""): """Add host key for a host.""" if not host: messages.error(request, _("Invalid host name given!")) else: cmdline = ["ssh-keyscan"] if port: cmdline.extend(["-p", str(port)]) cmdline.append(host) try: result = subprocess.run( cmdline, env=get_clean_env(), check=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) keys = [] for key in result.stdout.splitlines(): key = key.strip() if not is_key_line(key): continue keys.append(key) host, keytype, fingerprint = parse_hosts_line(key) messages.warning( request, _( "Added host key for %(host)s with fingerprint " "%(fingerprint)s (%(keytype)s), " "please verify that it is correct." ) % {"host": host, "fingerprint": fingerprint, "keytype": keytype}, ) if not keys: messages.error(request, _("Failed to fetch public key for a host!")) with open(ssh_file(KNOWN_HOSTS), "a") as handle: for key in keys: handle.write("{0}\n".format(key)) except subprocess.CalledProcessError as exc: messages.error( request, _("Failed to get host key: %s") % exc.stderr or exc.stdout ) except OSError as exc: messages.error(request, _("Failed to get host key: %s") % str(exc))
def add_host_key(request): """Add host key for a host.""" host = request.POST.get('host', '') port = request.POST.get('port', '') if len(host) == 0: messages.error(request, _('Invalid host name given!')) else: cmdline = ['ssh-keyscan'] if port: cmdline.extend(['-p', port]) cmdline.append(host) try: output = subprocess.check_output( cmdline, stderr=subprocess.STDOUT, env=get_clean_env(), ) keys = [] for key in output.decode('utf-8').splitlines(): key = key.strip() if not is_key_line(key): continue keys.append(key) host, keytype, fingerprint = parse_hosts_line(key) messages.warning( request, _('Added host key for %(host)s with fingerprint ' '%(fingerprint)s (%(keytype)s), ' 'please verify that it is correct.') % { 'host': host, 'fingerprint': fingerprint, 'keytype': keytype, }) if len(keys) == 0: messages.error(request, _('Failed to fetch public key for a host!')) with open(ssh_file(KNOWN_HOSTS), 'a') as handle: for key in keys: handle.write('{0}\n'.format(key)) except subprocess.CalledProcessError as exc: messages.error(request, _('Failed to get host key: %s') % exc.output) except OSError as exc: messages.error(request, _('Failed to get host key: %s') % str(exc))
def post(self, request, **kwargs): self.object = self.get_object() if not request.user.has_perm("project.edit", self.project): raise PermissionDenied() if "name" in request.POST: form = self._form = FontGroupForm(request.POST, instance=self.object, project=self.project) if form.is_valid(): instance = form.save(commit=False) try: instance.validate_unique() instance.save() return redirect(self.object) except ValidationError: messages.error(request, _("Entry by the same name already exists.")) return self.get(request, **kwargs) if "language" in request.POST: form = self._form = FontOverrideForm(request.POST) if form.is_valid(): instance = form.save(commit=False) instance.group = self.object try: instance.validate_unique() instance.save() return redirect(self.object) except ValidationError: messages.error(request, _("Entry by the same name already exists.")) return self.get(request, **kwargs) if "override" in request.POST: try: self.object.fontoverride_set.filter( pk=int(request.POST["override"])).delete() return redirect(self.object) except (ValueError, ObjectDoesNotExist): messages.error(request, _("No override found.")) self.object.delete() messages.error(request, _("Font group deleted.")) return redirect("fonts", project=self.project.slug)
def check_suggest_permissions(request, mode, translation, suggestion): """Check permission for suggestion handling.""" if mode in ('accept', 'accept_edit'): if not can_accept_suggestion(request.user, translation): messages.error( request, _('You do not have privilege to accept suggestions!')) return False elif mode == 'delete': if not can_delete_suggestion(request.user, translation, suggestion): messages.error( request, _('You do not have privilege to delete suggestions!')) return False elif mode in ('upvote', 'downvote'): if not can_vote_suggestion(request.user, translation): messages.error( request, _('You do not have privilege to vote for suggestions!')) return False return True
def check_suggest_permissions(request, mode, translation, suggestion): """Check permission for suggestion handling.""" user = request.user if mode in ('accept', 'accept_edit'): if not user.has_perm('suggestion.accept', translation): messages.error( request, _('You do not have privilege to accept suggestions!')) return False elif mode in ('delete', 'spam'): if not user.has_perm('suggestion.delete', suggestion, translation): messages.error( request, _('You do not have privilege to delete suggestions!')) return False elif mode in ('upvote', 'downvote'): if not user.has_perm('suggestion.vote', translation): messages.error( request, _('You do not have privilege to vote for suggestions!')) return False return True
def check_suggest_permissions(request, mode, unit, suggestion): """Check permission for suggestion handling.""" user = request.user if mode in ("accept", "accept_edit"): if not user.has_perm("suggestion.accept", unit): messages.error( request, _("You do not have privilege to accept suggestions!")) return False elif mode in ("delete", "spam"): if not user.has_perm("suggestion.delete", suggestion): messages.error( request, _("You do not have privilege to delete suggestions!")) return False elif mode in ("upvote", "downvote"): if not user.has_perm("suggestion.vote", unit): messages.error( request, _("You do not have privilege to vote for suggestions!")) return False return True
def handle_merge(translation, request, next_unit_url): ''' Handles unit merging. ''' if not can_translate(request.user, translation): messages.error( request, _('You don\'t have privileges to save translations!') ) return mergeform = MergeForm(translation, request.GET) if not mergeform.is_valid(): messages.error( request, _('Invalid merge request!') ) return unit = mergeform.cleaned_data['unit'] merged = Unit.objects.get( pk=mergeform.cleaned_data['merge'] ) if unit.checksum != merged.checksum: messages.error( request, _('Can not merge different messages!') ) else: # Store unit unit.target = merged.target unit.fuzzy = merged.fuzzy saved = unit.save_backend(request) # Update stats if there was change if saved: request.user.profile.translated += 1 request.user.profile.save() # Redirect to next entry return HttpResponseRedirect(next_unit_url)
def perform_suggestion(unit, form, request): """Handle suggesion saving.""" if form.cleaned_data['target'][0] == '': messages.error(request, _('Your suggestion is empty!')) # Stay on same entry return False elif not can_suggest(request.user, unit.translation): # Need privilege to add messages.error(request, _('You don\'t have privileges to add suggestions!')) # Stay on same entry return False # Invite user to become translator if there is nobody else # and the project is accepting translations translation = unit.translation if (not translation.subproject.suggestion_voting or not translation.subproject.suggestion_autoaccept): recent_changes = Change.objects.content(True).filter( translation=translation, ).exclude(user=None) if not recent_changes.exists(): messages.info( request, _('There is currently no active translator for this ' 'translation, please consider becoming a translator ' 'as your suggestion might otherwise remain unreviewed.')) messages.info( request, mark_safe('<a href="{0}">{1}</a>'.format( escape(get_doc_url('user/translating')), escape( _('See our documentation for more information ' 'on translating using Weblate.')), ))) # Create the suggestion result = Suggestion.objects.add( unit, join_plural(form.cleaned_data['target']), request, can_vote_suggestion(request.user, unit.translation)) if not result: messages.error(request, _('Your suggestion already exists!')) return result
def handle_revert(translation, request, next_unit_url): if not can_translate(request.user, translation): messages.error(request, _('You don\'t have privileges to save translations!')) return revertform = RevertForm(translation, request.GET) if not revertform.is_valid(): messages.error(request, _('Invalid revert request!')) return unit = revertform.cleaned_data['unit'] change = revertform.cleaned_data['revert_change'] if change.target == "": messages.error(request, _('Can not revert to empty translation!')) else: # Store unit unit.target = change.target unit.save_backend(request, change_action=Change.ACTION_REVERT) # Redirect to next entry return HttpResponseRedirect(next_unit_url)
def handle_revert(translation, request, next_unit_url): revertform = RevertForm(translation, request.GET) if not revertform.is_valid(): messages.error(request, _('Invalid revert request!')) return None unit = revertform.cleaned_data['unit'] change = revertform.cleaned_data['revert_change'] if not request.user.has_perm('unit.edit', unit): messages.error(request, _('Insufficient privileges for saving translations.')) return None if not change.can_revert(): messages.error(request, _('Can not revert to empty translation!')) return None # Store unit unit.translate( request.user, change.old, unit.state, change_action=Change.ACTION_REVERT ) # Redirect to next entry return HttpResponseRedirect(next_unit_url)
def perform_suggestion(unit, form, request): ''' Handle suggesion saving. ''' if form.cleaned_data['target'][0] == '': messages.error(request, _('Your suggestion is empty!')) # Stay on same entry return False elif not can_suggest(request.user, unit.translation): # Need privilege to add messages.error( request, _('You don\'t have privileges to add suggestions!') ) # Stay on same entry return False # Invite user to become translator if there is nobody else recent_changes = Change.objects.content(True).filter( translation=unit.translation, ).exclude( user=None ) if not recent_changes.exists(): messages.info(request, _( 'There is currently no active translator for this ' 'translation, please consider becoming a translator ' 'as your suggestion might otherwise remain unreviewed.' )) # Create the suggestion result = Suggestion.objects.add( unit, join_plural(form.cleaned_data['target']), request, ) if not result: messages.error(request, _('Your suggestion already exists!')) return result
def handle_revert(unit, request, next_unit_url): revertform = RevertForm(unit, request.GET) if not revertform.is_valid(): messages.error(request, _("Invalid revert request!")) return None change = revertform.cleaned_data["revert_change"] if not request.user.has_perm("unit.edit", unit): messages.error(request, _("Insufficient privileges for saving translations.")) return None if not change.can_revert(): messages.error(request, _("Can not revert to empty translation!")) return None # Store unit unit.translate( request.user, change.old, STATE_FUZZY if change.action == Change.ACTION_MARKED_EDIT else unit.state, change_action=Change.ACTION_REVERT, ) # Redirect to next entry return HttpResponseRedirect(next_unit_url)
def auth_fail(request, message): messages.error(request, message) return redirect(reverse('login'))
def save_backend(self, request, propagate=True, gen_change=True, change_action=None, user=None): """ Stores unit to backend. Optional user parameters defines authorship of a change. """ # For case when authorship specified, use user from request if user is None or user.is_anonymous: user = request.user # Update lock timestamp self.update_lock(request, user, change_action) # Store to backend try: (saved, pounit) = self.translation.update_unit(self, request, user) except FileLockException: self.log_error('failed to lock backend for %s!', self) messages.error( request, _('Failed to store message in the backend, ' 'lock timeout occurred!')) return False # Handle situation when backend did not find the message if pounit is None: self.log_error('message %s disappeared!', self) messages.error( request, _('Message not found in backend storage, ' 'it is probably corrupted.')) # Try reloading from backend self.translation.check_sync(True) return False # Return if there was no change # We have to explicitly check for fuzzy flag change on monolingual # files, where we handle it ourselves without storing to backend if (not saved and self.old_unit.fuzzy == self.fuzzy and self.old_unit.target == self.target): # Propagate if we should if propagate: self.propagate(request, change_action) return False # Update translated flag self.translated = pounit.is_translated() # Update comments as they might have been changed (eg, fuzzy flag # removed) self.flags = pounit.get_flags() if self.translation.is_template(): self.source = self.target self.content_hash = calculate_hash(self.source, self.context) # Save updated unit to database self.save(backend=True) # Update translation stats old_translated = self.translation.translated if change_action != Change.ACTION_UPLOAD: self.translation.update_stats() # Notify subscribed users about new translation notify_new_translation(self, self.old_unit, user) # Update user stats user.profile.translated += 1 user.profile.save() # Generate Change object for this change if gen_change: self.generate_change(request, user, self.old_unit, change_action) # Force commiting on completing translation if (old_translated < self.translation.translated and self.translation.translated == self.translation.total): self.translation.commit_pending(request) Change.objects.create(translation=self.translation, action=Change.ACTION_COMPLETE, user=user, author=user) # Update related source strings if working on a template if self.translation.is_template(): self.update_source_units(self.old_unit.source) # Propagate to other projects if propagate: self.propagate(request, change_action) return True
def translate(request, project, component, lang): """Generic entry point for translating, suggesting and searching.""" obj, project, unit_set = parse_params(request, project, component, lang) # Search results search_result = search(obj, unit_set, request) # Handle redirects if isinstance(search_result, HttpResponse): return search_result # Get numer of results num_results = len(search_result["ids"]) # Search offset offset = search_result["offset"] # Checksum unit access checksum_form = ChecksumForm(unit_set, request.GET or request.POST) if checksum_form.is_valid(): unit = checksum_form.cleaned_data["unit"] try: offset = search_result["ids"].index(unit.id) + 1 except ValueError: messages.warning(request, _("No string matched your search!")) return redirect(obj) else: # Check boundaries if not 0 < offset <= num_results: messages.info(request, _("The translation has come to an end.")) # Delete search del request.session[search_result["key"]] return redirect(obj) # Grab actual unit try: unit = unit_set.get(pk=search_result["ids"][offset - 1]) except Unit.DoesNotExist: # Can happen when using SID for other translation messages.error(request, _("Invalid search string!")) return redirect(obj) # Check locks locked = unit.translation.component.locked # Some URLs we will most likely use base_unit_url = "{}?{}&offset=".format(obj.get_translate_url(), search_result["url"]) this_unit_url = base_unit_url + str(offset) next_unit_url = base_unit_url + str(offset + 1) response = None # Any form submitted? if "skip" in request.POST: return redirect(next_unit_url) if request.method == "POST" and "merge" not in request.POST: if (not locked and "accept" not in request.POST and "accept_edit" not in request.POST and "delete" not in request.POST and "spam" not in request.POST and "upvote" not in request.POST and "downvote" not in request.POST): # Handle translation response = handle_translate(request, unit, this_unit_url, next_unit_url) elif not locked or "delete" in request.POST or "spam" in request.POST: # Handle accepting/deleting suggestions response = handle_suggestions(request, unit, this_unit_url, next_unit_url) # Handle translation merging elif "merge" in request.POST and not locked: response = handle_merge(unit, request, next_unit_url) # Handle reverting elif "revert" in request.GET and not locked: response = handle_revert(unit, request, this_unit_url) # Pass possible redirect further if response is not None: return response # Show secondary languages for signed in users if request.user.is_authenticated: secondary = unit.get_secondary_units(request.user) else: secondary = None # Spam protection antispam = AntispamForm() # Prepare form form = TranslationForm(request.user, unit) sort = get_sort_name(request) return render( request, "translate.html", { "this_unit_url": this_unit_url, "first_unit_url": base_unit_url + "1", "last_unit_url": base_unit_url + str(num_results), "next_unit_url": next_unit_url, "prev_unit_url": base_unit_url + str(offset - 1), "object": obj, "project": project, "unit": unit, "nearby": unit.nearby(request.user.profile.nearby_strings), "nearby_keys": unit.nearby_keys(request.user.profile.nearby_strings), "others": get_other_units(unit), "search_url": search_result["url"], "search_items": search_result["items"], "search_query": search_result["query"], "offset": offset, "sort_name": sort["name"], "sort_query": sort["query"], "filter_name": search_result["name"], "filter_count": num_results, "filter_pos": offset, "form": form, "antispam": antispam, "comment_form": CommentForm( project, initial={ "scope": "global" if unit.is_source else "translation" }, ), "context_form": ContextForm(instance=unit.source_unit, user=request.user), "search_form": search_result["form"].reset_offset(), "secondary": secondary, "locked": locked, "glossary": Term.objects.get_terms(unit), "addterm_form": TermForm(project), "last_changes": unit.change_set.prefetch().order()[:10], "screenshots": (unit.source_unit.screenshots.all() | unit.screenshots.all()).order, "last_changes_url": urlencode(unit.translation.get_reverse_url_kwargs()), "display_checks": list(get_display_checks(unit)), "machinery_services": json.dumps(list(MACHINE_TRANSLATION_SERVICES.keys())), }, )
def translate(request, project, component, lang): """Generic entry point for translating, suggesting and searching.""" translation = get_translation(request, project, component, lang) # Check locks locked = translation.component.locked # Search results search_result = search(translation, request) # Handle redirects if isinstance(search_result, HttpResponse): return search_result # Get numer of results num_results = len(search_result['ids']) # Search offset offset = search_result['offset'] # Checksum unit access if search_result['checksum']: try: unit = translation.unit_set.get(id_hash=search_result['checksum']) offset = search_result['ids'].index(unit.id) + 1 except (Unit.DoesNotExist, ValueError): messages.warning(request, _('No string matched your search!')) return redirect(translation) # Check boundaries if not 0 < offset <= num_results: messages.info(request, _('The translation has come to an end.')) # Delete search del request.session[search_result['key']] # Redirect to translation return redirect(translation) # Some URLs we will most likely use base_unit_url = '{0}?{1}&offset='.format( translation.get_translate_url(), search_result['url'] ) this_unit_url = base_unit_url + str(offset) next_unit_url = base_unit_url + str(offset + 1) response = None # Any form submitted? if 'skip' in request.POST: return redirect(next_unit_url) if request.method == 'POST': if (not locked and 'accept' not in request.POST and 'accept_edit' not in request.POST and 'delete' not in request.POST and 'spam' not in request.POST and 'upvote' not in request.POST and 'downvote' not in request.POST): # Handle translation response = handle_translate( request, translation, this_unit_url, next_unit_url ) elif not locked or 'delete' in request.POST or 'spam' in request.POST: # Handle accepting/deleting suggestions response = handle_suggestions( translation, request, this_unit_url, next_unit_url, ) # Handle translation merging elif 'merge' in request.GET and not locked: response = handle_merge( translation, request, next_unit_url ) # Handle reverting elif 'revert' in request.GET and not locked: response = handle_revert( translation, request, this_unit_url ) # Pass possible redirect further if response is not None: return response # Grab actual unit try: unit = translation.unit_set.get(pk=search_result['ids'][offset - 1]) except Unit.DoesNotExist: # Can happen when using SID for other translation messages.error(request, _('Invalid search string!')) return redirect(translation) # Show secondary languages for logged in users if request.user.is_authenticated: secondary = unit.get_secondary_units(request.user) else: secondary = None # Spam protection antispam = AntispamForm() # Prepare form form = TranslationForm(request.user, translation, unit) return render( request, 'translate.html', { 'this_unit_url': this_unit_url, 'first_unit_url': base_unit_url + '1', 'last_unit_url': base_unit_url + str(num_results), 'next_unit_url': next_unit_url, 'prev_unit_url': base_unit_url + str(offset - 1), 'object': translation, 'project': translation.component.project, 'unit': unit, 'others': get_other_units(unit), 'total': translation.unit_set.all().count(), 'search_url': search_result['url'], 'search_items': search_result['items'], 'search_query': search_result['query'], 'offset': offset, 'filter_name': search_result['name'], 'filter_count': num_results, 'filter_pos': offset, 'form': form, 'antispam': antispam, 'comment_form': CommentForm(), 'search_form': search_result['form'].reset_offset(), 'secondary': secondary, 'locked': locked, 'glossary': Dictionary.objects.get_words(unit), 'addword_form': InlineWordForm(), } )
def redirect_list(self, message=None): if message: messages.error(self.request, message) return redirect(self.get_success_url())
def search(request, project=None, component=None, lang=None): """Perform site-wide search on units.""" is_ratelimited = not check_rate_limit("search", request) search_form = SearchForm(user=request.user, data=request.GET) sort = get_sort_name(request) context = {"search_form": search_form} if component: obj = get_component(request, project, component) context["component"] = obj context["project"] = obj.project context["back_url"] = obj.get_absolute_url() elif project: obj = get_project(request, project) context["project"] = obj context["back_url"] = obj.get_absolute_url() else: obj = None context["back_url"] = None if lang: s_language = get_object_or_404(Language, code=lang) context["language"] = s_language if obj: if component: context["back_url"] = obj.translation_set.get( language=s_language).get_absolute_url() else: context["back_url"] = reverse("project-language", kwargs={ "project": project, "lang": lang }) else: context["back_url"] = s_language.get_absolute_url() if not is_ratelimited and request.GET and search_form.is_valid(): # This is ugly way to hide query builder when showing results search_form = SearchForm(user=request.user, data=request.GET, show_builder=False) search_form.is_valid() # Filter results by ACL units = Unit.objects.prefetch_full().prefetch() if component: units = units.filter(translation__component=obj) elif project: units = units.filter(translation__component__project=obj) else: units = units.filter_access(request.user) units = units.search(search_form.cleaned_data.get("q", ""), project=context.get("project")).distinct() if lang: units = units.filter(translation__language=context["language"]) units = get_paginator(request, units.order_by_request(search_form.cleaned_data)) # Rebuild context from scratch here to get new form context = { "search_form": search_form, "show_results": True, "page_obj": units, "title": _("Search for %s") % (search_form.cleaned_data["q"]), "query_string": search_form.urlencode(), "search_query": search_form.cleaned_data["q"], "search_items": search_form.items(), "filter_name": search_form.get_name(), "sort_name": sort["name"], "sort_query": sort["query"], } elif is_ratelimited: messages.error(request, _("Too many search queries, please try again later.")) elif request.GET: messages.error(request, _("Invalid search query!")) show_form_errors(request, search_form) return render(request, "search.html", context)
def search_replace(request, project, component=None, lang=None): obj, unit_set, context = parse_url(request, project, component, lang) form = ReplaceForm(request.POST) if not form.is_valid(): messages.error(request, _("Failed to process form!")) show_form_errors(request, form) return redirect(obj) search_text = form.cleaned_data["search"] replacement = form.cleaned_data["replacement"] matching = unit_set.filter(target__contains=search_text) updated = 0 if matching.exists(): confirm = ReplaceConfirmForm(matching, request.POST) limited = False if matching.count() > 300: matching = matching.order_by("id")[:250] limited = True if not confirm.is_valid(): for unit in matching: unit.replacement = unit.target.replace(search_text, replacement) context.update({ "matching": matching, "search_query": search_text, "replacement": replacement, "form": form, "limited": limited, "confirm": ReplaceConfirmForm(matching), }) return render(request, "replace.html", context) matching = confirm.cleaned_data["units"] with transaction.atomic(): for unit in matching.select_for_update(**get_nokey_args()): if not request.user.has_perm("unit.edit", unit): continue unit.translate( request.user, unit.target.replace(search_text, replacement), unit.state, change_action=Change.ACTION_REPLACE, ) updated += 1 import_message( request, updated, _("Search and replace completed, no strings were updated."), ngettext( "Search and replace completed, %d string was updated.", "Search and replace completed, %d strings were updated.", updated, ), ) return redirect(obj)
def upload_translation(request, project, subproject, lang): ''' Handling of translation uploads. ''' obj = get_translation(request, project, subproject, lang) if not can_upload_translation(request.user, obj): raise PermissionDenied() # Check method and lock if obj.is_locked(request.user): messages.error(request, _('Access denied.')) return redirect(obj) # Get correct form handler based on permissions form = get_upload_form( request.user, obj, request.POST, request.FILES ) # Check form validity if not form.is_valid(): messages.error(request, _('Please fix errors in the form.')) show_form_errors(request, form) return redirect(obj) # Create author name author = None if (can_author_translation(request.user, obj.subproject.project) and form.cleaned_data['author_name'] != '' and form.cleaned_data['author_email'] != ''): author = '%s <%s>' % ( form.cleaned_data['author_name'], form.cleaned_data['author_email'] ) # Check for overwriting overwrite = False if can_overwrite_translation(request.user, obj.subproject.project): overwrite = form.cleaned_data['overwrite'] # Do actual import try: ret, count = obj.merge_upload( request, request.FILES['file'], overwrite, author, merge_header=form.cleaned_data['merge_header'], merge_comments=form.cleaned_data['merge_comments'], method=form.cleaned_data['method'], fuzzy=form.cleaned_data['fuzzy'], ) import_message( request, count, _('No strings were imported from the uploaded file.'), ungettext( 'Processed %d string from the uploaded files.', 'Processed %d strings from the uploaded files.', count ) ) if not ret: messages.warning( request, _('There were no new strings in uploaded file!') ) except Exception as error: messages.error( request, _('File content merge failed: %s') % force_text(error) ) report_error(error, sys.exc_info(), request) return redirect(obj)