def get_translation_context(request): """Returns a common context for translation views. :param request: a :cls:`django.http.HttpRequest` object. """ resource_path = getattr(request, 'resource_path', '') vfolder_pk = getattr(request, 'current_vfolder', '') return { 'page': 'translate', 'cantranslate': check_permission("translate", request), 'cansuggest': check_permission("suggest", request), 'canreview': check_permission("review", request), 'is_admin': check_permission('administrate', request), 'profile': request.profile, 'pootle_path': request.pootle_path, 'ctx_path': request.ctx_path, 'current_vfolder_pk': vfolder_pk, 'display_priority': display_vfolder_priority(request), 'resource_path': resource_path, 'resource_path_parts': get_path_parts(resource_path), 'check_categories': get_qualitycheck_schema(), 'search_form': make_search_form(request=request), 'previous_url': get_previous_url(request), 'POOTLE_MT_BACKENDS': settings.POOTLE_MT_BACKENDS, 'AMAGAMA_URL': settings.AMAGAMA_URL, }
def _test_translate_view(language, request, response, kwargs, settings): ctx = response.context view_context_test( ctx, **dict( project=None, language=language, page="translate", ctx_path=language.directory.pootle_path, pootle_path=language.directory.pootle_path, resource_path="", resource_path_parts=[], profile=request.profile, editor_extends="languages/base.html", check_categories=get_qualitycheck_schema(), previous_url=get_previous_url(request), display_priority=False, is_admin=check_permission('administrate', request), cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), current_vfolder_pk="", POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL))
def _test_translate_view(tp, request, response, kwargs, settings): ctx = response.context kwargs["project_code"] = tp.project.code kwargs["language_code"] = tp.language.code resource_path = "%(dir_path)s%(filename)s" % kwargs request_path = "%s%s" % (tp.pootle_path, resource_path) vfolder, pootle_path = extract_vfolder_from_path(request_path) current_vfolder_pk = vfolder.pk if vfolder else "" display_priority = not current_vfolder_pk and ( VirtualFolderTreeItem.objects.filter(pootle_path__startswith=pootle_path).exists() ) assertions = dict( page="translate", translation_project=tp, language=tp.language, project=tp.project, is_admin=False, profile=request.profile, ctx_path=tp.pootle_path, pootle_path=request_path, resource_path=resource_path, resource_path_parts=get_path_parts(resource_path), editor_extends="translation_projects/base.html", check_categories=get_qualitycheck_schema(), previous_url=get_previous_url(request), current_vfolder_pk=current_vfolder_pk, display_priority=display_priority, cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL, ) view_context_test(ctx, **assertions)
def language_index(request, language_code): language = get_object_or_404(Language, code=language_code) request.permissions = get_matching_permissions(get_profile(request.user), language.directory) if not check_permission("view", request): raise PermissionDenied projects = language.translationproject_set.order_by('project__fullname') projectcount = len(projects) items = (make_project_item(translate_project) for translate_project in projects.iterator()) totals = language.getquickstats() average = nice_percentage(totals['translatedsourcewords'] * 100.0 / max(totals['totalsourcewords'], 1)) topstats = gentopstats_language(language) templatevars = { 'language': { 'code': language.code, 'name': tr_lang(language.fullname), 'description': language.description, 'stats': ungettext('%(projects)d project, %(average)d%% translated', '%(projects)d projects, %(average)d%% translated', projectcount, {"projects": projectcount, "average": average}), }, 'feed_path': '%s/' % language.code, 'description': language.description, 'projects': items, 'statsheadings': get_stats_headings(), 'topstats': topstats, } if check_permission('administrate', request): from pootle_language.forms import DescriptionForm templatevars['form'] = DescriptionForm(instance=language) return render_to_response("language/language_index.html", templatevars, context_instance=RequestContext(request))
def test_view_projects_translate(site_permissions, site_matrix_with_vfolders, client, nobody, default, settings): response = client.get(reverse("pootle-projects-translate")) ctx = response.context request = response.wsgi_request assertions = dict( page="translate", is_admin=False, language=None, project=None, profile=request.profile, pootle_path="/projects/", ctx_path="/projects/", resource_path="", resource_path_parts=[], editor_extends="projects/all/base.html", check_categories=get_qualitycheck_schema(), previous_url=get_previous_url(request), display_priority=False, cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), current_vfolder_pk="", POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL, ) view_context_test(ctx, **assertions)
def get_translation_context(request, is_terminology=False): """Return a common context for translation views. :param request: a :cls:`django.http.HttpRequest` object. :param is_terminology: boolean indicating if the translation context is relevant to a terminology project. """ return { 'cantranslate': check_permission("translate", request), 'cansuggest': check_permission("suggest", request), 'canreview': check_permission("review", request), 'is_admin': check_permission('administrate', request), 'profile': request.profile, 'pootle_path': request.pootle_path, 'ctx_path': request.ctx_path, 'resource_path': (request.resource_path if hasattr(request, 'resource_path') else ''), 'check_categories': get_qualitycheck_schema(), 'search_form': make_search_form(request=request, terminology=is_terminology), 'MT_BACKENDS': settings.MT_BACKENDS, 'LOOKUP_BACKENDS': settings.LOOKUP_BACKENDS, 'AMAGAMA_URL': settings.AMAGAMA_URL, }
def test_view_projects_translate(client, settings, request_users): user = request_users["user"] client.login( username=user.username, password=request_users["password"]) response = client.get(reverse("pootle-projects-translate")) if not user.is_superuser: assert response.status_code == 403 return ctx = response.context request = response.wsgi_request assertions = dict( page="translate", has_admin_access=user.is_superuser, language=None, project=None, pootle_path="/projects/", ctx_path="/projects/", resource_path="", resource_path_parts=[], editor_extends="projects/all/base.html", check_categories=get_qualitycheck_schema(), previous_url=get_previous_url(request), display_priority=False, cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), current_vfolder_pk="", POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL) view_context_test(ctx, **assertions)
def view(request, path): # FIXME: why do we have leading and trailing slashes in pootle_path? pootle_path = "/%s" % path directory = get_object_or_404(Directory, pootle_path=pootle_path) request.permissions = get_matching_permissions(get_profile(request.user), directory) if not check_permission("view", request): raise PermissionDenied template_vars = {"path": path, "directory": directory} if check_permission("administrate", request): template_vars["form"] = handle_form(request, directory) template_vars["title"] = directory_to_title(directory) if request.GET.get("all", False): template_vars["notices"] = Notice.objects.filter( directory__pootle_path__startswith=directory.pootle_path ).select_related("directory")[:30] else: template_vars["notices"] = Notice.objects.filter(directory=directory).select_related("directory")[:30] if not directory.is_language() and not directory.is_project(): try: request.translation_project = directory.get_translationproject() template_vars["navitems"] = [navbar_dict.make_directory_navbar_dict(request, directory)] template_vars["translation_project"] = request.translation_project template_vars["language"] = request.translation_project.language template_vars["project"] = request.translation_project.project except: pass return render_to_response("notices.html", template_vars, context_instance=RequestContext(request))
def __init__(self, request, data=None, files=None): choices = [('merge', _("Merge the file with the current file and turn conflicts into suggestions")), ('suggest', _("Add all new translations as suggestions"))] if check_permission('overwrite', request): choices.insert(0, ('overwrite', _("Overwrite the current file if it exists"))) translation_project = request.translation_project class StoreFormField(forms.ModelChoiceField): def label_from_instance(self, instance): return _(instance.pootle_path[len(translation_project.pootle_path):]) class DirectoryFormField(forms.ModelChoiceField): def label_from_instance(self, instance): return _(instance.pootle_path[len(translation_project.pootle_path):]) class UploadForm(forms.Form): file = forms.FileField(required=True, label=_('File')) overwrite = forms.ChoiceField(required=True, widget=forms.RadioSelect, label='', choices=choices, initial='merge') upload_to = StoreFormField(required=False, label=_('Upload to'), queryset=translation_project.stores.all(), help_text=_("Optionally select the file you want to merge with. If not specified, the uploaded file's name is used.")) upload_to_dir = DirectoryFormField(required=False, label=_('Upload to'), queryset=Directory.objects.filter(pootle_path__startswith=translation_project.pootle_path).exclude(pk=translation_project.directory.pk), help_text=_("Optionally select the file you want to merge with. If not specified, the uploaded file's name is used.")) self.Form = UploadForm super(UploadHandler, self).__init__(request, data, files) self.form.allow_overwrite = check_permission('overwrite', request) self.form.title = _("Upload File")
def view(request, path): #FIXME: why do we have leading and trailing slashes in pootle_path? pootle_path = '/%s' % path directory = get_object_or_404(Directory, pootle_path=pootle_path) request.permissions = get_matching_permissions(get_profile(request.user), directory) if not check_permission('view', request): raise PermissionDenied template_vars = {'path': path, 'directory': directory} if check_permission('administrate', request): template_vars['form'] = handle_form(request, directory) template_vars['title'] = directory_to_title(request, directory) if request.GET.get('all', False): template_vars['notices'] = Notice.objects.filter(directory__pootle_path__startswith=directory.pootle_path).select_related('directory')[:30] else: template_vars['notices'] = Notice.objects.filter(directory=directory).select_related('directory')[:30] if not directory.is_language() and not directory.is_project(): try: request.translation_project = directory.get_translationproject() template_vars['navitems'] = [navbar_dict.make_directory_navbar_dict(request, directory)] template_vars['translation_project'] = request.translation_project template_vars['language'] = request.translation_project.language template_vars['project'] = request.translation_project.project except: pass return render_to_response('notices.html', template_vars, context_instance=RequestContext(request))
def translate_page(request): cantranslate = check_permission("translate", request) cansuggest = check_permission("suggest", request) canreview = check_permission("review", request) translation_project = request.translation_project language = translation_project.language profile = request.profile store = getattr(request, "store", None) is_terminology = translation_project.project.is_terminology or store and store.is_terminology search_form = make_search_form(terminology=is_terminology) context = { 'cantranslate': cantranslate, 'cansuggest': cansuggest, 'canreview': canreview, 'search_form': search_form, 'store': store, 'store_id': store and store.id, 'language': language, 'translation_project': translation_project, 'profile': profile, 'source_language': translation_project.project.source_language, 'directory': getattr(request, "directory", None), 'MT_BACKENDS': settings.MT_BACKENDS, 'AMAGAMA_URL': settings.AMAGAMA_URL, 'advanced_search_title': _('Advanced search'), } return render_to_response('store/translate.html', context, context_instance=RequestContext(request))
def _test_translate_view(project, request, response, kwargs, settings): ctx = response.context user = request.profile kwargs["project_code"] = project.code ctx_path = "/projects/%(project_code)s/" % kwargs resource_path = "%(dir_path)s%(filename)s" % kwargs pootle_path = "%s%s" % (ctx_path, resource_path) view_context_test( ctx, **dict( page="translate", is_admin=False, language=None, project=project, profile=user, pootle_path="%s%s" % (ctx_path, resource_path), ctx_path=ctx_path, resource_path=resource_path, resource_path_parts=get_path_parts(resource_path), editor_extends="projects/base.html", check_categories=get_qualitycheck_schema(), previous_url=get_previous_url(request), display_priority=(VirtualFolderTreeItem.objects.filter(pootle_path__startswith=pootle_path).exists()), cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), current_vfolder_pk="", POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL, ) )
def translate_page(request): cantranslate = check_permission("translate", request) cansuggest = check_permission("suggest", request) canreview = check_permission("review", request) translation_project = request.translation_project language = translation_project.language profile = request.profile store = getattr(request, "store", None) is_terminology = translation_project.project.is_terminology or store and store.is_terminology search_form = make_search_form(terminology=is_terminology) context = { "cantranslate": cantranslate, "cansuggest": cansuggest, "canreview": canreview, "search_form": search_form, "store": store, "store_id": store and store.id, "language": language, "translation_project": translation_project, "profile": profile, "source_language": translation_project.project.source_language, "directory": getattr(request, "directory", None), "MT_BACKENDS": settings.MT_BACKENDS, "LOOKUP_BACKENDS": settings.LOOKUP_BACKENDS, "AMAGAMA_URL": settings.AMAGAMA_URL, "advanced_search_title": _("Advanced search"), } if is_terminology: return render_to_response("store/terms.html", context, context_instance=RequestContext(request)) else: return render_to_response("store/translate.html", context, context_instance=RequestContext(request))
def upload_file(request, directory, django_file, overwrite): translation_project = request.translation_project relative_root_dir = directory.pootle_path[len(translation_project.directory.pootle_path):] # for some reason factory checks explicitly for file existance and # if file is open, which makes it difficult to work with Django's # in memory uploads. # # setting _closed to False should work around this #FIXME: hackish, does this have any undesirable side effect? if getattr(django_file, '_closed', None) is None: try: django_file._closed = False except AttributeError: pass # factory also checks for _mode if getattr(django_file, '_mode', None) is None: try: django_file._mode = 1 except AttributeError: pass # mode is an attribute not a property in Django 1.1 if getattr(django_file, 'mode', None) is None: django_file.mode = 1 local_filename = get_local_filename(translation_project, django_file.name) pootle_path = directory.pootle_path + local_filename # The full filesystem path to 'local_filename' upload_path = get_upload_path(translation_project, relative_root_dir, local_filename) try: store = translation_project.stores.get(pootle_path=pootle_path) except Store.DoesNotExist: store = None file_exists = os.path.exists(absolute_real_path(upload_path)) if store is not None and overwrite == 'overwrite' and not check_permission('overwrite', request): raise PermissionDenied(_("You do not have rights to overwrite files here.")) if store is None and not check_permission('administrate', request): raise PermissionDenied(_("You do not have rights to upload new files here.")) if overwrite == 'merge' and not check_permission('translate', request): raise PermissionDenied(_("You do not have rights to upload files here.")) if overwrite == 'suggest' and not check_permission('suggest', request): raise PermissionDenied(_("You do not have rights to upload files here.")) if store is None or (overwrite == 'overwrite' and store.file != ""): overwrite_file(request, relative_root_dir, django_file, upload_path) return newstore = factory.getobject(django_file, classes=factory_classes) #FIXME: are we sure this is what we want to do? shouldn't we # diffrentiate between structure changing uploads and mere # pretranslate uploads? suggestions = overwrite == 'merge' notranslate = overwrite == 'suggest' #allownewstrings = check_permission('overwrite', request) or check_permission('administrate', request) or check_permission('commit', request) #obsoletemissing = allownewstrings and overwrite == 'merge' store.mergefile(newstore, request.user.username, suggestions=suggestions, notranslate=notranslate, allownewstrings=False, obsoletemissing=False)
def test_submit_fuzzy_unit(client, store0, request_users, settings, system): """Test un/fuzzying units.""" settings.POOTLE_CAPTCHA_ENABLED = False user = request_users["user"] unit = store0.units.filter(state=UNTRANSLATED).first() if user.username != "nobody": client.login( username=user.username, password=request_users["password"]) url = '/xhr/units/%d/' % unit.id old_target = unit.target new_target = "%s changed" % unit.target response = client.post( url, dict(target_f_0=(new_target), is_fuzzy="1", sfn="PTL.editor.processSubmission"), HTTP_X_REQUESTED_WITH='XMLHttpRequest') unit.refresh_from_db() if check_permission('translate', response.wsgi_request): assert response.status_code == 200 assert unit.state == FUZZY assert unit.target == new_target else: assert response.status_code == 403 assert unit.state == UNTRANSLATED assert unit.target == old_target response = client.post( url, dict(target_f_0=(new_target), is_fuzzy="0", sfn="PTL.editor.processSubmission"), HTTP_X_REQUESTED_WITH='XMLHttpRequest') unit.refresh_from_db() if check_permission('translate', response.wsgi_request): assert response.status_code == 200 assert unit.state == TRANSLATED assert unit.target == new_target else: assert response.status_code == 403 assert unit.state == UNTRANSLATED assert unit.target == old_target # state is always untranslated if target is empty response = client.post( url, dict(target_f_0="", is_fuzzy="1", sfn="PTL.editor.processSubmission"), HTTP_X_REQUESTED_WITH='XMLHttpRequest') unit.refresh_from_db() if check_permission('translate', response.wsgi_request): assert response.status_code == 200 assert unit.target == "" else: assert response.status_code == 403 assert unit.target == old_target assert unit.state == UNTRANSLATED
def test_view_projects_translate(client, settings, request_users): user = request_users["user"] client.login( username=user.username, password=request_users["password"]) response = client.get(reverse("pootle-projects-translate")) if not user.is_superuser: assert response.status_code == 403 return ctx = response.context request = response.wsgi_request user_projects = Project.accessible_by_user(request.user) user_projects = ( Project.objects.for_user(request.user) .filter(code__in=user_projects)) obj = ProjectSet(user_projects) checks = get_qualitychecks() schema = {sc["code"]: sc for sc in get_qualitycheck_schema()} check_data = obj.data_tool.get_checks() _checks = {} for check, checkid in checks.items(): if check not in check_data: continue _checkid = schema[checkid]["name"] _checks[_checkid] = _checks.get( _checkid, dict(checks=[], title=schema[checkid]["title"])) _checks[_checkid]["checks"].append( dict( code=check, title=check_names[check], count=check_data[check])) _checks = OrderedDict( (k, _checks[k]) for k in CATEGORY_IDS.keys() if _checks.get(k)) assertions = dict( page="translate", has_admin_access=user.is_superuser, language=None, project=None, pootle_path="/projects/", ctx_path="/projects/", resource_path="", resource_path_parts=[], editor_extends="projects/all/base.html", checks=_checks, previous_url=get_previous_url(request), display_priority=False, cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), current_vfolder_pk="", POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL) view_context_test(ctx, **assertions)
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")
def _test_translate_view(project, request, response, kwargs, settings): if not request.user.is_superuser: assert response.status_code == 403 return ctx = response.context kwargs["project_code"] = project.code ctx_path = ( "/projects/%(project_code)s/" % kwargs) resource_path = ( "%(dir_path)s%(filename)s" % kwargs) pootle_path = "%s%s" % (ctx_path, resource_path) display_priority = False checks = get_qualitychecks() schema = {sc["code"]: sc for sc in get_qualitycheck_schema()} check_data = ctx["object"].data_tool.get_checks() _checks = {} for check, checkid in checks.items(): if check not in check_data: continue _checkid = schema[checkid]["name"] _checks[_checkid] = _checks.get( _checkid, dict(checks=[], title=schema[checkid]["title"])) _checks[_checkid]["checks"].append( dict( code=check, title=check_names[check], count=check_data[check])) _checks = OrderedDict( (k, _checks[k]) for k in CATEGORY_IDS.keys() if _checks.get(k)) view_context_test( ctx, **dict( page="translate", has_admin_access=request.user.is_superuser, language=None, project=project, pootle_path=pootle_path, ctx_path=ctx_path, resource_path=resource_path, resource_path_parts=get_path_parts(resource_path), editor_extends="projects/base.html", checks=_checks, previous_url=get_previous_url(request), display_priority=display_priority, cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), current_vfolder_pk="", POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL))
def _test_translate_view(tp, request, response, kwargs, settings): ctx = response.context obj = ctx["object"] kwargs["project_code"] = tp.project.code kwargs["language_code"] = tp.language.code resource_path = "%(dir_path)s%(filename)s" % kwargs request_path = "%s%s" % (tp.pootle_path, resource_path) checks = get_qualitychecks() schema = {sc["code"]: sc for sc in get_qualitycheck_schema()} check_data = obj.data_tool.get_checks() _checks = {} for check, checkid in checks.items(): if check not in check_data: continue _checkid = schema[checkid]["name"] _checks[_checkid] = _checks.get( _checkid, dict(checks=[], title=schema[checkid]["title"])) _checks[_checkid]["checks"].append( dict( code=check, title=CHECK_NAMES[check], count=check_data[check])) _checks = OrderedDict( (k, _checks[k]) for k in CATEGORY_IDS.keys() if _checks.get(k)) current_vfolder_pk = "" display_priority = False if not kwargs["filename"]: vf_view = vfolders_data_view.get(obj.__class__)(obj, request.user) display_priority = vf_view.has_data unit_api_root = "/xhr/units/" assertions = dict( page="translate", translation_project=tp, language=tp.language, project=tp.project, has_admin_access=check_permission('administrate', request), ctx_path=tp.pootle_path, pootle_path=request_path, resource_path=resource_path, resource_path_parts=get_path_parts(resource_path), editor_extends="translation_projects/base.html", checks=_checks, previous_url=get_previous_url(request), current_vfolder_pk=current_vfolder_pk, display_priority=display_priority, cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), unit_api_root=unit_api_root, POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL) view_context_test(ctx, **assertions)
def upload_form_factory(request): translation_project = request.translation_project choices = [] if check_permission('overwrite', request): choices.append(('overwrite', _("Overwrite the current file if it " "exists"))) if check_permission('translate', request): choices.append(('merge', _("Merge the file with the current file and " "turn conflicts into suggestions"))) if check_permission('suggest', request): choices.append(('suggest', _("Add all new translations as " "suggestions"))) if check_permission('translate', request): initial = 'merge' else: initial = 'suggest' class StoreFormField(forms.ModelChoiceField): def label_from_instance(self, instance): return instance.pootle_path[len(request.pootle_path):] class DirectoryFormField(forms.ModelChoiceField): def label_from_instance(self, instance): return instance.pootle_path[len(translation_project.pootle_path):] class UploadForm(forms.Form): file = forms.FileField(required=True, label=_('File')) overwrite = forms.ChoiceField( required=True, widget=forms.RadioSelect, label='', choices=choices, initial=initial ) upload_to = StoreFormField( required=False, label=_('Upload to'), queryset=translation_project.stores.filter( pootle_path__startswith=request.pootle_path), help_text=_("Optionally select the file you want to merge with. " "If not specified, the uploaded file's name is used.") ) upload_to_dir = DirectoryFormField( required=False, label=_('Upload to'), queryset=Directory.objects.filter( pootle_path__startswith=translation_project.pootle_path). \ exclude(pk=translation_project.directory.pk), help_text=_("Optionally select the file you want to merge with. " "If not specified, the uploaded file's name is used.") ) return UploadForm
def project_language_index(request, project_code): """page listing all languages added to project""" project = get_object_or_404(Project, code=project_code) request.permissions = get_matching_permissions( get_profile(request.user), project.directory ) if not check_permission('view', request): raise PermissionDenied can_edit = check_permission('administrate', request) translation_projects = project.translationproject_set.all() items = [make_language_item(request, translation_project) \ for translation_project in translation_projects.iterator()] items.sort(lambda x, y: locale.strcoll(x['title'], y['title'])) languagecount = len(translation_projects) project_stats = get_raw_stats(project) average = project_stats['translated']['percentage'] topstats = gentopstats_project(project) table_fields = ['name', 'progress', 'total', 'need-translation', 'activity'] table = { 'id': 'project', 'proportional': False, 'fields': table_fields, 'headings': get_table_headings(table_fields), 'items': items, } templatevars = { 'project': { 'code': project.code, 'name': project.fullname, 'description': project.description, 'summary': ungettext('%(languages)d language, %(average)d%% translated', '%(languages)d languages, %(average)d%% translated', languagecount, {"languages": languagecount, "average": average}), }, 'topstats': topstats, 'can_edit': can_edit, 'table': table, } if can_edit: from pootle_project.forms import DescriptionForm templatevars['form'] = DescriptionForm(instance=project) return render_to_response('project/project.html', templatevars, context_instance=RequestContext(request))
def view(request, path): #FIXME: why do we have leading and trailing slashes in pootle_path? pootle_path = '/%s' % path directory = get_object_or_404(Directory, pootle_path=pootle_path) request.permissions = get_matching_permissions(get_profile(request.user), directory) if not check_permission('view', request): raise PermissionDenied template_vars = {'path': path, 'directory': directory} # Find language and project defaults, passed to handle_form proj = None lang = None if not directory.is_language() and not directory.is_project(): translation_project = directory.translation_project lang = translation_project.language proj = translation_project.project else: if directory.is_language(): lang = directory.language proj = None if directory.is_project(): lang = None proj = directory.project if check_permission('administrate', request): # Thus, form is only set for the template if the user has # 'administrate' permission template_vars['form'] = handle_form(request, directory, proj, lang, template_vars) template_vars['title'] = directory_to_title(directory) else: template_vars['form'] = None if request.GET.get('all', False): template_vars['notices'] = Notice.objects.filter(directory__pootle_path__startswith=directory.pootle_path).select_related('directory')[:30] else: template_vars['notices'] = Notice.objects.filter(directory=directory).select_related('directory')[:30] if not directory.is_language() and not directory.is_project(): request.translation_project = directory.translation_project template_vars['translation_project'] = request.translation_project template_vars['language'] = request.translation_project.language template_vars['project'] = request.translation_project.project return render_to_response('notices.html', template_vars, context_instance=RequestContext(request))
def upload_zip(request, path_obj): if (check_permission('translate', request) or check_permission('suggest', request) or check_permission('overwrite', request)): text = _('Upload (.zip)') link = '#' return { 'icon': 'icon-upload', 'class': 'js-overview-actions-upload', 'href': link, 'text': text, }
def _test_translate_view(tp, request, response, kwargs, settings): ctx = response.context obj = ctx["object"] kwargs["project_code"] = tp.project.code kwargs["language_code"] = tp.language.code resource_path = "%(dir_path)s%(filename)s" % kwargs request_path = "%s%s" % (tp.pootle_path, resource_path) if request.path.startswith("/++vfolder"): vfolder = VirtualFolder.objects.get( name=request.resolver_match.kwargs["vfolder_name"]) current_vfolder_pk = vfolder.pk display_priority = False unit_api_root = reverse( "vfolder-pootle-xhr-units", kwargs=dict(vfolder_name=vfolder.name)) resource_path = ( "/".join( ["++vfolder", vfolder.name, ctx['object'].pootle_path.replace(tp.pootle_path, "")])) else: vfolder = None current_vfolder_pk = "" display_priority = False if not kwargs["filename"]: vf_view = vfolders_data_view.get(obj.__class__)(obj, request.user) display_priority = vf_view.has_data unit_api_root = "/xhr/units/" assertions = dict( page="translate", translation_project=tp, language=tp.language, project=tp.project, has_admin_access=check_permission('administrate', request), ctx_path=tp.pootle_path, pootle_path=request_path, resource_path=resource_path, resource_path_parts=get_path_parts(resource_path), editor_extends="translation_projects/base.html", check_categories=get_qualitycheck_schema(), previous_url=get_previous_url(request), current_vfolder_pk=current_vfolder_pk, display_priority=display_priority, cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), unit_api_root=unit_api_root, POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL) view_context_test(ctx, **assertions)
def translate_page(request): cantranslate = check_permission("translate", request) cansuggest = check_permission("suggest", request) canreview = check_permission("review", request) translation_project = request.translation_project language = translation_project.language project = translation_project.project profile = request.profile store = getattr(request, "store", None) directory = getattr(request, "directory", None) is_single_file = store and True or False path = is_single_file and store.path or directory.path pootle_path = (is_single_file and store.pootle_path or directory.pootle_path) is_terminology = (project.is_terminology or store and store.is_terminology) search_form = make_search_form(request=request, terminology=is_terminology) previous_overview_url = previous_view_url(request, ['overview']) context = { 'cantranslate': cantranslate, 'cansuggest': cansuggest, 'canreview': canreview, 'search_form': search_form, 'store': store, 'store_id': store and store.id, 'directory': directory, 'directory_id': directory and directory.id, 'path': path, 'pootle_path': pootle_path, 'is_single_file': is_single_file, 'language': language, 'project': project, 'translation_project': translation_project, 'profile': profile, 'source_language': translation_project.project.source_language, 'previous_overview_url': previous_overview_url, 'MT_BACKENDS': settings.MT_BACKENDS, 'LOOKUP_BACKENDS': settings.LOOKUP_BACKENDS, 'AMAGAMA_URL': settings.AMAGAMA_URL, } return render_to_response('store/translate.html', context, context_instance=RequestContext(request))
def __init__(self, request, data=None, files=None): choices = [('merge', _("Merge the file with the current file and turn conflicts into suggestions")), ('suggest', _("Add all new translations as suggestions"))] if check_permission('overwrite', request): choices.insert(0, ('overwrite', _("Overwrite the current file if it exists"))) class UploadForm(forms.Form): file = forms.FileField(required=True, label=_('File')) overwrite = forms.ChoiceField(required=True, widget=forms.RadioSelect, label='', choices=choices, initial='merge') self.Form = UploadForm super(UploadHandler, self).__init__(request, data, files) self.form.allow_overwrite = check_permission('overwrite', request) self.form.title = _("Upload File")
def upload_zip(request, path_obj, **kwargs): if (check_permission('translate', request) or check_permission('suggest', request) or check_permission('overwrite', request)): text = _('Upload') tooltip = _('Upload translation files or archives in .zip format') link = '#upload' return { 'icon': 'icon-upload', 'class': 'js-popup-inline', 'href': link, 'text': text, 'tooltip': tooltip, }
def get_items(request, model, get_last_action, name_func): items = [] if not check_permission('view', request): return items for item in model.iterator(): stats = item.getquickstats() stats = add_percentages(stats) lastact = get_last_action(item) items.append({ 'code': item.code, 'name': name_func(item.fullname), 'lastactivity': lastact, 'trans': stats["translatedsourcewords"], 'fuzzy': stats["fuzzysourcewords"], 'untrans': stats["untranslatedsourcewords"], 'total': stats["totalsourcewords"], 'transper': stats["translatedpercentage"], 'fuzzyper': stats["fuzzypercentage"], 'untransper': stats["untranslatedpercentage"], 'completed_title': _("%(percentage)d%% complete", {'percentage': stats['translatedpercentage']}), }) items.sort(lambda x, y: locale.strcoll(x['name'], y['name'])) return items
def overview(request, translation_project, dir_path, filename=None): if not check_permission("view", request): raise PermissionDenied(_("You do not have rights to access this " "translation project.")) 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 else: directory = get_object_or_404(Directory, pootle_path=current_path) store = None request.current_path = current_path view_obj = ProjectIndexView(forms=dict(upload=UploadHandler, ) ) return render_to_response("translation_project/overview.html", view_obj(request, translation_project, directory, store), context_instance=RequestContext(request))
def reject_suggestion(request, unit, suggid): json = { 'udbid': unit.id, 'sugid': suggid, } try: sugg = unit.suggestion_set.get(id=suggid) except ObjectDoesNotExist: raise Http404 # In order to be able to reject a suggestion, users have to either: # 1. Have `review` rights, or # 2. Be the author of the suggestion being rejected if (not check_permission('review', request) and (request.user.is_anonymous() or request.user != sugg.user)): raise PermissionDenied(_('Insufficient rights to access review mode.')) unit.reject_suggestion(sugg, request.translation_project, request.user) r_data = QueryDict(request.body) if "comment" in r_data and r_data["comment"]: kwargs = dict( comment=r_data["comment"], user=request.user, ) comment_form = UnsecuredCommentForm(sugg, kwargs) if comment_form.is_valid(): comment_form.save() json['user_score'] = request.user.public_score return JsonResponse(json)
def unit_form_factory(language, snplurals=None, request=None): if snplurals is not None: tnplurals = language.nplurals else: tnplurals = 1 action_disabled = False if request is not None: cantranslate = check_permission("translate", request) cansuggest = check_permission("suggest", request) if not (cansuggest or cantranslate): action_disabled = True target_attrs = { 'lang': language.code, 'dir': language.direction, 'class': 'translation expanding focusthis js-translation-area', 'rows': 2, 'tabindex': 10, } fuzzy_attrs = { 'accesskey': 'f', 'class': 'fuzzycheck', 'tabindex': 13, } if action_disabled: target_attrs['disabled'] = 'disabled' fuzzy_attrs['disabled'] = 'disabled' class UnitForm(forms.ModelForm): class Meta: model = Unit fields = ( 'id', 'index', 'target_f', 'state', ) id = forms.IntegerField(required=False) target_f = MultiStringFormField( nplurals=tnplurals, required=False, attrs=target_attrs, ) state = UnitStateField( required=False, label=_('Needs work'), widget=forms.CheckboxInput( attrs=fuzzy_attrs, check_test=lambda x: x == FUZZY, ), ) similarity = forms.FloatField(required=False) mt_similarity = forms.FloatField(required=False) def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super(UnitForm, self).__init__(*args, **kwargs) self.updated_fields = [] self.fields['target_f'].widget.attrs['data-translation-aid'] = \ self['target_f'].value() def clean_target_f(self): value = self.cleaned_data['target_f'] if self.instance.target.strings != multistring(value or [u'']): self.instance._target_updated = True self.updated_fields.append( (SubmissionFields.TARGET, to_db(self.instance.target), to_db(value))) return value def clean_state(self): old_state = self.instance.state # Integer is_fuzzy = self.cleaned_data['state'] # Boolean new_target = self.cleaned_data['target_f'] if (self.request is not None and not check_permission('administrate', self.request) and is_fuzzy): raise forms.ValidationError(_('Fuzzy flag must be cleared')) if new_target: if old_state == UNTRANSLATED: self.instance._save_action = TRANSLATION_ADDED self.instance.store.mark_dirty( CachedMethods.WORDCOUNT_STATS) else: self.instance._save_action = TRANSLATION_CHANGED if is_fuzzy: new_state = FUZZY else: new_state = TRANSLATED else: new_state = UNTRANSLATED if old_state > FUZZY: self.instance._save_action = TRANSLATION_DELETED self.instance.store.mark_dirty( CachedMethods.WORDCOUNT_STATS) if is_fuzzy != (old_state == FUZZY): # when Unit toggles its FUZZY state the number of translated words # also changes self.instance.store.mark_dirty(CachedMethods.WORDCOUNT_STATS, CachedMethods.LAST_ACTION) if old_state != new_state and old_state != OBSOLETE: self.instance._state_updated = True self.updated_fields.append( (SubmissionFields.STATE, old_state, new_state)) return new_state self.instance._state_updated = False return old_state def clean_similarity(self): value = self.cleaned_data['similarity'] if 0 <= value <= 1 or value is None: return value raise forms.ValidationError( _('Value of `similarity` should be in in the [0..1] range')) def clean_mt_similarity(self): value = self.cleaned_data['mt_similarity'] if 0 <= value <= 1 or value is None: return value raise forms.ValidationError( _('Value of `mt_similarity` should be in in the [0..1] range')) return UnitForm
def is_admin(self): return check_permission('administrate', self.request)
def unit_form_factory(language, snplurals=None, request=None): if snplurals is not None: tnplurals = language.nplurals else: tnplurals = 1 action_disabled = False if request is not None: cantranslate = check_permission("translate", request) cansuggest = check_permission("suggest", request) if not (cansuggest or cantranslate): action_disabled = True target_attrs = { 'lang': language.code, 'dir': language.direction, 'class': 'translation expanding focusthis js-translation-area', 'rows': 2, 'tabindex': 10, } fuzzy_attrs = { 'accesskey': 'f', 'class': 'fuzzycheck', 'tabindex': 13, } if action_disabled: target_attrs['disabled'] = 'disabled' fuzzy_attrs['disabled'] = 'disabled' class UnitForm(forms.ModelForm): class Meta(object): model = Unit fields = ('target_f', ) target_f = MultiStringFormField( nplurals=tnplurals, required=False, attrs=target_attrs, ) is_fuzzy = forms.BooleanField( required=False, label=_("Needs work"), widget=forms.CheckboxInput(attrs=fuzzy_attrs)) suggestion = forms.ModelChoiceField(queryset=Suggestion.objects.all(), required=False) comment = forms.CharField(required=False) def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) self.user = self.request.user super(UnitForm, self).__init__(*args, **kwargs) self._updated_fields = [] self.fields['target_f'].widget.attrs['data-translation-aid'] = \ self['target_f'].value() self.initial.update(dict(is_fuzzy=(self.instance.state == FUZZY))) @property def updated_fields(self): order_dict = { SubmissionFields.STATE: 0, SubmissionFields.TARGET: 1, } return sorted(self._updated_fields, key=lambda x: order_dict[x[0]]) def clean_target_f(self): value = self.cleaned_data['target_f'] if self.instance.target != multistring(value or [u'']): self._updated_fields.append( (SubmissionFields.TARGET, to_db(self.instance.target), to_db(value))) return value def clean_is_fuzzy(self): return self.data.get("is_fuzzy", None) and True or False def clean(self): old_state = self.instance.state # Integer is_fuzzy = self.cleaned_data['is_fuzzy'] # Boolean new_target = self.cleaned_data['target_f'] # If suggestion is provided set `old_state` should be `TRANSLATED`. if self.cleaned_data['suggestion']: old_state = TRANSLATED # Skip `TARGET` field submission if suggestion value is equal # to submitted translation if new_target == self.cleaned_data['suggestion'].target_f: self._updated_fields = [] not_cleared = (self.request is not None and not check_permission('administrate', self.request) and is_fuzzy) if not_cleared: self.add_error( 'is_fuzzy', forms.ValidationError( _('Needs work flag must be cleared'))) if new_target: if is_fuzzy: new_state = FUZZY else: new_state = TRANSLATED else: new_state = UNTRANSLATED if old_state not in [new_state, OBSOLETE]: self._updated_fields.append( (SubmissionFields.STATE, old_state, new_state)) self.cleaned_data['state'] = new_state else: self.cleaned_data['state'] = old_state return super(UnitForm, self).clean() def save(self, *args, **kwargs): if not self.updated_fields: return changed_with = kwargs.pop("changed_with", None) suggestion = self.cleaned_data["suggestion"] with update_store_after(self.instance.store): user = (suggestion.user if suggestion else self.user) self.instance.save(user=user, changed_with=changed_with) return self.instance return UnitForm
def _test_browse_view(tp, request, response, kwargs): cookie_data = json.loads( unquote(response.cookies[SIDEBAR_COOKIE_NAME].value)) assert cookie_data["foo"] == "bar" assert "announcements_projects_%s" % tp.project.code in cookie_data assert "announcements_%s" % tp.language.code in cookie_data assert ("announcements_%s_%s" % (tp.language.code, tp.project.code) in cookie_data) ctx = response.context kwargs["project_code"] = tp.project.code kwargs["language_code"] = tp.language.code resource_path = "%(dir_path)s%(filename)s" % kwargs pootle_path = "%s%s" % (tp.pootle_path, resource_path) if not (kwargs["dir_path"] or kwargs.get("filename")): obj = tp.directory elif not kwargs.get("filename"): obj = Directory.objects.get(pootle_path=pootle_path) else: obj = Store.objects.get(pootle_path=pootle_path) if obj.tp_path == "/": data_obj = obj.tp else: data_obj = obj if not kwargs.get("filename"): vf_view = vfolders_data_view.get(obj.__class__)(obj, request.user) vf_stats = ({} if not vf_view else StatsDisplay( data_obj, stats=vf_view.stats).stats) stats = (dict(vfolders=vf_stats["children"]) if vf_stats else {}) stats.update( StatsDisplay( data_obj, stats=data_obj.data_tool.get_stats(user=request.user)).stats) vfolders = True else: stats = StatsDisplay( data_obj, data_obj.data_tool.get_stats(user=request.user)).stats vfolders = None filters = {} if vfolders: filters['sort'] = 'priority' dirs_with_vfolders = set( split_pootle_path(path)[2].split("/")[0] for path in tp.stores.filter( vfolders__isnull=False).values_list("pootle_path", flat=True)) directories = [ make_directory_item( child, **(dict( sort="priority") if child.name in dirs_with_vfolders else {})) for child in obj.get_children() if isinstance(child, Directory) ] stores = [ make_store_item(child) for child in obj.get_children() if isinstance(child, Store) ] items = directories + stores for item in items: if item["code"] in stats["children"]: item["stats"] = stats["children"][item["code"]] elif item["title"] in stats["children"]: item["stats"] = stats["children"][item["title"]] if not kwargs.get("filename"): table_fields = [ 'name', 'progress', 'total', 'need-translation', 'suggestions', 'critical', 'last-updated', 'activity' ] table = { 'id': 'tp', 'fields': table_fields, 'headings': get_table_headings(table_fields), 'items': items } else: table = None checks = ChecksDisplay(obj).checks_by_category del stats["children"] User = get_user_model() top_scorers = User.top_scorers(language=tp.language.code, project=tp.project.code, limit=11) assertions = dict( page="browse", object=obj, translation_project=tp, language=tp.language, project=tp.project, has_admin_access=check_permission('administrate', request), is_store=(kwargs.get("filename") and True or False), browser_extends="translation_projects/base.html", pootle_path=pootle_path, resource_path=resource_path, resource_path_parts=get_path_parts(resource_path), translation_states=get_translation_states(obj), checks=checks, top_scorers=top_scorers, top_scorers_data=get_top_scorers_data(top_scorers, 10), url_action_continue=obj.get_translate_url(state='incomplete', **filters), url_action_fixcritical=obj.get_critical_url(**filters), url_action_review=obj.get_translate_url(state='suggestions', **filters), url_action_view_all=obj.get_translate_url(state='all'), stats=stats, parent=get_parent(obj)) if table: assertions["table"] = table sidebar = get_sidebar_announcements_context(request, (tp.project, tp.language, tp)) for k in ["has_sidebar", "is_sidebar_open", "announcements"]: assertions[k] = sidebar[0][k] view_context_test(ctx, **assertions) if vfolders: for vfolder in ctx["vfolders"]["items"]: assert (vfolder["is_grayed"] and not ctx["has_admin_access"]) is False assert ctx["vfolders"]["items"] == vf_view.table_items assert (('display_download' in ctx and ctx['display_download']) == (request.user.is_authenticated() and check_permission( 'translate', request)))
def handle_upload_form(request, tp): """Process the upload form.""" valid_extensions = tp.project.filetype_tool.valid_extensions if "po" not in valid_extensions: return {} language = tp.language team = language_team.get(tp.language.__class__)(language) uploader_list = [ (request.user.id, request.user.display_name), ] if check_permission('administrate', request): User = get_user_model() uploader_list = [(user.id, user.display_name) for user in (team.submitters | team.reviewers | team.admins | team.superusers)] if request.method == "POST" and "file" in request.FILES: upload_form = UploadForm(request.POST, request.FILES, uploader_list=uploader_list) if upload_form.is_valid(): uploader_id = upload_form.cleaned_data["user_id"] django_file = request.FILES["file"] uploader = request.user if uploader_id and uploader_id != uploader.id: User = get_user_model() uploader = User.objects.get( id=upload_form.cleaned_data["user_id"]) try: if is_zipfile(django_file): with ZipFile(django_file, "r") as zf: for path in zf.namelist(): if path.endswith("/"): # is a directory continue ext = os.path.splitext(path)[1].strip(".") if ext not in valid_extensions: continue with zf.open(path, "r") as f: import_file(f, user=uploader) else: # It is necessary to seek to the beginning because # is_zipfile f***s the file, and thus cannot be read. django_file.seek(0) import_file(django_file, user=uploader) except Exception as e: upload_form.add_error("file", e) return { "upload_form": upload_form, } else: return { "upload_form": upload_form, } # Always return a blank upload form unless the upload form is not valid. return { "upload_form": UploadForm(uploader_list=uploader_list, initial=dict(user_id=request.user.id)), }
def project_admin(request, project_code): """adding and deleting project languages""" current_project = Project.objects.get(code=project_code) request.permissions = get_matching_permissions(get_profile(request.user), current_project.directory) if not check_permission('administrate', request): raise PermissionDenied( _("You do not have rights to administer " "this project.")) template_translation_project = current_project \ .get_template_translationproject() class TranslationProjectForm(forms.ModelForm): if template_translation_project is not None: update = forms.BooleanField(required=False, label=_("Update against templates")) #FIXME: maybe we can detect if initialize is needed to avoid # displaying it when not relevant #initialize = forms.BooleanField(required=False, label=_("Initialize")) project = forms.ModelChoiceField( queryset=Project.objects.filter(pk=current_project.pk), initial=current_project.pk, widget=forms.HiddenInput) language = LiberalModelChoiceField( label=_("Language"), queryset=Language.objects.exclude( translationproject__project=current_project), widget=forms.Select(attrs={ 'class': 'js-select2 select2-language', }), ) class Meta: prefix = "existing_language" model = TranslationProject def process_extra_fields(self): if self.instance.pk is not None: if self.cleaned_data.get('initialize', None): self.instance.initialize() if (self.cleaned_data.get('update', None) or not self.instance.stores.count()): self.instance.update_against_templates() queryset = TranslationProject.objects.filter( project=current_project).order_by('pootle_path') model_args = { 'project': { 'code': current_project.code, 'name': current_project.fullname, } } link = lambda instance: '<a href="%s">%s</a>' % ( l(instance.pootle_path + 'admin_permissions.html'), instance.language, ) return util.edit(request, 'project/project_admin.html', TranslationProject, model_args, link, linkfield="language", queryset=queryset, can_delete=True, form=TranslationProjectForm, formset=TranslationProjectFormSet, exclude=('description', ))
def must_display(cls, request, *args, **kwargs): return check_permission('translate', request) or \ check_permission('suggest', request) or \ check_permission('overwrite', request)
def browse(request, translation_project, dir_path, filename=None): project = translation_project.project language = translation_project.language directory = request.directory store = request.store is_admin = check_permission('administrate', request) ctx, cookie_data = get_sidebar_announcements_context( request, project.code, language.code) ctx.update(get_browser_context(request)) # TODO improve plugin logic if "import_export" in settings.INSTALLED_APPS and request.user.is_authenticated( ): from import_export.views import handle_upload_form ctx.update(handle_upload_form(request)) has_download = (not translation_project.is_terminology_project and (check_permission('translate', request) or check_permission('suggest', request))) ctx.update({ 'display_download': has_download, 'has_sidebar': True, }) stats = request.resource_obj.get_stats() if store is None: table_fields = [ 'name', 'progress', 'total', 'need-translation', 'suggestions', 'critical', 'last-updated', 'activity' ] ctx.update({ 'table': { 'id': 'tp', 'fields': table_fields, 'headings': get_table_headings(table_fields), 'items': get_children(directory), } }) if 'virtualfolder' in settings.INSTALLED_APPS: vfolders = get_vfolders(directory, all_vfolders=is_admin) if len(vfolders) > 0: table_fields = [ 'name', 'priority', 'progress', 'total', 'need-translation', 'suggestions', 'critical', 'last-updated', 'activity' ] ctx.update({ 'vfolders': { 'id': 'vfolders', 'fields': table_fields, 'headings': get_table_headings(table_fields), 'items': vfolders, }, }) #FIXME: set vfolders stats in the resource, don't inject them here. stats['vfolders'] = {} for vfolder_treeitem in directory.vf_treeitems.iterator(): if request.user.is_superuser or vfolder_treeitem.is_visible: stats['vfolders'][vfolder_treeitem.code] = \ vfolder_treeitem.get_stats(include_children=False) ctx.update({ 'parent': get_parent(directory if store is None else store), 'translation_project': translation_project, 'project': project, 'language': language, 'stats': jsonify(stats), 'is_admin': is_admin, 'is_store': store is not None, 'browser_extends': 'translation_projects/base.html', }) response = render(request, 'browser/index.html', ctx) if cookie_data: response.set_cookie(SIDEBAR_COOKIE_NAME, cookie_data) return response
def is_active(self, request): """Check if the action is active.""" return check_permission(self.permission, request)
def __init__(self, request, data=None, files=None): choices = [] if check_permission('overwrite', request): choices.append( ('overwrite', _("Overwrite the current file if it exists"))) if check_permission('translate', request): choices.append(('merge', _("Merge the file with the current file and turn " "conflicts into suggestions"))) if check_permission('suggest', request): choices.append( ('suggest', _("Add all new translations as suggestions"))) translation_project = request.translation_project class StoreFormField(forms.ModelChoiceField): def label_from_instance(self, instance): return instance.pootle_path[len(request.current_path):] class DirectoryFormField(forms.ModelChoiceField): def label_from_instance(self, instance): return instance.pootle_path[len(translation_project.pootle_path ):] class UploadForm(forms.Form): file = forms.FileField(required=True, label=_('File')) if check_permission('translate', request): initial = 'merge' else: initial = 'suggest' overwrite = forms.ChoiceField(required=True, widget=forms.RadioSelect, label='', choices=choices, initial=initial) upload_to = StoreFormField( required=False, label=_('Upload to'), queryset=translation_project.stores.filter( pootle_path__startswith=request.current_path), help_text=_("Optionally select the file you want to " "merge with. If not specified, the uploaded " "file's name is used.")) upload_to_dir = DirectoryFormField( required=False, label=_('Upload to'), queryset=Directory.objects.filter( pootle_path__startswith=translation_project.pootle_path).\ exclude(pk=translation_project.directory.pk), help_text=_("Optionally select the file you want to " "merge with. If not specified, the uploaded " "file's name is used.")) self.Form = UploadForm super(UploadHandler, self).__init__(request, data, files) self.form.allow_overwrite = check_permission('overwrite', request) self.form.title = _("Upload File")
def overview(request, translation_project, dir_path, filename=None): project = translation_project.project language = translation_project.language directory = request.directory store = request.store # TODO: cleanup and refactor, retrieve from cache try: ann_virtual_path = 'announcements/projects/' + project.code announcement = StaticPage.objects.live(request.user).get( virtual_path=ann_virtual_path, ) except StaticPage.DoesNotExist: announcement = None has_announcement = announcement is not None has_sidebar = has_announcement is_sidebar_open = True stored_mtime = None new_mtime = None cookie_data = {} if ANN_COOKIE_NAME in request.COOKIES: json_str = unquote(request.COOKIES[ANN_COOKIE_NAME]) cookie_data = json.loads(json_str) if 'isOpen' in cookie_data: is_sidebar_open = cookie_data['isOpen'] if project.code in cookie_data: stored_mtime = cookie_data[project.code] if announcement is not None: ann_mtime = dateformat.format(announcement.modified_on, 'U') if ann_mtime != stored_mtime: is_sidebar_open = True new_mtime = ann_mtime ctx = get_overview_context(request) # TODO improve plugin logic if "import_export" in settings.INSTALLED_APPS and request.user.is_authenticated( ): from import_export.views import handle_upload_form from pootle_app.models.permissions import check_permission ctx.update(handle_upload_form(request)) has_download = (check_permission('translate', request) or check_permission('suggest', request)) ctx.update({ 'display_download': has_download, }) has_sidebar = True ctx.update({ 'translation_project': translation_project, 'project': project, 'language': language, 'stats': jsonify(request.resource_obj.get_stats()), 'browser_extends': 'translation_projects/base.html', 'announcement': announcement, 'is_sidebar_open': is_sidebar_open, 'has_sidebar': has_sidebar, }) if store is None: table_fields = [ 'name', 'progress', 'total', 'need-translation', 'suggestions', 'critical', 'last-updated', 'activity' ] ctx.update({ 'table': { 'id': 'tp', 'fields': table_fields, 'headings': get_table_headings(table_fields), 'parent': get_parent(directory), 'items': get_children(directory), } }) response = render(request, 'browser/overview.html', ctx) if new_mtime is not None: cookie_data[project.code] = new_mtime cookie_data = quote(json.dumps(cookie_data)) response.set_cookie(ANN_COOKIE_NAME, cookie_data) return response
def decorated_f(request, path_obj, *args, **kwargs): request.permissions = get_matching_permissions(get_profile(request.user), path_obj.directory) if check_permission(permission_code, request): return f(request, path_obj, *args, **kwargs) else: raise PermissionDenied(_("You do not have rights to administer %s.", path_obj.fullname))
def has_admin_access(self): return check_permission('administrate', self.request)
def test_submit_with_suggestion_and_comment(client, request_users, settings, system): """Tests translation can be applied after suggestion is accepted.""" settings.POOTLE_CAPTCHA_ENABLED = False Comment = get_comment_model() unit = Unit.objects.filter(suggestion__state__name='pending', state=UNTRANSLATED)[0] last_sub_pk = unit.submission_set.order_by("id").values_list( "id", flat=True).last() or 0 sugg = Suggestion.objects.filter(unit=unit, state__name='pending')[0] user = request_users["user"] if user.username != "nobody": client.login(username=user.username, password=request_users["password"]) url = '/xhr/units/%d/' % unit.id edited_target = "Edited %s" % sugg.target_f comment = 'This is a comment!' qdict = QueryDict(mutable=True) qdict.update({ 'state': False, 'target_f_0': edited_target, 'suggestion': sugg.id, 'comment': comment }) qdict._mutable = False response = client.post(url, qdict, HTTP_X_REQUESTED_WITH='XMLHttpRequest') suggestion = Suggestion.objects.get(id=sugg.id) unit = Unit.objects.get(id=unit.id) new_subs = unit.submission_set.filter(id__gt=last_sub_pk).order_by("id") if check_permission('translate', response.wsgi_request): assert response.status_code == 200 content = json.loads(response.content) assert content['newtargets'] == [edited_target] assert content['user_score'] == response.wsgi_request.user.public_score assert content['checks'] is None unit_source = unit.unit_source assert unit_source.created_by == system assert unit_source.created_with == SubmissionTypes.SYSTEM assert unit.change.submitted_by == suggestion.user if user == suggestion.user: assert unit.change.reviewed_by is None assert unit.change.reviewed_on is None else: assert unit.change.reviewed_by == user assert unit.change.reviewed_on == unit.mtime assert unit.change.changed_with == SubmissionTypes.WEB assert suggestion.state.name == 'accepted' assert suggestion.is_accepted assert str(unit.target) == edited_target assert (Comment.objects.for_model(suggestion).get().comment == comment) assert new_subs.count() == 2 target_sub = new_subs[0] assert target_sub.old_value == "" assert target_sub.new_value == unit.target assert target_sub.field == SubmissionFields.TARGET assert target_sub.type == SubmissionTypes.WEB assert target_sub.submitter == unit.change.submitted_by assert target_sub.suggestion == suggestion assert target_sub.revision == unit.revision assert target_sub.creation_time == unit.mtime state_sub = new_subs[1] assert state_sub.old_value == str(UNTRANSLATED) assert state_sub.new_value == str(unit.state) assert state_sub.suggestion == suggestion assert state_sub.field == SubmissionFields.STATE assert state_sub.type == SubmissionTypes.WEB assert state_sub.submitter == unit.change.submitted_by assert state_sub.revision == unit.revision assert state_sub.creation_time == unit.mtime else: assert response.status_code == 403 assert suggestion.state.name == "pending" assert suggestion.is_pending assert unit.target == "" assert new_subs.count() == 0 with pytest.raises(UnitChange.DoesNotExist): unit.change
def upload_file(request, directory, django_file, overwrite, store=None): translation_project = request.translation_project relative_root_dir = directory.pootle_path[len(translation_project. pootle_path):] # for some reason factory checks explicitly for file existance and # if file is open, which makes it difficult to work with Django's # in memory uploads. # # setting _closed to False should work around this #FIXME: hackish, does this have any undesirable side effect? if getattr(django_file, '_closed', None) is None: try: django_file._closed = False except AttributeError: pass # factory also checks for _mode if getattr(django_file, '_mode', None) is None: try: django_file._mode = 1 except AttributeError: pass # mode is an attribute not a property in Django 1.1 if getattr(django_file, 'mode', None) is None: django_file.mode = 1 if store and store.file: # uploading to an existing file pootle_path = store.pootle_path upload_path = store.real_path elif store: # uploading to a virtual store pootle_path = store.pootle_path upload_path = get_upload_path(translation_project, relative_root_dir, store.name) else: local_filename = get_local_filename(translation_project, django_file.name) pootle_path = directory.pootle_path + local_filename # The full filesystem path to 'local_filename' upload_path = get_upload_path(translation_project, relative_root_dir, local_filename) try: store = translation_project.stores.get(pootle_path=pootle_path) except Store.DoesNotExist: store = None if (store is not None and overwrite == 'overwrite' and not check_permission('overwrite', request)): raise PermissionDenied( _("You do not have rights to overwrite " "files here.")) if store is None and not check_permission('administrate', request): raise PermissionDenied( _("You do not have rights to upload new " "files here.")) if overwrite == 'merge' and not check_permission('translate', request): raise PermissionDenied( _("You do not have rights to upload " "files here.")) if overwrite == 'suggest' and not check_permission('suggest', request): raise PermissionDenied( _("You do not have rights to upload " "files here.")) if store is None or (overwrite == 'overwrite' and store.file != ""): overwrite_file(request, relative_root_dir, django_file, upload_path) return if store.file and store.file.read() == django_file.read(): logging.debug(u"identical file uploaded to %s, not merging", store.pootle_path) return django_file.seek(0) from translate.storage import factory newstore = factory.getobject(django_file, classes=factory_classes) #FIXME: are we sure this is what we want to do? shouldn't we # diffrentiate between structure changing uploads and mere # pretranslate uploads? suggestions = overwrite == 'merge' notranslate = overwrite == 'suggest' allownewstrings = overwrite == 'overwrite' and store.file == '' store.mergefile(newstore, get_profile(request.user), suggestions=suggestions, notranslate=notranslate, allownewstrings=allownewstrings, obsoletemissing=allownewstrings)
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")
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 can_edit: from pootle_translationproject.forms import DescriptionForm template_vars['form'] = DescriptionForm( instance=translation_project) return template_vars
def unit_form_factory(language, snplurals=None, request=None): if snplurals is not None: tnplurals = language.nplurals else: tnplurals = 1 action_disabled = False if request is not None: cantranslate = check_permission("translate", request) cansuggest = check_permission("suggest", request) if not (cansuggest or cantranslate): action_disabled = True target_attrs = { 'lang': language.code, 'dir': language.direction, 'class': 'translation expanding focusthis js-translation-area', 'rows': 2, 'tabindex': 10, } fuzzy_attrs = { 'accesskey': 'f', 'class': 'fuzzycheck', 'tabindex': 13, } if action_disabled: target_attrs['disabled'] = 'disabled' fuzzy_attrs['disabled'] = 'disabled' class UnitForm(forms.ModelForm): class Meta(object): model = Unit fields = ('target_f', 'state',) target_f = MultiStringFormField( nplurals=tnplurals, required=False, attrs=target_attrs, ) state = UnitStateField( required=False, label=_('Needs work'), widget=forms.CheckboxInput( attrs=fuzzy_attrs, check_test=lambda x: x == FUZZY, ), ) similarity = forms.FloatField(required=False) mt_similarity = forms.FloatField(required=False) suggestion = forms.ModelChoiceField( queryset=Suggestion.objects.all(), required=False) comment = forms.CharField(required=False) def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super(UnitForm, self).__init__(*args, **kwargs) self._updated_fields = [] self.fields['target_f'].widget.attrs['data-translation-aid'] = \ self['target_f'].value() @property def updated_fields(self): order_dict = { SubmissionFields.STATE: 0, SubmissionFields.TARGET: 1, } return sorted(self._updated_fields, key=lambda x: order_dict[x[0]]) def clean_target_f(self): value = self.cleaned_data['target_f'] if self.instance.target != multistring(value or [u'']): self.instance._target_updated = True self._updated_fields.append((SubmissionFields.TARGET, to_db(self.instance.target), to_db(value))) return value def clean_similarity(self): value = self.cleaned_data['similarity'] if 0 <= value <= 1 or value is None: return value raise forms.ValidationError( _('Value of `similarity` should be in in the [0..1] range') ) def clean_mt_similarity(self): value = self.cleaned_data['mt_similarity'] if 0 <= value <= 1 or value is None: return value raise forms.ValidationError( _('Value of `mt_similarity` should be in in the [0..1] range') ) def clean(self): old_state = self.instance.state # Integer is_fuzzy = self.cleaned_data['state'] # Boolean new_target = self.cleaned_data['target_f'] # If suggestion is provided set `old_state` should be `TRANSLATED`. if self.cleaned_data['suggestion']: old_state = TRANSLATED # Skip `TARGET` field submission if suggestion value is equal # to submitted translation if new_target == self.cleaned_data['suggestion'].target_f: self._updated_fields = [] if (self.request is not None and not check_permission('administrate', self.request) and is_fuzzy): self.add_error('state', forms.ValidationError( _('Needs work flag must be ' 'cleared'))) if new_target: if old_state == UNTRANSLATED: self.instance._save_action = TRANSLATION_ADDED self.instance.store.mark_dirty( CachedMethods.WORDCOUNT_STATS) else: self.instance._save_action = TRANSLATION_CHANGED if is_fuzzy: new_state = FUZZY else: new_state = TRANSLATED else: new_state = UNTRANSLATED if old_state > FUZZY: self.instance._save_action = TRANSLATION_DELETED self.instance.store.mark_dirty( CachedMethods.WORDCOUNT_STATS) if is_fuzzy != (old_state == FUZZY): # when Unit toggles its FUZZY state the number of translated # words also changes self.instance.store.mark_dirty(CachedMethods.WORDCOUNT_STATS, CachedMethods.LAST_ACTION) if old_state not in [new_state, OBSOLETE]: self.instance._state_updated = True self._updated_fields.append((SubmissionFields.STATE, old_state, new_state)) self.cleaned_data['state'] = new_state else: self.instance._state_updated = False self.cleaned_data['state'] = old_state return super(UnitForm, self).clean() return UnitForm
def must_display(cls, request, *args, **kwargs): return check_permission('commit', request) and \ hasversioning(request.translation_project.abs_real_path)
def project_language_index(request, project_code): """page listing all languages added to project""" project = get_object_or_404(Project, code=project_code) request.permissions = get_matching_permissions(get_profile(request.user), project.directory) if not check_permission('view', request): raise PermissionDenied can_edit = check_permission('administrate', request) translation_projects = project.translationproject_set.all() items = [make_language_item(request, translation_project) \ for translation_project in translation_projects.iterator()] items.sort(lambda x, y: locale.strcoll(x['title'], y['title'])) languagecount = len(translation_projects) project_stats = get_raw_stats(project) average = project_stats['translated']['percentage'] topstats = gentopstats_project(project) table_fields = [ 'name', 'progress', 'total', 'need-translation', 'activity' ] table = { 'id': 'project', 'proportional': False, 'fields': table_fields, 'headings': get_table_headings(table_fields), 'items': items, } templatevars = { 'project': { 'code': project.code, 'name': project.fullname, 'description': project.description, 'summary': ungettext('%(languages)d language, %(average)d%% translated', '%(languages)d languages, %(average)d%% translated', languagecount, { "languages": languagecount, "average": average }), }, 'topstats': topstats, 'can_edit': can_edit, 'table': table, } if can_edit: from pootle_project.forms import DescriptionForm templatevars['form'] = DescriptionForm(instance=project) return render_to_response('project/project.html', templatevars, context_instance=RequestContext(request))
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))
def _test_browse_view(tp, request, response, kwargs): cookie_data = json.loads( unquote(response.cookies[SIDEBAR_COOKIE_NAME].value)) assert cookie_data["foo"] == "bar" assert "announcements_projects_%s" % tp.project.code in cookie_data assert "announcements_%s" % tp.language.code in cookie_data assert ( "announcements_%s_%s" % (tp.language.code, tp.project.code) in cookie_data) ctx = response.context kwargs["project_code"] = tp.project.code kwargs["language_code"] = tp.language.code resource_path = "%(dir_path)s%(filename)s" % kwargs pootle_path = "%s%s" % (tp.pootle_path, resource_path) if not (kwargs["dir_path"] or kwargs.get("filename")): ob = tp.directory elif not kwargs.get("filename"): ob = Directory.objects.get( pootle_path=pootle_path) else: ob = Store.objects.get( pootle_path=pootle_path) if not kwargs.get("filename"): vftis = ob.vf_treeitems.select_related("vfolder") if not ctx["has_admin_access"]: vftis = vftis.filter(vfolder__is_public=True) vfolders = [ make_vfolder_treeitem_dict(vfolder_treeitem) for vfolder_treeitem in vftis.order_by('-vfolder__priority') if (ctx["has_admin_access"] or vfolder_treeitem.is_visible)] stats = {"vfolders": {}} for vfolder_treeitem in vfolders or []: stats['vfolders'][ vfolder_treeitem['code']] = vfolder_treeitem["stats"] del vfolder_treeitem["stats"] if stats["vfolders"]: stats.update(ob.get_stats()) else: stats = ob.get_stats() else: stats = ob.get_stats() vfolders = None filters = {} if vfolders: filters['sort'] = 'priority' dirs_with_vfolders = vftis_for_child_dirs(ob).values_list( "directory__pk", flat=True) directories = [ make_directory_item( child, **(dict(sort="priority") if child.pk in dirs_with_vfolders else {})) for child in ob.get_children() if isinstance(child, Directory)] stores = [ make_store_item(child) for child in ob.get_children() if isinstance(child, Store)] if not kwargs.get("filename"): table_fields = [ 'name', 'progress', 'total', 'need-translation', 'suggestions', 'critical', 'last-updated', 'activity'] table = { 'id': 'tp', 'fields': table_fields, 'headings': get_table_headings(table_fields), 'items': directories + stores} else: table = None User = get_user_model() assertions = dict( page="browse", object=ob, translation_project=tp, language=tp.language, project=tp.project, has_admin_access=check_permission('administrate', request), is_store=(kwargs.get("filename") and True or False), browser_extends="translation_projects/base.html", pootle_path=pootle_path, resource_path=resource_path, resource_path_parts=get_path_parts(resource_path), translation_states=get_translation_states(ob), checks=get_qualitycheck_list(ob), top_scorers=User.top_scorers(language=tp.language.code, project=tp.project.code, limit=10), url_action_continue=ob.get_translate_url( state='incomplete', **filters), url_action_fixcritical=ob.get_critical_url(**filters), url_action_review=ob.get_translate_url( state='suggestions', **filters), url_action_view_all=ob.get_translate_url(state='all'), stats=stats, parent=get_parent(ob)) if table: assertions["table"] = table sidebar = get_sidebar_announcements_context( request, (tp.project, tp.language, tp)) for k in ["has_sidebar", "is_sidebar_open", "announcements"]: assertions[k] = sidebar[0][k] view_context_test(ctx, **assertions) if vfolders: for vfolder in ctx["vfolders"]["items"]: assert (vfolder["is_grayed"] and not ctx["has_admin_access"]) is False assert ( ctx["vfolders"]["items"] == vfolders) assert (('display_download' in ctx and ctx['display_download']) == (request.user.is_authenticated() and check_permission('translate', request)))
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 form_class = unit_form_factory(language, len(prev_unit.source.strings)) 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() 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(): form_class = unit_form_factory(language, len(edit_unit.source.strings)) 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) # 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 if 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).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).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))
def unit_form_factory(language, snplurals=None, request=None): if snplurals is not None: tnplurals = language.nplurals else: tnplurals = 1 action_disabled = False if request is not None: cantranslate = check_permission("translate", request) cansuggest = check_permission("suggest", request) if not (cansuggest or cantranslate): action_disabled = True target_attrs = { 'lang': language.code, 'dir': language.get_direction(), 'class': 'translation expanding focusthis', 'rows': 5, 'tabindex': 10, } fuzzy_attrs = { 'accesskey': 'f', 'class': 'fuzzycheck', 'tabindex': 13, } if action_disabled: target_attrs['disabled'] = 'disabled' fuzzy_attrs['disabled'] = 'disabled' class UnitForm(forms.ModelForm): class Meta: model = Unit exclude = ['store', 'developer_comment', 'translator_comment', 'submitted_by', 'commented_by'] id = forms.IntegerField(required=False) source_f = MultiStringFormField(nplurals=snplurals or 1, required=False, textarea=False) target_f = MultiStringFormField(nplurals=tnplurals, required=False, attrs=target_attrs) state = forms.BooleanField(required=False, label=_('Fuzzy'), widget=forms.CheckboxInput(attrs=fuzzy_attrs, check_test=lambda x: x == FUZZY)) def __init__(self, *args, **argv): super(UnitForm, self).__init__(*args, **argv) self.updated_fields = [] def clean_source_f(self): value = self.cleaned_data['source_f'] if self.instance.source.strings != value: self.instance._source_updated = True self.updated_fields.append((SubmissionFields.SOURCE, to_db(self.instance.source), to_db(value))) if snplurals == 1: # plural with single form, insert placeholder value.append(PLURAL_PLACEHOLDER) return value def clean_target_f(self): value = self.cleaned_data['target_f'] if self.instance.target.strings != multistring(value or [u'']): self.instance._target_updated = True self.updated_fields.append((SubmissionFields.TARGET, to_db(self.instance.target), to_db(value))) return value def clean_state(self): old_state = self.instance.state #integer value = self.cleaned_data['state'] #boolean new_target = self.cleaned_data['target_f'] new_state = None if new_target: if value: new_state = FUZZY else: new_state = TRANSLATED else: new_state = UNTRANSLATED if old_state != new_state: self.instance._state_updated = True self.updated_fields.append((SubmissionFields.STATE, old_state, new_state)) else: self.instance._state_updated = False return new_state return UnitForm
def overview(request, translation_project, dir_path, filename=None, goal=None): from django.utils import dateformat from staticpages.models import StaticPage from pootle.scripts.actions import EXTDIR, StoreAction, TranslationProjectAction from .actions import action_groups if filename: ctx = { 'store_tags': request.store.tag_like_objects, } template_name = "translation_projects/store_overview.html" else: ctx = { 'tp_tags': translation_project.tag_like_objects, } template_name = "browser/overview.html" if (check_permission('translate', request) or check_permission('suggest', request) or check_permission('overwrite', request)): ctx.update({ 'upload_form': _handle_upload_form(request, translation_project), }) can_edit = check_permission('administrate', request) project = translation_project.project language = translation_project.language resource_obj = request.store or request.directory #TODO enable again some actions when drilling down a goal. if goal is None: actions = action_groups(request, resource_obj) else: actions = [] action_output = '' running = request.GET.get(EXTDIR, '') #TODO enable the following again when drilling down a goal. if running and goal is None: if request.store: act = StoreAction else: act = TranslationProjectAction try: action = act.lookup(running) except KeyError: messages.error(request, _("Unable to find '%(action)s' in '%(extdir)s'") % {'action': act, 'extdir': running}) else: if not getattr(action, 'nosync', False): (request.store or translation_project).sync() if action.is_active(request): vcs_dir = settings.VCS_DIRECTORY po_dir = settings.PODIRECTORY tp_dir = request.directory.get_real_path() store_fn = '*' if request.store: tp_dir_slash = add_trailing_slash(tp_dir) if request.store.file.name.startswith(tp_dir_slash): # Note: store_f used below in reverse() call. store_f = request.store.file.name[len(tp_dir_slash):] store_fn = store_f.replace('/', os.sep) # Clear possibly stale output/error (even from other # resource_obj). action.set_output('') action.set_error('') try: action.run(path=resource_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 = (_("Error 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(resource_obj) if export_path: import mimetypes abs_path = absolute_real_path(export_path) filename = os.path.basename(export_path) mimetype, encoding = mimetypes.guess_type(filename) mimetype = mimetype or 'application/octet-stream' with open(abs_path, 'rb') as f: response = HttpResponse(f.read(), mimetype=mimetype) response['Content-Disposition'] = ( 'attachment; filename="%s"' % filename) return response if not action_output: if not request.store: rev_args = [language.code, project.code, ''] overview_url = reverse('pootle-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('pootle-tp-overview', args=rev_args) return redirect(overview_url) # TODO: cleanup and refactor, retrieve from cache try: ann_virtual_path = 'announcements/' + project.code announcement = StaticPage.objects.live(request.user).get( virtual_path=ann_virtual_path, ) except StaticPage.DoesNotExist: announcement = None display_announcement = True stored_mtime = None new_mtime = None cookie_data = {} if ANN_COOKIE_NAME in request.COOKIES: json_str = unquote(request.COOKIES[ANN_COOKIE_NAME]) cookie_data = json.loads(json_str) if 'isOpen' in cookie_data: display_announcement = cookie_data['isOpen'] if project.code in cookie_data: stored_mtime = cookie_data[project.code] if announcement is not None: ann_mtime = dateformat.format(announcement.modified_on, 'U') if ann_mtime != stored_mtime: display_announcement = True new_mtime = ann_mtime tp_goals = translation_project.all_goals ctx.update(get_overview_context(request)) ctx.update({ 'resource_obj': request.store or request.directory, # Dirty hack. 'translation_project': translation_project, 'description': translation_project.description, 'project': project, 'language': language, 'tp_goals': tp_goals, 'goal': goal, 'feed_path': request.directory.pootle_path[1:], 'action_groups': actions, 'action_output': action_output, 'can_edit': can_edit, 'browser_extends': 'translation_projects/base.html', 'announcement': announcement, 'announcement_displayed': display_announcement, }) tp_pootle_path = translation_project.pootle_path if request.store is None: table_fields = ['name', 'progress', 'total', 'need-translation', 'suggestions', 'critical', 'last-updated', 'activity'] if goal is not None: # Then show the drill down view for the specified goal. continue_url = goal.get_translate_url_for_path(request.pootle_path, state='incomplete') critical_url = goal.get_critical_url_for_path(request.pootle_path) review_url = goal.get_translate_url_for_path(request.pootle_path, state='suggestions') all_url = goal.get_translate_url_for_path(request.pootle_path) ctx.update({ 'table': { 'id': 'tp-goals', 'fields': table_fields, 'headings': get_table_headings(table_fields), 'parent': get_goal_parent(request.directory, goal), 'items': get_goal_children(request.directory, goal), }, 'url_action_continue': continue_url, 'url_action_fixcritical': critical_url, 'url_action_review': review_url, 'url_action_view_all': all_url, }) else: # Then show the files tab. ctx.update({ 'table': { 'id': 'tp-files', 'fields': table_fields, 'headings': get_table_headings(table_fields), 'parent': get_parent(request.directory), 'items': get_children(request.directory), }, }) if can_edit: if request.store is None: add_tag_action_url = reverse('pootle-xhr-tag-tp', args=[language.code, project.code]) else: add_tag_action_url = reverse('pootle-xhr-tag-store', args=[resource_obj.pk]) ctx.update({ 'form': DescriptionForm(instance=translation_project), 'form_action': reverse('pootle-tp-admin-settings', args=[language.code, project.code]), 'add_tag_form': TagForm(), 'add_tag_action_url': add_tag_action_url, }) if goal is not None: ctx.update({ 'goal_form': GoalForm(instance=goal), 'goal_form_action': reverse('pootle-xhr-edit-goal', args=[goal.slug]), }) response = render(request, template_name, ctx) if new_mtime is not None: cookie_data[project.code] = new_mtime cookie_data = quote(json.dumps(cookie_data)) response.set_cookie(ANN_COOKIE_NAME, cookie_data) return response
def _test_browse_view(tp, request, response, kwargs): assert (request.user.is_anonymous or "announcements/projects/%s" % tp.project.code in request.session) assert (request.user.is_anonymous or "announcements/%s" % tp.language.code in request.session) assert (request.user.is_anonymous or "announcements/%s/%s" % (tp.language.code, tp.project.code) in request.session) ctx = response.context kwargs["project_code"] = tp.project.code kwargs["language_code"] = tp.language.code resource_path = "%(dir_path)s%(filename)s" % kwargs pootle_path = "%s%s" % (tp.pootle_path, resource_path) if not (kwargs["dir_path"] or kwargs.get("filename")): obj = tp.directory elif not kwargs.get("filename"): obj = Directory.objects.get(pootle_path=pootle_path) else: obj = Store.objects.get(pootle_path=pootle_path) if obj.tp_path == "/": data_obj = obj.tp else: data_obj = obj stats = StatsDisplay( data_obj, stats=data_obj.data_tool.get_stats(user=request.user)).stats if not kwargs.get("filename"): vfolders = True else: vfolders = None filters = {} if vfolders: filters['sort'] = 'priority' checks = ChecksDisplay(obj).checks_by_category del stats["children"] score_data = scores.get(tp.__class__)(tp) chunk_size = TOP_CONTRIBUTORS_CHUNK_SIZE top_scorers = score_data.top_scorers def scores_to_json(score): score["user"] = score["user"].to_dict() return score top_scorers = score_data.display(limit=chunk_size, formatter=scores_to_json) top_scorer_data = dict( items=list(top_scorers), has_more_items=len(score_data.top_scorers) > chunk_size) assertions = dict( page="browse", object=obj, translation_project=tp, language=tp.language, project=tp.project, has_admin_access=check_permission('administrate', request), is_store=(kwargs.get("filename") and True or False), browser_extends="translation_projects/base.html", pootle_path=pootle_path, resource_path=resource_path, resource_path_parts=get_path_parts(resource_path), translation_states=get_translation_states(obj), checks=checks, top_scorers=top_scorer_data, url_action_continue=obj.get_translate_url(state='incomplete', **filters), url_action_fixcritical=obj.get_critical_url(**filters), url_action_review=obj.get_translate_url(state='suggestions', **filters), url_action_view_all=obj.get_translate_url(state='all'), stats=stats, parent=get_parent(obj)) sidebar = get_sidebar_announcements_context(request, (tp.project, tp.language, tp)) for k in ["has_sidebar", "is_sidebar_open", "announcements"]: assertions[k] = sidebar[k] view_context_test(ctx, **assertions) assert (('display_download' in ctx and ctx['display_download']) == (request.user.is_authenticated and check_permission( 'translate', request)))
def _test_translate_view(tp, request, response, kwargs, settings): ctx = response.context obj = ctx["object"] kwargs["project_code"] = tp.project.code kwargs["language_code"] = tp.language.code resource_path = "%(dir_path)s%(filename)s" % kwargs request_path = "%s%s" % (tp.pootle_path, resource_path) checks = get_qualitychecks() schema = {sc["code"]: sc for sc in get_qualitycheck_schema()} check_data = obj.data_tool.get_checks() _checks = {} for check, checkid in checks.items(): if check not in check_data: continue _checkid = schema[checkid]["name"] _checks[_checkid] = _checks.get( _checkid, dict(checks=[], title=schema[checkid]["title"])) _checks[_checkid]["checks"].append( dict(code=check, title=check_names[check], count=check_data[check])) _checks = OrderedDict( (k, _checks[k]) for k in CATEGORY_IDS.keys() if _checks.get(k)) if request.path.startswith("/++vfolder"): vfolder = VirtualFolder.objects.get( name=request.resolver_match.kwargs["vfolder_name"]) current_vfolder_pk = vfolder.pk display_priority = False unit_api_root = reverse("vfolder-pootle-xhr-units", kwargs=dict(vfolder_name=vfolder.name)) resource_path = ("/".join([ "++vfolder", vfolder.name, ctx['object'].pootle_path.replace(tp.pootle_path, "") ])) else: vfolder = None current_vfolder_pk = "" display_priority = False if not kwargs["filename"]: vf_view = vfolders_data_view.get(obj.__class__)(obj, request.user) display_priority = vf_view.has_data unit_api_root = "/xhr/units/" assertions = dict(page="translate", translation_project=tp, language=tp.language, project=tp.project, has_admin_access=check_permission( 'administrate', request), ctx_path=tp.pootle_path, pootle_path=request_path, resource_path=resource_path, resource_path_parts=get_path_parts(resource_path), editor_extends="translation_projects/base.html", checks=_checks, previous_url=get_previous_url(request), current_vfolder_pk=current_vfolder_pk, display_priority=display_priority, cantranslate=check_permission("translate", request), cansuggest=check_permission("suggest", request), canreview=check_permission("review", request), search_form=make_search_form(request=request), unit_api_root=unit_api_root, POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL) view_context_test(ctx, **assertions)
def unit_form_factory(language, snplurals=None, request=None): if snplurals is not None: tnplurals = language.nplurals else: tnplurals = 1 action_disabled = False if request is not None: cantranslate = check_permission("translate", request) cansuggest = check_permission("suggest", request) if not (cansuggest or cantranslate): action_disabled = True target_attrs = { 'lang': language.code, 'dir': language.direction, 'class': 'translation expanding focusthis js-translation-area', 'rows': 5, 'tabindex': 10, } fuzzy_attrs = { 'accesskey': 'f', 'class': 'fuzzycheck', 'tabindex': 13, } if action_disabled: target_attrs['disabled'] = 'disabled' fuzzy_attrs['disabled'] = 'disabled' class UnitForm(forms.ModelForm): class Meta: model = Unit exclude = ['store', 'developer_comment', 'translator_comment', 'submitted_by', 'commented_by'] id = forms.IntegerField(required=False) source_f = MultiStringFormField( nplurals=snplurals or 1, required=False, textarea=False, ) target_f = MultiStringFormField( nplurals=tnplurals, required=False, attrs=target_attrs, ) state = UnitStateField( required=False, label=_('Needs work'), widget=forms.CheckboxInput( attrs=fuzzy_attrs, check_test=lambda x: x == FUZZY, ), ) def __init__(self, *args, **argv): super(UnitForm, self).__init__(*args, **argv) self.updated_fields = [] def clean_source_f(self): value = self.cleaned_data['source_f'] if self.instance.source.strings != value: self.instance._source_updated = True self.updated_fields.append((SubmissionFields.SOURCE, to_db(self.instance.source), to_db(value))) if snplurals == 1: # Plural with single form, insert placeholder. value.append(PLURAL_PLACEHOLDER) return value def clean_target_f(self): value = self.cleaned_data['target_f'] if self.instance.target.strings != multistring(value or [u'']): self.instance._target_updated = True self.updated_fields.append((SubmissionFields.TARGET, to_db(self.instance.target), to_db(value))) return value def clean_state(self): old_state = self.instance.state # Integer is_fuzzy = self.cleaned_data['state'] # Boolean new_target = self.cleaned_data['target_f'] if new_target: if old_state == UNTRANSLATED: self.instance.store \ .flag_for_deletion(CachedMethods.TRANSLATED) if is_fuzzy: new_state = FUZZY else: new_state = TRANSLATED else: new_state = UNTRANSLATED if is_fuzzy != (old_state == FUZZY): # when Unit toggles its FUZZY state the number of translated words # also changes self.instance.store.flag_for_deletion(CachedMethods.FUZZY, CachedMethods.TRANSLATED, CachedMethods.LAST_ACTION, CachedMethods.PATH_SUMMARY) if old_state != new_state: self.instance._state_updated = True self.updated_fields.append((SubmissionFields.STATE, old_state, new_state)) else: self.instance._state_updated = False return new_state return UnitForm
def unit_form_factory(language, snplurals=None, request=None): if snplurals is not None: tnplurals = language.nplurals else: tnplurals = 1 action_disabled = False if request is not None: cantranslate = check_permission("translate", request) cansuggest = check_permission("suggest", request) if not (cansuggest or cantranslate): action_disabled = True target_attrs = { 'lang': language.code, 'dir': language.direction, 'class': 'translation expanding focusthis js-translation-area', 'rows': 2, 'tabindex': 10, } fuzzy_attrs = { 'accesskey': 'f', 'class': 'fuzzycheck', 'tabindex': 13, } if action_disabled: target_attrs['disabled'] = 'disabled' fuzzy_attrs['disabled'] = 'disabled' class UnitForm(forms.ModelForm): class Meta(object): model = Unit fields = ( 'target_f', 'state', ) target_f = MultiStringFormField( nplurals=tnplurals, required=False, attrs=target_attrs, ) state = UnitStateField( required=False, label=_('Needs work'), widget=forms.CheckboxInput( attrs=fuzzy_attrs, check_test=lambda x: x == FUZZY, ), ) suggestion = forms.ModelChoiceField(queryset=Suggestion.objects.all(), required=False) comment = forms.CharField(required=False) def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) self.user = self.request.user super(UnitForm, self).__init__(*args, **kwargs) self._updated_fields = [] self.fields['target_f'].widget.attrs['data-translation-aid'] = \ self['target_f'].value() @property def updated_fields(self): order_dict = { SubmissionFields.STATE: 0, SubmissionFields.TARGET: 1, } return sorted(self._updated_fields, key=lambda x: order_dict[x[0]]) def clean_target_f(self): value = self.cleaned_data['target_f'] if self.instance.target != multistring(value or [u'']): self._updated_fields.append( (SubmissionFields.TARGET, to_db(self.instance.target), to_db(value))) return value def clean(self): old_state = self.instance.state # Integer is_fuzzy = self.cleaned_data['state'] # Boolean new_target = self.cleaned_data['target_f'] # If suggestion is provided set `old_state` should be `TRANSLATED`. if self.cleaned_data['suggestion']: old_state = TRANSLATED # Skip `TARGET` field submission if suggestion value is equal # to submitted translation if new_target == self.cleaned_data['suggestion'].target_f: self._updated_fields = [] if (self.request is not None and not check_permission('administrate', self.request) and is_fuzzy): self.add_error( 'state', forms.ValidationError( _('Needs work flag must be ' 'cleared'))) if new_target: if is_fuzzy: new_state = FUZZY else: new_state = TRANSLATED else: new_state = UNTRANSLATED if old_state not in [new_state, OBSOLETE]: self._updated_fields.append( (SubmissionFields.STATE, old_state, new_state)) self.cleaned_data['state'] = new_state else: self.cleaned_data['state'] = old_state return super(UnitForm, self).clean() 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, store=unit.store, field=field, type=SubmissionTypes.NORMAL, old_value=old_value, new_value=new_value) sub.save() return unit return UnitForm