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 |