def test_extract_vfolder_from_path(): """Tests that vfolder is correctly extracted from path, if any.""" subdir0 = TranslationProject.objects.get( language__code="language1", project__code="project1", ).directory.child_dirs.first() # Check that subdir0 pootle_path matches no vfolder. path = subdir0.pootle_path assert (None, path) == extract_vfolder_from_path(path) # Check that vfoldertreeitem pootle_path returns a vfolder and a clean path. vfolder_item = { 'name': 'vfolder0', 'location': subdir0.pootle_path, 'priority': 4, 'is_public': True, 'filter_rules': subdir0.child_stores.first().name, } vfolder0 = VirtualFolder(**vfolder_item) vfolder0.save() path = subdir0.vf_treeitems.first().pootle_path assert (vfolder0, subdir0.pootle_path) == extract_vfolder_from_path(path) # Check that the right vfolder is matched and returned. subdir1_first_store = subdir0.child_dirs.first().child_stores.first() vfolder_location = subdir0.parent.pootle_path filter_path = subdir1_first_store.pootle_path.replace(vfolder_location, "") vfolder_item.update({ 'location': vfolder_location, 'priority': 2, 'filter_rules': filter_path, }) vfolder1 = VirtualFolder(**vfolder_item) vfolder1.save() path = subdir0.vf_treeitems.first().pootle_path assert (vfolder0, subdir0.pootle_path) == extract_vfolder_from_path(path) # Despite the virtual folders share the same name they have different # locations, but the VirtualFolderTreeItem pootle_path is unique, thus only # one exists. assert 1 == VirtualFolderTreeItem.objects.filter(pootle_path=path).count()
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 _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 not kwargs['filename'] and ctx['object'].has_vfolders) assertions = dict(page="translate", translation_project=tp, language=tp.language, project=tp.project, is_admin=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), POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL) view_context_test(ctx, **assertions)
def extracted_path(self): if 'virtualfolder' not in settings.INSTALLED_APPS: return None, self.request_path from virtualfolder.helpers import extract_vfolder_from_path from virtualfolder.models import VirtualFolderTreeItem return extract_vfolder_from_path( self.request_path, vfti=VirtualFolderTreeItem.objects.select_related( "directory", "vfolder"))
def extracted_path(self): if 'virtualfolder' not in settings.INSTALLED_APPS: return None, self.request_path from virtualfolder.helpers import extract_vfolder_from_path from virtualfolder.models import VirtualFolderTreeItem return extract_vfolder_from_path( self.request_path, vfti=VirtualFolderTreeItem.objects.select_related( "directory", "vfolder"))
def clean(self): from .views import ALLOWED_SORTS if "checks" in self.errors: del self.errors["checks"] self.cleaned_data["checks"] = None if "user" in self.errors: del self.errors["user"] self.cleaned_data["user"] = self.request_user if self.errors: return if self.default_count: count = ( self.cleaned_data.get("count", self.default_count) or self.default_count) user_count = ( self.cleaned_data["user"].get_unit_rows() or self.default_count) self.cleaned_data['count'] = min(count, user_count) self.cleaned_data["vfolder"] = None pootle_path = self.cleaned_data.get("path") if 'virtualfolder' in settings.INSTALLED_APPS: from virtualfolder.helpers import extract_vfolder_from_path from virtualfolder.models import VirtualFolderTreeItem vfolder, pootle_path = extract_vfolder_from_path( pootle_path, vfti=VirtualFolderTreeItem.objects.select_related( "directory", "vfolder")) self.cleaned_data["vfolder"] = vfolder self.cleaned_data["pootle_path"] = pootle_path path_keys = [ "project_code", "language_code", "dir_path", "filename"] try: path_kwargs = { k: v for k, v in resolve(pootle_path).kwargs.items() if k in path_keys} except Resolver404: raise forms.ValidationError('Unrecognised path') self.cleaned_data.update(path_kwargs) sort_on = "units" if "filter" in self.cleaned_data: unit_filter = self.cleaned_data["filter"] if unit_filter in ('suggestions', 'user-suggestions'): sort_on = 'suggestions' elif unit_filter in ('user-submissions', ): sort_on = 'submissions' sort_by_param = self.cleaned_data["sort"] self.cleaned_data["sort_by"] = ALLOWED_SORTS[sort_on].get(sort_by_param) self.cleaned_data["sort_on"] = sort_on
def clean(self): if "checks" in self.errors: del self.errors["checks"] self.cleaned_data["checks"] = None if "user" in self.errors: del self.errors["user"] self.cleaned_data["user"] = self.request_user if self.errors: return if self.default_count: count = ( self.cleaned_data.get("count", self.default_count) or self.default_count) user_count = ( self.cleaned_data["user"].get_unit_rows() or self.default_count) self.cleaned_data['count'] = min(count, user_count) self.cleaned_data["vfolder"] = None pootle_path = self.cleaned_data.get("path") if 'virtualfolder' in settings.INSTALLED_APPS: from virtualfolder.helpers import extract_vfolder_from_path from virtualfolder.models import VirtualFolderTreeItem vfolder, pootle_path = extract_vfolder_from_path( pootle_path, vfti=VirtualFolderTreeItem.objects.select_related( "directory", "vfolder")) self.cleaned_data["vfolder"] = vfolder self.cleaned_data["pootle_path"] = pootle_path path_keys = [ "project_code", "language_code", "dir_path", "filename"] try: path_kwargs = { k: v for k, v in resolve(pootle_path).kwargs.items() if k in path_keys} except Resolver404: raise forms.ValidationError('Unrecognised path') self.cleaned_data.update(path_kwargs) sort_on = "units" if "filter" in self.cleaned_data: unit_filter = self.cleaned_data["filter"] if unit_filter in ('suggestions', 'user-suggestions'): sort_on = 'suggestions' elif unit_filter in ('user-submissions', ): sort_on = 'submissions' sort_by_param = self.cleaned_data["sort"] self.cleaned_data["sort_by"] = ALLOWED_SORTS[sort_on].get(sort_by_param) self.cleaned_data["sort_on"] = sort_on
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 not kwargs['filename'] and ctx['object'].has_vfolders) 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), POOTLE_MT_BACKENDS=settings.POOTLE_MT_BACKENDS, AMAGAMA_URL=settings.AMAGAMA_URL) view_context_test(ctx, **assertions)
def extracted_path(self): return extract_vfolder_from_path( self.request_path, vfti=VirtualFolderTreeItem.objects.select_related( "directory", "vfolder"))
def set_resource(request, path_obj, dir_path, filename): """Loads :cls:`pootle_app.models.Directory` and :cls:`pootle_store.models.Store` models and populates the request object. :param path_obj: A path-like object object. :param dir_path: Path relative to the root of `path_obj`. :param filename: Optional filename. """ obj_directory = getattr(path_obj, 'directory', path_obj) ctx_path = obj_directory.pootle_path resource_path = dir_path pootle_path = ctx_path + dir_path directory = None store = None is_404 = False # Get a clean pootle path for retrieving the directory or store. # A clean pootle path is a pootle path without any virtual folder name on # it. For example /af/test_vfolders/browser/chrome/ is the corresponding # clean pootle path for /af/test_vfolders/browser/vfolder8/chrome/ vfolder, clean_pootle_path = extract_vfolder_from_path(pootle_path) if filename: pootle_path = pootle_path + filename clean_pootle_path = clean_pootle_path + filename resource_path = resource_path + filename try: store = Store.objects.live().select_related( 'translation_project', 'parent', ).get(pootle_path=clean_pootle_path) directory = store.parent except Store.DoesNotExist: is_404 = True if directory is None and not is_404: if dir_path: try: directory = Directory.objects.live().get(pootle_path=clean_pootle_path) except Directory.DoesNotExist: is_404 = True else: directory = obj_directory if is_404: # Try parent directory language_code, project_code, dp, fn = split_pootle_path(clean_pootle_path) if not filename: dir_path = dir_path[:dir_path[:-1].rfind('/') + 1] url = reverse('pootle-tp-browse', args=[language_code, project_code, dir_path]) request.redirect_url = url raise Http404 request.store = store request.directory = directory request.pootle_path = pootle_path request.current_vfolder = getattr(vfolder, 'pk', '') request.resource_obj = store or (directory if dir_path else path_obj) request.resource_path = resource_path request.ctx_obj = path_obj or request.resource_obj request.ctx_path = ctx_path
def get_units(request): """Gets source and target texts and its metadata. :return: A JSON-encoded string containing the source and target texts grouped by the store they belong to. The optional `count` GET parameter defines the chunk size to consider. The user's preference will be used by default. When the `initial` GET parameter is present, a sorted list of the result set ids will be returned too. """ pootle_path = request.GET.get("path", None) if pootle_path is None: raise Http400(_("Arguments missing.")) User = get_user_model() request.profile = User.get(request.user) limit = request.profile.get_unit_rows() vfolder = None if "virtualfolder" in settings.INSTALLED_APPS: from virtualfolder.helpers import extract_vfolder_from_path vfolder, pootle_path = extract_vfolder_from_path(pootle_path) units_qs = Unit.objects.get_for_path(pootle_path, request.profile) if vfolder is not None: units_qs = units_qs.filter(vfolders=vfolder) units_qs = units_qs.select_related("store__translation_project__project", "store__translation_project__language") step_queryset = get_step_query(request, units_qs) is_initial_request = request.GET.get("initial", False) chunk_size = request.GET.get("count", limit) uids_param = filter(None, request.GET.get("uids", "").split(u",")) uids = filter(None, map(to_int, uids_param)) units = [] unit_groups = [] uid_list = [] if is_initial_request: sort_by_field = None if len(step_queryset.query.order_by) == 1: sort_by_field = step_queryset.query.order_by[0] sort_on = None for key, item in ALLOWED_SORTS.items(): if sort_by_field in item.values(): sort_on = key break if sort_by_field is None or sort_on == "units": # Since `extra()` has been used before, it's necessary to explicitly # request the `store__pootle_path` field. This is a subtetly in # Django's ORM. uid_list = [u["id"] for u in step_queryset.values("id", "store__pootle_path")] else: # Not using `values_list()` here because it doesn't know about all # existing relations when `extra()` has been used before in the # queryset. This affects annotated names such as those ending in # `__max`, where Django thinks we're trying to lookup a field on a # relationship field. That's why `sort_by_field` alias for `__max` # is used here. This alias must be queried in # `values('sort_by_field', 'id')` with `id` otherwise # Django looks for `sort_by_field` field in the initial table. # https://code.djangoproject.com/ticket/19434 uid_list = [u["id"] for u in step_queryset.values("id", "sort_by_field", "store__pootle_path")] if len(uids) == 1: try: uid = uids[0] index = uid_list.index(uid) begin = max(index - chunk_size, 0) end = min(index + chunk_size + 1, len(uid_list)) uids = uid_list[begin:end] except ValueError: raise Http404 # `uid` not found in `uid_list` else: count = 2 * chunk_size uids = uid_list[:count] if not units and uids: units = step_queryset.filter(id__in=uids) units_by_path = groupby(units, lambda x: x.store.pootle_path) for pootle_path, units in units_by_path: unit_groups.append(_path_units_with_meta(pootle_path, units)) response = {"unitGroups": unit_groups} if uid_list: response["uIds"] = uid_list return JsonResponse(response)
def calculate_search_results(kwargs, user): pootle_path = kwargs["pootle_path"] category = kwargs.get("category") checks = kwargs.get("checks") offset = kwargs.get("offset", 0) limit = kwargs.get("count", 9) modified_since = kwargs.get("modified-since") search = kwargs.get("search") sfields = kwargs.get("sfields") soptions = kwargs.get("soptions", []) sort = kwargs.get("sort", None) language_code, project_code, dir_path, filename = ( split_pootle_path(kwargs["pootle_path"])) uids = [ int(x) for x in kwargs.get("uids", "").split(",") if x] unit_filter = kwargs.get("filter") if modified_since: modified_since = parse_datetime(modified_since) vfolder = None if 'virtualfolder' in settings.INSTALLED_APPS: vfolder, pootle_path = extract_vfolder_from_path( pootle_path, vfti=VirtualFolderTreeItem.objects.select_related( "directory", "vfolder")) qs = ( Unit.objects.get_translatable(user=user, **resolve(pootle_path).kwargs) .order_by("store", "index")) if vfolder is not None: qs = qs.filter(vfolders=vfolder) # if "filter" is present in request vars... if unit_filter: # filter the results accordingly qs = UnitSearchFilter().filter( qs, unit_filter, user=user, checks=checks, category=get_category_id(category)) # filter by modified if modified_since: qs = qs.filter(submitted_on__gt=modified_since).distinct() # sort results if unit_filter in ["my-suggestions", "user-suggestions"]: sort_on = "suggestions" elif unit_filter in ["my-submissions", "user-submissions"]: sort_on = "submissions" else: sort_on = "units" sort_by = ALLOWED_SORTS[sort_on].get(sort, None) if sort_by is not None: # filtered sort if sort_on in SIMPLY_SORTED: qs = qs.order_by(sort_by, "store__pootle_path", "index") else: if sort_by[0] == '-': max_field = sort_by[1:] sort_order = '-sort_by_field' else: max_field = sort_by sort_order = 'sort_by_field' qs = ( qs.annotate(sort_by_field=Max(max_field)) .order_by(sort_order, "store__pootle_path", "index")) # text search if search and sfields: qs = UnitTextSearch(qs).search( search, [sfields], "exact" in soptions) find_unit = ( not offset and language_code and project_code and filename and uids) start = offset total = qs.count() if find_unit: # find the uid in the Store uid_list = list(qs.values_list("pk", flat=True)) unit_index = uid_list.index(uids[0]) start = int(unit_index / (2 * limit)) * (2 * limit) end = min(start + (2 * limit), total) unit_groups = [] units_by_path = groupby( qs.values(*GroupedResults.select_fields)[start:end], lambda x: x["store__pootle_path"]) for pootle_path, units in units_by_path: unit_groups.append( {pootle_path: StoreResults(units).data}) total = qs.count() return total, start, min(end, total), unit_groups
def extracted_path(self): return extract_vfolder_from_path( self.request_path, vfti=VirtualFolderTreeItem.objects.select_related( "directory", "vfolder"))
def calculate_search_results(kwargs, user): pootle_path = kwargs["pootle_path"] category = kwargs.get("category") checks = kwargs.get("checks") initial = kwargs.get("initial", False) limit = kwargs.get("count", 9) modified_since = kwargs.get("modified-since") search = kwargs.get("search") sfields = kwargs.get("sfields") soptions = kwargs.get("soptions", []) sort = kwargs.get("sort", None) uids = [ int(x) for x in kwargs.get("uids", "").split(",") if x] unit_filter = kwargs.get("filter") if modified_since: modified_since = parse_datetime(modified_since) vfolder = None if 'virtualfolder' in settings.INSTALLED_APPS: vfolder, pootle_path = extract_vfolder_from_path( pootle_path, vfti=VirtualFolderTreeItem.objects.select_related( "directory", "vfolder")) qs = ( Unit.objects.get_translatable(user=user, **resolve(pootle_path).kwargs) .filter(store__pootle_path__startswith=pootle_path) .order_by("store", "index")) if vfolder is not None: qs = qs.filter(vfolders=vfolder) # if "filter" is present in request vars... if unit_filter: # filter the results accordingly qs = UnitSearchFilter().filter( qs, unit_filter, user=user, checks=checks, category=get_category_id(category)) # filter by modified if modified_since: qs = qs.filter(submitted_on__gt=modified_since).distinct() # sort results if unit_filter in ["my-suggestions", "user-suggestions"]: sort_on = "suggestions" elif unit_filter in ["my-submissions", "user-submissions"]: sort_on = "submissions" else: sort_on = "units" sort_by = ALLOWED_SORTS[sort_on].get(sort, None) if sort_by is not None: # filtered sort if sort_on in SIMPLY_SORTED: qs = qs.order_by(sort_by, "store__pootle_path", "index") else: if sort_by[0] == '-': max_field = sort_by[1:] sort_order = '-sort_by_field' else: max_field = sort_by sort_order = 'sort_by_field' qs = ( qs.annotate(sort_by_field=Max(max_field)) .order_by(sort_order, "store__pootle_path", "index")) # text search if search and sfields: qs = UnitTextSearch(qs).search( search, [sfields], "exact" in soptions) begin = 0 end = None uid_list = [] if initial: uid_list = list(qs.values_list("pk", flat=True)) if uids and len(uids) == 1: # if uid is set get the index of the uid index = uid_list.index(uids[0]) begin = max(index - limit, 0) end = min(index + limit + 1, len(uid_list)) elif uids: qs = qs.filter(id__in=uids) if end is None: end = 2 * limit unit_groups = [] units_by_path = groupby( qs.values(*GroupedResults.select_fields)[begin:end], lambda x: x["store__pootle_path"]) for pootle_path, units in units_by_path: unit_groups.append( {pootle_path: StoreResults(units).data}) return uid_list, unit_groups
def calculate_search_results(kwargs, user): pootle_path = kwargs["pootle_path"] category = kwargs.get("category") checks = kwargs.get("checks") initial = kwargs.get("initial", False) limit = kwargs.get("count", 9) modified_since = kwargs.get("modified-since") search = kwargs.get("search") sfields = kwargs.get("sfields") soptions = kwargs.get("soptions", []) sort = kwargs.get("sort", None) uids = [int(x) for x in kwargs.get("uids", "").split(",") if x] unit_filter = kwargs.get("filter") if modified_since: modified_since = parse_datetime(modified_since) vfolder = None if 'virtualfolder' in settings.INSTALLED_APPS: vfolder, pootle_path = extract_vfolder_from_path( pootle_path, vfti=VirtualFolderTreeItem.objects.select_related( "directory", "vfolder")) qs = (Unit.objects.get_translatable( user=user, **resolve(pootle_path).kwargs).filter( store__pootle_path__startswith=pootle_path).order_by( "store", "index")) if vfolder is not None: qs = qs.filter(vfolders=vfolder) # if "filter" is present in request vars... if unit_filter: # filter the results accordingly qs = UnitSearchFilter().filter(qs, unit_filter, user=user, checks=checks, category=get_category_id(category)) # filter by modified if modified_since: qs = qs.filter(submitted_on__gt=modified_since).distinct() # sort results if unit_filter in ["my-suggestions", "user-suggestions"]: sort_on = "suggestions" elif unit_filter in ["my-submissions", "user-submissions"]: sort_on = "submissions" else: sort_on = "units" sort_by = ALLOWED_SORTS[sort_on].get(sort, None) if sort_by is not None: # filtered sort if sort_on in SIMPLY_SORTED: qs = qs.order_by(sort_by, "store__pootle_path", "index") else: if sort_by[0] == '-': max_field = sort_by[1:] sort_order = '-sort_by_field' else: max_field = sort_by sort_order = 'sort_by_field' qs = (qs.annotate(sort_by_field=Max(max_field)).order_by( sort_order, "store__pootle_path", "index")) # text search if search and sfields: qs = UnitTextSearch(qs).search(search, [sfields], "exact" in soptions) begin = 0 end = None uid_list = [] if initial: uid_list = list(qs.values_list("pk", flat=True)) if uids and len(uids) == 1: # if uid is set get the index of the uid index = uid_list.index(uids[0]) begin = max(index - limit, 0) end = min(index + limit + 1, len(uid_list)) elif uids: qs = qs.filter(id__in=uids) if end is None: end = 2 * limit unit_groups = [] units_by_path = groupby( qs.values(*GroupedResults.select_fields)[begin:end], lambda x: x["store__pootle_path"]) for pootle_path, units in units_by_path: unit_groups.append({pootle_path: StoreResults(units).data}) return uid_list, unit_groups
def calculate_search_results(kwargs, user): pootle_path = kwargs["pootle_path"] category = kwargs.get("category") checks = kwargs.get("checks") offset = kwargs.get("offset", 0) limit = kwargs.get("count", 9) modified_since = kwargs.get("modified-since") search = kwargs.get("search") sfields = kwargs.get("sfields") soptions = kwargs.get("soptions", []) sort = kwargs.get("sort", None) language_code, project_code, dir_path, filename = split_pootle_path(kwargs["pootle_path"]) uids = [int(x) for x in kwargs.get("uids", "").split(",") if x] unit_filter = kwargs.get("filter") if modified_since: modified_since = parse_datetime(modified_since) vfolder = None if "virtualfolder" in settings.INSTALLED_APPS: vfolder, pootle_path = extract_vfolder_from_path( pootle_path, vfti=VirtualFolderTreeItem.objects.select_related("directory", "vfolder") ) qs = Unit.objects.get_translatable(user=user, **resolve(pootle_path).kwargs).order_by("store", "index") if vfolder is not None: qs = qs.filter(vfolders=vfolder) # if "filter" is present in request vars... if unit_filter: # filter the results accordingly qs = UnitSearchFilter().filter(qs, unit_filter, user=user, checks=checks, category=get_category_id(category)) # filter by modified if modified_since: qs = qs.filter(submitted_on__gt=modified_since).distinct() # sort results if unit_filter in ["my-suggestions", "user-suggestions"]: sort_on = "suggestions" elif unit_filter in ["my-submissions", "user-submissions"]: sort_on = "submissions" else: sort_on = "units" sort_by = ALLOWED_SORTS[sort_on].get(sort, None) if sort_by is not None: # filtered sort if sort_on in SIMPLY_SORTED: qs = qs.order_by(sort_by, "store__pootle_path", "index") else: if sort_by[0] == "-": max_field = sort_by[1:] sort_order = "-sort_by_field" else: max_field = sort_by sort_order = "sort_by_field" qs = qs.annotate(sort_by_field=Max(max_field)).order_by(sort_order, "store__pootle_path", "index") # text search if search and sfields: qs = UnitTextSearch(qs).search(search, [sfields], "exact" in soptions) find_unit = not offset and language_code and project_code and filename and uids start = offset total = qs.count() if find_unit: # find the uid in the Store uid_list = list(qs.values_list("pk", flat=True)) unit_index = uid_list.index(uids[0]) start = int(unit_index / (2 * limit)) * (2 * limit) end = min(start + (2 * limit), total) unit_groups = [] units_by_path = groupby(qs.values(*GroupedResults.select_fields)[start:end], lambda x: x["store__pootle_path"]) for pootle_path, units in units_by_path: unit_groups.append({pootle_path: StoreResults(units).data}) total = qs.count() return total, start, min(end, total), unit_groups
def get_units(request): """Gets source and target texts and its metadata. :return: A JSON-encoded string containing the source and target texts grouped by the store they belong to. The optional `count` GET parameter defines the chunk size to consider. The user's preference will be used by default. When the `initial` GET parameter is present, a sorted list of the result set ids will be returned too. """ pootle_path = request.GET.get('path', None) if pootle_path is None: raise Http400(_('Arguments missing.')) User = get_user_model() request.profile = User.get(request.user) limit = request.profile.get_unit_rows() vfolder = None if 'virtualfolder' in settings.INSTALLED_APPS: from virtualfolder.helpers import extract_vfolder_from_path vfolder, pootle_path = extract_vfolder_from_path(pootle_path) units_qs = Unit.objects.get_for_path(pootle_path, request.profile) if vfolder is not None: units_qs = units_qs.filter(vfolders=vfolder) units_qs = units_qs.select_related( 'store__translation_project__project', 'store__translation_project__language', ) step_queryset = get_step_query(request, units_qs) is_initial_request = request.GET.get('initial', False) chunk_size = request.GET.get('count', limit) uids_param = filter(None, request.GET.get('uids', '').split(u',')) uids = filter(None, map(to_int, uids_param)) units = [] unit_groups = [] uid_list = [] if is_initial_request: sort_by_field = None if len(step_queryset.query.order_by) == 1: sort_by_field = step_queryset.query.order_by[0] sort_on = None for key, item in ALLOWED_SORTS.items(): if sort_by_field in item.values(): sort_on = key break if sort_by_field is None or sort_on == 'units': uid_list = list(step_queryset.values_list('id', flat=True)) else: # Not using `values_list()` here because it doesn't know about all # existing relations when `extra()` has been used before in the # queryset. This affects annotated names such as those ending in # `__max`, where Django thinks we're trying to lookup a field on a # relationship field. That's why `sort_by_field` alias for `__max` # is used here. This alias must be queried in # `values('sort_by_field', 'id')` with `id` otherwise # Django looks for `sort_by_field` field in the initial table. # https://code.djangoproject.com/ticket/19434 uid_list = [ u['id'] for u in step_queryset.values('id', 'sort_by_field') ] if len(uids) == 1: try: uid = uids[0] index = uid_list.index(uid) begin = max(index - chunk_size, 0) end = min(index + chunk_size + 1, len(uid_list)) uids = uid_list[begin:end] except ValueError: raise Http404 # `uid` not found in `uid_list` else: count = 2 * chunk_size uids = uid_list[:count] if not units and uids: units = step_queryset.filter(id__in=uids) units_by_path = groupby(units, lambda x: x.store.pootle_path) for pootle_path, units in units_by_path: unit_groups.append(_path_units_with_meta(pootle_path, units)) response = { 'unitGroups': unit_groups, } if uid_list: response['uIds'] = uid_list return JsonResponse(response)