Commit 21973244d51d342ce40ab7c20ea8b46fb5d4334d
Committed by
Gust
1 parent
19615e85
Exists in
master
and in
39 other branches
Remove haystack search from dashboard an profile
-Generalizes a structure for proxies to define its collaboration models -Remove haystack search from profile and search pages in pro of the colab own database
Showing
10 changed files
with
169 additions
and
71 deletions
Show diff stats
colab/accounts/views.py
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | # encoding: utf-8 | 2 | # encoding: utf-8 |
| 3 | +import importlib | ||
| 4 | +import inspect | ||
| 3 | 5 | ||
| 4 | from collections import OrderedDict | 6 | from collections import OrderedDict |
| 5 | 7 | ||
| @@ -15,6 +17,7 @@ from django.shortcuts import render, redirect, get_object_or_404 | @@ -15,6 +17,7 @@ from django.shortcuts import render, redirect, get_object_or_404 | ||
| 15 | from django.core.urlresolvers import reverse | 17 | from django.core.urlresolvers import reverse |
| 16 | from django.core.exceptions import PermissionDenied | 18 | from django.core.exceptions import PermissionDenied |
| 17 | from django.views.generic import DetailView, UpdateView, TemplateView | 19 | from django.views.generic import DetailView, UpdateView, TemplateView |
| 20 | +from django.apps import apps | ||
| 18 | 21 | ||
| 19 | from conversejs import xmpp | 22 | from conversejs import xmpp |
| 20 | from conversejs.models import XMPPAccount | 23 | from conversejs.models import XMPPAccount |
| @@ -22,7 +25,7 @@ from haystack.query import SearchQuerySet | @@ -22,7 +25,7 @@ from haystack.query import SearchQuerySet | ||
| 22 | 25 | ||
| 23 | from colab.super_archives.models import (EmailAddress, Message, | 26 | from colab.super_archives.models import (EmailAddress, Message, |
| 24 | EmailAddressValidation) | 27 | EmailAddressValidation) |
| 25 | -from colab.search.utils import trans | 28 | +from colab.search.utils import trans, getCollaborationData |
| 26 | # from proxy.trac.models import WikiCollabCount, TicketCollabCount | 29 | # from proxy.trac.models import WikiCollabCount, TicketCollabCount |
| 27 | from .forms import (UserCreationForm, UserForm, ListsForm, | 30 | from .forms import (UserCreationForm, UserForm, ListsForm, |
| 28 | UserUpdateForm, ChangeXMPPPasswordForm) | 31 | UserUpdateForm, ChangeXMPPPasswordForm) |
| @@ -71,48 +74,19 @@ class UserProfileDetailView(UserProfileBaseMixin, DetailView): | @@ -71,48 +74,19 @@ class UserProfileDetailView(UserProfileBaseMixin, DetailView): | ||
| 71 | 74 | ||
| 72 | count_types = OrderedDict() | 75 | count_types = OrderedDict() |
| 73 | 76 | ||
| 74 | - fields_or_lookup = ( | ||
| 75 | - {'collaborators__contains': user.username}, | ||
| 76 | - {'fullname_and_username__contains': user.username}, | ||
| 77 | - ) | 77 | + # TODO: remove when mailman becomes a proxied plugin |
| 78 | + messages = Message.objects.filter(from_address__user__pk=user.pk) | ||
| 79 | + count_types[trans('thread')] = messages.count() | ||
| 78 | 80 | ||
| 79 | - counter_class = {} | ||
| 80 | - # { | ||
| 81 | - # 'wiki': WikiCollabCount, | ||
| 82 | - # 'ticket': TicketCollabCount, | ||
| 83 | - # } | 81 | + collaborations, count_types_extras = getCollaborationData(user) |
| 82 | + collaborations.extend(messages) | ||
| 84 | 83 | ||
| 85 | - types = ['thread'] | ||
| 86 | - # types.extend(['ticket', 'wiki', 'changeset', 'attachment']) | 84 | + collaborations = sorted(collaborations, key=lambda elem : elem.modified, reverse=True) |
| 87 | 85 | ||
| 88 | - messages = Message.objects.filter(from_address__user__pk=user.pk) | ||
| 89 | - for type in types: | ||
| 90 | - CounterClass = counter_class.get(type) | ||
| 91 | - if CounterClass: | ||
| 92 | - try: | ||
| 93 | - counter = CounterClass.objects.get(author=user.username) | ||
| 94 | - except CounterClass.DoesNotExist: | ||
| 95 | - count_types[trans(type)] = 0 | ||
| 96 | - else: | ||
| 97 | - count_types[trans(type)] = counter.count | ||
| 98 | - elif type == 'thread': | ||
| 99 | - count_types[trans(type)] = messages.count() | ||
| 100 | - else: | ||
| 101 | - sqs = SearchQuerySet() | ||
| 102 | - for filter_or in fields_or_lookup: | ||
| 103 | - sqs = sqs.filter_or(type=type, **filter_or) | ||
| 104 | - count_types[trans(type)] = sqs.count() | 86 | + count_types.update(count_types_extras) |
| 105 | 87 | ||
| 106 | context['type_count'] = count_types | 88 | context['type_count'] = count_types |
| 107 | - | ||
| 108 | - sqs = SearchQuerySet() | ||
| 109 | - for filter_or in fields_or_lookup: | ||
| 110 | - sqs = sqs.filter_or(**filter_or).exclude(type='thread') | ||
| 111 | - | ||
| 112 | - try: | ||
| 113 | - context['results'] = sqs.order_by('-modified', '-created')[:10] | ||
| 114 | - except SearchBackendError: | ||
| 115 | - context['results'] = sqs.order_by('-modified')[:10] | 89 | + context['results'] = collaborations[:10] |
| 116 | 90 | ||
| 117 | email_pks = [addr.pk for addr in user.emails.iterator()] | 91 | email_pks = [addr.pk for addr in user.emails.iterator()] |
| 118 | query = Message.objects.filter(from_address__in=email_pks) | 92 | query = Message.objects.filter(from_address__in=email_pks) |
| @@ -127,7 +101,6 @@ class UserProfileDetailView(UserProfileBaseMixin, DetailView): | @@ -127,7 +101,6 @@ class UserProfileDetailView(UserProfileBaseMixin, DetailView): | ||
| 127 | context.update(kwargs) | 101 | context.update(kwargs) |
| 128 | return super(UserProfileDetailView, self).get_context_data(**context) | 102 | return super(UserProfileDetailView, self).get_context_data(**context) |
| 129 | 103 | ||
| 130 | - | ||
| 131 | def signup(request): | 104 | def signup(request): |
| 132 | BROWSERID_ENABLED = getattr(settings, 'BROWSERID_ENABLED', False) | 105 | BROWSERID_ENABLED = getattr(settings, 'BROWSERID_ENABLED', False) |
| 133 | 106 |
colab/home/views.py
| 1 | - | ||
| 2 | from collections import OrderedDict | 1 | from collections import OrderedDict |
| 3 | 2 | ||
| 4 | from django.conf import settings | 3 | from django.conf import settings |
| @@ -8,53 +7,49 @@ from django.http import HttpResponse, Http404 | @@ -8,53 +7,49 @@ from django.http import HttpResponse, Http404 | ||
| 8 | 7 | ||
| 9 | from haystack.query import SearchQuerySet | 8 | from haystack.query import SearchQuerySet |
| 10 | 9 | ||
| 10 | +<<<<<<< HEAD | ||
| 11 | # from proxy.trac.models import WikiCollabCount, TicketCollabCount | 11 | # from proxy.trac.models import WikiCollabCount, TicketCollabCount |
| 12 | from colab.search.utils import trans | 12 | from colab.search.utils import trans |
| 13 | from colab.super_archives.models import Thread | 13 | from colab.super_archives.models import Thread |
| 14 | +======= | ||
| 15 | +from colab.search.utils import trans, getCollaborationData | ||
| 16 | +from colab.super_archives.models import Thread, Message | ||
| 17 | +from colab.search.preview_block import PreviewBlock | ||
| 18 | +from colab.accounts.models import User | ||
| 19 | +>>>>>>> Remove haystack search from dashboard an profile | ||
| 14 | 20 | ||
| 15 | 21 | ||
| 16 | def dashboard(request): | 22 | def dashboard(request): |
| 17 | """Dashboard page""" | 23 | """Dashboard page""" |
| 24 | + | ||
| 18 | latest_threads = Thread.objects.all()[:6] | 25 | latest_threads = Thread.objects.all()[:6] |
| 19 | - hottest_threads = Thread.highest_score.from_haystack()[:6] | ||
| 20 | - | ||
| 21 | - count_types = cache.get('home_chart') | ||
| 22 | - if count_types is None: | ||
| 23 | - count_types = OrderedDict() | ||
| 24 | - count_types['thread'] = SearchQuerySet().filter( | ||
| 25 | - type='thread', | ||
| 26 | - ).count() | ||
| 27 | - # TODO: this section should be inside trac app and only use it here | ||
| 28 | - # if settings.TRAC_ENABLED: | ||
| 29 | - # for type in ['changeset', 'attachment']: | ||
| 30 | - # count_types[type] = SearchQuerySet().filter( | ||
| 31 | - # type=type, | ||
| 32 | - # ).count() | ||
| 33 | - | ||
| 34 | - # count_types['ticket'] = sum([ | ||
| 35 | - # ticket.count for ticket in TicketCollabCount.objects.all() | ||
| 36 | - # ]) | ||
| 37 | - | ||
| 38 | - # count_types['wiki'] = sum([ | ||
| 39 | - # wiki.count for wiki in WikiCollabCount.objects.all() | ||
| 40 | - # ]) | ||
| 41 | - | ||
| 42 | - cache.set('home_chart', count_types) | 26 | + highest_score_threads = Thread.highest_score.all()[:6] |
| 27 | + | ||
| 28 | + hottest_threads = [] | ||
| 29 | + for thread in highest_score_threads: | ||
| 30 | + hottest_threads.append(thread.latest_message) | ||
| 31 | + | ||
| 32 | + latest_results, count_types = getCollaborationData() | ||
| 33 | + threads = Thread.objects.all() | ||
| 34 | + messages = [] | ||
| 35 | + for t in threads: | ||
| 36 | + messages.append(t.latest_message) | ||
| 37 | + | ||
| 38 | + latest_results.extend(messages) | ||
| 39 | + latest_results = sorted(latest_results, | ||
| 40 | + key=lambda elem : elem.modified, reverse=True) | ||
| 43 | 41 | ||
| 44 | for key in count_types.keys(): | 42 | for key in count_types.keys(): |
| 45 | count_types[trans(key)] = count_types.pop(key) | 43 | count_types[trans(key)] = count_types.pop(key) |
| 46 | 44 | ||
| 47 | context = { | 45 | context = { |
| 48 | 'hottest_threads': hottest_threads[:6], | 46 | 'hottest_threads': hottest_threads[:6], |
| 49 | - 'latest_threads': latest_threads, | 47 | + 'latest_threads': latest_threads[:6], |
| 50 | 'type_count': count_types, | 48 | 'type_count': count_types, |
| 51 | - 'latest_results': SearchQuerySet().all().order_by( | ||
| 52 | - '-modified', '-created' | ||
| 53 | - )[:6], | 49 | + 'latest_results': latest_results[:6], |
| 54 | } | 50 | } |
| 55 | return render(request, 'home.html', context) | 51 | return render(request, 'home.html', context) |
| 56 | 52 | ||
| 57 | - | ||
| 58 | def robots(request): | 53 | def robots(request): |
| 59 | if getattr(settings, 'ROBOTS_NOINDEX', False): | 54 | if getattr(settings, 'ROBOTS_NOINDEX', False): |
| 60 | return HttpResponse('User-agent: *\nDisallow: /', | 55 | return HttpResponse('User-agent: *\nDisallow: /', |
colab/proxy/gitlab/apps.py
| @@ -3,8 +3,36 @@ from django.utils.translation import ugettext_lazy as _ | @@ -3,8 +3,36 @@ from django.utils.translation import ugettext_lazy as _ | ||
| 3 | 3 | ||
| 4 | from ..utils.apps import ColabProxiedAppConfig | 4 | from ..utils.apps import ColabProxiedAppConfig |
| 5 | 5 | ||
| 6 | - | ||
| 7 | class ProxyGitlabAppConfig(ColabProxiedAppConfig): | 6 | class ProxyGitlabAppConfig(ColabProxiedAppConfig): |
| 7 | + ''' | ||
| 8 | + You can define a collaboration_models list to tell colab which | ||
| 9 | + models and what values should be displayed as collaborations. | ||
| 10 | + | ||
| 11 | + See the example bellow: | ||
| 12 | + | ||
| 13 | + Field model refers to the model to be displayed. | ||
| 14 | + Field model_verbose is the human name to be displayed in charts. | ||
| 15 | + Field collaborator_username tells which user(username) is associated with this collaboration. | ||
| 16 | + | ||
| 17 | + The value of the hashes maps the attribute or method of the model to be put in those positions. | ||
| 18 | + | ||
| 19 | + collaboration_models = [ | ||
| 20 | + { | ||
| 21 | + 'model' : 'User', | ||
| 22 | + 'model_verbose' : 'User', | ||
| 23 | + 'tag' : '', | ||
| 24 | + 'title' : 'username', | ||
| 25 | + 'description' : 'get_full_name', | ||
| 26 | + 'fullname' : '', | ||
| 27 | + 'modified' : 'modified', | ||
| 28 | + 'modified_by' : '', | ||
| 29 | + 'modified_by_url' : '', | ||
| 30 | + 'url' : '', | ||
| 31 | + 'type' : '', | ||
| 32 | + 'collaborator_username' : 'username', | ||
| 33 | + }, | ||
| 34 | + ] | ||
| 35 | + ''' | ||
| 8 | name = 'colab.proxy.gitlab' | 36 | name = 'colab.proxy.gitlab' |
| 9 | verbose_name = 'Gitlab Proxy' | 37 | verbose_name = 'Gitlab Proxy' |
| 10 | 38 | ||
| @@ -23,3 +51,5 @@ class ProxyGitlabAppConfig(ColabProxiedAppConfig): | @@ -23,3 +51,5 @@ class ProxyGitlabAppConfig(ColabProxiedAppConfig): | ||
| 23 | 51 | ||
| 24 | ), | 52 | ), |
| 25 | } | 53 | } |
| 54 | + | ||
| 55 | + collaboration_models = [] |
colab/proxy/jenkins/apps.py
colab/proxy/noosfero/apps.py
colab/proxy/redmine/apps.py
| @@ -5,3 +5,5 @@ from ..utils.apps import ColabProxiedAppConfig | @@ -5,3 +5,5 @@ from ..utils.apps import ColabProxiedAppConfig | ||
| 5 | class ProxyRedmineAppConfig(ColabProxiedAppConfig): | 5 | class ProxyRedmineAppConfig(ColabProxiedAppConfig): |
| 6 | name = 'colab.proxy.redmine' | 6 | name = 'colab.proxy.redmine' |
| 7 | verbose_name = 'Redmine Proxy' | 7 | verbose_name = 'Redmine Proxy' |
| 8 | + | ||
| 9 | + collaboration_models = [] |
colab/proxy/trac/apps.py
| @@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
| 1 | +class PreviewBlock(): | ||
| 2 | + tag = None | ||
| 3 | + title = None | ||
| 4 | + description = None | ||
| 5 | + fullname = None | ||
| 6 | + modified = None | ||
| 7 | + modified_by = None | ||
| 8 | + url = None | ||
| 9 | + type = None | ||
| 10 | + modified_by_url = None | ||
| 11 | + collaborator_username = None | ||
| 12 | + | ||
| 13 | + def __init__(self, **kwargs): | ||
| 14 | + for key, value in kwargs.items(): | ||
| 15 | + setattr(self, key, value) |
colab/search/templates/search/search-message-preview.html
| @@ -11,7 +11,6 @@ | @@ -11,7 +11,6 @@ | ||
| 11 | <span class="subject"> | 11 | <span class="subject"> |
| 12 | <a href="{{ result.url }}#msg-{{ result.pk }}" | 12 | <a href="{{ result.url }}#msg-{{ result.pk }}" |
| 13 | title="{% filter striptags|truncatewords:50 %}{{ result.description|escape }}{% endfilter %}"> | 13 | title="{% filter striptags|truncatewords:50 %}{{ result.description|escape }}{% endfilter %}"> |
| 14 | - {{ result.title }} | ||
| 15 | </a> | 14 | </a> |
| 16 | </span> | 15 | </span> |
| 17 | 16 |
colab/search/utils.py
| 1 | +import importlib | ||
| 2 | +import inspect | ||
| 1 | 3 | ||
| 4 | +from collections import OrderedDict | ||
| 5 | + | ||
| 6 | +from django.core.cache import cache | ||
| 2 | from django.utils.translation import ugettext as _ | 7 | from django.utils.translation import ugettext as _ |
| 8 | +from django.apps import apps | ||
| 9 | +from django.conf import settings | ||
| 10 | +from colab.super_archives.models import Thread, Message | ||
| 11 | +from colab.search.preview_block import PreviewBlock | ||
| 3 | 12 | ||
| 4 | 13 | ||
| 5 | def trans(key): | 14 | def trans(key): |
| @@ -11,4 +20,73 @@ def trans(key): | @@ -11,4 +20,73 @@ def trans(key): | ||
| 11 | 'attachment': _('Attachments'), | 20 | 'attachment': _('Attachments'), |
| 12 | } | 21 | } |
| 13 | 22 | ||
| 23 | + app_names = settings.PROXIED_APPS.keys() | ||
| 24 | + | ||
| 25 | + for app_name in app_names: | ||
| 26 | + collaboration_models = apps.get_app_config(app_name).collaboration_models | ||
| 27 | + | ||
| 28 | + for collaboration in collaboration_models: | ||
| 29 | + module = importlib.import_module('colab.proxy.{}.models'.format(app_name)) | ||
| 30 | + elements = eval("module." + collaboration['model']).objects.all() | ||
| 31 | + translations[ collaboration['model'].lower() ] = collaboration['model_verbose'] | ||
| 32 | + | ||
| 14 | return translations.get(key, key) | 33 | return translations.get(key, key) |
| 34 | + | ||
| 35 | +def getCollaborationData(filter_by_user = None): | ||
| 36 | + | ||
| 37 | + latest_results = [] | ||
| 38 | + count_types = cache.get('home_chart') | ||
| 39 | + populate_count_types = False | ||
| 40 | + | ||
| 41 | + if count_types is None: | ||
| 42 | + populate_count_types = True | ||
| 43 | + count_types = OrderedDict() | ||
| 44 | + count_types['thread'] = Thread.objects.count() | ||
| 45 | + | ||
| 46 | + app_names = settings.PROXIED_APPS.keys() | ||
| 47 | + | ||
| 48 | + for app_name in app_names: | ||
| 49 | + collaboration_models = apps.get_app_config(app_name).collaboration_models | ||
| 50 | + | ||
| 51 | + for collaboration in collaboration_models: | ||
| 52 | + module = importlib.import_module('colab.proxy.{}.models'.format(app_name)) | ||
| 53 | + elements = eval("module." + collaboration['model']).objects | ||
| 54 | + | ||
| 55 | + if filter_by_user: | ||
| 56 | + dic = {} | ||
| 57 | + dic[collaboration['collaborator_username']] = filter_by_user | ||
| 58 | + elements = elements.filter(**dic) | ||
| 59 | + else: | ||
| 60 | + elements = elements.all() | ||
| 61 | + | ||
| 62 | + latest_results.extend(parsePreviewBlock(elements, collaboration)) | ||
| 63 | + | ||
| 64 | + if populate_count_types: | ||
| 65 | + count_types[ collaboration['model'].lower() ] = elements.count() | ||
| 66 | + | ||
| 67 | + if populate_count_types: | ||
| 68 | + cache.set('home_chart', count_types) | ||
| 69 | + | ||
| 70 | + for key in count_types.keys(): | ||
| 71 | + count_types[trans(key)] = count_types.pop(key) | ||
| 72 | + | ||
| 73 | + return latest_results, count_types | ||
| 74 | + | ||
| 75 | +def parsePreviewBlock(elements, collaboration): | ||
| 76 | + results = [] | ||
| 77 | + for element in elements: | ||
| 78 | + previewblock = PreviewBlock() | ||
| 79 | + attributes = collaboration.keys() | ||
| 80 | + | ||
| 81 | + for keyname in attributes: | ||
| 82 | + if keyname == 'model' or keyname == 'model_verbose' or len(collaboration[keyname].strip()) == 0: | ||
| 83 | + continue | ||
| 84 | + value = getattr(element, collaboration[keyname]) | ||
| 85 | + if(inspect.ismethod(value)): | ||
| 86 | + setattr(previewblock, keyname, value() ) | ||
| 87 | + else: | ||
| 88 | + setattr(previewblock, keyname, value ) | ||
| 89 | + | ||
| 90 | + results.append(previewblock) | ||
| 91 | + | ||
| 92 | + return results | ||
| 15 | \ No newline at end of file | 93 | \ No newline at end of file |