Commit b534565bb6f84185e046b1e613039dc0f0f90064
1 parent
0625388d
Exists in
master
and in
39 other branches
Merge com a ultima versao do bitcket: https://bitbucket.org/seocam/atu-colab/src/4ee3ca57614e
git-svn-id: http://repositorio.interlegis.gov.br/colab/trunk@6126 bee1b3ed-c3eb-0310-9994-b88e04532788
Showing
24 changed files
with
363 additions
and
71 deletions
Show diff stats
TODO.rst
... | ... | @@ -9,9 +9,9 @@ TODO |
9 | 9 | * Yure: Adicionar data do ultimo import de emails no footer |
10 | 10 | * Yure: Detectar links no conteudo e exibi-los como tal |
11 | 11 | * Yure: BUG: Display of HTML emails are wrong |
12 | -* Yure: Cadastrar usuário em lista pelo formulario de cadastro | |
13 | 12 | * Arquivo "search.html" existente em "atu-colab/colab/templates" pode ser melhorado com relação ao conteúdo repetitivo dos "Tipos" exibidos no "Filtro" da página |
14 | -* Criar validador de urls para twitter, facebook e página pessoal do user profile | |
13 | +* BUG: Criar validador de urls para twitter, facebook e página pessoal do user profile | |
14 | +* Mostrar dados do twitter, facebook, gtalk e página pessoal somente para os usuários que estiverem logados | |
15 | 15 | |
16 | 16 | * Configurar ADMINS no arquivo settings_local.py |
17 | 17 | * HTTPS para o trac, subversion e colab |
... | ... | @@ -20,11 +20,10 @@ TODO |
20 | 20 | * Timezones no trac/colab/solr nao estao compativeis |
21 | 21 | |
22 | 22 | * Template de login nao exibe corretamente no firefox/linux |
23 | -* Quando usuario se cadastra com email errado o email nunca eh validado, | |
24 | -e o username fica preso 'pra sempre'. | |
23 | +* Quando usuario se cadastra com email errado o email nunca eh validado, e o username fica preso 'pra sempre'. | |
25 | 24 | * Nome dos usuarios errado nos emails que vem do Solr |
26 | 25 | * Adicionar ordering na busca |
27 | -* Criar tipo usuario no solr | |
26 | +* Criar tipo usuario no solr | |
28 | 27 | * Substituir sistema de cadastro por django-registration |
29 | 28 | * Utilizar pysolr para efetuar queries no Solr |
30 | 29 | * Melhorar buscas (case insensitive match, palavras com acentos) |
... | ... | @@ -40,13 +39,13 @@ e o username fica preso 'pra sempre'. |
40 | 39 | * Merge emails dos usuarios |
41 | 40 | * Implementar badge system |
42 | 41 | * Melhorar filtros |
43 | -* Link do thread preview deve enviar para mensagem da thread (anchor) (Útil? discutir com Jean) | |
42 | +* Link do thread preview deve enviar para mensagem da thread (anchor) | |
44 | 43 | * Tornar todas as strings traduziveis |
45 | 44 | * Sugestão de como a divisão do edital seria melhor |
46 | 45 | * Indexar anexos da wiki (using Tika http://wiki.apache.org/solr/ExtractingRequestHandler) |
47 | 46 | * Filtrar usando calendario (como google analytics) |
48 | 47 | * Melhorar relevancia das buscas usando dismax queryparser |
49 | -* Chat estilo Gmail | |
48 | +* Chat estilo Gmail usando o mensageiro Interlegis | |
50 | 49 | * Sistema de gerencia de conteúdo |
51 | 50 | * Versao mobile |
52 | 51 | * Exibir discussões relacionadas na barra da direita das discussões |
... | ... | @@ -56,9 +55,14 @@ e o username fica preso 'pra sempre'. |
56 | 55 | * Contar page views no trac (ticket, wiki e changeset) e utiliza-los para rankear paginas nas buscas |
57 | 56 | * Mostrar highlight nas buscas |
58 | 57 | * Sistema de tags para as mensagens |
58 | +* Tag cloud para as mensagens, ao lado direito da thread | |
59 | 59 | * Pagina home para cada lista com os mesmo filtros da home atual |
60 | 60 | * Permitir que usuario entre e saia de listas ao editar perfil |
61 | 61 | * Planet Interlegis (agregador de blogs) |
62 | -* Filtros especificos para tipos diferentes na busca | |
62 | +* Filtros específicos para tipos diferentes na busca da thread | |
63 | +* Link para a mensagem original no histórico do Mailman (popup ajax) | |
64 | +* Filtro de mensagens nas listas acumulativos, podendo ligar e desligar todos | |
65 | +* Reduzir campos na tela de cadastro, transferindo-os como aba para a tela de profile, junto com a aba de listas a se inscrever) | |
66 | + | |
63 | 67 | * Indice criado manualmente. Automatizar: |
64 | 68 | * create index super_archives_message_body_idx ON super_archives_message ((substring(body,0,1024))); | ... | ... |
... | ... | @@ -0,0 +1,74 @@ |
1 | +#!/usr/bin/env python | |
2 | +# encoding: utf-8 | |
3 | + | |
4 | +from django.contrib.syndication.views import Feed | |
5 | +from django.utils.translation import ugettext as _ | |
6 | + | |
7 | +from colab.super_archives.models import Thread | |
8 | +from colab.super_archives import queries | |
9 | +from colab import solrutils | |
10 | + | |
11 | +class LatestThreadsFeeds(Feed): | |
12 | + title = _(u'Últimas Discussões') | |
13 | + link = '/rss/threads/latest/' | |
14 | + | |
15 | + def items(self): | |
16 | + return queries.get_latest_threads()[:20] | |
17 | + | |
18 | + def item_link(self, item): | |
19 | + return item.latest_message.url | |
20 | + | |
21 | + def item_title(self, item): | |
22 | + return item.latest_message.subject_clean | |
23 | + | |
24 | + def item_description(self, item): | |
25 | + return item.latest_message.body | |
26 | + | |
27 | + | |
28 | +class HottestThreadsFeeds(Feed): | |
29 | + title = _(u'Discussões Mais Relevantes') | |
30 | + link = '/rss/threads/hottest/' | |
31 | + | |
32 | + def items(self): | |
33 | + return queries.get_hottest_threads()[:20] | |
34 | + | |
35 | + def item_link(self, item): | |
36 | + return item.latest_message.url | |
37 | + | |
38 | + def item_title(self, item): | |
39 | + return item.latest_message.subject_clean | |
40 | + | |
41 | + def item_description(self, item): | |
42 | + return item.latest_message.body | |
43 | + | |
44 | + | |
45 | +class LatestColabFeeds(Feed): | |
46 | + title = _(u'Últimas Colaborações') | |
47 | + link = '/rss/colab/latest/' | |
48 | + | |
49 | + def items(self): | |
50 | + items = solrutils.get_latest_collaborations(20) | |
51 | + return items | |
52 | + | |
53 | + def item_title(self, item): | |
54 | + type_ = item.get('Type') + ': ' | |
55 | + mailinglist = item.get('mailinglist') | |
56 | + | |
57 | + if mailinglist: | |
58 | + prefix = type_ + mailinglist + ' - ' | |
59 | + else: | |
60 | + prefix = type_ | |
61 | + | |
62 | + return prefix + item.get('Title') | |
63 | + | |
64 | + def item_description(self, item): | |
65 | + return item.get('Description') | |
66 | + | |
67 | + def item_link(self, item): | |
68 | + if item.get('Type') != 'thread': | |
69 | + url = item.get('url') | |
70 | + else: | |
71 | + url = 'http://colab.interlegis.leg.br' | |
72 | + url += item.get('url') | |
73 | + return url | |
74 | + | ... | ... |
... | ... | @@ -0,0 +1,9 @@ |
1 | +from django.conf.urls.defaults import patterns, url | |
2 | +import feeds | |
3 | + | |
4 | +urlpatterns = patterns('', | |
5 | + url(r'threads/latest/$', feeds.LatestThreadsFeeds()), | |
6 | + url(r'colab/latest/$', feeds.LatestColabFeeds()), | |
7 | + url(r'threads/hottest/$', feeds.HottestThreadsFeeds()), | |
8 | +) | |
9 | + | ... | ... |
colab/settings.py
colab/settings_local-dev.py
... | ... | @@ -10,9 +10,15 @@ MANAGERS = ADMINS |
10 | 10 | DATABASES = { |
11 | 11 | 'default': { |
12 | 12 | 'ENGINE': 'django.db.backends.sqlite3', |
13 | - 'NAME': 'colab.db', | |
13 | + 'NAME': 'colab.db', | |
14 | 14 | } |
15 | 15 | } |
16 | 16 | |
17 | 17 | # Make this unique, and don't share it with anybody. |
18 | 18 | SECRET_KEY = ')(jksdfhsjkadfhjkh234ns!8fqu-1186h$vuj' |
19 | + | |
20 | +import socks | |
21 | +SOCKS_TYPE = socks.PROXY_TYPE_SOCKS5 | |
22 | +SOCKS_SERVER = '127.0.0.1' | |
23 | +SOCKS_PORT = 9050 | |
24 | + | ... | ... |
colab/signup.py
... | ... | @@ -4,8 +4,8 @@ |
4 | 4 | from django.conf import settings |
5 | 5 | from django.utils.html import strip_tags |
6 | 6 | from django.utils.translation import ugettext as _ |
7 | -from django.core.mail import EmailMultiAlternatives | |
8 | 7 | from django.template.loader import render_to_string |
8 | +from django.core.mail import EmailMultiAlternatives, send_mail | |
9 | 9 | |
10 | 10 | |
11 | 11 | def send_verification_email(request, user): |
... | ... | @@ -47,4 +47,15 @@ def send_reset_password_email(request, user): |
47 | 47 | email_msg.attach_alternative(html_content, 'text/html') |
48 | 48 | email_msg.send() |
49 | 49 | |
50 | - | |
51 | 50 | \ No newline at end of file |
51 | +def send_email_lists(user, mailing_lists): | |
52 | + subject = _(u'Inscrição na lista de discussão') | |
53 | + from_ = user.email | |
54 | + to = [] | |
55 | + for list_name in mailing_lists: | |
56 | + # TODO: The following line needs to be generic. Domain should be stored in settings file | |
57 | + # or database (perharps read directly from mailman). | |
58 | + subscribe_addr = list_name + '-subscribe@listas.interlegis.gov.br' | |
59 | + to.append(subscribe_addr) | |
60 | + | |
61 | + send_mail(subject, '', from_, to) | |
62 | + | ... | ... |
colab/solrutils.py
... | ... | @@ -178,7 +178,7 @@ def select(query, results_per_page=None, page_number=None, sort=None, fields=Non |
178 | 178 | if socks_server: |
179 | 179 | import socks |
180 | 180 | logging.debug('Socks enabled: %s:%s', settings.SOCKS_SERVER, |
181 | - settings.SOLR_PORT) | |
181 | + settings.SOCKS_PORT) | |
182 | 182 | |
183 | 183 | socks.setdefaultproxy(settings.SOCKS_TYPE, |
184 | 184 | settings.SOCKS_SERVER, | ... | ... |
colab/super_archives/forms.py
... | ... | @@ -5,6 +5,7 @@ from django.core.exceptions import ValidationError |
5 | 5 | from django.contrib.auth.models import User |
6 | 6 | from django.contrib.auth.forms import UserCreationForm as UserCreationForm_ |
7 | 7 | |
8 | +from colab.super_archives.models import MailingList | |
8 | 9 | from colab.super_archives.validators import UniqueValidator |
9 | 10 | |
10 | 11 | # XXX: I know that this code does not look nice AT ALL. |
... | ... | @@ -26,7 +27,20 @@ facebook_field = forms.URLField(label=u'Facebook', required=False) |
26 | 27 | google_talk_field = forms.EmailField(label=u'Google Talk', required=False) |
27 | 28 | webpage_field = forms.URLField(label=u'Página Pessoal/Blog', required=False) |
28 | 29 | |
29 | - | |
30 | +all_lists = MailingList.objects.all() | |
31 | +lists_names = [] | |
32 | +for list_ in all_lists: | |
33 | + choice = (list_.name, list_.name) | |
34 | + lists_names.append(choice) | |
35 | + | |
36 | +lists_field = forms.MultipleChoiceField( | |
37 | + label=u'Listas', | |
38 | + required=False, | |
39 | + widget=forms.CheckboxSelectMultiple, | |
40 | + choices=lists_names | |
41 | +) | |
42 | + | |
43 | + | |
30 | 44 | class UserCreationForm(UserCreationForm_): |
31 | 45 | first_name = first_name_field |
32 | 46 | last_name = last_name_field |
... | ... | @@ -37,8 +51,9 @@ class UserCreationForm(UserCreationForm_): |
37 | 51 | facebook = facebook_field |
38 | 52 | google_talk = google_talk_field |
39 | 53 | webpage = webpage_field |
54 | + lists = lists_field | |
40 | 55 | |
41 | - | |
56 | + | |
42 | 57 | class UserUpdateForm(forms.Form): |
43 | 58 | username = username_field |
44 | 59 | username.required = False | ... | ... |
colab/super_archives/migrations/0008_add_mailinglist_name_to_url.py
0 → 100644
... | ... | @@ -0,0 +1,142 @@ |
1 | +# encoding: utf-8 | |
2 | +import datetime | |
3 | +from south.db import db | |
4 | +from south.v2 import DataMigration | |
5 | +from django.db import models | |
6 | + | |
7 | +class Migration(DataMigration): | |
8 | + | |
9 | + def forwards(self, orm): | |
10 | + page_hits = orm.PageHit.objects.all() | |
11 | + for page_hit in page_hits: | |
12 | + if page_hit.url_path.startswith('/archives/thread/'): | |
13 | + token = page_hit.url_path.split('/')[-1] | |
14 | + threads = orm.Thread.objects.filter(subject_token=token) | |
15 | + if not len(threads): continue | |
16 | + thread = threads[0] | |
17 | + new_url = '/archives/thread/%s/%s' % (thread.mailinglist.name, | |
18 | + thread.subject_token) | |
19 | + page_hit.url_path = new_url | |
20 | + page_hit.save() | |
21 | + | |
22 | + | |
23 | + def backwards(self, orm): | |
24 | + raise RuntimeError("Cannot reverse this migration.") | |
25 | + | |
26 | + models = { | |
27 | + 'auth.group': { | |
28 | + 'Meta': {'object_name': 'Group'}, | |
29 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
30 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | |
31 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | |
32 | + }, | |
33 | + 'auth.permission': { | |
34 | + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, | |
35 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | |
36 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), | |
37 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
38 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | |
39 | + }, | |
40 | + 'auth.user': { | |
41 | + 'Meta': {'object_name': 'User'}, | |
42 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | |
43 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), | |
44 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | |
45 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), | |
46 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
47 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | |
48 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | |
49 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | |
50 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | |
51 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | |
52 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | |
53 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), | |
54 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) | |
55 | + }, | |
56 | + 'contenttypes.contenttype': { | |
57 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | |
58 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | |
59 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
60 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | |
61 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | |
62 | + }, | |
63 | + 'super_archives.emailaddress': { | |
64 | + 'Meta': {'object_name': 'EmailAddress'}, | |
65 | + 'address': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}), | |
66 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
67 | + 'md5': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}), | |
68 | + 'real_name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'blank': 'True'}), | |
69 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emails'", 'null': 'True', 'to': "orm['auth.User']"}) | |
70 | + }, | |
71 | + 'super_archives.mailinglist': { | |
72 | + 'Meta': {'object_name': 'MailingList'}, | |
73 | + 'description': ('django.db.models.fields.TextField', [], {}), | |
74 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), | |
75 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
76 | + 'last_imported_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | |
77 | + 'logo': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), | |
78 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}) | |
79 | + }, | |
80 | + 'super_archives.mailinglistmembership': { | |
81 | + 'Meta': {'object_name': 'MailingListMembership'}, | |
82 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
83 | + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}), | |
84 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) | |
85 | + }, | |
86 | + 'super_archives.message': { | |
87 | + 'Meta': {'object_name': 'Message'}, | |
88 | + 'body': ('django.db.models.fields.TextField', [], {'default': "''"}), | |
89 | + 'from_address': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.EmailAddress']"}), | |
90 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
91 | + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}), | |
92 | + 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}), | |
93 | + 'received_time': ('django.db.models.fields.DateTimeField', [], {}), | |
94 | + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | |
95 | + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}), | |
96 | + 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}), | |
97 | + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'}) | |
98 | + }, | |
99 | + 'super_archives.messagemetadata': { | |
100 | + 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}), | |
101 | + 'Meta': {'object_name': 'MessageMetadata'}, | |
102 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
103 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}), | |
104 | + 'value': ('django.db.models.fields.TextField', [], {}) | |
105 | + }, | |
106 | + 'super_archives.pagehit': { | |
107 | + 'Meta': {'object_name': 'PageHit'}, | |
108 | + 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | |
109 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
110 | + 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'}) | |
111 | + }, | |
112 | + 'super_archives.thread': { | |
113 | + 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'}, | |
114 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
115 | + 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}), | |
116 | + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}), | |
117 | + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | |
118 | + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | |
119 | + 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'}) | |
120 | + }, | |
121 | + 'super_archives.userprofile': { | |
122 | + 'Meta': {'object_name': 'UserProfile'}, | |
123 | + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), | |
124 | + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}), | |
125 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
126 | + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), | |
127 | + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), | |
128 | + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), | |
129 | + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}), | |
130 | + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}), | |
131 | + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'}) | |
132 | + }, | |
133 | + 'super_archives.vote': { | |
134 | + 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'}, | |
135 | + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), | |
136 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |
137 | + 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}), | |
138 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) | |
139 | + } | |
140 | + } | |
141 | + | |
142 | + complete_apps = ['super_archives'] | ... | ... |
colab/super_archives/models.py
... | ... | @@ -148,7 +148,8 @@ class Thread(models.Model): |
148 | 148 | |
149 | 149 | # Calculate page_view_score |
150 | 150 | try: |
151 | - url = reverse('thread_view', args=[self.subject_token]) | |
151 | + url = reverse('thread_view', args=[self.mailinglist.name, | |
152 | + self.subject_token]) | |
152 | 153 | pagehit = PageHit.objects.get(url_path=url) |
153 | 154 | page_view_score = pagehit.hit_count * 10 |
154 | 155 | except (NoReverseMatch, PageHit.DoesNotExist): |
... | ... | @@ -217,7 +218,8 @@ class Message(models.Model): |
217 | 218 | @property |
218 | 219 | def url(self): |
219 | 220 | """Shortcut to get thread url""" |
220 | - return reverse('thread_view', args=[self.thread.subject_token]) | |
221 | + return reverse('thread_view', args=[self.mailinglist.name, | |
222 | + self.thread.subject_token]) | |
221 | 223 | |
222 | 224 | @property |
223 | 225 | def Description(self): | ... | ... |
colab/super_archives/queries.py
... | ... | @@ -26,15 +26,18 @@ def get_messages_by_voted(): |
26 | 26 | return messages.order_by('-vote_count', 'received_time') |
27 | 27 | |
28 | 28 | |
29 | -def get_first_message_in_thread(thread_token): | |
30 | - return get_messages_by_date().filter(thread__subject_token=thread_token)[0] | |
31 | - | |
29 | +def get_first_message_in_thread(mailinglist, thread_token): | |
30 | + query = get_messages_by_date() | |
31 | + query = query.filter(mailinglist__name=mailinglist) | |
32 | + query = query.filter(thread__subject_token=thread_token)[0] | |
33 | + return query | |
34 | + | |
32 | 35 | |
33 | 36 | def get_latest_threads(): |
34 | 37 | return Thread.objects.order_by('-latest_message__received_time') |
35 | 38 | |
36 | 39 | |
37 | -def get_hotest_threads(): | |
40 | +def get_hottest_threads(): | |
38 | 41 | return Thread.objects.order_by('-score', '-latest_message__received_time') |
39 | 42 | |
40 | 43 | ... | ... |
colab/super_archives/templates/message-list.html
... | ... | @@ -11,8 +11,8 @@ |
11 | 11 | |
12 | 12 | <h4>Ordenar por</h4> |
13 | 13 | <ul> |
14 | - <li {% ifequal order_by "hotest" %} class="selected" title="{% trans "Retirar filtro" %}" {% endifequal %}> | |
15 | - <a href="{% ifequal order_by "hotest" %} {% append_to_get order="",p=1 %} {% else %} {% append_to_get order='hotest',p=1 %} {% endifequal %}"> | |
14 | + <li {% ifequal order_by "hottest" %} class="selected" title="{% trans "Retirar filtro" %}" {% endifequal %}> | |
15 | + <a href="{% ifequal order_by "hottest" %} {% append_to_get order="",p=1 %} {% else %} {% append_to_get order='hottest',p=1 %} {% endifequal %}"> | |
16 | 16 | Relevância</a></li> |
17 | 17 | <li {% ifequal order_by "latest" %} class="selected" title="{% trans "Retirar filtro" %}" {% endifequal %}> |
18 | 18 | <a href="{% ifequal order_by "latest" %} {% append_to_get order="",p=1 %} {% else %} {% append_to_get order='latest',p=1 %} {% endifequal %}"> | ... | ... |
colab/super_archives/templatetags/append_to_get.py
... | ... | @@ -37,7 +37,16 @@ class AppendGetNode(template.Node): |
37 | 37 | path = context['request'].META['PATH_INFO'] |
38 | 38 | |
39 | 39 | if len(get): |
40 | - path = '?' + urllib.urlencode(get) | |
40 | + # Convert all unicode objects in the get dict to | |
41 | + # str (utf-8 encoded) | |
42 | + get_utf_encoded = {} | |
43 | + for (key, value) in get.items(): | |
44 | + if isinstance(value, unicode): | |
45 | + value = value.encode('utf-8') | |
46 | + get_utf_encoded.update({key: value}) | |
47 | + get_utf_encoded = dict(get_utf_encoded) | |
48 | + | |
49 | + path = '?' + urllib.urlencode(get_utf_encoded) | |
41 | 50 | |
42 | 51 | return path |
43 | 52 | ... | ... |
colab/super_archives/templatetags/form_field.py
... | ... | @@ -24,40 +24,41 @@ class RenderFormField(template.Node): |
24 | 24 | def render(self, context): |
25 | 25 | editable = context.get('editable', True) |
26 | 26 | |
27 | - class_ = '' | |
28 | - errors = '' | |
29 | - form_field_tag = '' | |
27 | + class_ = u'' | |
28 | + errors = u'' | |
29 | + form_field_tag = u'' | |
30 | 30 | try: |
31 | 31 | form_field = self.form_field_nocontext.resolve(context) |
32 | 32 | except template.VariableDoesNotExist: |
33 | - return '' | |
33 | + return u'' | |
34 | 34 | |
35 | 35 | if form_field.errors: |
36 | - class_ += 'error' | |
36 | + class_ += u'error' | |
37 | 37 | if form_field.field.required: |
38 | - class_ += ' required' | |
38 | + class_ += u' required' | |
39 | 39 | if form_field.errors: |
40 | - errors = '<br/>' + form_field.errors.as_text() | |
40 | + errors = u'<br/>' + form_field.errors.as_text() | |
41 | 41 | |
42 | 42 | try: |
43 | 43 | default_value = self.default_value_nocontext.resolve(context) |
44 | 44 | except template.VariableDoesNotExist: |
45 | - default_value = '' | |
45 | + default_value = u'' | |
46 | 46 | |
47 | 47 | if editable: |
48 | - form_field_tag = '<br/>' + str(form_field) | |
48 | + form_field_tag = u'<br/>' + unicode(form_field) | |
49 | 49 | elif isinstance(form_field.field, forms.URLField): |
50 | - form_field_tag = """<a href="%s" target="_blank">%s</a>""" % ( | |
50 | + form_field_tag = u"""<a href="%s" target="_blank">%s</a>""" % ( | |
51 | 51 | default_value, default_value) |
52 | 52 | else: |
53 | 53 | form_field_tag = default_value |
54 | 54 | |
55 | - return """<p class="%s">%s: %s %s</p>""" % ( | |
55 | + return u"""<p class="%s">%s: %s %s</p>""" % ( | |
56 | 56 | class_, |
57 | 57 | form_field.label_tag(), |
58 | 58 | form_field_tag, |
59 | 59 | errors |
60 | 60 | ) |
61 | - | |
61 | + | |
62 | + | |
62 | 63 | register = template.Library() |
63 | 64 | register.tag('render_form_field', render_form_field) | ... | ... |
colab/super_archives/urls.py
... | ... | @@ -2,7 +2,7 @@ from django.conf.urls.defaults import patterns, include, url |
2 | 2 | |
3 | 3 | urlpatterns = patterns('', |
4 | 4 | # url(r'thread/(?P<thread>\d+)/$', 'super_archives.views.thread', name='thread'), |
5 | - url(r'thread/(?P<thread_token>[-\w]+)$', | |
5 | + url(r'thread/(?P<mailinglist>[-\w]+)/(?P<thread_token>[-\w]+)$', | |
6 | 6 | 'colab.super_archives.views.thread', name="thread_view"), |
7 | 7 | url(r'thread/$', |
8 | 8 | 'colab.super_archives.views.list_messages', name='thread_list') | ... | ... |
colab/super_archives/views.py
... | ... | @@ -8,9 +8,9 @@ from colab.super_archives import queries |
8 | 8 | from colab.super_archives.models import MailingList, Thread |
9 | 9 | |
10 | 10 | |
11 | -def thread(request, thread_token): | |
11 | +def thread(request, mailinglist, thread_token): | |
12 | 12 | |
13 | - first_message = queries.get_first_message_in_thread(thread_token) | |
13 | + first_message = queries.get_first_message_in_thread(mailinglist, thread_token) | |
14 | 14 | order_by = request.GET.get('order') |
15 | 15 | if order_by == 'voted': |
16 | 16 | msgs_query = queries.get_messages_by_voted() |
... | ... | @@ -18,6 +18,7 @@ def thread(request, thread_token): |
18 | 18 | msgs_query = queries.get_messages_by_date() |
19 | 19 | |
20 | 20 | msgs_query = msgs_query.filter(thread__subject_token=thread_token) |
21 | + msgs_query = msgs_query.filter(mailinglist__name=mailinglist) | |
21 | 22 | emails = msgs_query.exclude(id=first_message.id) |
22 | 23 | |
23 | 24 | total_votes = first_message.votes_count() |
... | ... | @@ -25,7 +26,8 @@ def thread(request, thread_token): |
25 | 26 | total_votes += email.votes_count() |
26 | 27 | |
27 | 28 | # Update relevance score |
28 | - thread = Thread.objects.get(subject_token=thread_token) | |
29 | + query = Thread.objects.filter(mailinglist__name=mailinglist) | |
30 | + thread = query.get(subject_token=thread_token) | |
29 | 31 | thread.update_score() |
30 | 32 | |
31 | 33 | template_data = { |
... | ... | @@ -44,8 +46,8 @@ def list_messages(request): |
44 | 46 | selected_list = request.GET.get('list') |
45 | 47 | |
46 | 48 | order_by = request.GET.get('order') |
47 | - if order_by == 'hotest': | |
48 | - threads = queries.get_hotest_threads() | |
49 | + if order_by == 'hottest': | |
50 | + threads = queries.get_hottest_threads() | |
49 | 51 | else: |
50 | 52 | threads = queries.get_latest_threads() |
51 | 53 | ... | ... |
colab/templates/home.html
... | ... | @@ -18,7 +18,7 @@ |
18 | 18 | {% block main-content %} |
19 | 19 | |
20 | 20 | <div class="span-12 colborder"> |
21 | - <h3>{% trans "Últimas Colaborações:" %}</h3> | |
21 | + <h3>{% trans "Últimas Colaborações" %}</h3> | |
22 | 22 | <ul> |
23 | 23 | {% for doc in latest_docs %} |
24 | 24 | {% include "message-preview.html" %} |
... | ... | @@ -31,7 +31,7 @@ |
31 | 31 | </div> |
32 | 32 | |
33 | 33 | <div class="span-11 last"> |
34 | - <h3>{% trans "Distribuição das Colaborações:" %}</h3> | |
34 | + <h3>{% trans "Distribuição das Colaborações" %}</h3> | |
35 | 35 | <div id="collabs"></div> |
36 | 36 | </div> |
37 | 37 | |
... | ... | @@ -39,20 +39,20 @@ |
39 | 39 | <hr/> |
40 | 40 | |
41 | 41 | <div class="span-12 colborder"> |
42 | - <h3>{% trans "Discussões Mais Relevantes:" %}</h3> | |
42 | + <h3>{% trans "Discussões Mais Relevantes" %}</h3> | |
43 | 43 | <ul> |
44 | - {% for thread in hotest_threads %} | |
44 | + {% for thread in hottest_threads %} | |
45 | 45 | {% include "message-preview.html" with doc=thread.latest_message %} |
46 | 46 | {% endfor %} |
47 | 47 | </ul> |
48 | 48 | <hr class="space"/> |
49 | - <a class="right" href="{% url thread_list %}?order=hotest"> | |
49 | + <a class="right" href="{% url thread_list %}?order=hottest"> | |
50 | 50 | {% trans "Ver mais discussões relevantes..." %} |
51 | 51 | </a> |
52 | 52 | </div> |
53 | 53 | |
54 | 54 | <div class="span-11 last"> |
55 | - <h3>{% trans "Últimas Discussões:" %}</h3> | |
55 | + <h3>{% trans "Últimas Discussões" %}</h3> | |
56 | 56 | <ul> |
57 | 57 | {% for thread in latest_threads %} |
58 | 58 | {% include "message-preview.html" with doc=thread.latest_message %} | ... | ... |
colab/templates/signup-form.html
... | ... | @@ -54,7 +54,12 @@ |
54 | 54 | {% render_form_field form.google_talk %} |
55 | 55 | {% render_form_field form.webpage %} |
56 | 56 | </fieldset> |
57 | - | |
57 | + | |
58 | + <fieldset class="box span-11"> | |
59 | + <legend>Inscrever-se nas Listas</legend> | |
60 | + {% render_form_field form.lists %} | |
61 | + </fieldset> | |
62 | + | |
58 | 63 | <div class="span-24"> |
59 | 64 | <input class="right" type="submit" value="Cadastrar"/> |
60 | 65 | </div> | ... | ... |
colab/templates/user-profile.html
... | ... | @@ -9,20 +9,20 @@ |
9 | 9 | {% block main-content %} |
10 | 10 | {% if not user_profile %} |
11 | 11 | <span class="notice span-24"> |
12 | - <b>Usuário não cadastrado.</b> Você é dono deste perfil? | |
12 | + <b>Usuário não cadastrado.</b> Você é dono deste perfil? | |
13 | 13 | <a href="{% url signup %}">Clique aqui |
14 | 14 | e cadastre-se.</a> |
15 | 15 | </span> |
16 | 16 | |
17 | - {% else %} | |
18 | - | |
17 | + {% else %} | |
18 | + | |
19 | 19 | {% ifequal request.user.username user_profile.user.username %} |
20 | 20 | <span class="success span-24"> |
21 | - Ei, olha você aqui! Quer | |
21 | + Ei, olha você aqui! Quer | |
22 | 22 | <a href="{% url user_profile_update request.user %}">editar seu perfil</a>? |
23 | 23 | </span> |
24 | 24 | {% endifequal %} |
25 | - | |
25 | + | |
26 | 26 | {% endif %} |
27 | 27 | |
28 | 28 | <div id="user-profile"> |
... | ... | @@ -32,12 +32,12 @@ |
32 | 32 | <img class="avatar" width="120px" heigth="120px" |
33 | 33 | src="http://www.gravatar.com/avatar/{{ email_address.md5 }}?s=120&d=identicon" /> |
34 | 34 | </div> |
35 | - | |
35 | + | |
36 | 36 | <div class="span-20 last"> |
37 | 37 | <div class="span-10"> |
38 | 38 | <form action="{% url user_profile_update request.user %}" method='post'> |
39 | 39 | {% csrf_token %} |
40 | - | |
40 | + | |
41 | 41 | <h3>Informações Pessoais</h3> |
42 | 42 | <ul id="user-info"> |
43 | 43 | <li> |
... | ... | @@ -53,9 +53,9 @@ |
53 | 53 | {% render_form_field form.role user_profile.role %} |
54 | 54 | </li> |
55 | 55 | </ul> |
56 | - | |
56 | + | |
57 | 57 | <hr class="space" /> |
58 | - | |
58 | + | |
59 | 59 | <h3>Outras Informações</h3> |
60 | 60 | <ul> |
61 | 61 | <li> |
... | ... | @@ -71,7 +71,7 @@ |
71 | 71 | {% render_form_field form.webpage user_profile.webpage %} |
72 | 72 | </li> |
73 | 73 | </ul> |
74 | - | |
74 | + | |
75 | 75 | <hr class="space"/> |
76 | 76 | {% if editable %} |
77 | 77 | <span class="span-5"> |
... | ... | @@ -80,30 +80,30 @@ |
80 | 80 | {% endif %} |
81 | 81 | </form> |
82 | 82 | </div> |
83 | - | |
83 | + | |
84 | 84 | {% if type_count %} |
85 | 85 | <div class="span-10 last"> |
86 | - <h3 class="center">{% trans "Colaborações por área" %}</h3> | |
86 | + <h3 class="center">{% trans "Colaborações por Área" %}</h3> | |
87 | 87 | <div id="collabs"></div> |
88 | 88 | </div> |
89 | 89 | {% endif %} |
90 | 90 | </div> |
91 | - | |
91 | + | |
92 | 92 | <hr class="space" /> |
93 | - | |
93 | + | |
94 | 94 | <div class="span-13"> |
95 | - <h3>{% trans "Últimas mensagens enviadas" %} </h3> | |
95 | + <h3>{% trans "Últimas Mensagens Enviadas" %} </h3> | |
96 | 96 | <ul class="colborder"> |
97 | 97 | {% for doc in emails %} |
98 | 98 | {% include "message-preview.html" %} |
99 | 99 | {% empty %} |
100 | 100 | <li>Não existem mensagens enviadas por este usuário até o momento.</li> |
101 | - {% endfor %} | |
101 | + {% endfor %} | |
102 | 102 | </ul> |
103 | 103 | </div> |
104 | - | |
104 | + | |
105 | 105 | <div class="span-11 last"> |
106 | - <h3>{% trans "Participações na comunidade:" %}</h3> | |
106 | + <h3>{% trans "Participações na Comunidade" %}</h3> | |
107 | 107 | <ul> |
108 | 108 | {% for doc in docs %} |
109 | 109 | {% include "message-preview.html" %} |
... | ... | @@ -112,6 +112,6 @@ |
112 | 112 | {% endfor %} |
113 | 113 | </ul> |
114 | 114 | </div> |
115 | - | |
115 | + | |
116 | 116 | </div> |
117 | 117 | {% endblock %} | ... | ... |
colab/urls.py
... | ... | @@ -10,6 +10,8 @@ urlpatterns = patterns('', |
10 | 10 | url(r'^archives/', include('colab.super_archives.urls')), |
11 | 11 | |
12 | 12 | url(r'^api/', include('colab.api.urls')), |
13 | + | |
14 | + url(r'^rss/', include('colab.rss.urls')), | |
13 | 15 | |
14 | 16 | url(r'^user/(?P<username>[\w@+.-]+)/?$', |
15 | 17 | 'colab.views.userprofile.by_username', name='user_profile'), |
... | ... | @@ -45,7 +47,7 @@ urlpatterns = patterns('', |
45 | 47 | |
46 | 48 | url(r'^account/logout/$', 'django.contrib.auth.views.logout', |
47 | 49 | {'next_page': '/'}, name='logout'), |
48 | - | |
50 | + | |
49 | 51 | # Uncomment the next line to enable the admin: |
50 | 52 | url(r'^colab/admin/', include(admin.site.urls)), |
51 | 53 | ) | ... | ... |
colab/views/other.py
... | ... | @@ -18,10 +18,10 @@ def home(request): |
18 | 18 | """Index page view""" |
19 | 19 | |
20 | 20 | latest_threads = queries.get_latest_threads() |
21 | - hotest_threads = queries.get_hotest_threads() | |
21 | + hottest_threads = queries.get_hottest_threads() | |
22 | 22 | |
23 | 23 | template_data = { |
24 | - 'hotest_threads': hotest_threads[:6], | |
24 | + 'hottest_threads': hottest_threads[:6], | |
25 | 25 | 'latest_threads': latest_threads[:6], |
26 | 26 | 'type_count': solrutils.count_types(sample=1000), |
27 | 27 | 'latest_docs': solrutils.get_latest_collaborations(6), | ... | ... |
colab/views/signup.py
... | ... | @@ -60,6 +60,11 @@ def signup(request): |
60 | 60 | |
61 | 61 | signup_.send_verification_email(request, user) |
62 | 62 | |
63 | + mailing_lists = form.cleaned_data.get('lists') | |
64 | + if mailing_lists: | |
65 | + signup_.send_email_lists(user, mailing_lists) | |
66 | + | |
67 | + | |
63 | 68 | # Check if the user's email have been used previously |
64 | 69 | # in the mainling lists to link the user to old messages |
65 | 70 | email_addr, created = EmailAddress.objects.get_or_create(address=user.email) | ... | ... |
solr-conf/data-config.xml
... | ... | @@ -321,7 +321,8 @@ |
321 | 321 | <field column="UID" template="THREAD_${thread.id}" /> |
322 | 322 | <field column="getId" template="${thread.name}" /> |
323 | 323 | <field column="Type" template="thread" /> |
324 | - <field column="path_string" template="/archives/thread/${thread.name}" /> | |
324 | + <field column="path_string" | |
325 | + template="/archives/thread/${thread.mailinglist}/${thread.name}" /> | |
325 | 326 | <field column="created" name="created" |
326 | 327 | dateTimeFormat="yyyy-MM-dd hh:mm:ss" /> |
327 | 328 | <field column="modified" name="modified" | ... | ... |