Commit 21973244d51d342ce40ab7c20ea8b46fb5d4334d

Authored by Rodrigo Siqueira de Melo
Committed by Gust
1 parent 19615e85

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
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
@@ -14,3 +14,5 @@ class ProxyJenkinsAppConfig(ColabProxiedAppConfig): @@ -14,3 +14,5 @@ class ProxyJenkinsAppConfig(ColabProxiedAppConfig):
14 (_('Continuos Integration'), ''), 14 (_('Continuos Integration'), ''),
15 ), 15 ),
16 } 16 }
  17 +
  18 + collaboration_models = []
colab/proxy/noosfero/apps.py
@@ -19,3 +19,5 @@ class ProxyNoosferoAppConfig(ColabProxiedAppConfig): @@ -19,3 +19,5 @@ class ProxyNoosferoAppConfig(ColabProxiedAppConfig):
19 (_('Control panel'), 'myprofile'), 19 (_('Control panel'), 'myprofile'),
20 ), 20 ),
21 } 21 }
  22 +
  23 + collaboration_models = []
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
@@ -22,3 +22,5 @@ class ProxyTracAppConfig(ColabProxiedAppConfig): @@ -22,3 +22,5 @@ class ProxyTracAppConfig(ColabProxiedAppConfig):
22 (_('New Wiki Page'), 'wiki/WikiNewPage'), 22 (_('New Wiki Page'), 'wiki/WikiNewPage'),
23 ), 23 ),
24 } 24 }
  25 +
  26 + collaboration_models = []
colab/search/preview_block.py 0 → 100644
@@ -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