Example #1
0
    def do_upload(self, request, translation_project, directory):
        if self.form.is_valid() and 'file' in request.FILES:
            django_file = self.form.cleaned_data['file']
            overwrite = self.form.cleaned_data['overwrite']
            scan_translation_project_files(translation_project)
            oldstats = translation_project.getquickstats()
            # The URL relative to the URL of the translation project. Thus, if
            # directory.pootle_path == /af/pootle/foo/bar, then
            # relative_root_dir == foo/bar.
            if django_file.name.endswith('.zip'):
                archive = True
                upload_archive(request, directory, django_file, overwrite)
            else:
                archive = False
                upload_file(request, directory, django_file, overwrite)
            scan_translation_project_files(translation_project)
            newstats = translation_project.getquickstats()

            # create a submission, doesn't fix stats but at least
            # shows up in last activity column
            s = Submission(creation_time=datetime.datetime.utcnow(),
                           translation_project=translation_project,
                           submitter=get_profile(request.user))
            s.save()

            post_file_upload.send(sender=translation_project, user=request.user, oldstats=oldstats,
                                  newstats=newstats, archive=archive)
        return {'upload': self}
Example #2
0
    def toggle_qualitycheck(self, check_id, false_positive, user):
        check = self.qualitycheck_set.get(id=check_id)

        if check.false_positive == false_positive:
            return

        check.false_positive = false_positive
        check.save()

        self._log_user = user
        if false_positive:
            self._save_action = MUTE_QUALITYCHECK
        else:
            self._save_action = UNMUTE_QUALITYCHECK

        # create submission
        if false_positive:
            sub_type = SubmissionTypes.MUTE_CHECK
        else:
            sub_type = SubmissionTypes.UNMUTE_CHECK

        sub = Submission(creation_time=make_aware(timezone.now()),
                         translation_project=self.store.translation_project,
                         submitter=user, field=SubmissionFields.NONE,
                         unit=self, store=self.store, type=sub_type,
                         quality_check=check)
        sub.save()

        # update timestamp
        # log user action
        self.save()
Example #3
0
def submit(request, unit):
    """Processes translation submissions and stores them in the database.

    :return: An object in JSON notation that contains the previous and last
             units for the unit next to unit ``uid``.
    """
    json = {}

    translation_project = request.translation_project
    language = translation_project.language

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    # Store current time so that it is the same for all submissions
    current_time = timezone.now()

    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit, request=request)

    if form.is_valid():
        if form.updated_fields:
            for field, old_value, new_value in form.updated_fields:
                sub = Submission(
                    creation_time=current_time,
                    translation_project=translation_project,
                    submitter=request.profile,
                    unit=unit,
                    store=unit.store,
                    field=field,
                    type=SubmissionTypes.NORMAL,
                    old_value=old_value,
                    new_value=new_value,
                    similarity=form.cleaned_data["similarity"],
                    mt_similarity=form.cleaned_data["mt_similarity"],
                )
                sub.save()

            # Update current unit instance's attributes
            # important to set these attributes after saving Submission
            # because we need to access the unit's state before it was saved
            if SubmissionFields.TARGET in (f[0] for f in form.updated_fields):
                form.instance.submitted_by = request.profile
                form.instance.submitted_on = current_time
                form.instance.reviewed_by = None
                form.instance.reviewed_on = None

            form.instance._log_user = request.profile

            form.save()

            json["checks"] = _get_critical_checks_snippet(request, unit)

        json["user_score"] = request.profile.public_score

        return JsonResponse(json)

    return JsonResponseBadRequest({"msg": _("Failed to process submission.")})
Example #4
0
    def toggle_qualitycheck(self, check_id, false_positive, user):
        check = self.qualitycheck_set.get(id=check_id)

        if check.false_positive == false_positive:
            return

        self.revision = Revision.incr()
        self.save(
            reviewed_by=user)
        check.false_positive = false_positive
        check.save()

        # create submission
        old_value = MUTED
        new_value = UNMUTED
        if false_positive:
            old_value = UNMUTED
            new_value = MUTED

        update_time = make_aware(timezone.now())
        sub = Submission(
            creation_time=update_time,
            translation_project=self.store.translation_project,
            submitter=user,
            field=SubmissionFields.NONE,
            unit=self,
            type=SubmissionTypes.WEB,
            old_value=old_value,
            new_value=new_value,
            quality_check=check)
        sub.save()
Example #5
0
 def save(self, *args, **kwargs):
     changed_with = kwargs.pop("changed_with", None)
     kwargs["commit"] = False
     unit = super(UnitForm, self).save(*args, **kwargs)
     with update_data_after(unit.store):
         current_time = timezone.now()
         if SubmissionFields.TARGET in (f[0] for f in self.updated_fields):
             unit.submitted_by = self.user
             unit.submitted_on = current_time
             unit.reviewed_by = None
             unit.reviewed_on = None
         suggestion = self.cleaned_data["suggestion"]
         user = (
             suggestion.user
             if suggestion
             else self.user)
         unit.save(
             submitted_on=current_time,
             submitted_by=user,
             changed_with=changed_with)
         translation_project = unit.store.translation_project
         for field, old_value, new_value in self.updated_fields:
             if field == SubmissionFields.TARGET and suggestion:
                 old_value = str(suggestion.target_f)
             sub = Submission(
                 creation_time=current_time,
                 translation_project=translation_project,
                 submitter=self.user,
                 unit=unit,
                 field=field,
                 type=SubmissionTypes.WEB,
                 old_value=old_value,
                 new_value=new_value)
             sub.save()
     return unit
Example #6
0
def submit(request, unit):
    """Processes translation submissions and stores them in the database.

    :return: An object in JSON notation that contains the previous and last
             units for the unit next to unit ``uid``.
    """
    json = {}

    cantranslate = check_permission("translate", request)
    if not cantranslate:
        raise PermissionDenied(_("You do not have rights to access "
                                 "translation mode."))

    translation_project = request.translation_project
    language = translation_project.language

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    # Update current unit instance's attributes
    unit.submitted_by = request.profile
    unit.submitted_on = datetime.utcnow()

    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit)

    if form.is_valid():
        if form.updated_fields:
            # Store creation time so that it is the same for all submissions
            creation_time=datetime.utcnow()
            for field, old_value, new_value in form.updated_fields:
                sub = Submission(
                        creation_time=creation_time,
                        translation_project=translation_project,
                        submitter=request.profile,
                        unit=unit,
                        field=field,
                        type=SubmissionTypes.NORMAL,
                        old_value=old_value,
                        new_value=new_value,
                )
                sub.save()

            form.save()
            translation_submitted.send(
                    sender=translation_project,
                    unit=form.instance,
                    profile=request.profile,
            )

        rcode = 200
    else:
        # Form failed
        #FIXME: we should display validation errors here
        rcode = 400
        json["msg"] = _("Failed to process submission.")
    response = jsonify(json)
    return HttpResponse(response, status=rcode, mimetype="application/json")
Example #7
0
def accept_suggestion(request, unit, suggid):
    json = {
        'udbid': unit.id,
        'sugid': suggid,
    }
    translation_project = request.translation_project

    if request.POST.get('accept'):
        try:
            suggestion = unit.suggestion_set.get(id=suggid)
        except ObjectDoesNotExist:
            raise Http404

        old_target = unit.target
        success = unit.accept_suggestion(suggid)

        json['newtargets'] = [highlight_whitespace(target)
                              for target in unit.target.strings]
        json['newdiffs'] = {}
        for sugg in unit.get_suggestions():
            json['newdiffs'][sugg.id] = \
                    [highlight_diffs(unit.target.strings[i], target)
                     for i, target in enumerate(sugg.target.strings)]

        if suggestion is not None and success:
            if suggestion.user:
                translation_submitted.send(sender=translation_project,
                                           unit=unit, profile=suggestion.user)

            # FIXME: we need a totally different model for tracking stats, this
            # is just lame
            suggstat, created = SuggestionStat.objects.get_or_create(
                    translation_project=translation_project,
                    suggester=suggestion.user,
                    state='pending',
                    unit=unit.id,
            )
            suggstat.reviewer = request.profile
            suggstat.state = 'accepted'
            suggstat.save()

            # For now assume the target changed
            # TODO: check all fields for changes
            creation_time = timezone.now()
            sub = Submission(
                    creation_time=creation_time,
                    translation_project=translation_project,
                    submitter=suggestion.user,
                    from_suggestion=suggstat,
                    unit=unit,
                    field=SubmissionFields.TARGET,
                    type=SubmissionTypes.SUGG_ACCEPT,
                    old_value=old_target,
                    new_value=unit.target,
            )
            sub.save()

    response = jsonify(json)
    return HttpResponse(response, mimetype="application/json")
Example #8
0
def process_submit(request, unit, type):
    """
    Processes submissions and suggestions and stores them in the database.

    @return: An object in JSON notation that contains the previous
    and last units for the unit next to unit C{uid}.
    """
    json = {}
    cantranslate = check_permission("translate", request)
    cansuggest = check_permission("suggest", request)
    if type == "submission" and not cantranslate or type == "suggestion" and not cansuggest:
        raise PermissionDenied(_("You do not have rights to access translation mode."))

    translation_project = request.translation_project
    language = translation_project.language

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit)

    if form.is_valid():
        if type == "submission":
            if (
                form.instance._target_updated
                or form.instance._translator_comment_updated
                or form.instance._state_updated
            ):
                form.save()
                translation_submitted.send(sender=translation_project, unit=form.instance, profile=request.profile)

                sub = Submission(translation_project=translation_project, submitter=request.profile)
                sub.save()
        elif type == "suggestion":
            if form.instance._target_updated:
                # HACKISH: django 1.2 stupidly modifies instance on
                # model form validation, reload unit from db
                unit = Unit.objects.get(id=unit.id)
                sugg = unit.add_suggestion(form.cleaned_data["target_f"], request.profile)
                if sugg:
                    SuggestionStat.objects.get_or_create(
                        translation_project=translation_project,
                        suggester=request.profile,
                        state="pending",
                        unit=unit.id,
                    )
        rcode = 200
    else:
        # Form failed
        # FIXME: we should display validation errors here
        rcode = 400
        json["msg"] = _("Failed to process submit.")
    response = jsonify(json)
    return HttpResponse(response, status=rcode, mimetype="application/json")
Example #9
0
def _handle_upload_form(request, translation_project):
    """Process the upload form in TP overview."""
    from pootle_app.signals import post_file_upload

    upload_form_class = upload_form_factory(request)

    if request.method == 'POST' and 'file' in request.FILES:
        upload_form = upload_form_class(request.POST, request.FILES)

        if not upload_form.is_valid():
            return upload_form
        else:
            django_file = upload_form.cleaned_data['file']
            overwrite = upload_form.cleaned_data['overwrite']
            upload_to = upload_form.cleaned_data['upload_to']
            upload_to_dir = upload_form.cleaned_data['upload_to_dir']

            # XXX Why do we scan here?
            translation_project.scan_files(vcs_sync=False)
            oldstats = translation_project.get_stats()

            # The URL relative to the URL of the translation project. Thus, if
            # directory.pootle_path == /af/pootle/foo/bar, then
            # relative_root_dir == foo/bar.
            if django_file.name.endswith('.zip'):
                archive = True
                target_directory = upload_to_dir or request.directory
                upload_archive(request, target_directory, django_file,
                               overwrite)
            else:
                archive = False
                upload_file(request, request.directory, django_file, overwrite,
                            store=upload_to)

            translation_project.scan_files(vcs_sync=False)
            newstats = translation_project.get_stats()

            # Create a submission. Doesn't fix stats but at least shows up in
            # last activity column.
            from django.utils import timezone
            s = Submission(
                creation_time=timezone.now(),
                translation_project=translation_project,
                submitter=request.user,
                type=SubmissionTypes.UPLOAD,
                # The other fields are only relevant to unit-based changes.
            )
            s.save()

            post_file_upload.send(sender=translation_project,
                                  user=request.user, oldstats=oldstats,
                                  newstats=newstats, archive=archive)

    # Always return a blank upload form unless the upload form is not valid.
    return upload_form_class()
Example #10
0
def _create_comment_submission(unit, user, creation_time, comment):
    sub = Submission(
        creation_time=creation_time,
        translation_project=unit.store.translation_project,
        submitter=user,
        unit=unit,
        field=SubmissionFields.COMMENT,
        type=SubmissionTypes.WEB,
        new_value=comment,
    )
    sub.save()
    return sub
Example #11
0
def accept_suggestion(request, uid, suggid):
    unit = get_object_or_404(Unit, id=uid)
    directory = unit.store.parent
    translation_project = unit.store.translation_project

    if not check_profile_permission(
        get_profile(request.user), 'review', directory):
        raise PermissionDenied

    response = {
        'udbid': unit.id,
        'sugid': suggid,
        }

    if request.POST.get('accept'):
        try:
            suggestion = unit.suggestion_set.get(id=suggid)
        except ObjectDoesNotExist:
            suggestion = None

        response['success'] = unit.accept_suggestion(suggid)
        response['newtargets'] = [
            highlight_whitespace(target) for target in unit.target.strings]
        response['newdiffs'] = {}
        for sugg in unit.get_suggestions():
            response['newdiffs'][sugg.id] = [
                highlight_diffs(unit.target.strings[i], target) \
                for i, target in enumerate(sugg.target.strings)]

        if suggestion is not None and response['success']:
            if suggestion.user:
                translation_submitted.send(
                    sender=translation_project, unit=unit,
                    profile=suggestion.user)
            # FIXME: we need a totally different model for tracking
            # stats, this is just lame
            suggstat, created = SuggestionStat.objects.get_or_create(
                translation_project=translation_project,
                suggester=suggestion.user,
                state='pending',
                unit=unit.id)
            suggstat.reviewer = get_profile(request.user)
            suggstat.state = 'accepted'
            suggstat.save()

            sub = Submission(translation_project=translation_project,
                             submitter=get_profile(request.user),
                             from_suggestion=suggstat)
            sub.save()

    response = simplejson.dumps(response)
    return HttpResponse(response, mimetype="application/json")
Example #12
0
def accept_suggestion(request, uid, suggid):
    json = {}
    try:
        unit = Unit.objects.get(id=uid)
        directory = unit.store.parent
        translation_project = unit.store.translation_project
        profile = get_profile(request.user)

        if not check_profile_permission(profile, 'review', directory):
            json["success"] = False
            json["msg"] = _("You do not have rights to access review mode.")
        else:
            json["udbid"] = unit.id
            json["sugid"] = suggid
            if request.POST.get('accept'):
                try:
                    sugg = unit.suggestion_set.get(id=suggid)
                except ObjectDoesNotExist:
                    sugg = None

                json['success'] = unit.accept_suggestion(suggid)
                json['newtargets'] = [highlight_whitespace(target) for target in unit.target.strings]
                json['newdiffs'] = {}
                for sugg in unit.get_suggestions():
                    json['newdiffs'][sugg.id] = [highlight_diffs(unit.target.strings[i], target) \
                                                     for i, target in enumerate(sugg.target.strings)]

                if sugg is not None and json['success']:
                    #FIXME: we need a totally different model for tracking stats, this is just lame
                    suggstat, created = SuggestionStat.objects.get_or_create(translation_project=translation_project,
                                                                    suggester=sugg.user,
                                                                    state='pending',
                                                                    unit=unit.id)
                    suggstat.reviewer = profile
                    suggstat.state = 'accepted'
                    suggstat.save()

                    sub = Submission(translation_project=translation_project,
                                     submitter=profile,
                                     from_suggestion=suggstat)
                    sub.save()
    except Unit.DoesNotExist:
        json["success"] = False
        json["msg"] = _("Unit %(uid)s does not exist." %
                        {'uid': uid})

    response = simplejson.dumps(json)
    return HttpResponse(response, mimetype="application/json")
Example #13
0
def _create_comment_on_unit(unit, user, comment):
    from pootle_statistics.models import (Submission, SubmissionFields,
                                          SubmissionTypes)

    unit.translator_comment = comment
    unit.save(user=user)
    sub = Submission(
        creation_time=unit.change.commented_on,
        translation_project=unit.store.translation_project,
        submitter=user,
        unit=unit,
        field=SubmissionFields.COMMENT,
        type=SubmissionTypes.WEB,
        new_value=comment,
    )
    sub.save()
Example #14
0
def _mark_unit_fuzzy(unit, user):
    from pootle_store.constants import FUZZY
    from pootle_statistics.models import (Submission, SubmissionFields,
                                          SubmissionTypes)
    unit.markfuzzy()
    unit.save()
    sub = Submission(
        creation_time=unit.mtime,
        translation_project=unit.store.translation_project,
        submitter=user,
        unit=unit,
        field=SubmissionFields.STATE,
        type=SubmissionTypes.WEB,
        old_value=unit.state,
        new_value=FUZZY,
    )
    sub.save()
Example #15
0
    def GET(self, template_vars, request, translation_project, directory,
            store=None):
        can_edit = check_permission('administrate', request)

        project = translation_project.project
        language = translation_project.language

        path_obj = store or directory

        path_stats = get_raw_stats(path_obj, include_suggestions=True)
        path_summary = get_path_summary(path_obj, path_stats)
        actions = action_groups(request, path_obj, path_stats=path_stats)

        template_vars.update({
            'translation_project': translation_project,
            'project': project,
            'language': language,
            'directory': directory,
            'path_summary': path_summary,
            'stats': path_stats,
            'topstats': gentopstats_translation_project(translation_project),
            'feed_path': directory.pootle_path[1:],
            'action_groups': actions,
            'can_edit': can_edit,
        })

        if store is not None:
            template_vars.update({
                'store': store
            })
        else:
            table_fields = ['name', 'progress', 'total', 'need-translation',
                            'suggestions']
            template_vars.update({
                'table': {
                    'id': 'tp',
                    'proportional': True,
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'items': get_children(translation_project, directory),
                }
            })

            # If current directory is the TP root directory.
            if not directory.path:
                template_vars.update({
                    'latest_action': translation_project.get_latest_submission()
                })
            else:
                template_vars.update({
                    'latest_action': Submission.get_latest_for_dir(path_obj)
                })

        if can_edit:
            from pootle_translationproject.forms import DescriptionForm
            template_vars['form'] = DescriptionForm(instance=translation_project)

        return template_vars
Example #16
0
        def save(self, **kwargs):
            """Register the submission and save the comment."""
            if self.has_changed():
                creation_time = timezone.now()
                translation_project = self.request.translation_project

                sub = Submission(
                    creation_time=creation_time,
                    translation_project=translation_project,
                    submitter=self.request.user,
                    unit=self.instance,
                    field=SubmissionFields.COMMENT,
                    type=SubmissionTypes.WEB,
                    old_value=self.previous_value,
                    new_value=self.cleaned_data['translator_comment']
                )
                sub.save()
            super(UnitCommentForm, self).save(**kwargs)
Example #17
0
File: views.py Project: kant/pootle
    def do_upload(self, request, translation_project, directory, store):

        if self.form.is_valid() and 'file' in request.FILES:
            django_file = self.form.cleaned_data['file']
            overwrite = self.form.cleaned_data['overwrite']
            upload_to = self.form.cleaned_data['upload_to']
            upload_to_dir = self.form.cleaned_data['upload_to_dir']
            # XXX Why do we scan here?
            translation_project.scan_files(vcs_sync=False)
            oldstats = translation_project.getquickstats()

            # The URL relative to the URL of the translation project. Thus, if
            # directory.pootle_path == /af/pootle/foo/bar, then
            # relative_root_dir == foo/bar.
            if django_file.name.endswith('.zip'):
                archive = True
                target_directory = upload_to_dir or directory
                upload_archive(request, target_directory, django_file,
                               overwrite)
            else:
                archive = False
                upload_file(request, directory, django_file, overwrite,
                            store=upload_to)

            translation_project.scan_files(vcs_sync=False)
            newstats = translation_project.getquickstats()

            # create a submission, doesn't fix stats but at least
            # shows up in last activity column
            from django.utils import timezone
            s = Submission(
                    creation_time=timezone.now(),
                    translation_project=translation_project,
                    submitter=get_profile(request.user),
                    type=SubmissionTypes.UPLOAD,
                    # the other fields are only relevant to unit-based changes
            )
            s.save()

            post_file_upload.send(
                    sender=translation_project, user=request.user,
                    oldstats=oldstats, newstats=newstats, archive=archive)

        return {'upload': self}
Example #18
0
 def save_unit(self):
     user = self.request_user
     current_time = make_aware(timezone.now())
     updated = []
     target = multistring(self.cleaned_data["target_f"] or [u''])
     if target != self.unit.target:
         self.unit.submitted_by = user
         self.unit.submitted_on = current_time
         self.unit.reviewed_by = None
         self.unit.reviewed_on = None
         updated.append(
             (SubmissionFields.TARGET,
              self.unit.target_f,
              self.cleaned_data["target_f"]))
         self.unit.target = self.cleaned_data["target_f"]
     if self.unit.target:
         if self.cleaned_data["is_fuzzy"]:
             self.unit.state = FUZZY
         else:
             self.unit.state = TRANSLATED
     else:
         self.unit.state = UNTRANSLATED
     self.unit.save(
         submitted_on=current_time,
         submitted_by=user,
         changed_with=SubmissionTypes.WEB)
     if self.unit.state_updated:
         updated.append(
             (SubmissionFields.STATE,
              self.unit._frozen.state,
              self.unit.state))
     translation_project = self.unit.store.translation_project
     for field, old_value, new_value in updated:
         sub = Submission(
             creation_time=current_time,
             translation_project=translation_project,
             submitter=user,
             unit=self.unit,
             field=field,
             type=SubmissionTypes.WEB,
             old_value=old_value,
             new_value=new_value)
         sub.save()
Example #19
0
def _mark_unit_fuzzy(unit, user):
    from pootle_store.util import FUZZY
    from pootle_statistics.models import (Submission, SubmissionFields,
                                          SubmissionTypes)
    sub = Submission(
        creation_time=unit.commented_on,
        translation_project=unit.store.translation_project,
        submitter=user,
        unit=unit,
        store=unit.store,
        field=SubmissionFields.STATE,
        type=SubmissionTypes.NORMAL,
        old_value=unit.state,
        new_value=FUZZY,
    )
    sub.save()
    unit.markfuzzy()
    unit._state_updated = True
    unit.save()
Example #20
0
        def save(self):
            """Registers the submission and saves the comment."""
            if self.has_changed():
                creation_time = timezone.now()
                translation_project = self.request.translation_project

                sub = Submission(
                    creation_time=creation_time,
                    translation_project=translation_project,
                    submitter=self.request.profile,
                    unit=self.instance,
                    field=SubmissionFields.COMMENT,
                    type=SubmissionTypes.NORMAL,
                    old_value=u"",
                    new_value=self.cleaned_data['translator_comment']
                )
                sub.save()

            super(UnitCommentForm, self).save()
Example #21
0
def _create_comment_on_unit(unit, user, comment):
    from pootle_statistics.models import Submission, SubmissionFields, SubmissionTypes

    unit.translator_comment = comment
    unit.commented_on = timezone.now()
    unit.commented_by = user
    sub = Submission(
        creation_time=unit.commented_on,
        translation_project=unit.store.translation_project,
        submitter=user,
        unit=unit,
        store=unit.store,
        field=SubmissionFields.COMMENT,
        type=SubmissionTypes.NORMAL,
        new_value=comment,
    )
    sub.save()
    unit._comment_updated = True
    unit.save()
Example #22
0
 def create_submission(self, suggestion, suggestion_type, user, **kwargs):
     return Submission(
         creation_time=kwargs.get("creation_time",
                                  suggestion.creation_time),
         translation_project=suggestion.unit.store.translation_project,
         submitter=user,
         unit=suggestion.unit,
         store=suggestion.unit.store,
         type=suggestion_type,
         suggestion=suggestion)
Example #23
0
def accept_suggestion(request, unit, suggid):
    json = {}
    translation_project = request.translation_project
    json["udbid"] = unit.id
    json["sugid"] = suggid
    if request.POST.get('accept'):
        try:
            suggestion = unit.suggestion_set.get(id=suggid)
        except ObjectDoesNotExist:
            raise Http404

        success = unit.accept_suggestion(suggid)
        json['newtargets'] = [
            highlight_whitespace(target) for target in unit.target.strings
        ]
        json['newdiffs'] = {}
        for sugg in unit.get_suggestions():
            json['newdiffs'][sugg.id] = [highlight_diffs(unit.target.strings[i], target) \
                                         for i, target in enumerate(sugg.target.strings)]

        if suggestion is not None and success:
            if suggestion.user:
                translation_submitted.send(sender=translation_project,
                                           unit=unit,
                                           profile=suggestion.user)
            #FIXME: we need a totally different model for tracking stats, this is just lame
            if suggestion.user != request.profile:
                suggstat, created = SuggestionStat.objects.get_or_create(
                    translation_project=translation_project,
                    suggester=suggestion.user,
                    state='pending',
                    unit=unit.id)
                suggstat.reviewer = request.profile
                suggstat.state = 'accepted'
                suggstat.save()
            else:
                suggstat = None
            sub = Submission(translation_project=translation_project,
                             submitter=suggestion.user,
                             from_suggestion=suggstat)
            sub.save()
    response = jsonify(json)
    return HttpResponse(response, mimetype="application/json")
Example #24
0
        def save(self):
            """Registers the submission and saves the comment."""
            if self.has_changed():
                creation_time = timezone.now()
                translation_project = self.request.translation_project

                sub = Submission(
                    creation_time=creation_time,
                    translation_project=translation_project,
                    submitter=self.request.profile,
                    unit=self.instance,
                    field=SubmissionFields.COMMENT,
                    type=SubmissionTypes.NORMAL,
                    old_value=u"",
                    new_value=self.cleaned_data['translator_comment']
                )
                sub.save()

            super(UnitCommentForm, self).save()
Example #25
0
def _mark_unit_fuzzy(unit, user):
    from pootle_store.util import FUZZY
    from pootle_statistics.models import (Submission, SubmissionFields,
                                          SubmissionTypes)
    sub = Submission(
        creation_time=unit.commented_on,
        translation_project=unit.store.translation_project,
        submitter=user,
        unit=unit,
        store=unit.store,
        field=SubmissionFields.STATE,
        type=SubmissionTypes.NORMAL,
        old_value=unit.state,
        new_value=FUZZY,
    )
    sub.save()
    unit.markfuzzy()
    unit._state_updated = True
    unit.save()
Example #26
0
    def accept_suggestion(self, suggestion):
        unit = suggestion.unit
        translation_project = unit.store.translation_project

        # Save for later
        old_state = unit.state
        old_target = unit.target

        # Update some basic attributes so we can create submissions. Note
        # these do not conflict with `ScoreLog`'s interests, so it's safe
        unit.target = suggestion.target
        if unit.state == FUZZY:
            unit.state = TRANSLATED

        current_time = timezone.now()
        suggestion.state = SuggestionStates.ACCEPTED
        suggestion.reviewer = self.reviewer
        suggestion.review_time = current_time
        suggestion.save()
        create_subs = OrderedDict()
        if old_state != unit.state:
            create_subs[SubmissionFields.STATE] = [old_state, unit.state]
        create_subs[SubmissionFields.TARGET] = [old_target, unit.target]
        subs_created = []
        for field in create_subs:
            kwargs = {
                'creation_time': current_time,
                'translation_project': translation_project,
                'submitter': self.reviewer,
                'unit': unit,
                'store': unit.store,
                'field': field,
                'type': SubmissionTypes.SUGG_ACCEPT,
                'old_value': create_subs[field][0],
                'new_value': create_subs[field][1],
            }
            if field == SubmissionFields.TARGET:
                kwargs['suggestion'] = suggestion

            subs_created.append(Submission(**kwargs))
        if subs_created:
            unit.submission_set.add(*subs_created, bulk=False)

        # FIXME: remove such a dependency on `ScoreLog`
        # Update current unit instance's attributes
        # important to set these attributes after saving Submission
        # because in the `ScoreLog` we need to access the unit's certain
        # attributes before it was saved
        # THIS NEEDS TO GO ^^
        unit.submitted_by = suggestion.user
        unit.submitted_on = current_time
        unit.reviewed_by = self.reviewer
        unit.reviewed_on = unit.submitted_on
        unit._log_user = self.reviewer
        unit.save()
Example #27
0
        def save(self, **kwargs):
            """Register the submission and save the comment."""
            if self.has_changed():
                self.instance._comment_updated = True
                creation_time = timezone.now()
                translation_project = self.request.translation_project

                sub = Submission(
                    creation_time=creation_time,
                    translation_project=translation_project,
                    submitter=self.request.user,
                    unit=self.instance,
                    store=self.instance.store,
                    field=SubmissionFields.COMMENT,
                    type=SubmissionTypes.NORMAL,
                    old_value=self.previous_value,
                    new_value=self.cleaned_data['translator_comment'])
                sub.save()

            super(UnitCommentForm, self).save(**kwargs)
Example #28
0
def _create_comment_on_unit(unit, user, comment):
    from pootle_statistics.models import (Submission, SubmissionFields,
                                          SubmissionTypes)

    unit.translator_comment = comment
    unit.commented_on = timezone.now()
    unit.commented_by = user
    sub = Submission(
        creation_time=unit.commented_on,
        translation_project=unit.store.translation_project,
        submitter=user,
        unit=unit,
        store=unit.store,
        field=SubmissionFields.COMMENT,
        type=SubmissionTypes.NORMAL,
        new_value=comment,
    )
    sub.save()
    unit._comment_updated = True
    unit.save()
Example #29
0
        def save(self, **kwargs):
            """Register the submission and save the comment."""
            if self.has_changed():
                self.instance._comment_updated = True
                creation_time = timezone.now()
                translation_project = self.request.translation_project

                sub = Submission(
                    creation_time=creation_time,
                    translation_project=translation_project,
                    submitter=self.request.profile,
                    unit=self.instance,
                    store=self.instance.store,
                    field=SubmissionFields.COMMENT,
                    type=SubmissionTypes.NORMAL,
                    old_value=self.previous_value,
                    new_value=self.cleaned_data["translator_comment"],
                )
                sub.save()

            super(UnitCommentForm, self).save(**kwargs)
Example #30
0
    def do_upload(self, request, translation_project, directory):
        if self.form.is_valid() and 'file' in request.FILES:
            django_file = self.form.cleaned_data['file']
            overwrite = self.form.cleaned_data['overwrite']
            upload_to = self.form.cleaned_data['upload_to']
            upload_to_dir = self.form.cleaned_data['upload_to_dir']
            translation_project.scan_files()
            oldstats = translation_project.getquickstats()
            # The URL relative to the URL of the translation project. Thus, if
            # directory.pootle_path == /af/pootle/foo/bar, then
            # relative_root_dir == foo/bar.
            if django_file.name.endswith('.zip'):
                archive = True
                target_directory = upload_to_dir or directory
                upload_archive(request, target_directory, django_file,
                               overwrite)
            else:
                archive = False
                upload_file(request,
                            directory,
                            django_file,
                            overwrite,
                            store=upload_to)
            translation_project.scan_files()
            newstats = translation_project.getquickstats()

            # create a submission, doesn't fix stats but at least
            # shows up in last activity column
            s = Submission(creation_time=datetime.datetime.utcnow(),
                           translation_project=translation_project,
                           submitter=get_profile(request.user))
            s.save()

            post_file_upload.send(sender=translation_project,
                                  user=request.user,
                                  oldstats=oldstats,
                                  newstats=newstats,
                                  archive=archive)
        return {'upload': self}
Example #31
0
 def save_unit(self):
     current_time = make_aware(timezone.now())
     updated = []
     if self.cleaned_data["target_f"]:
         self.unit.target = self.cleaned_data["target_f"]
         self.unit.save(
             submitted_on=current_time,
             submitted_by=self.target_object.user,
             reviewed_on=current_time,
             reviewed_by=self.request_user,
             changed_with=SubmissionTypes.WEB)
         updated.append(
             (SubmissionFields.TARGET,
              self.unit._frozen.target,
              self.unit.target))
     if self.unit.state_updated:
         updated.append(
             (SubmissionFields.STATE,
              self.unit._frozen.state,
              self.unit.state))
     translation_project = self.unit.store.translation_project
     for field, old_value, new_value in updated:
         sub = Submission(
             creation_time=current_time,
             translation_project=translation_project,
             suggestion=self.target_object,
             submitter=self.target_object.user,
             unit=self.unit,
             field=field,
             type=SubmissionTypes.WEB,
             old_value=old_value,
             new_value=new_value)
         sub.save()
     self.suggestion_review.accept(
         update_unit=(
             False
             if self.cleaned_data["target_f"]
             else True))
Example #32
0
def accept_suggestion(request, unit, suggid):
    json = {}
    translation_project = request.translation_project
    json["udbid"] = unit.id
    json["sugid"] = suggid
    if request.POST.get('accept'):
        try:
            suggestion = unit.suggestion_set.get(id=suggid)
        except ObjectDoesNotExist:
            raise Http404

        success = unit.accept_suggestion(suggid)
        json['newtargets'] = [highlight_whitespace(target) for target in unit.target.strings]
        json['newdiffs'] = {}
        for sugg in unit.get_suggestions():
            json['newdiffs'][sugg.id] = [highlight_diffs(unit.target.strings[i], target) \
                                         for i, target in enumerate(sugg.target.strings)]

        if suggestion is not None and success:
            if suggestion.user:
                translation_submitted.send(sender=translation_project, unit=unit, profile=suggestion.user)
            #FIXME: we need a totally different model for tracking stats, this is just lame
            if suggestion.user != request.profile:
                suggstat, created = SuggestionStat.objects.get_or_create(translation_project=translation_project,
                                                                     suggester=suggestion.user,
                                                                     state='pending',
                                                                     unit=unit.id)
                suggstat.reviewer = request.profile
                suggstat.state = 'accepted'
                suggstat.save()
            else:
                suggstat = None
            sub = Submission(translation_project=translation_project,
                             submitter=suggestion.user,
                             from_suggestion=suggstat)
            sub.save()
    response = jsonify(json)
    return HttpResponse(response, mimetype="application/json")
Example #33
0
    def record_submissions(self,
                           unit,
                           old_target,
                           old_state,
                           current_time,
                           user,
                           submission_type=None,
                           **kwargs):
        """Records all applicable submissions for `unit`.

        EXTREME HAZARD: this relies on implicit `._<field>_updated` members
        being available in `unit`. Let's look into replacing such members with
        something saner (#3895).
        """
        state_updated = kwargs.get("state_updated") or unit._state_updated
        target_updated = kwargs.get("target_updated") or unit._target_updated
        comment_updated = kwargs.get(
            "comment_updated") or unit._comment_updated

        create_subs = OrderedDict()

        if state_updated:
            create_subs[SubmissionFields.STATE] = [old_state, unit.state]

        if target_updated:
            create_subs[SubmissionFields.TARGET] = [old_target, unit.target_f]

        if comment_updated:
            create_subs[SubmissionFields.COMMENT] = [
                '', unit.translator_comment or ''
            ]

        if submission_type is None:
            submission_type = SubmissionTypes.SYSTEM

        subs_created = []
        for field in create_subs:
            subs_created.append(
                Submission(creation_time=current_time,
                           translation_project_id=self.translation_project_id,
                           submitter=user,
                           unit=unit,
                           store_id=self.id,
                           field=field,
                           type=submission_type,
                           old_value=create_subs[field][0],
                           new_value=create_subs[field][1]))
        if subs_created:
            unit.submission_set.add(*subs_created, bulk=False)
Example #34
0
    def record_submissions(self,
                           unit,
                           old_target,
                           old_state,
                           current_time,
                           user,
                           submission_type=None,
                           **kwargs):
        """Records all applicable submissions for `unit`.
        """
        state_updated = kwargs.get("state_updated")
        target_updated = kwargs.get("target_updated")
        comment_updated = kwargs.get("comment_updated")
        create_subs = OrderedDict()

        if state_updated:
            create_subs[SubmissionFields.STATE] = [old_state, unit.state]

        if target_updated:
            create_subs[SubmissionFields.TARGET] = [old_target, unit.target_f]

        if comment_updated:
            create_subs[SubmissionFields.COMMENT] = [
                '', unit.translator_comment or ''
            ]

        if submission_type is None:
            submission_type = SubmissionTypes.SYSTEM

        subs_created = []
        for field in create_subs:
            subs_created.append(
                Submission(creation_time=current_time,
                           translation_project_id=self.translation_project_id,
                           submitter=user,
                           unit=unit,
                           revision=unit.revision,
                           store_id=self.id,
                           field=field,
                           type=submission_type,
                           old_value=create_subs[field][0],
                           new_value=create_subs[field][1]))
        if subs_created:
            unit.submission_set.add(*subs_created, bulk=False)
Example #35
0
def translate_page(request, units_queryset, store=None):
    if not check_permission("view", request):
        raise PermissionDenied(
            _("You do not have rights to access this translation project."))

    cantranslate = check_permission("translate", request)
    cansuggest = check_permission("suggest", request)
    canreview = check_permission("review", request)
    translation_project = request.translation_project
    language = translation_project.language
    # shouldn't we globalize profile context
    profile = get_profile(request.user)

    step_queryset = None

    # Process search first
    search_form = None
    if 'search' in request.GET and 'sfields' in request.GET:
        search_form = SearchForm(request.GET)
        if search_form.is_valid():
            step_queryset = get_search_step_query(request.translation_project,
                                                  search_form, units_queryset)
    else:
        search_form = SearchForm()

    # which units are we interested in?
    if step_queryset is None:
        step_queryset = get_step_query(request, units_queryset)

    prev_unit, edit_unit, pager = get_current_units(request, step_queryset,
                                                    units_queryset)

    # time to process POST submission
    form = None
    if prev_unit is not None and ('submit' in request.POST
                                  or 'suggest' in request.POST):
        # check permissions
        if 'submit'  in request.POST and not cantranslate or \
           'suggest' in request.POST and not cansuggest:
            raise PermissionDenied

        if prev_unit.hasplural():
            snplurals = len(prev_unit.source.strings)
        else:
            snplurals = None
        form_class = unit_form_factory(language, snplurals)
        form = form_class(request.POST, instance=prev_unit)
        if form.is_valid():
            if cantranslate and 'submit' in request.POST:
                if form.instance._target_updated or form.instance._translator_comment_updated or \
                       form.instance._state_updated:
                    form.save()
                    translation_submitted.send(sender=translation_project,
                                               unit=form.instance,
                                               profile=profile)

                    sub = Submission(translation_project=translation_project,
                                     submitter=get_profile(request.user))
                    sub.save()

            elif cansuggest and 'suggest' in request.POST:
                if form.instance._target_updated:
                    #HACKISH: django 1.2 stupidly modifies instance on
                    # model form validation, reload unit from db
                    prev_unit = Unit.objects.get(id=prev_unit.id)
                    sugg = prev_unit.add_suggestion(
                        form.cleaned_data['target_f'],
                        get_profile(request.user))
                    if sugg:
                        SuggestionStat.objects.get_or_create(
                            translation_project=translation_project,
                            suggester=get_profile(request.user),
                            state='pending',
                            unit=prev_unit.id)
        else:
            # form failed, don't skip to next unit
            edit_unit = prev_unit

    if edit_unit is None:
        # no more units to step through, display end of translation message
        return translate_end(request, translation_project)

    # only create form for edit_unit if prev_unit was processed successfully
    if form is None or form.is_valid():
        if edit_unit.hasplural():
            snplurals = len(edit_unit.source.strings)
        else:
            snplurals = None
        form_class = unit_form_factory(language, snplurals)
        form = form_class(instance=edit_unit)

    if store is None:
        store = edit_unit.store
        pager_query = units_queryset
        preceding = (pager_query.filter(store=store, index__lt=edit_unit.index) | \
                     pager_query.filter(store__pootle_path__lt=store.pootle_path)).count()
        store_preceding = store.units.filter(index__lt=edit_unit.index).count()
    else:
        pager_query = store.units
        preceding = pager_query.filter(index__lt=edit_unit.index).count()
        store_preceding = preceding

    unit_rows = profile.get_unit_rows()

    # regardless of the query used to step through units, we will
    # display units in their original context, and display a pager for
    # the store not for the unit_step query
    if pager is None:
        page = preceding / unit_rows + 1
        pager = paginate(request,
                         pager_query,
                         items=unit_rows,
                         page=page,
                         orphans=0)

    # we always display the active unit in the middle of the page to
    # provide context for translators
    context_rows = (unit_rows - 1) / 2
    if store_preceding > context_rows:
        unit_position = store_preceding % unit_rows
        page_length = pager.end_index() - pager.start_index() + 1
        if page_length < unit_rows:
            if pager.has_other_pages():
                units_query = store.units[page_length:]
            else:
                units_query = store.units
            page = store_preceding / unit_rows
            units = paginate(request,
                             units_query,
                             items=unit_rows,
                             page=page,
                             orphans=0).object_list
        elif unit_position < context_rows:
            # units too close to the top of the batch
            offset = unit_rows - (context_rows - unit_position)
            units_query = store.units[offset:]
            page = store_preceding / unit_rows
            units = paginate(request,
                             units_query,
                             items=unit_rows,
                             page=page,
                             orphans=0).object_list
        elif unit_position >= unit_rows - context_rows:
            # units too close to the bottom of the batch
            offset = context_rows - (unit_rows - unit_position - 1)
            units_query = store.units[offset:]
            page = store_preceding / unit_rows + 1
            units = paginate(request,
                             units_query,
                             items=unit_rows,
                             page=page,
                             orphans=0).object_list
        else:
            units = pager.object_list
    else:
        units = store.units[:unit_rows]

    # caluclate url querystring so state is retained on POST
    # we can't just use request URL cause unit and page GET vars cancel state
    GET_vars = []
    for key, values in request.GET.lists():
        if key not in ('page', 'unit'):
            for value in values:
                GET_vars.append('%s=%s' % (key, value))

    # links for quality check documentation
    checks = []
    for check in request.GET.get('matchnames', '').split(','):
        if not check:
            continue
        safe_check = escape(check)
        link = '<a href="http://translate.sourceforge.net/wiki/toolkit/pofilter_tests#%s" target="_blank">%s</a>' % (
            safe_check, safe_check)
        checks.append(_('checking %s', link))

    # precalculate alternative source languages
    alt_src_langs = get_alt_src_langs(request, profile, translation_project)
    alt_src_codes = alt_src_langs.values_list('code', flat=True)

    context = {
        'unit_rows': unit_rows,
        'alt_src_langs': alt_src_langs,
        'alt_src_codes': alt_src_codes,
        'cantranslate': cantranslate,
        'cansuggest': cansuggest,
        'canreview': canreview,
        'form': form,
        'search_form': search_form,
        'edit_unit': edit_unit,
        'store': store,
        'pager': pager,
        'units': units,
        'language': language,
        'translation_project': translation_project,
        'project': translation_project.project,
        'profile': profile,
        'source_language': translation_project.project.source_language,
        'directory': store.parent,
        'GET_state': '&'.join(GET_vars),
        'checks': checks,
        'MT_BACKENDS': settings.MT_BACKENDS,
    }
    return render_to_response('store/translate.html',
                              context,
                              context_instance=RequestContext(request))
Example #36
0
def submit(request, unit):
    """Processes translation submissions and stores them in the database.

    :return: An object in JSON notation that contains the previous and last
             units for the unit next to unit ``uid``.
    """
    json = {}

    translation_project = request.translation_project
    language = translation_project.language

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    # Store current time so that it is the same for all submissions
    current_time = timezone.now()

    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit, request=request)

    if form.is_valid():
        if form.updated_fields:
            for field, old_value, new_value in form.updated_fields:
                sub = Submission(
                    creation_time=current_time,
                    translation_project=translation_project,
                    submitter=request.profile,
                    unit=unit,
                    store=unit.store,
                    field=field,
                    type=SubmissionTypes.NORMAL,
                    old_value=old_value,
                    new_value=new_value,
                    similarity=form.cleaned_data['similarity'],
                    mt_similarity=form.cleaned_data['mt_similarity'],
                )
                sub.save()

            # Update current unit instance's attributes
            # important to set these attributes after saving Submission
            # because we need to access the unit's state before it was saved
            if SubmissionFields.TARGET in \
                    map(lambda x: x[0], form.updated_fields):
                form.instance.submitted_by = request.profile
                form.instance.submitted_on = current_time
                form.instance.reviewed_by = None
                form.instance.reviewed_on = None

            form.instance._log_user = request.profile

            form.save()
            translation_submitted.send(
                sender=translation_project,
                unit=form.instance,
                profile=request.profile,
            )

            has_critical_checks = unit.qualitycheck_set.filter(
                category=Category.CRITICAL).exists()

            if has_critical_checks:
                can_review = check_user_permission(request.profile, 'review',
                                                   unit.store.parent)
                ctx = {'canreview': can_review, 'unit': unit}
                template = loader.get_template('editor/units/xhr_checks.html')
                context = RequestContext(request, ctx)
                json['checks'] = template.render(context)

        rcode = 200
        json['user_score'] = request.profile.public_score
    else:
        # Form failed
        #FIXME: we should display validation errors here
        rcode = 400
        json["msg"] = _("Failed to process submission.")

    response = jsonify(json)
    return HttpResponse(response,
                        status=rcode,
                        content_type="application/json")
Example #37
0
def process_submit(request, unit, type):
    """Processes submissions and suggestions and stores them in the database.

    :return: An object in JSON notation that contains the previous and last
             units for the unit next to unit ``uid``.
    """
    json = {}
    cantranslate = check_permission("translate", request)
    cansuggest = check_permission("suggest", request)
    if type == 'submission' and not cantranslate or type == 'suggestion' and not cansuggest:
        raise PermissionDenied(_("You do not have rights to access translation mode."))

    translation_project = request.translation_project
    language = translation_project.language

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    import copy
    old_unit = copy.copy(unit)
    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit)

    if form.is_valid():
        if type == 'submission' and form.updated_fields:
            # Store creation time so that it is the same for all submissions:
            creation_time=datetime.utcnow()
            for field, old_value, new_value in form.updated_fields:
                sub = Submission(
                        creation_time=creation_time,
                        translation_project=translation_project,
                        submitter=request.profile,
                        unit=unit,
                        field=field,
                        type=NORMAL,
                        old_value=old_value,
                        new_value=new_value,
                )
                sub.save()

            form.save()
            translation_submitted.send(
                    sender=translation_project,
                    unit=form.instance,
                    profile=request.profile,
            )

        elif type == 'suggestion':
            if form.instance._target_updated:
                #HACKISH: django 1.2 stupidly modifies instance on
                # model form validation, reload unit from db
                unit = Unit.objects.get(id=unit.id)
                sugg = unit.add_suggestion(form.cleaned_data['target_f'], request.profile)
                if sugg:
                    SuggestionStat.objects.get_or_create(translation_project=translation_project,
                                                         suggester=request.profile,
                                                         state='pending', unit=unit.id)
        rcode = 200
    else:
        # Form failed
        #FIXME: we should display validation errors here
        rcode = 400
        json["msg"] = _("Failed to process submit.")
    response = jsonify(json)
    return HttpResponse(response, status=rcode, mimetype="application/json")
Example #38
0
def overview(request, translation_project, dir_path, filename=None):
    current_path = translation_project.directory.pootle_path + dir_path

    if filename:
        current_path = current_path + filename
        store = get_object_or_404(Store, pootle_path=current_path)
        directory = store.parent
        template_vars = {
            'store_tags': store.tags.all().order_by('name'),
        }
        template = "translation_project/store_overview.html"
    else:
        store = None
        directory = get_object_or_404(Directory, pootle_path=current_path)
        template_vars = {
            'tp_tags': translation_project.tags.all().order_by('name'),
        }
        template = "translation_project/overview.html"

    if (check_permission('translate', request)
            or check_permission('suggest', request)
            or check_permission('overwrite', request)):

        template_vars.update({
            'upload_form':
            _handle_upload_form(request, current_path, translation_project,
                                directory),
        })

    can_edit = check_permission('administrate', request)

    project = translation_project.project
    language = translation_project.language

    path_obj = store or directory

    latest_action = ''
    # If current directory is the TP root directory.
    if not directory.path:
        latest_action = translation_project.get_latest_submission()
    elif store is None:  # If this is not a file.
        latest_action = Submission.get_latest_for_dir(path_obj)

    path_stats = get_raw_stats(path_obj, include_suggestions=True)
    path_summary = get_path_summary(path_obj, path_stats, latest_action)
    actions = action_groups(request, path_obj, path_stats=path_stats)
    action_output = ''
    running = request.GET.get(EXTDIR, '')
    if running:
        if store:
            act = StoreAction
        else:
            act = TranslationProjectAction
        try:
            action = act.lookup(running)
        except KeyError:
            messages.error(request, _("Unable to find %s %s") % (act, running))
        else:
            if not getattr(action, 'nosync', False):
                (store or translation_project).sync()
            if action.is_active(request):
                vcs_dir = settings.VCS_DIRECTORY
                po_dir = settings.PODIRECTORY
                tp_dir = directory.get_real_path()
                store_fn = '*'
                if store:
                    tp_dir_slash = add_trailing_slash(tp_dir)
                    if store.file.name.startswith(tp_dir_slash):
                        # Note: store_f used below in reverse() call.
                        store_f = store.file.name[len(tp_dir_slash):]
                        store_fn = store_f.replace('/', os.sep)

                # Clear possibly stale output/error (even from other path_obj).
                action.set_output('')
                action.set_error('')
                try:
                    action.run(path=path_obj,
                               root=po_dir,
                               tpdir=tp_dir,
                               project=project.code,
                               language=language.code,
                               store=store_fn,
                               style=translation_project.file_style,
                               vc_root=vcs_dir)
                except StandardError:
                    err = (_("Exception while running '%s' extension action") %
                           action.title)
                    logging.exception(err)
                    if (action.error):
                        messages.error(request, action.error)
                    else:
                        messages.error(request, err)
                else:
                    if (action.error):
                        messages.warning(request, action.error)

                action_output = action.output
                if getattr(action, 'get_download', None):
                    export_path = action.get_download(path_obj)
                    if export_path:
                        response = HttpResponse('/export/' + export_path)
                        response['Content-Disposition'] = (
                            'attachment; filename="%s"' %
                            os.path.basename(export_path))
                        return response

                if not action_output:
                    if not store:
                        rev_args = [language.code, project.code, '']
                        overview_url = reverse('tp.overview', args=rev_args)
                    else:
                        slash = store_f.rfind('/')
                        store_d = ''
                        if slash > 0:
                            store_d = store_f[:slash]
                            store_f = store_f[slash + 1:]
                        elif slash == 0:
                            store_f = store_f[1:]
                        rev_args = [
                            language.code, project.code, store_d, store_f
                        ]
                        overview_url = reverse('tp.overview', args=rev_args)
                    return HttpResponseRedirect(overview_url)

    template_vars.update({
        'translation_project':
        translation_project,
        'project':
        project,
        'language':
        language,
        'path_obj':
        path_obj,
        'resource_path':
        request.resource_path,
        'path_summary':
        path_summary,
        'stats':
        path_stats,
        'topstats':
        gentopstats_translation_project(translation_project),
        'feed_path':
        directory.pootle_path[1:],
        'action_groups':
        actions,
        'action_output':
        action_output,
        'can_edit':
        can_edit,
    })

    if store is None:
        table_fields = [
            'name', 'progress', 'total', 'need-translation', 'suggestions'
        ]
        template_vars.update({
            'table': {
                'id': 'tp',
                'proportional': True,
                'fields': table_fields,
                'headings': get_table_headings(table_fields),
                'items': get_children(translation_project, directory),
            }
        })

    if can_edit:
        if store is None:
            url_kwargs = {
                'language_code': language.code,
                'project_code': project.code,
            }
            add_tag_action_url = reverse('tp.ajax_add_tag', kwargs=url_kwargs)
        else:
            add_tag_action_url = reverse('pootle-store-ajax-add-tag',
                                         args=[path_obj.pk])

        template_vars.update({
            'form':
            DescriptionForm(instance=translation_project),
            'add_tag_form':
            TagForm(),
            'add_tag_action_url':
            add_tag_action_url,
        })

    return render_to_response(template,
                              template_vars,
                              context_instance=RequestContext(request))
Example #39
0
def overview(request, translation_project, dir_path, filename=None):
    current_path = translation_project.directory.pootle_path + dir_path

    if filename:
        current_path = current_path + filename
        store = get_object_or_404(Store, pootle_path=current_path)
        directory = store.parent
        template_vars = {
            'store_tags': store.tags.all().order_by('name'),
        }
        template = "translation_project/store_overview.html"
    else:
        store = None
        directory = get_object_or_404(Directory, pootle_path=current_path)
        template_vars = {
            'tp_tags': translation_project.tags.all().order_by('name'),
        }
        template = "translation_project/overview.html"

    if (check_permission('translate', request) or
        check_permission('suggest', request) or
        check_permission('overwrite', request)):

        template_vars.update({
            'upload_form': _handle_upload_form(request, current_path,
                                               translation_project, directory),
        })

    can_edit = check_permission('administrate', request)

    project = translation_project.project
    language = translation_project.language

    path_obj = store or directory

    latest_action = ''
    # If current directory is the TP root directory.
    if not directory.path:
        latest_action = translation_project.get_latest_submission()
    elif store is None:  # If this is not a file.
        latest_action = Submission.get_latest_for_dir(path_obj)

    path_stats = get_raw_stats(path_obj, include_suggestions=True)
    path_summary = get_path_summary(path_obj, path_stats, latest_action)
    actions = action_groups(request, path_obj, path_stats=path_stats)
    action_output = ''
    running = request.GET.get(EXTDIR, '')
    if running:
        if store:
            act = StoreAction
        else:
            act = TranslationProjectAction
        try:
            action = act.lookup(running)
        except KeyError:
            messages.error(request, _("Unable to find %s %s") % (act, running))
        else:
            if not getattr(action, 'nosync', False):
                (store or translation_project).sync()
            if action.is_active(request):
                vcs_dir = settings.VCS_DIRECTORY
                po_dir = settings.PODIRECTORY
                tp_dir = directory.get_real_path()
                store_fn = '*'
                if store:
                    tp_dir_slash = add_trailing_slash(tp_dir)
                    if store.file.name.startswith(tp_dir_slash):
                        # Note: store_f used below in reverse() call.
                        store_f = store.file.name[len(tp_dir_slash):]
                        store_fn = store_f.replace('/', os.sep)

                # Clear possibly stale output/error (even from other path_obj).
                action.set_output('')
                action.set_error('')
                try:
                    action.run(path=path_obj, root=po_dir, tpdir=tp_dir,
                               project=project.code, language=language.code,
                               store=store_fn,
                               style=translation_project.file_style,
                               vc_root=vcs_dir)
                except StandardError:
                    err = (_("Exception while running '%s' extension action") %
                           action.title)
                    logging.exception(err)
                    if (action.error):
                        messages.error(request, action.error)
                    else:
                        messages.error(request, err)
                else:
                    if (action.error):
                        messages.warning(request, action.error)

                action_output = action.output
                if getattr(action, 'get_download', None):
                    export_path = action.get_download(path_obj)
                    if export_path:
                        response = HttpResponse('/export/' + export_path)
                        response['Content-Disposition'] = (
                                'attachment; filename="%s"' %
                                os.path.basename(export_path))
                        return response

                if not action_output:
                    if not store:
                        rev_args = [language.code, project.code, '']
                        overview_url = reverse('tp.overview', args=rev_args)
                    else:
                        slash = store_f.rfind('/')
                        store_d = ''
                        if slash > 0:
                            store_d = store_f[:slash]
                            store_f = store_f[slash + 1:]
                        elif slash == 0:
                            store_f = store_f[1:]
                        rev_args = [language.code, project.code, store_d,
                                    store_f]
                        overview_url = reverse('tp.overview', args=rev_args)
                    return HttpResponseRedirect(overview_url)

    template_vars.update({
        'translation_project': translation_project,
        'project': project,
        'language': language,
        'path_obj': path_obj,
        'resource_path': request.resource_path,
        'path_summary': path_summary,
        'stats': path_stats,
        'topstats': gentopstats_translation_project(translation_project),
        'feed_path': directory.pootle_path[1:],
        'action_groups': actions,
        'action_output': action_output,
        'can_edit': can_edit,
    })

    if store is None:
        table_fields = ['name', 'progress', 'total', 'need-translation',
                        'suggestions']
        template_vars.update({
            'table': {
                'id': 'tp',
                'proportional': True,
                'fields': table_fields,
                'headings': get_table_headings(table_fields),
                'items': get_children(translation_project, directory),
            }
        })

    if can_edit:
        if store is None:
            url_kwargs = {
                'language_code': language.code,
                'project_code': project.code,
            }
            add_tag_action_url = reverse('tp.ajax_add_tag', kwargs=url_kwargs)
        else:
            add_tag_action_url = reverse('pootle-store-ajax-add-tag',
                                         args=[path_obj.pk])

        template_vars.update({
            'form': DescriptionForm(instance=translation_project),
            'add_tag_form': TagForm(),
            'add_tag_action_url': add_tag_action_url,
        })

    return render_to_response(template, template_vars,
                              context_instance=RequestContext(request))
Example #40
0
def accept_suggestion(request, unit, suggid):
    json = {
        'udbid': unit.id,
        'sugid': suggid,
    }
    translation_project = request.translation_project

    if request.POST.get('accept'):
        try:
            suggestion = unit.suggestion_set.get(id=suggid)
        except ObjectDoesNotExist:
            raise Http404

        old_target = unit.target
        success = unit.accept_suggestion(suggid)

        json['newtargets'] = [
            highlight_whitespace(target) for target in unit.target.strings
        ]
        json['newdiffs'] = {}
        for sugg in unit.get_suggestions():
            json['newdiffs'][sugg.id] = \
                    [highlight_diffs(unit.target.strings[i], target)
                     for i, target in enumerate(sugg.target.strings)]

        if suggestion is not None and success:
            if suggestion.user:
                translation_submitted.send(sender=translation_project,
                                           unit=unit,
                                           profile=suggestion.user)

            # FIXME: we need a totally different model for tracking stats, this
            # is just lame
            suggstat, created = SuggestionStat.objects.get_or_create(
                translation_project=translation_project,
                suggester=suggestion.user,
                state='pending',
                unit=unit.id,
            )
            suggstat.reviewer = request.profile
            suggstat.state = 'accepted'
            suggstat.save()

            # For now assume the target changed
            # TODO: check all fields for changes
            creation_time = timezone.now()
            sub = Submission(
                creation_time=creation_time,
                translation_project=translation_project,
                submitter=suggestion.user,
                from_suggestion=suggstat,
                unit=unit,
                field=SubmissionFields.TARGET,
                type=SubmissionTypes.SUGG_ACCEPT,
                old_value=old_target,
                new_value=unit.target,
            )
            sub.save()

    response = jsonify(json)
    return HttpResponse(response, mimetype="application/json")
Example #41
0
def process_submit(request, pootle_path, uid, type):
    """
    @return: An object in JSON notation that contains the previous
    and last units for the unit next to unit C{uid}.

    This object also contains success status that indicates if the submission
    has been succesfully saved or not.
    """
    json = {}
    if pootle_path[0] != '/':
        pootle_path = '/' + pootle_path

    try:
        unit = Unit.objects.get(id=uid, store__pootle_path=pootle_path)
        directory = unit.store.parent
        profile = get_profile(request.user)
        cantranslate = check_profile_permission(profile, "translate",
                                                directory)
        cansuggest = check_profile_permission(profile, "suggest", directory)
        if type == 'submission' and not cantranslate or \
           type == 'suggestion' and not cansuggest:
            json["success"] = False
            json["msg"] = _(
                "You do not have rights to access translation mode.")
        else:
            translation_project = unit.store.translation_project
            language = translation_project.language
            form_class = unit_form_factory(language, len(unit.source.strings))
            form = form_class(request.POST, instance=unit)
            if form.is_valid():
                if type == 'submission':
                    if form.instance._target_updated or \
                       form.instance._translator_comment_updated or \
                       form.instance._state_updated:
                        form.save()
                        sub = Submission(
                            translation_project=translation_project,
                            submitter=get_profile(request.user))
                        sub.save()
                elif type == 'suggestion':
                    if form.instance._target_updated:
                        #HACKISH: django 1.2 stupidly modifies instance on
                        # model form validation, reload unit from db
                        unit = Unit.objects.get(id=unit.id)
                        sugg = unit.add_suggestion(
                            form.cleaned_data['target_f'],
                            get_profile(request.user))
                        if sugg:
                            SuggestionStat.objects.get_or_create(
                                translation_project=translation_project,
                                suggester=get_profile(request.user),
                                state='pending',
                                unit=unit.id)

                current_page = int(request.POST.get('page', 1))
                all_units = unit.store.units
                units_qs = _filter_queryset(request.POST, all_units)
                unit_rows = profile.get_unit_rows()
                current_unit = unit
                if current_unit is not None:
                    current_index = _get_index_in_qs(units_qs, current_unit)
                    preceding = units_qs[:current_index].count()
                    page = preceding / unit_rows + 1
                    if page != current_page:
                        pager = paginate(request,
                                         units_qs,
                                         items=unit_rows,
                                         page=page)
                        json["pager"] = _build_pager_dict(pager)
                    try:
                        new_index = current_index + 1
                        json["new_uid"] = units_qs[new_index].id
                    except IndexError:
                        # End of set: let's assume the new unit is the last we had
                        new_unit = unit
                        json["new_uid"] = None
                    json["success"] = True
            else:
                # Form failed
                json["success"] = False
                json["msg"] = _("Failed to process submit.")
    except Store.DoesNotExist:
        json["success"] = False
        json["msg"] = _("Store %(path)s does not exist." %
                        {'path': pootle_path})
    except Unit.DoesNotExist:
        json["success"] = False
        json["msg"] = _("Unit %(uid)s does not exist on %(path)s." % {
            'uid': uid,
            'path': pootle_path
        })

    response = simplejson.dumps(json)
    return HttpResponse(response, mimetype="application/json")
Example #42
0
def submit(request, unit):
    """Processes translation submissions and stores them in the database.

    :return: An object in JSON notation that contains the previous and last
             units for the unit next to unit ``uid``.
    """
    json = {}

    cantranslate = check_permission("translate", request)
    if not cantranslate:
        raise PermissionDenied(_("You do not have rights to access "
                                 "translation mode."))

    translation_project = request.translation_project
    language = translation_project.language

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    # Store current time so that it is the same for all submissions
    current_time = timezone.now()

    # Update current unit instance's attributes
    unit.submitted_by = request.profile
    unit.submitted_on = current_time

    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit)

    if form.is_valid():
        if form.updated_fields:
            for field, old_value, new_value in form.updated_fields:
                sub = Submission(
                        creation_time=current_time,
                        translation_project=translation_project,
                        submitter=request.profile,
                        unit=unit,
                        field=field,
                        type=SubmissionTypes.NORMAL,
                        old_value=old_value,
                        new_value=new_value,
                )
                sub.save()

            form.save()
            translation_submitted.send(
                    sender=translation_project,
                    unit=form.instance,
                    profile=request.profile,
            )

        rcode = 200
    else:
        # Form failed
        #FIXME: we should display validation errors here
        rcode = 400
        json["msg"] = _("Failed to process submission.")
    response = jsonify(json)
    return HttpResponse(response, status=rcode, mimetype="application/json")
Example #43
0
def submit(request, unit):
    """Processes translation submissions and stores them in the database.

    :return: An object in JSON notation that contains the previous and last
             units for the unit next to unit ``uid``.
    """
    json = {}

    translation_project = request.translation_project
    language = translation_project.language
    user = request.user

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    # Store current time so that it is the same for all submissions
    current_time = timezone.now()

    # Update current unit instance's attributes
    unit.submitted_by = request.user
    unit.submitted_on = current_time

    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit, request=request)

    if form.is_valid():
        if form.updated_fields:
            for field, old_value, new_value in form.updated_fields:
                sub = Submission(
                        creation_time=current_time,
                        translation_project=translation_project,
                        submitter=request.user,
                        unit=unit,
                        field=field,
                        type=SubmissionTypes.NORMAL,
                        old_value=old_value,
                        new_value=new_value,
                )
                sub.save()
            form.instance._log_user = request.user
            form.save()
            translation_submitted.send(
                    sender=translation_project,
                    unit=form.instance,
                    user=request.user,
            )

            has_critical_checks = unit.qualitycheck_set.filter(
                category=Category.CRITICAL
            ).exists()

            if has_critical_checks:
                can_review = check_user_permission(user, "review", unit.store.parent)
                ctx = {
                    'canreview': can_review,
                    'unit': unit
                }
                template = loader.get_template('editor/units/xhr_checks.html')
                context = RequestContext(request, ctx)
                json['checks'] = template.render(context)

        rcode = 200
    else:
        # Form failed
        #FIXME: we should display validation errors here
        rcode = 400
        json["msg"] = _("Failed to process submission.")

    response = jsonify(json)
    return HttpResponse(response, status=rcode, mimetype="application/json")
Example #44
0
def submit(request, unit):
    """Processes translation submissions and stores them in the database.

    :return: An object in JSON notation that contains the previous and last
             units for the unit next to unit ``uid``.
    """
    json = {}

    translation_project = request.translation_project
    language = translation_project.language
    old_unit = copy.copy(unit)

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    # Store current time so that it is the same for all submissions
    current_time = timezone.now()

    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit, request=request)

    if form.is_valid():
        suggestion = form.cleaned_data['suggestion']
        if suggestion:
            old_unit.accept_suggestion(suggestion, request.translation_project,
                                       request.user)
            if form.cleaned_data['comment']:
                kwargs = dict(
                    comment=form.cleaned_data['comment'],
                    user=request.user,
                )
                comment_form = UnsecuredCommentForm(suggestion, kwargs)
                if comment_form.is_valid():
                    comment_form.save()

        if form.updated_fields:
            for field, old_value, new_value in form.updated_fields:
                if field == SubmissionFields.TARGET and suggestion:
                    old_value = str(suggestion.target_f)
                sub = Submission(
                    creation_time=current_time,
                    translation_project=translation_project,
                    submitter=request.user,
                    unit=unit,
                    store=unit.store,
                    field=field,
                    type=SubmissionTypes.NORMAL,
                    old_value=old_value,
                    new_value=new_value,
                    similarity=form.cleaned_data['similarity'],
                    mt_similarity=form.cleaned_data['mt_similarity'],
                )
                sub.save()

            # Update current unit instance's attributes
            # important to set these attributes after saving Submission
            # because we need to access the unit's state before it was saved
            if SubmissionFields.TARGET in (f[0] for f in form.updated_fields):
                form.instance.submitted_by = request.user
                form.instance.submitted_on = current_time
                form.instance.reviewed_by = None
                form.instance.reviewed_on = None

            form.instance._log_user = request.user

            form.save()

            json['checks'] = _get_critical_checks_snippet(request, unit)

        json['user_score'] = request.user.public_score

        return JsonResponse(json)

    return JsonResponseBadRequest({'msg': _("Failed to process submission.")})
Example #45
0
def submit(request, unit):
    """Processes translation submissions and stores them in the database.

    :return: An object in JSON notation that contains the previous and last
             units for the unit next to unit ``uid``.
    """
    json = {}

    cantranslate = check_permission("translate", request)
    if not cantranslate:
        raise PermissionDenied(_("You do not have rights to access "
                                 "translation mode."))

    translation_project = request.translation_project
    language = translation_project.language

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    # Store current time so that it is the same for all submissions
    current_time = timezone.now()

    # Update current unit instance's attributes
    unit.submitted_by = request.profile
    unit.submitted_on = current_time

    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit)

    if form.is_valid():
        if form.updated_fields:
            for field, old_value, new_value in form.updated_fields:
                # (jgonzale|2014-09-05|INTL-591): log unsolicited modification to the source field
                if field == SubmissionFields.SOURCE:
                    logging.warning(
                        u'Corrupted submission for (unit_id, {0}) - ' \
                        u'(submitter, {1}) ' \
                        u'(source_old_value, {2}) ' \
                        u'(request info - {3})'.format(unit.id, request.profile, old_value, repr(request))
                    )
                sub = Submission(
                        creation_time=current_time,
                        translation_project=translation_project,
                        submitter=request.profile,
                        unit=unit,
                        field=field,
                        type=SubmissionTypes.NORMAL,
                        old_value=old_value,
                        new_value=new_value,
                )
                sub.save()

            form.save()
            translation_submitted.send(
                    sender=translation_project,
                    unit=form.instance,
                    profile=request.profile,
            )

        rcode = 200
    else:
        # Form failed
        #FIXME: we should display validation errors here
        rcode = 400
        json["msg"] = _("Failed to process submission.")
    response = jsonify(json)
    return HttpResponse(response, status=rcode, mimetype="application/json")
Example #46
0
def submit(request, unit):
    """Processes translation submissions and stores them in the database.

    :return: An object in JSON notation that contains the previous and last
             units for the unit next to unit ``uid``.
    """
    json = {}

    translation_project = request.translation_project
    language = translation_project.language
    old_unit = copy.copy(unit)

    if unit.hasplural():
        snplurals = len(unit.source.strings)
    else:
        snplurals = None

    # Store current time so that it is the same for all submissions
    current_time = timezone.now()

    form_class = unit_form_factory(language, snplurals, request)
    form = form_class(request.POST, instance=unit, request=request)

    if form.is_valid():
        suggestion = form.cleaned_data['suggestion']
        if suggestion:
            old_unit.accept_suggestion(suggestion,
                                       request.translation_project, request.user)
            if form.cleaned_data['comment']:
                kwargs = dict(
                    comment=form.cleaned_data['comment'],
                    user=request.user,
                )
                comment_form = UnsecuredCommentForm(suggestion, kwargs)
                if comment_form.is_valid():
                    comment_form.save()

        if form.updated_fields:
            for field, old_value, new_value in form.updated_fields:
                if field == SubmissionFields.TARGET and suggestion:
                    old_value = str(suggestion.target_f)
                sub = Submission(
                    creation_time=current_time,
                    translation_project=translation_project,
                    submitter=request.user,
                    unit=unit,
                    store=unit.store,
                    field=field,
                    type=SubmissionTypes.NORMAL,
                    old_value=old_value,
                    new_value=new_value,
                    similarity=form.cleaned_data['similarity'],
                    mt_similarity=form.cleaned_data['mt_similarity'],
                )
                sub.save()

            # Update current unit instance's attributes
            # important to set these attributes after saving Submission
            # because we need to access the unit's state before it was saved
            if SubmissionFields.TARGET in (f[0] for f in form.updated_fields):
                form.instance.submitted_by = request.user
                form.instance.submitted_on = current_time
                form.instance.reviewed_by = None
                form.instance.reviewed_on = None

            form.instance._log_user = request.user

            form.save()

            json['checks'] = _get_critical_checks_snippet(request, unit)

        json['user_score'] = request.user.public_score

        return JsonResponse(json)

    return JsonResponseBadRequest({'msg': _("Failed to process submission.")})
Example #47
0
def translate_page(request, units_queryset, store=None):
    if not check_permission("view", request):
        raise PermissionDenied(_("You do not have rights to access this translation project."))

    cantranslate = check_permission("translate", request)
    cansuggest = check_permission("suggest", request)
    canreview = check_permission("review", request)
    translation_project = request.translation_project
    language = translation_project.language
    # shouldn't we globalize profile context
    profile = get_profile(request.user)

    step_queryset = None

    # Process search first
    search_form = None
    if 'search' in request.GET and 'sfields' in request.GET:
        search_form = SearchForm(request.GET)
        if search_form.is_valid():
            step_queryset = get_search_step_query(request.translation_project, search_form, units_queryset)
    else:
        search_form = SearchForm()

    # which units are we interested in?
    if step_queryset is None:
        step_queryset = get_step_query(request, units_queryset)

    prev_unit, edit_unit, pager = get_current_units(request, step_queryset, units_queryset)

    # time to process POST submission
    form = None
    if prev_unit is not None and ('submit' in request.POST or 'suggest' in request.POST):
        # check permissions
        if 'submit'  in request.POST and not cantranslate or \
           'suggest' in request.POST and not cansuggest:
            raise PermissionDenied

        if prev_unit.hasplural():
            snplurals = len(prev_unit.source.strings)
        else:
            snplurals = None
        form_class = unit_form_factory(language, snplurals)
        form = form_class(request.POST, instance=prev_unit)
        if form.is_valid():
            if cantranslate and 'submit' in request.POST:
                if form.instance._target_updated or form.instance._translator_comment_updated or \
                       form.instance._state_updated:
                    form.save()
                    translation_submitted.send(sender=translation_project,
                                               unit=form.instance, profile=profile)

                    sub = Submission(translation_project=translation_project,
                                     submitter=get_profile(request.user))
                    sub.save()

            elif cansuggest and 'suggest' in request.POST:
                if form.instance._target_updated:
                    #HACKISH: django 1.2 stupidly modifies instance on
                    # model form validation, reload unit from db
                    prev_unit = Unit.objects.get(id=prev_unit.id)
                    sugg = prev_unit.add_suggestion(form.cleaned_data['target_f'], get_profile(request.user))
                    if sugg:
                        SuggestionStat.objects.get_or_create(translation_project=translation_project,
                                                             suggester=get_profile(request.user),
                                                             state='pending', unit=prev_unit.id)
        else:
            # form failed, don't skip to next unit
            edit_unit = prev_unit

    if edit_unit is None:
        # no more units to step through, display end of translation message
        return translate_end(request, translation_project)

    # only create form for edit_unit if prev_unit was processed successfully
    if form is None or form.is_valid():
        if edit_unit.hasplural():
            snplurals = len(edit_unit.source.strings)
        else:
            snplurals = None
        form_class = unit_form_factory(language, snplurals)
        form = form_class(instance=edit_unit)

    if store is None:
        store = edit_unit.store
        pager_query = units_queryset
        preceding = (pager_query.filter(store=store, index__lt=edit_unit.index) | \
                     pager_query.filter(store__pootle_path__lt=store.pootle_path)).count()
        store_preceding = store.units.filter(index__lt=edit_unit.index).count()
    else:
        pager_query = store.units
        preceding = pager_query.filter(index__lt=edit_unit.index).count()
        store_preceding = preceding

    unit_rows = profile.get_unit_rows()

    # regardless of the query used to step through units, we will
    # display units in their original context, and display a pager for
    # the store not for the unit_step query
    if pager is None:
        page = preceding / unit_rows + 1
        pager = paginate(request, pager_query, items=unit_rows, page=page, orphans=0)

    # we always display the active unit in the middle of the page to
    # provide context for translators
    context_rows = (unit_rows - 1) / 2
    if store_preceding > context_rows:
        unit_position = store_preceding % unit_rows
        page_length = pager.end_index() - pager.start_index() + 1
        if page_length < unit_rows:
            if pager.has_other_pages():
                units_query = store.units[page_length:]
            else:
                units_query = store.units
            page = store_preceding / unit_rows
            units = paginate(request, units_query, items=unit_rows, page=page, orphans=0).object_list
        elif unit_position < context_rows:
            # units too close to the top of the batch
            offset = unit_rows - (context_rows - unit_position)
            units_query = store.units[offset:]
            page = store_preceding / unit_rows
            units = paginate(request, units_query, items=unit_rows, page=page, orphans=0).object_list
        elif unit_position >= unit_rows - context_rows:
            # units too close to the bottom of the batch
            offset = context_rows - (unit_rows - unit_position - 1)
            units_query = store.units[offset:]
            page = store_preceding / unit_rows + 1
            units = paginate(request, units_query, items=unit_rows, page=page, orphans=0).object_list
        else:
            units = pager.object_list
    else:
        units = store.units[:unit_rows]

    # caluclate url querystring so state is retained on POST
    # we can't just use request URL cause unit and page GET vars cancel state
    GET_vars = []
    for key, values in request.GET.lists():
        if key not in ('page', 'unit'):
            for value in values:
                GET_vars.append('%s=%s' % (key, value))

    # links for quality check documentation
    checks = []
    for check in request.GET.get('matchnames','').split(','):
        if not check:
            continue
        safe_check = escape(check)
        link = '<a href="http://translate.sourceforge.net/wiki/toolkit/pofilter_tests#%s" target="_blank">%s</a>' % (safe_check, safe_check)
        checks.append(_('checking %s', link))

    # precalculate alternative source languages
    alt_src_langs = get_alt_src_langs(request, profile, translation_project)
    alt_src_codes = alt_src_langs.values_list('code', flat=True)

    context = {
        'unit_rows': unit_rows,
        'alt_src_langs': alt_src_langs,
        'alt_src_codes': alt_src_codes,
        'cantranslate': cantranslate,
        'cansuggest': cansuggest,
        'canreview': canreview,
        'form': form,
        'search_form': search_form,
        'edit_unit': edit_unit,
        'store': store,
        'pager': pager,
        'units': units,
        'language': language,
        'translation_project': translation_project,
        'project': translation_project.project,
        'profile': profile,
        'source_language': translation_project.project.source_language,
        'directory': store.parent,
        'GET_state': '&'.join(GET_vars),
        'checks': checks,
        'MT_BACKENDS': settings.MT_BACKENDS,
        }
    return render_to_response('store/translate.html', context, context_instance=RequestContext(request))