def invalidate_language_list_cache(**kwargs): instance = kwargs["instance"] # XXX: maybe use custom signals or simple function calls? if instance.__class__.__name__ not in ['Language', 'TranslationProject']: return key = make_method_key('LiveLanguageManager', 'cached_dict', '*') cache.delete_pattern(key) key = make_method_key('LiveLanguageManager', 'all_cached_dict', '*') cache.delete_pattern(key)
def cached_dict(self, locale_code='en-us', show_all=False): """Retrieves a sorted list of live language codes and names. By default only returns live languages for enabled projects, but it can also return live languages for disabled projects if specified. :param locale_code: the UI locale for which language full names need to be localized. :param show_all: tells whether to return all live languages (both for disabled and enabled projects) or only live languages for enabled projects. :return: an `OrderedDict` """ key_prefix = 'all_cached_dict' if show_all else 'cached_dict' key = make_method_key(self, key_prefix, locale_code) languages = cache.get(key, None) if languages is None: qs = self.get_all_queryset() if show_all else self.get_queryset() languages = OrderedDict( sorted([(lang[0], tr_lang(lang[1])) for lang in qs.values_list('code', 'fullname')], cmp=locale.strcoll, key=lambda x: x[1])) cache.set(key, languages, CACHE_TIMEOUT) return languages
def resources(self): """Returns a list of :cls:`~pootle_app.models.Directory` and :cls:`~pootle_store.models.Store` resource paths available for this :cls:`~pootle_project.models.Project` across all languages. """ cache_key = make_method_key(self, 'resources', self.code) resources = cache.get(cache_key, None) if resources is not None: return resources logging.debug(u'Cache miss for %s', cache_key) resources_path = ''.join(['/%/', self.code, '/%']) sql_query = ''' SELECT pootle_path FROM pootle_store_store WHERE pootle_path LIKE %s UNION SELECT pootle_path FROM pootle_app_directory WHERE pootle_path LIKE %s; ''' cursor = connection.cursor() cursor.execute(sql_query, [resources_path, resources_path]) results = cursor.fetchall() # Calculate TP-relative paths and sort them resources = sorted({to_tp_relative_path(result[0]) for result in results}, key=get_path_sortkey) cache.set(cache_key, resources, settings.OBJECT_CACHE_TIMEOUT) return resources
def cached_dict(self, user): """Return a cached ordered dictionary of projects tuples for `user`. - Admins always get all projects. - Regular users only get enabled projects accessible to them. :param user: The user for whom projects need to be retrieved for. :return: An ordered dictionary of project tuples including (`fullname`, `disabled`) and `code` is a key in the dictionary. """ if not user.is_superuser: cache_params = {'username': user.username} else: cache_params = {'is_admin': user.is_superuser} cache_key = make_method_key('Project', 'cached_dict', cache_params) projects = cache.get(cache_key) if not projects: logging.debug('Cache miss for %s', cache_key) projects_dict = self.for_user(user).order_by('fullname') \ .values('code', 'fullname', 'disabled') projects = OrderedDict( (project.pop('code'), project) for project in projects_dict ) cache.set(cache_key, projects, settings.POOTLE_CACHE_TIMEOUT) return projects
def resources(self): """Returns a list of :cls:`~pootle_app.models.Directory` and :cls:`~pootle_store.models.Store` resource paths available for this :cls:`~pootle_project.models.Project` across all languages. """ from virtualfolder.models import VirtualFolderTreeItem cache_key = make_method_key(self, 'resources', self.code) resources = cache.get(cache_key, None) if resources is not None: return resources stores = Store.objects.live().order_by().filter( translation_project__project__pk=self.pk) dirs = Directory.objects.live().order_by().filter( pootle_path__regex=r"^/[^/]*/%s/" % self.code) vftis = (VirtualFolderTreeItem.objects.filter( vfolder__is_public=True, pootle_path__regex=r"^/[^/]*/%s/" % self.code) if 'virtualfolder' in settings.INSTALLED_APPS else []) resources = sorted( { to_tp_relative_path(pootle_path) for pootle_path in ( set(stores.values_list("pootle_path", flat=True)) | set(dirs.values_list("pootle_path", flat=True)) | set( vftis.values_list("pootle_path", flat=True ) if vftis else [])) }, key=get_path_sortkey) cache.set(cache_key, resources, settings.POOTLE_CACHE_TIMEOUT) return resources
def invalidate_language_list_cache(sender, instance, **kwargs): # XXX: maybe use custom signals or simple function calls? if instance.__class__.__name__ not in ["Language", "TranslationProject"]: return key = make_method_key("LiveLanguageManager", "cached_dict", "*") cache.delete_pattern(key)
def invalidate_accessible_projects_cache(sender, instance, **kwargs): # XXX: maybe use custom signals or simple function calls? if (instance.__class__.__name__ not in ['Project', 'TranslationProject', 'PermissionSet']): return # FIXME: use Redis directly to clear these caches effectively cache.delete_many([ make_method_key('Project', 'cached_dict', {'is_admin': False}), make_method_key('Project', 'cached_dict', {'is_admin': True}), ]) User = get_user_model() users_list = User.objects.values_list('username', flat=True) cache.delete_many(map(lambda x: 'projects:accessible:%s' % x, users_list))
def resources(self): """Returns a list of :cls:`~pootle_app.models.Directory` and :cls:`~pootle_store.models.Store` resource paths available for this :cls:`~pootle_project.models.Project` across all languages. """ from virtualfolder.models import VirtualFolderTreeItem cache_key = make_method_key(self, 'resources', self.code) resources = cache.get(cache_key, None) if resources is not None: return resources stores = Store.objects.live().order_by().filter( translation_project__project__pk=self.pk) dirs = Directory.objects.live().order_by().filter( pootle_path__regex=r"^/[^/]*/%s/" % self.code) vftis = ( VirtualFolderTreeItem.objects.filter( vfolder__is_public=True, pootle_path__regex=r"^/[^/]*/%s/" % self.code) if 'virtualfolder' in settings.INSTALLED_APPS else []) resources = sorted( {to_tp_relative_path(pootle_path) for pootle_path in (set(stores.values_list("pootle_path", flat=True)) | set(dirs.values_list("pootle_path", flat=True)) | set(vftis.values_list("pootle_path", flat=True) if vftis else []))}, key=get_path_sortkey) cache.set(cache_key, resources, settings.POOTLE_CACHE_TIMEOUT) return resources
def cached_dict(self, user): """Return a cached ordered dictionary of projects tuples for `user`. - Admins always get all projects. - Regular users only get enabled projects accessible to them. :param user: The user for whom projects need to be retrieved for. :return: An ordered dictionary of project tuples including (`fullname`, `disabled`) and `code` is a key in the dictionary. """ if not user.is_superuser: cache_params = {"username": user.username} else: cache_params = {"is_admin": user.is_superuser} cache_key = make_method_key("Project", "cached_dict", cache_params) projects = cache.get(cache_key) if not projects: logging.debug("Cache miss for %s", cache_key) projects_dict = ( self.for_user(user) .order_by("fullname") .values("code", "fullname", "disabled") ) projects = OrderedDict( (project.pop("code"), project) for project in projects_dict ) cache.set(cache_key, projects, CACHE_TIMEOUT) return projects
def resources(self): """Returns a list of :cls:`~pootle_app.models.Directory` and :cls:`~pootle_store.models.Store` resource paths available for this :cls:`~pootle_project.models.Project` across all languages. """ cache_key = make_method_key(self, "resources", self.code) resources = cache.get(cache_key, None) if resources is not None: return resources stores = ( Store.objects.live() .order_by() .filter(translation_project__project__pk=self.pk) ) dirs = ( Directory.objects.live() .order_by() .filter(pootle_path__regex=r"^/[^/]*/%s/" % self.code) ) resources = sorted( { to_tp_relative_path(pootle_path) for pootle_path in ( set(stores.values_list("pootle_path", flat=True)) | set(dirs.values_list("pootle_path", flat=True)) ) }, key=get_path_sortkey, ) cache.set(cache_key, resources, CACHE_TIMEOUT) return resources
def cached_dict(self, locale_code='en-us', show_all=False): """Retrieves a sorted list of live language codes and names. By default only returns live languages for enabled projects, but it can also return live languages for disabled projects if specified. :param locale_code: the UI locale for which language full names need to be localized. :param show_all: tells whether to return all live languages (both for disabled and enabled projects) or only live languages for enabled projects. :return: an `OrderedDict` """ key_prefix = 'all_cached_dict' if show_all else 'cached_dict' key = make_method_key(self, key_prefix, locale_code) languages = cache.get(key, None) if languages is None: qs = self.get_all_queryset() if show_all else self.get_queryset() languages = OrderedDict( sorted([(lang[0], tr_lang(lang[1])) for lang in qs.values_list('code', 'fullname')], cmp=locale.strcoll, key=lambda x: x[1]) ) cache.set(key, languages, settings.POOTLE_CACHE_TIMEOUT) return languages
def top_scorers(cls, days=30, language=None, project=None, limit=5): """Returns users with the top scores. :param days: period of days to account for scores. :param language: limit results to the given language code. :param project: limit results to the given project code. :param limit: limit results to this number of users. Values other than positive numbers will return the entire result set. """ cache_kwargs = { 'days': days, 'language': language, 'project': project, 'limit': limit, } cache_key = make_method_key(cls, 'top_scorers', cache_kwargs) top_scorers = cache.get(cache_key, None) if top_scorers is not None: return top_scorers now = timezone.now() past = now + datetime.timedelta(-days) lookup_kwargs = { 'creation_time__range': [past, now], } if language is not None: lookup_kwargs.update({ 'submission__translation_project__language__code': language, }) if project is not None: lookup_kwargs.update({ 'submission__translation_project__project__code': project, }) meta_user_ids = cls.objects.meta_users().values_list('id', flat=True) top_scores = ScoreLog.objects.values("user").filter( **lookup_kwargs).exclude(user__pk__in=meta_user_ids, ).annotate( total_score=Sum('score_delta'), ).order_by('-total_score') if isinstance(limit, (int, long)) and limit > 0: top_scores = top_scores[:limit] users = dict((user.id, user) for user in cls.objects.filter( pk__in=[item['user'] for item in top_scores])) top_scorers = [] for item in top_scores: user = users[item['user']] user.total_score = item['total_score'] top_scorers.append(user) cache.set(cache_key, list(top_scorers), 60) return top_scorers
def invalidate_accessible_projects_cache(sender, instance, **kwargs): # XXX: maybe use custom signals or simple function calls? if (instance.__class__.__name__ not in ['Project', 'TranslationProject', 'PermissionSet']): return cache.delete_pattern(make_method_key('Project', 'cached_dict', '*')) cache.delete('projects:all') cache.delete_pattern('projects:accessible:*')
def invalidate_resources_cache(sender, instance, **kwargs): if instance.__class__.__name__ not in ['Directory', 'Store']: return # Don't invalidate if the save didn't create new objects if (('created' in kwargs and 'raw' in kwargs) and (not kwargs['created'] or kwargs['raw'])): return lang, proj, dir, fn = split_pootle_path(instance.pootle_path) if proj is not None: cache.delete(make_method_key(Project, 'resources', proj))
def invalidate_accessible_projects_cache(**kwargs): instance = kwargs["instance"] # XXX: maybe use custom signals or simple function calls? if instance.__class__.__name__ not in [ "Project", "TranslationProject", "PermissionSet", ]: return cache.delete_pattern(make_method_key("Project", "cached_dict", "*")) cache.delete("projects:all") cache.delete_pattern("projects:accessible:*")
def invalidate_resources_cache(**kwargs): instance = kwargs["instance"] if instance.__class__.__name__ not in ['Directory', 'Store']: return # Don't invalidate if the save didn't create new objects if (('created' in kwargs and 'raw' in kwargs) and (not kwargs['created'] or kwargs['raw'])): return proj_code = split_pootle_path(instance.pootle_path)[1] if proj_code is not None: cache.delete(make_method_key(Project, 'resources', proj_code))
def top_scorers(cls, days=30, language=None, project=None, limit=5): """Returns users with the top scores. :param days: period of days to account for scores. :param language: limit results to the given language code. :param project: limit results to the given project code. :param limit: limit results to this number of users. Values other than positive numbers will return the entire result set. """ cache_kwargs = { 'days': days, 'language': language, 'project': project, 'limit': limit, } cache_key = make_method_key(cls, 'top_scorers', cache_kwargs) top_scorers = cache.get(cache_key, None) if top_scorers is not None: return top_scorers now = timezone.now() past = now + datetime.timedelta(-days) lookup_kwargs = { 'scorelog__creation_time__range': [past, now], } if language is not None: lookup_kwargs.update({ 'scorelog__submission__translation_project__language__code': language, }) if project is not None: lookup_kwargs.update({ 'scorelog__submission__translation_project__project__code': project, }) top_scorers = cls.objects.hide_meta().filter( **lookup_kwargs ).annotate( total_score=Sum('scorelog__score_delta'), ).order_by('-total_score') if isinstance(limit, (int, long)) and limit > 0: top_scorers = top_scorers[:limit] cache.set(cache_key, list(top_scorers), 60) return top_scorers
def invalidate_resources_cache(**kwargs): instance = kwargs["instance"] if instance.__class__.__name__ not in ['Directory', 'Store']: return # Don't invalidate if the save didn't create new objects no_new_objects = (('created' in kwargs and 'raw' in kwargs) and (not kwargs['created'] or kwargs['raw'])) if no_new_objects and instance.parent.get_children(): return proj_code = split_pootle_path(instance.pootle_path)[1] if proj_code is not None: cache.delete(make_method_key(Project, 'resources', proj_code))
def invalidate_resources_cache_for_vfolders(sender, instance, **kwargs): if instance.__class__.__name__ == 'VirtualFolder': try: # In case this is vfolder_post_save. affected_projects = kwargs['projects'] except KeyError: # In case this is pre_delete. affected_projects = Project.objects.filter( translationproject__stores__unit__vfolders=instance ).distinct().values_list('code', flat=True) cache.delete_many([ make_method_key('Project', 'resources', proj) for proj in affected_projects ])
def invalidate_resources_cache(**kwargs): instance = kwargs["instance"] if instance.__class__.__name__ not in ["Directory", "Store"]: return # Don't invalidate if the save didn't create new objects no_new_objects = ("created" in kwargs and "raw" in kwargs) and (not kwargs["created"] or kwargs["raw"]) if no_new_objects and instance.parent.get_children(): return proj_code = split_pootle_path(instance.pootle_path)[1] if proj_code is not None: cache.delete(make_method_key(Project, "resources", proj_code))
def cached_dict(self, user): """Return a cached list of projects tuples for `user`. :param user: The user for whom projects need to be retrieved for. :return: A list of project tuples including (code, fullname) """ cache_key = make_method_key('Project', 'cached_dict', {'is_admin': user.is_superuser}) projects = cache.get(cache_key) if not projects: logging.debug('Cache miss for %s', cache_key) projects = OrderedDict( self.for_user(user).order_by('fullname').values_list( 'code', 'fullname')) cache.set(cache_key, projects, settings.OBJECT_CACHE_TIMEOUT) return projects
def cached_dict(self, locale_code='en-us'): """Retrieves a sorted list of live language codes and names. :param locale_code: the UI locale for which language full names need to be localized. :return: an `OrderedDict` """ key = make_method_key(self, 'cached_dict', locale_code) languages = cache.get(key, None) if languages is None: languages = OrderedDict( sorted([(lang[0], tr_lang(lang[1])) for lang in self.values_list('code', 'fullname')], cmp=locale.strcoll, key=lambda x: x[1])) cache.set(key, languages, settings.POOTLE_CACHE_TIMEOUT) return languages
def cached_dict(self, user): """Return a cached list of projects tuples for `user`. :param user: The user for whom projects need to be retrieved for. :return: A list of project tuples including (code, fullname) """ cache_key = make_method_key('Project', 'cached_dict', {'is_admin': user.is_superuser}) projects = cache.get(cache_key) if not projects: logging.debug('Cache miss for %s', cache_key) projects = OrderedDict( self.for_user(user).order_by('fullname') .values_list('code', 'fullname') ) cache.set(cache_key, projects, settings.OBJECT_CACHE_TIMEOUT) return projects
def cached_dict(self, locale_code='en-us'): """Retrieves a sorted list of live language codes and names. :param locale_code: the UI locale for which language full names need to be localized. :return: an `OrderedDict` """ key = make_method_key(self, 'cached_dict', locale_code) languages = cache.get(key, None) if languages is None: languages = OrderedDict( sorted([(lang[0], tr_lang(lang[1])) for lang in self.values_list('code', 'fullname')], cmp=locale.strcoll, key=lambda x: x[1]) ) cache.set(key, languages, settings.OBJECT_CACHE_TIMEOUT) return languages
def resources(self): """Returns a list of :cls:`~pootle_app.models.Directory` and :cls:`~pootle_store.models.Store` resource paths available for this :cls:`~pootle_project.models.Project` across all languages. """ cache_key = make_method_key(self, 'resources', self.code) resources = cache.get(cache_key, None) if resources is not None: return resources logging.debug(u'Cache miss for %s', cache_key) resources_path = ''.join(['/%/', self.code, '/%']) sql_query = ''' SELECT DISTINCT REPLACE(pootle_path, CONCAT(SUBSTRING_INDEX(pootle_path, '/', 3), '/'), '') FROM ( SELECT pootle_path FROM pootle_store_store WHERE pootle_path LIKE %s UNION SELECT pootle_path FROM pootle_app_directory WHERE pootle_path LIKE %s ) AS t; ''' cursor = connection.cursor() cursor.execute(sql_query, [resources_path, resources_path]) results = cursor.fetchall() # Flatten tuple and sort in a list resources = list(reduce(lambda x,y: x+y, results)) resources.sort(key=get_path_sortkey) cache.set(cache_key, resources, settings.OBJECT_CACHE_TIMEOUT) return resources
def resources(self): """Returns a list of :cls:`~pootle_app.models.Directory` and :cls:`~pootle_store.models.Store` resource paths available for this :cls:`~pootle_project.models.Project` across all languages. """ cache_key = make_method_key(self, 'resources', self.code) resources = cache.get(cache_key, None) if resources is not None: return resources stores = Store.objects.live().order_by().filter( translation_project__project_id=self.pk) dirs = Directory.objects.live().order_by().filter(tp__project_id=self.pk) resources = sorted( {tp_path[1:] for tp_path in (set(stores.values_list("tp_path", flat=True)) | set(dirs.values_list("tp_path", flat=True)))}, key=get_path_sortkey) cache.set(cache_key, resources, settings.POOTLE_CACHE_TIMEOUT) return resources
def resources(self): """Returns a list of :cls:`~pootle_app.models.Directory` and :cls:`~pootle_store.models.Store` resource paths available for this :cls:`~pootle_project.models.Project` across all languages. """ cache_key = make_method_key(self, 'resources', self.code) resources = cache.get(cache_key, None) if resources is not None: return resources logging.debug(u'Cache miss for %s', cache_key) resources_path = ''.join(['/%/', self.code, '/%']) sql_query = ''' SELECT pootle_path FROM pootle_store_store WHERE pootle_path LIKE %s UNION SELECT pootle_path FROM pootle_app_directory WHERE pootle_path LIKE %s; ''' cursor = connection.cursor() cursor.execute(sql_query, [resources_path, resources_path]) results = cursor.fetchall() # Calculate TP-relative paths and sort them resources = sorted( {to_tp_relative_path(result[0]) for result in results}, key=get_path_sortkey) cache.set(cache_key, resources, settings.OBJECT_CACHE_TIMEOUT) return resources
def top_scorers(cls, days=30, language=None, project=None, limit=5): """Returns users with the top scores. :param days: period of days to account for scores. :param language: limit results to the given language code. :param project: limit results to the given project code. :param limit: limit results to this number of users. Values other than positive numbers will return the entire result set. """ cache_kwargs = { 'days': days, 'language': language, 'project': project, 'limit': limit, } cache_key = make_method_key(cls, 'top_scorers', cache_kwargs) top_scorers = cache.get(cache_key, None) if top_scorers is not None: return top_scorers now = timezone.now() past = now + datetime.timedelta(-days) lookup_kwargs = { 'creation_time__range': [past, now], } if language is not None: lookup_kwargs.update({ 'submission__translation_project__language__code': language, }) if project is not None: lookup_kwargs.update({ 'submission__translation_project__project__code': project, }) meta_user_ids = cls.objects.meta_users().values_list('id', flat=True) top_scores = ScoreLog.objects.values("user").filter( **lookup_kwargs ).exclude( user__pk__in=meta_user_ids, ).annotate( total_score=Sum('score_delta'), ).order_by('-total_score') if isinstance(limit, (int, long)) and limit > 0: top_scores = top_scores[:limit] users = dict( (user.id, user) for user in cls.objects.filter( pk__in=[item['user'] for item in top_scores] ) ) top_scorers = [] for item in top_scores: user = users[item['user']] user.total_score = item['total_score'] top_scorers.append(user) cache.set(cache_key, list(top_scorers), 60) return top_scorers
def clear_language_list_cache(): key = make_method_key("LiveLanguageManager", "cached_dict", "*") cache.delete_pattern(key) key_all = make_method_key("LiveLanguageManager", "all_cached_dict", "*") cache.delete_pattern(key_all)
def clear_language_list_cache(): key = make_method_key('LiveLanguageManager', 'cached_dict', '*') cache.delete_pattern(key)
def top_scorers(cls, days=30, language=None, project=None, limit=5, offset=0): """Returns users with the top scores. :param days: period of days to account for scores. :param language: limit results to the given language code. :param project: limit results to the given project code. :param limit: limit results to this number of users. Values other than positive numbers will return the entire result set. """ cache_kwargs = { 'days': days, 'language': language, 'project': project, 'limit': limit, 'offset': offset, } cache_key = make_method_key(cls, 'top_scorers', cache_kwargs) top_scorers = cache.get(cache_key, None) if top_scorers is not None: return top_scorers now = timezone.now() past = now + datetime.timedelta(-days) lookup_kwargs = { 'creation_time__range': [past, now], } if language is not None: lookup_kwargs.update({ 'submission__translation_project__language__code': language, }) if project is not None: lookup_kwargs.update({ 'submission__translation_project__project__code': project, }) meta_user_ids = cls.objects.meta_users().values_list('id', flat=True) top_scores = ScoreLog.objects.values("user").filter( **lookup_kwargs ).exclude( user__pk__in=meta_user_ids, ).annotate( total_score=Sum('score_delta'), suggested=Sum( Case( When( action_code=TranslationActionCodes.SUGG_ADDED, then='wordcount' ), default=0, output_field=models.IntegerField() ) ), translated=Sum( Case( When( translated_wordcount__isnull=False, then='translated_wordcount' ), default=0, output_field=models.IntegerField() ) ), reviewed=Sum( Case( When( action_code__in=[ TranslationActionCodes.SUGG_REVIEWED_ACCEPTED, TranslationActionCodes.REVIEWED, TranslationActionCodes.EDITED, ], translated_wordcount__isnull=True, then='wordcount', ), default=0, output_field=models.IntegerField() ) ), ).order_by('-total_score')[offset:] if isinstance(limit, (int, long)) and limit > 0: top_scores = top_scores[:limit] users = dict( (user.id, user) for user in cls.objects.filter( pk__in=[item['user'] for item in top_scores] ) ) top_scorers = [] for item in top_scores: item['user'] = users[item['user']] item['public_total_score'] = formatter.number( round(item['total_score'])) top_scorers.append(item) cache.set(cache_key, top_scorers, 60) return top_scorers
def resources(self): """Returns a list of :cls:`~pootle_app.models.Directory` and :cls:`~pootle_store.models.Store` resource paths available for this :cls:`~pootle_project.models.Project` across all languages. """ cache_key = make_method_key(self, 'resources', self.code) resources = cache.get(cache_key, None) if resources is not None: return resources logging.debug(u'Cache miss for %s', cache_key) resources_path = ''.join(['/%/', self.code, '/%']) if connection.vendor == 'mysql': sql_query = ''' SELECT DISTINCT REPLACE(pootle_path, CONCAT(SUBSTRING_INDEX(pootle_path, '/', 3), '/'), '') FROM ( SELECT pootle_path FROM pootle_store_store WHERE pootle_path LIKE %s UNION SELECT pootle_path FROM pootle_app_directory WHERE pootle_path LIKE %s ) AS t; ''' elif connection.vendor == 'postgresql': sql_query = ''' SELECT DISTINCT REPLACE(pootle_path, ARRAY_TO_STRING(( STRING_TO_ARRAY(pootle_path,'/') )[1:3], '/') || '/', '') FROM ( SELECT pootle_path FROM pootle_store_store WHERE pootle_path LIKE %s UNION SELECT pootle_path FROM pootle_app_directory WHERE pootle_path LIKE %s ) AS t; ''' elif connection.vendor == 'sqlite': # Due to the limitations of SQLite there is no way to do this just # using raw SQL. from pootle_store.models import Store store_objs = Store.objects.extra( where=[ 'pootle_store_store.pootle_path LIKE %s', 'pootle_store_store.pootle_path NOT LIKE %s', ], params=[resources_path, '/templates/%']).select_related('parent').distinct() # Populate with stores and their parent directories, avoiding any # duplicates resources = [] for store in store_objs.iterator(): directory = store.parent if (not directory.is_translationproject() and all(directory.path != path for path in resources)): resources.append(directory.path) if all(store.path != path for path in resources): resources.append(store.path) resources.sort(key=get_path_sortkey) cache.set(cache_key, resources, settings.OBJECT_CACHE_TIMEOUT) return resources cursor = connection.cursor() cursor.execute(sql_query, [resources_path, resources_path]) results = cursor.fetchall() # Flatten tuple and sort in a list resources = list(reduce(lambda x, y: x + y, results)) resources.sort(key=get_path_sortkey) cache.set(cache_key, resources, settings.OBJECT_CACHE_TIMEOUT) return resources
def resources(self): """Returns a list of :cls:`~pootle_app.models.Directory` and :cls:`~pootle_store.models.Store` resource paths available for this :cls:`~pootle_project.models.Project` across all languages. """ cache_key = make_method_key(self, 'resources', self.code) resources = cache.get(cache_key, None) if resources is not None: return resources logging.debug(u'Cache miss for %s', cache_key) resources_path = ''.join(['/%/', self.code, '/%']) if connection.vendor == 'mysql': sql_query = ''' SELECT DISTINCT REPLACE(pootle_path, CONCAT(SUBSTRING_INDEX(pootle_path, '/', 3), '/'), '') FROM ( SELECT pootle_path FROM pootle_store_store WHERE pootle_path LIKE %s UNION SELECT pootle_path FROM pootle_app_directory WHERE pootle_path LIKE %s ) AS t; ''' elif connection.vendor == 'postgresql': sql_query = ''' SELECT DISTINCT REPLACE(pootle_path, ARRAY_TO_STRING(( STRING_TO_ARRAY(pootle_path,'/') )[1:3], '/') || '/', '') FROM ( SELECT pootle_path FROM pootle_store_store WHERE pootle_path LIKE %s UNION SELECT pootle_path FROM pootle_app_directory WHERE pootle_path LIKE %s ) AS t; ''' elif connection.vendor == 'sqlite': # Due to the limitations of SQLite there is no way to do this just # using raw SQL. from pootle_store.models import Store store_objs = Store.objects.extra( where=[ 'pootle_store_store.pootle_path LIKE %s', 'pootle_store_store.pootle_path NOT LIKE %s', ], params=[resources_path, '/templates/%'] ).select_related('parent').distinct() # Populate with stores and their parent directories, avoiding any # duplicates resources = [] for store in store_objs.iterator(): directory = store.parent if (not directory.is_translationproject() and all(directory.path != path for path in resources)): resources.append(directory.path) if all(store.path != path for path in resources): resources.append(store.path) resources.sort(key=get_path_sortkey) cache.set(cache_key, resources, settings.OBJECT_CACHE_TIMEOUT) return resources cursor = connection.cursor() cursor.execute(sql_query, [resources_path, resources_path]) results = cursor.fetchall() # Flatten tuple and sort in a list resources = list(reduce(lambda x,y: x+y, results)) resources.sort(key=get_path_sortkey) cache.set(cache_key, resources, settings.OBJECT_CACHE_TIMEOUT) return resources
def top_scorers(cls, days=30, language=None, project=None, limit=5, offset=0): """Returns users with the top scores. :param days: period of days to account for scores. :param language: limit results to the given language code. :param project: limit results to the given project code. :param limit: limit results to this number of users. Values other than positive numbers will return the entire result set. """ cache_kwargs = { 'days': days, 'language': language, 'project': project, 'limit': limit, 'offset': offset, } cache_key = make_method_key(cls, 'top_scorers', cache_kwargs) top_scorers = cache.get(cache_key, None) if top_scorers is not None: return top_scorers now = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0) past = now + datetime.timedelta(-days) lookup_kwargs = { 'creation_time__range': [past, now], } if language is not None: lookup_kwargs.update({ 'submission__translation_project__language__code': language, }) if project is not None: lookup_kwargs.update({ 'submission__translation_project__project__code': project, }) meta_user_ids = cls.objects.meta_users().values_list('id', flat=True) top_scores = ScoreLog.objects.values("user").filter( **lookup_kwargs).exclude(user__pk__in=meta_user_ids, ).annotate( total_score=Sum('score_delta'), suggested=Sum( Case(When(action_code=TranslationActionCodes.SUGG_ADDED, then='wordcount'), default=0, output_field=models.IntegerField())), translated=Sum( Case(When(translated_wordcount__isnull=False, then='translated_wordcount'), default=0, output_field=models.IntegerField())), reviewed=Sum( Case(When( action_code__in=[ TranslationActionCodes.SUGG_REVIEWED_ACCEPTED, TranslationActionCodes.REVIEWED, TranslationActionCodes.EDITED, ], translated_wordcount__isnull=True, then='wordcount', ), default=0, output_field=models.IntegerField())), ).order_by('-total_score')[offset:] if isinstance(limit, (int, long)) and limit > 0: top_scores = top_scores[:limit] users = dict((user.id, user) for user in cls.objects.filter( pk__in=[item['user'] for item in top_scores])) top_scorers = [] for item in top_scores: item['user'] = users[item['user']] item['public_total_score'] = _humanize_score(item['total_score']) top_scorers.append(item) cache.set(cache_key, top_scorers, 60) return top_scorers