def tag_list(context, owner, plus_exclude=None): # TODO: memcache this if plus_exclude is not None: add = u','.join(plus_exclude) plus_exclude_lower = [x.lower() for x in plus_exclude] else: add = u'' plus_exclude_lower = [] no_plus = u'<a href="/search/?q=%(fulltag)s"%(class)s data-votes="%(votes)s">%(tag)s</a>' plus = no_plus + u'<a href="/search/?q=' + add + ',%(tag)s"%(class)s>+</a>' user = context['user'] show_hidden_option = user.is_authenticated() \ and user.get_profile().show_hidden_tags show_hidden = show_hidden_option == UserProfile.HIDDEN_TAGS_SHOW_ALWAYS content_type = ContentType.objects.get_for_model(owner) if content_type.app_label == 'task' and content_type.model == 'task': if show_hidden_option == UserProfile.HIDDEN_TAGS_SHOW_IF_SOLVED: # TODO: do not rely on cache_solution solution = getattr(owner, 'cache_solution', None) show_hidden = solution and solution.is_solved() v0 = [] # not hidden v1 = [] # hidden for tagged_item in get_object_tagged_items(owner): name = tagged_item.tag.name votes = tagged_item.votes_sum attr = {'votes': votes, 'class': '', 'fulltag': name} if name[0] != '$': attr['tag'] = name elif show_hidden: attr['tag'] = name[1:] attr['class'] = 'tag-hidden' else: continue if votes <= VOTE_WRONG: attr['class'] += ' tag-wrong' if attr['class']: attr['class'] = ' class="{}"'.format(attr['class'].strip()) if not plus_exclude or name.lower() in plus_exclude_lower: fmt = no_plus else: fmt = plus (v0 if name[0] != '$' else v1).append(fmt % attr) # Update apps/tags/static/tags.coffee and .scss if changing this! return mark_safe( u'<div class="tag-list tag-list-tooltip" data-content-type-id="{}" ' u'data-object-id="{}">{}</div>'.format( content_type.id, owner.id, u" ".join(v0 + v1)))
def get_task_folder_ids(task): """ Returns the list of IDs of all folders containing given task. Combines result of many-to-many relation and folder-filters. Does not check permissions, and not supposed to do any checks. Note that even search results are copied into FolderTask for folder-filters, there may still be some of those Folders whose m2m is not refreshed (i.e. their .cache_searchcache is None). """ # Implementation of permission check is very complicated, do not implement # it here! Use get_visible_folder_tree instead. tags = [x.tag for x in get_object_tagged_items(task)] # One possible solution is: # Folder.objects.for_user(user, permission) \ # .filter(tasks=task, search_cache_elements__cache=search_cache) \ # .distinct() # but the complexity of this query is O(count(Folder)). # That's why we separately take IDs from FolderTask and IDs from # reverse_cache and then select them through their IDs. # Folders with many-to-many relation m2m_ids = FolderTask.objects.filter(task=task).values_list('folder_id', flat=True) # Folders with tag filter search_cache = reverse_search([x.name for x in tags]) if search_cache: content_type = ContentType.objects.get_for_model(Folder) search_ids = SearchCacheElement.objects.filter(cache=search_cache, content_type=content_type).values_list('object_id', flat=True) else: search_ids = [] ids = list(m2m_ids) + list(search_ids) # Remove duplicates (does not preserve order) return list(set(ids))
def CHECK(x, y, z = None): names = [item.tag.name for item in get_object_tagged_items(x)] self.assertEqual(sorted(names), sorted(y), z)