Commit beb38b3b52b555759c4bbc4757e983e0113eafa0
1 parent
ca702a62
Exists in
master
and in
39 other branches
Fazendo merge com https://bitbucket.org/seocam/atu-colab/src/f70c46c4b63d
git-svn-id: http://repositorio.interlegis.gov.br/colab/trunk@6215 bee1b3ed-c3eb-0310-9994-b88e04532788
Showing
17 changed files
with
291 additions
and
19 deletions
Show diff stats
colab/api/handlers.py
| @@ -7,6 +7,7 @@ from django.contrib.auth.decorators import login_required | @@ -7,6 +7,7 @@ from django.contrib.auth.decorators import login_required | ||
| 7 | from piston.utils import rc | 7 | from piston.utils import rc |
| 8 | from piston.handler import BaseHandler | 8 | from piston.handler import BaseHandler |
| 9 | 9 | ||
| 10 | +from colab import solrutils | ||
| 10 | from colab.super_archives.models import Message, PageHit | 11 | from colab.super_archives.models import Message, PageHit |
| 11 | 12 | ||
| 12 | 13 | ||
| @@ -69,3 +70,34 @@ class CountHandler(BaseHandler): | @@ -69,3 +70,34 @@ class CountHandler(BaseHandler): | ||
| 69 | 70 | ||
| 70 | return rc.CREATED | 71 | return rc.CREATED |
| 71 | 72 | ||
| 73 | +class SearchHandler(BaseHandler): | ||
| 74 | + allowed_methods = ('GET', ) | ||
| 75 | + | ||
| 76 | + def read(self, request): | ||
| 77 | + query = request.GET.get('q') | ||
| 78 | + page = request.GET.get('p', 1) | ||
| 79 | + results_per_page = request.GET.get('n', 50) | ||
| 80 | + order = request.GET.get('o') | ||
| 81 | + | ||
| 82 | + if not query: | ||
| 83 | + return 'Query cannot be empty.' | ||
| 84 | + else: | ||
| 85 | + query = query.encode('utf-8') | ||
| 86 | + | ||
| 87 | + try: | ||
| 88 | + n = int(results_per_page) | ||
| 89 | + except ValueError: | ||
| 90 | + n = 10 | ||
| 91 | + | ||
| 92 | + if 1 > n > 500: | ||
| 93 | + n = 1 | ||
| 94 | + | ||
| 95 | + try: | ||
| 96 | + page = int(page) | ||
| 97 | + except ValueError: | ||
| 98 | + page = 1 | ||
| 99 | + | ||
| 100 | + if page < 1: | ||
| 101 | + page = 1 | ||
| 102 | + | ||
| 103 | + return solrutils.select(query, results_per_page, page, order) |
colab/api/urls.py
| @@ -2,13 +2,15 @@ from django.conf.urls.defaults import patterns, include, url | @@ -2,13 +2,15 @@ from django.conf.urls.defaults import patterns, include, url | ||
| 2 | 2 | ||
| 3 | from piston.resource import Resource | 3 | from piston.resource import Resource |
| 4 | 4 | ||
| 5 | -from colab.api.handlers import VoteHandler, CountHandler | 5 | +from colab.api.handlers import VoteHandler, CountHandler, SearchHandler |
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | vote_handler = Resource(VoteHandler) | 8 | vote_handler = Resource(VoteHandler) |
| 9 | count_handler = Resource(CountHandler) | 9 | count_handler = Resource(CountHandler) |
| 10 | +search_handler = Resource(SearchHandler) | ||
| 10 | 11 | ||
| 11 | urlpatterns = patterns('', | 12 | urlpatterns = patterns('', |
| 12 | url(r'message/(?P<message_id>\d+)/vote$', vote_handler), | 13 | url(r'message/(?P<message_id>\d+)/vote$', vote_handler), |
| 13 | url(r'hit/$', count_handler), | 14 | url(r'hit/$', count_handler), |
| 14 | -) | ||
| 15 | \ No newline at end of file | 15 | \ No newline at end of file |
| 16 | + url(r'search/$', search_handler), | ||
| 17 | +) |
colab/settings.py
| @@ -153,7 +153,7 @@ SOLR_HOSTNAME = '10.1.2.154' | @@ -153,7 +153,7 @@ SOLR_HOSTNAME = '10.1.2.154' | ||
| 153 | SOLR_PORT = '8080' | 153 | SOLR_PORT = '8080' |
| 154 | SOLR_SELECT_PATH = '/solr/select' | 154 | SOLR_SELECT_PATH = '/solr/select' |
| 155 | 155 | ||
| 156 | -SOLR_COLAB_URI = 'http://colab.interlegis.gov.br' | 156 | +SOLR_COLAB_URI = 'http://colab.interlegis.leg.br' |
| 157 | SOLR_BASE_QUERY = """ | 157 | SOLR_BASE_QUERY = """ |
| 158 | ((Type:changeset OR Type:ticket OR Type:wiki OR Type:thread) AND Title:["" TO *]) | 158 | ((Type:changeset OR Type:ticket OR Type:wiki OR Type:thread) AND Title:["" TO *]) |
| 159 | """ | 159 | """ |
colab/settings_local-dev.py
| @@ -14,11 +14,13 @@ DATABASES = { | @@ -14,11 +14,13 @@ DATABASES = { | ||
| 14 | } | 14 | } |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | +SOLR_COLAB_URI = None | ||
| 18 | + | ||
| 17 | # Make this unique, and don't share it with anybody. | 19 | # Make this unique, and don't share it with anybody. |
| 18 | SECRET_KEY = ')(jksdfhsjkadfhjkh234ns!8fqu-1186h$vuj' | 20 | SECRET_KEY = ')(jksdfhsjkadfhjkh234ns!8fqu-1186h$vuj' |
| 19 | 21 | ||
| 20 | -import socks | ||
| 21 | -SOCKS_TYPE = socks.PROXY_TYPE_SOCKS5 | ||
| 22 | -SOCKS_SERVER = '127.0.0.1' | ||
| 23 | -SOCKS_PORT = 9050 | 22 | +#import socks |
| 23 | +#SOCKS_TYPE = socks.PROXY_TYPE_SOCKS5 | ||
| 24 | +#SOCKS_SERVER = '127.0.0.1' | ||
| 25 | +#SOCKS_PORT = 9050 | ||
| 24 | 26 |
colab/solrutils.py
| @@ -61,7 +61,7 @@ def get_document_url(doc): | @@ -61,7 +61,7 @@ def get_document_url(doc): | ||
| 61 | doc_type = doc.get('Type') | 61 | doc_type = doc.get('Type') |
| 62 | 62 | ||
| 63 | url = '' | 63 | url = '' |
| 64 | - if doc_type in ('ticket', 'wiki', 'changeset'): | 64 | + if settings.SOLR_COLAB_URI: |
| 65 | url += settings.SOLR_COLAB_URI | 65 | url += settings.SOLR_COLAB_URI |
| 66 | 66 | ||
| 67 | url += doc.get('path_string', '') | 67 | url += doc.get('path_string', '') |
296 Bytes
colab/super_archives/admin.py
| @@ -3,7 +3,7 @@ from django.contrib import admin | @@ -3,7 +3,7 @@ from django.contrib import admin | ||
| 3 | from colab.super_archives.models import Message, Thread, UserProfile | 3 | from colab.super_archives.models import Message, Thread, UserProfile |
| 4 | 4 | ||
| 5 | class MessageAdmin(admin.ModelAdmin): | 5 | class MessageAdmin(admin.ModelAdmin): |
| 6 | - list_filter = ('spam', 'mailinglist', 'received_time', ) | 6 | + list_filter = ('spam', 'thread__mailinglist', 'received_time', ) |
| 7 | search_fields = ( | 7 | search_fields = ( |
| 8 | 'id', | 8 | 'id', |
| 9 | 'subject', | 9 | 'subject', |
colab/super_archives/management/commands/import_emails.py
| @@ -130,14 +130,14 @@ class Command(BaseCommand, object): | @@ -130,14 +130,14 @@ class Command(BaseCommand, object): | ||
| 130 | for index, msg in self.parse_emails(mbox_path, n_msgs): | 130 | for index, msg in self.parse_emails(mbox_path, n_msgs): |
| 131 | yield mailinglist_name, msg, index | 131 | yield mailinglist_name, msg, index |
| 132 | 132 | ||
| 133 | - def get_thread(self, email): | 133 | + def get_thread(self, email, mailinglist): |
| 134 | """Group messages by thread looking for similar subjects""" | 134 | """Group messages by thread looking for similar subjects""" |
| 135 | 135 | ||
| 136 | subject_slug = slugify(email.subject_clean) | 136 | subject_slug = slugify(email.subject_clean) |
| 137 | thread = self.THREAD_CACHE.get(subject_slug) | 137 | thread = self.THREAD_CACHE.get(subject_slug) |
| 138 | if thread is None: | 138 | if thread is None: |
| 139 | thread = Thread.objects.get_or_create( | 139 | thread = Thread.objects.get_or_create( |
| 140 | - mailinglist=email.mailinglist, | 140 | + mailinglist=mailinglist, |
| 141 | subject_token=subject_slug | 141 | subject_token=subject_slug |
| 142 | )[0] | 142 | )[0] |
| 143 | 143 | ||
| @@ -156,7 +156,10 @@ class Command(BaseCommand, object): | @@ -156,7 +156,10 @@ class Command(BaseCommand, object): | ||
| 156 | 156 | ||
| 157 | try: | 157 | try: |
| 158 | # If the message is already at the database don't do anything | 158 | # If the message is already at the database don't do anything |
| 159 | - Message.objects.get(message_id=email_msg.get('Message-ID')) | 159 | + message = Message.objects.get( |
| 160 | + message_id=email_msg.get('Message-ID')) | ||
| 161 | + if message.thread.mailinglist.name != mailinglist.name: | ||
| 162 | + raise ObjectDoesNotExist | ||
| 160 | except ObjectDoesNotExist: | 163 | except ObjectDoesNotExist: |
| 161 | self.create_email(mailinglist, email_msg) | 164 | self.create_email(mailinglist, email_msg) |
| 162 | 165 | ||
| @@ -181,13 +184,12 @@ class Command(BaseCommand, object): | @@ -181,13 +184,12 @@ class Command(BaseCommand, object): | ||
| 181 | email = Message.objects.create( | 184 | email = Message.objects.create( |
| 182 | message_id=email_msg.get('Message-ID'), | 185 | message_id=email_msg.get('Message-ID'), |
| 183 | from_address=email_addr, | 186 | from_address=email_addr, |
| 184 | - mailinglist=mailinglist, | ||
| 185 | subject=subject, | 187 | subject=subject, |
| 186 | subject_clean=self.RE_SUBJECT_CLEAN.sub('', subject).strip(), | 188 | subject_clean=self.RE_SUBJECT_CLEAN.sub('', subject).strip(), |
| 187 | body=email_msg.get_body(), | 189 | body=email_msg.get_body(), |
| 188 | received_time=email_msg.get_received_datetime(), | 190 | received_time=email_msg.get_received_datetime(), |
| 189 | ) | 191 | ) |
| 190 | - email.thread = self.get_thread(email) | 192 | + email.thread = self.get_thread(email, mailinglist) |
| 191 | email.save() | 193 | email.save() |
| 192 | 194 | ||
| 193 | @transaction.commit_manually | 195 | @transaction.commit_manually |
| @@ -245,4 +247,4 @@ class Command(BaseCommand, object): | @@ -245,4 +247,4 @@ class Command(BaseCommand, object): | ||
| 245 | options.get('all'), options.get('exclude_lists')) | 247 | options.get('all'), options.get('exclude_lists')) |
| 246 | 248 | ||
| 247 | os.remove(lock_file) | 249 | os.remove(lock_file) |
| 248 | - | ||
| 249 | \ No newline at end of file | 250 | \ No newline at end of file |
| 251 | + |
colab/super_archives/migrations/0009_auto__del_field_message_mailinglist.py
0 → 100644
| @@ -0,0 +1,136 @@ | @@ -0,0 +1,136 @@ | ||
| 1 | +# encoding: utf-8 | ||
| 2 | +import datetime | ||
| 3 | +from south.db import db | ||
| 4 | +from south.v2 import SchemaMigration | ||
| 5 | +from django.db import models | ||
| 6 | + | ||
| 7 | +class Migration(SchemaMigration): | ||
| 8 | + | ||
| 9 | + def forwards(self, orm): | ||
| 10 | + | ||
| 11 | + # Deleting field 'Message.mailinglist' | ||
| 12 | + db.delete_column('super_archives_message', 'mailinglist_id') | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + def backwards(self, orm): | ||
| 16 | + | ||
| 17 | + # User chose to not deal with backwards NULL issues for 'Message.mailinglist' | ||
| 18 | + raise RuntimeError("Cannot reverse this migration. 'Message.mailinglist' and its values cannot be restored.") | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + models = { | ||
| 22 | + 'auth.group': { | ||
| 23 | + 'Meta': {'object_name': 'Group'}, | ||
| 24 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 25 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
| 26 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
| 27 | + }, | ||
| 28 | + 'auth.permission': { | ||
| 29 | + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, | ||
| 30 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
| 31 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), | ||
| 32 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 33 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
| 34 | + }, | ||
| 35 | + 'auth.user': { | ||
| 36 | + 'Meta': {'object_name': 'User'}, | ||
| 37 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
| 38 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), | ||
| 39 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
| 40 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), | ||
| 41 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 42 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
| 43 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
| 44 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
| 45 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
| 46 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
| 47 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
| 48 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), | ||
| 49 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) | ||
| 50 | + }, | ||
| 51 | + 'contenttypes.contenttype': { | ||
| 52 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
| 53 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
| 54 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 55 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
| 56 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
| 57 | + }, | ||
| 58 | + 'super_archives.emailaddress': { | ||
| 59 | + 'Meta': {'object_name': 'EmailAddress'}, | ||
| 60 | + 'address': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}), | ||
| 61 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 62 | + 'md5': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}), | ||
| 63 | + 'real_name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'blank': 'True'}), | ||
| 64 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emails'", 'null': 'True', 'to': "orm['auth.User']"}) | ||
| 65 | + }, | ||
| 66 | + 'super_archives.mailinglist': { | ||
| 67 | + 'Meta': {'object_name': 'MailingList'}, | ||
| 68 | + 'description': ('django.db.models.fields.TextField', [], {}), | ||
| 69 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), | ||
| 70 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 71 | + 'last_imported_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
| 72 | + 'logo': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), | ||
| 73 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}) | ||
| 74 | + }, | ||
| 75 | + 'super_archives.mailinglistmembership': { | ||
| 76 | + 'Meta': {'object_name': 'MailingListMembership'}, | ||
| 77 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 78 | + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}), | ||
| 79 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) | ||
| 80 | + }, | ||
| 81 | + 'super_archives.message': { | ||
| 82 | + 'Meta': {'object_name': 'Message'}, | ||
| 83 | + 'body': ('django.db.models.fields.TextField', [], {'default': "''"}), | ||
| 84 | + 'from_address': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.EmailAddress']"}), | ||
| 85 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 86 | + 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}), | ||
| 87 | + 'received_time': ('django.db.models.fields.DateTimeField', [], {}), | ||
| 88 | + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
| 89 | + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}), | ||
| 90 | + 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}), | ||
| 91 | + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'}) | ||
| 92 | + }, | ||
| 93 | + 'super_archives.messagemetadata': { | ||
| 94 | + 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}), | ||
| 95 | + 'Meta': {'object_name': 'MessageMetadata'}, | ||
| 96 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 97 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}), | ||
| 98 | + 'value': ('django.db.models.fields.TextField', [], {}) | ||
| 99 | + }, | ||
| 100 | + 'super_archives.pagehit': { | ||
| 101 | + 'Meta': {'object_name': 'PageHit'}, | ||
| 102 | + 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
| 103 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 104 | + 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'}) | ||
| 105 | + }, | ||
| 106 | + 'super_archives.thread': { | ||
| 107 | + 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'}, | ||
| 108 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 109 | + 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}), | ||
| 110 | + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}), | ||
| 111 | + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
| 112 | + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
| 113 | + 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'}) | ||
| 114 | + }, | ||
| 115 | + 'super_archives.userprofile': { | ||
| 116 | + 'Meta': {'object_name': 'UserProfile'}, | ||
| 117 | + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), | ||
| 118 | + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}), | ||
| 119 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 120 | + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), | ||
| 121 | + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), | ||
| 122 | + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), | ||
| 123 | + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}), | ||
| 124 | + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}), | ||
| 125 | + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'}) | ||
| 126 | + }, | ||
| 127 | + 'super_archives.vote': { | ||
| 128 | + 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'}, | ||
| 129 | + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), | ||
| 130 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 131 | + 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}), | ||
| 132 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + complete_apps = ['super_archives'] |
colab/super_archives/models.py
| @@ -194,6 +194,14 @@ class Message(models.Model): | @@ -194,6 +194,14 @@ class Message(models.Model): | ||
| 194 | return '(%s) %s: %s' % (self.id, | 194 | return '(%s) %s: %s' % (self.id, |
| 195 | self.from_address.get_full_name(), | 195 | self.from_address.get_full_name(), |
| 196 | self.subject_clean) | 196 | self.subject_clean) |
| 197 | + | ||
| 198 | + @property | ||
| 199 | + def mailinglist(self): | ||
| 200 | + if not self.thread or not self.thread.mailinglist: | ||
| 201 | + return None | ||
| 202 | + | ||
| 203 | + return self.thread.mailinglist | ||
| 204 | + | ||
| 197 | 205 | ||
| 198 | def vote_list(self): | 206 | def vote_list(self): |
| 199 | """Return a list of user that voted in this message.""" | 207 | """Return a list of user that voted in this message.""" |
colab/super_archives/queries.py
| @@ -28,7 +28,7 @@ def get_messages_by_voted(): | @@ -28,7 +28,7 @@ def get_messages_by_voted(): | ||
| 28 | 28 | ||
| 29 | def get_first_message_in_thread(mailinglist, thread_token): | 29 | def get_first_message_in_thread(mailinglist, thread_token): |
| 30 | query = get_messages_by_date() | 30 | query = get_messages_by_date() |
| 31 | - query = query.filter(mailinglist__name=mailinglist) | 31 | + query = query.filter(thread__mailinglist__name=mailinglist) |
| 32 | query = query.filter(thread__subject_token=thread_token)[0] | 32 | query = query.filter(thread__subject_token=thread_token)[0] |
| 33 | return query | 33 | return query |
| 34 | 34 |
colab/super_archives/views.py
| @@ -18,7 +18,7 @@ def thread(request, mailinglist, thread_token): | @@ -18,7 +18,7 @@ def thread(request, mailinglist, thread_token): | ||
| 18 | msgs_query = queries.get_messages_by_date() | 18 | msgs_query = queries.get_messages_by_date() |
| 19 | 19 | ||
| 20 | msgs_query = msgs_query.filter(thread__subject_token=thread_token) | 20 | msgs_query = msgs_query.filter(thread__subject_token=thread_token) |
| 21 | - msgs_query = msgs_query.filter(mailinglist__name=mailinglist) | 21 | + msgs_query = msgs_query.filter(thread__mailinglist__name=mailinglist) |
| 22 | emails = msgs_query.exclude(id=first_message.id) | 22 | emails = msgs_query.exclude(id=first_message.id) |
| 23 | 23 | ||
| 24 | total_votes = first_message.votes_count() | 24 | total_votes = first_message.votes_count() |
colab/templates/base.html
| @@ -137,6 +137,7 @@ | @@ -137,6 +137,7 @@ | ||
| 137 | 137 | ||
| 138 | <div id="footer" class="span-24 center"> | 138 | <div id="footer" class="span-24 center"> |
| 139 | {% block footer %} | 139 | {% block footer %} |
| 140 | + <p><a href="{% url opendata %}"><img src="{{ STATIC_URL }}img/opendata3.png"/></a></p> | ||
| 140 | <p>O conteúdo deste site está publicado sob a licença <a | 141 | <p>O conteúdo deste site está publicado sob a licença <a |
| 141 | href="http://creativecommons.org/licenses/by-nc-sa/2.0/br/">Creative | 142 | href="http://creativecommons.org/licenses/by-nc-sa/2.0/br/">Creative |
| 142 | Commons - atribuição e não-comercial</a> | 143 | Commons - atribuição e não-comercial</a> |
| @@ -0,0 +1,84 @@ | @@ -0,0 +1,84 @@ | ||
| 1 | +{% extends "base.html" %} | ||
| 2 | +{% load i18n %} | ||
| 3 | + | ||
| 4 | +{% block main-content %} | ||
| 5 | + <div class="span-18"> | ||
| 6 | + {% blocktrans %} | ||
| 7 | + <h2>Dados abertos - Comunidades Interlegis</h2> | ||
| 8 | + <p>Neste momento o sistema Colab disponibiliza grande parte de seus dados | ||
| 9 | + através do seu sistema de buscas.</p> | ||
| 10 | + <p>Caso você esteja interessado em integrar seu sistema com o ambiente Colab | ||
| 11 | + e necessite de outros dados não fornecidos por esta API, por favor | ||
| 12 | + entre em contato conosco através do sistemas de tiquetes (é necessário | ||
| 13 | + estar cadastrado para criar um tiquete).</p> | ||
| 14 | + | ||
| 15 | + <h3>Realizando buscas através da API</h3> | ||
| 16 | + <p>A API de buscas do Colab funciona através de um serviço HTTP/REST sempre | ||
| 17 | + retornando objetos JSON com resultado. </p> | ||
| 18 | + <p>A URL base utilizada para a busca é: | ||
| 19 | + <a href="/api/search/">http://colab.interlegis.leg.br/api/search/</a></p> | ||
| 20 | + | ||
| 21 | + <h3>Parâmetros:</h3> | ||
| 22 | + <ul class="prepend-1"> | ||
| 23 | + <li> | ||
| 24 | + <h4><i>Query</i> - q</h4> | ||
| 25 | + A <i>query</i> é a "pergunta" enviada | ||
| 26 | + para o servidor de buscas. Uma <i>query</i> é composta por | ||
| 27 | + <b>campo:valor</b>, onde campo representa um tipo de dados do sistema, | ||
| 28 | + por exemplo <b>collaborator</b> e valor representa o dado armazenado | ||
| 29 | + pelo sistema, por exemplo <b>jeanferri</b>. | ||
| 30 | + Segue a lista de campos disponíveis para a busca: | ||
| 31 | + <ul class="prepend-1"> | ||
| 32 | + <li><b><br/> | ||
| 33 | + Type</b>: wiki, thread, ticket, changeset.</li> | ||
| 34 | + <li><b>Title</b>: nome da página, título da discussão ou tiquete, descrição do changeset.</li> | ||
| 35 | + <li><b>Description</b>: trecho da página ou da discussão, descrição do tíquete ou changeset.</li> | ||
| 36 | + <li><b>Creator</b>: nome de usuário de quem criou o documento.</li> | ||
| 37 | + <li><b>creator_real_name</b>: nome real de quem criou o documento.</li> | ||
| 38 | + <li><b>create</b>: data de criação.</li> | ||
| 39 | + <li><b>modified</b>: data de modificação.</li> | ||
| 40 | + <li><b>mailinglist</b>: lista de discussões (apenas para o tipo thread).</li> | ||
| 41 | + <li><b>name</b>: nome da página wiki.</li> | ||
| 42 | + <li><b>comment</b>: comentários dos tíquetes (todos concatenados).</li> | ||
| 43 | + <li><b>content</b>: contúdo da página wiki ou mensagens da discussão (todas concatenadas). </li> | ||
| 44 | + <li><b>keyword</b>: keywords (apenas para tíquete).</li> | ||
| 45 | + <li><b>milestone</b>: milestone (apenas para tíquete).</li> | ||
| 46 | + <li><b>priority</b>: prioridade (apenas para tíquete).</li> | ||
| 47 | + <li><b>component</b>: componente (apenas para tíquete).</li> | ||
| 48 | + <li><b>version</b>: versão (apenas para tíquete).</li> | ||
| 49 | + <li><b>severity</b>: severidade (apenas para tíquete).</li> | ||
| 50 | + <li><b>owner</b>: responsável (apenas para tíquete).</li> | ||
| 51 | + <li><b>status</b>: status (apenas para tíquete).</li> | ||
| 52 | + <li><b>revision</b>: revisão (apenas para tíquete).</li> | ||
| 53 | + <li><b>subject</b>: sinônimo de título (apenas para discussões).</li> | ||
| 54 | + </ul> | ||
| 55 | + </li> | ||
| 56 | + <br/><hr/> | ||
| 57 | + | ||
| 58 | + <li> | ||
| 59 | + <h4>Resultados por Página - n </h4> | ||
| 60 | + Número de resultados que devem ser exibidos por página. Seu | ||
| 61 | + valor deveser um número inteiro entre 1 e 500. | ||
| 62 | + <i>Default: 50</i>. | ||
| 63 | + </li> | ||
| 64 | + <br/><hr/> | ||
| 65 | + | ||
| 66 | + <li> | ||
| 67 | + <h4>Página - p</h4> | ||
| 68 | + Número da página que será exibida. Seu valor deve ser um | ||
| 69 | + número inteiro igual ou maior que 1. <i>Default: 1</i>. | ||
| 70 | + </li> | ||
| 71 | + <br/><hr/> | ||
| 72 | + | ||
| 73 | + <li> | ||
| 74 | + <h4>Ordem - o</h4> | ||
| 75 | + Ordem em que os resultados serão exibidos. Seu valor deve | ||
| 76 | + ser uma string no formato <b>campo direção</b> onde campo | ||
| 77 | + são os mesmos apresentados no parametro <i>query</i> e | ||
| 78 | + direção pode ser <b>asc</b> para ascendente ou <b>desc</b> | ||
| 79 | + para descendente. <i>Default: score desc</i>. | ||
| 80 | + </li> | ||
| 81 | + <br/> | ||
| 82 | + </ul> | ||
| 83 | + {% endblocktrans %} | ||
| 84 | +{% endblock %} |
colab/urls.py
| 1 | from django.conf.urls.defaults import patterns, include, url | 1 | from django.conf.urls.defaults import patterns, include, url |
| 2 | +from django.views.generic.simple import direct_to_template | ||
| 2 | 3 | ||
| 3 | # Uncomment the next two lines to enable the admin: | 4 | # Uncomment the next two lines to enable the admin: |
| 4 | from django.contrib import admin | 5 | from django.contrib import admin |
| @@ -8,11 +9,14 @@ urlpatterns = patterns('', | @@ -8,11 +9,14 @@ urlpatterns = patterns('', | ||
| 8 | url(r'^$', 'colab.views.other.home', name='home'), | 9 | url(r'^$', 'colab.views.other.home', name='home'), |
| 9 | 10 | ||
| 10 | url(r'^archives/', include('colab.super_archives.urls')), | 11 | url(r'^archives/', include('colab.super_archives.urls')), |
| 11 | - | 12 | + |
| 12 | url(r'^api/', include('colab.api.urls')), | 13 | url(r'^api/', include('colab.api.urls')), |
| 13 | 14 | ||
| 14 | url(r'^rss/', include('colab.rss.urls')), | 15 | url(r'^rss/', include('colab.rss.urls')), |
| 15 | 16 | ||
| 17 | + url(r'open-data/$', direct_to_template, {'template': 'open-data.html'}, | ||
| 18 | + name='opendata'), | ||
| 19 | + | ||
| 16 | url(r'^user/(?P<username>[\w@+.-]+)/?$', | 20 | url(r'^user/(?P<username>[\w@+.-]+)/?$', |
| 17 | 'colab.views.userprofile.by_username', name='user_profile'), | 21 | 'colab.views.userprofile.by_username', name='user_profile'), |
| 18 | 22 |
etc/apache2/sites-available/colab
| @@ -23,6 +23,7 @@ | @@ -23,6 +23,7 @@ | ||
| 23 | RewriteRule ^/query(.*) http://colab-backend.interlegis.leg.br/query$1 [P] | 23 | RewriteRule ^/query(.*) http://colab-backend.interlegis.leg.br/query$1 [P] |
| 24 | RewriteRule ^/about(.*) http://colab-backend.interlegis.leg.br/about$1 [P] | 24 | RewriteRule ^/about(.*) http://colab-backend.interlegis.leg.br/about$1 [P] |
| 25 | RewriteRule ^/prefs(.*) http://colab-backend.interlegis.leg.br/prefs$1 [P] | 25 | RewriteRule ^/prefs(.*) http://colab-backend.interlegis.leg.br/prefs$1 [P] |
| 26 | + RewriteRule ^/log(.*) http://colab-backend.interlegis.leg.br/log$1 [P] | ||
| 26 | RewriteRule ^/login(.*) http://colab-backend.interlegis.leg.br/login$1 [P] | 27 | RewriteRule ^/login(.*) http://colab-backend.interlegis.leg.br/login$1 [P] |
| 27 | RewriteRule ^/logout(.*) http://colab-backend.interlegis.leg.br/logout$1 [P] | 28 | RewriteRule ^/logout(.*) http://colab-backend.interlegis.leg.br/logout$1 [P] |
| 28 | RewriteRule ^/attachment(.*) http://colab-backend.interlegis.leg.br/attachment$1 [P] | 29 | RewriteRule ^/attachment(.*) http://colab-backend.interlegis.leg.br/attachment$1 [P] |
setup.py
| @@ -4,7 +4,7 @@ from setuptools import setup, find_packages | @@ -4,7 +4,7 @@ from setuptools import setup, find_packages | ||
| 4 | from setupext import Data_Files, install_Data_Files | 4 | from setupext import Data_Files, install_Data_Files |
| 5 | 5 | ||
| 6 | setup(name='colab', | 6 | setup(name='colab', |
| 7 | - version='0.1-dev', | 7 | + version='3.0', |
| 8 | author='Sergio Oliveira', | 8 | author='Sergio Oliveira', |
| 9 | author_email='seocam@seocam.com', | 9 | author_email='seocam@seocam.com', |
| 10 | url='https://bitbucket.org/seocam/atu-colab', | 10 | url='https://bitbucket.org/seocam/atu-colab', |