Commit 156aa73a85a79c34c6e013862bbce59a49d0d15b

Authored by Sergio Oliveira
Committed by Marcio Mazza
1 parent 556e3b9c

Moving stuff around

Showing 74 changed files with 2958 additions and 2958 deletions   Show diff stats
colab/api/__init__.py
colab/api/handlers.py
@@ -1,103 +0,0 @@ @@ -1,103 +0,0 @@
1 -  
2 -from django.core.cache import cache  
3 -from django.db import IntegrityError  
4 -from django.core.exceptions import ObjectDoesNotExist  
5 -from django.contrib.auth.decorators import login_required  
6 -  
7 -from piston.utils import rc  
8 -from piston.handler import BaseHandler  
9 -  
10 -from colab import solrutils  
11 -from colab.super_archives.models import Message, PageHit  
12 -  
13 -  
14 -class VoteHandler(BaseHandler):  
15 - allowed_methods = ('GET', 'POST', 'DELETE')  
16 -  
17 - def create(self, request, message_id):  
18 - if not request.user.is_authenticated():  
19 - return rc.FORBIDDEN  
20 -  
21 - try:  
22 - Message.objects.get(id=message_id).vote(request.user)  
23 - except IntegrityError:  
24 - return rc.DUPLICATE_ENTRY  
25 -  
26 - return rc.CREATED  
27 -  
28 - def read(self, request, message_id):  
29 - return Message.objects.get(id=message_id).votes_count()  
30 -  
31 - def delete(self, request, message_id):  
32 - if not request.user.is_authenticated():  
33 - return rc.FORBIDDEN  
34 -  
35 - try:  
36 - Message.objects.get(id=message_id).unvote(request.user)  
37 - except ObjectDoesNotExist:  
38 - return rc.NOT_HERE  
39 -  
40 - return rc.DELETED  
41 -  
42 -  
43 -class CountHandler(BaseHandler):  
44 - allowed_methods = ('POST')  
45 -  
46 - def create(self, request):  
47 - """Add one page view for the given url"""  
48 -  
49 - # If missing the path_info argument we can't do anything  
50 - path_info = request.POST.get('path_info')  
51 - if not path_info:  
52 - return rc.BAD_REQUEST  
53 -  
54 - # Here we cache the user's IP to ensure that the same  
55 - # IP won't hit the same page again for while  
56 - ip_addr = request.META.get('REMOTE_ADDR')  
57 - page_hits_cache = cache.get('page_hits', {})  
58 - duplicate = page_hits_cache.get(path_info, {}).get(ip_addr)  
59 -  
60 - if duplicate:  
61 - return rc.DUPLICATE_ENTRY  
62 - else:  
63 - page_hits_cache.update({path_info: {ip_addr: True }})  
64 - cache.set('page_hits', page_hits_cache)  
65 -  
66 - # Everything ok, so just increment the page count  
67 - page_hit = PageHit.objects.get_or_create(url_path=path_info)[0]  
68 - page_hit.hit_count += 1  
69 - page_hit.save()  
70 -  
71 - return rc.CREATED  
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
@@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
1 -from django.conf.urls.defaults import patterns, include, url  
2 -  
3 -from piston.resource import Resource  
4 -  
5 -from colab.api.handlers import VoteHandler, CountHandler, SearchHandler  
6 -  
7 -  
8 -vote_handler = Resource(VoteHandler)  
9 -count_handler = Resource(CountHandler)  
10 -search_handler = Resource(SearchHandler)  
11 -  
12 -urlpatterns = patterns('',  
13 - url(r'message/(?P<message_id>\d+)/vote$', vote_handler),  
14 - url(r'hit/$', count_handler),  
15 - url(r'search/$', search_handler),  
16 -)  
colab/rss/__init__.py
colab/rss/feeds.py
@@ -1,78 +0,0 @@ @@ -1,78 +0,0 @@
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'Latest Discussions')  
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 - title = '[' + item.mailinglist.name + '] '  
23 - title += item.latest_message.subject_clean  
24 - return title  
25 -  
26 - def item_description(self, item):  
27 - return item.latest_message.body  
28 -  
29 -  
30 -class HottestThreadsFeeds(Feed):  
31 - title = _(u'Discussions Most Relevance')  
32 - link = '/rss/threads/hottest/'  
33 -  
34 - def items(self):  
35 - return queries.get_hottest_threads()[:20]  
36 -  
37 - def item_link(self, item):  
38 - return item.latest_message.url  
39 -  
40 - def item_title(self, item):  
41 - title = '[' + item.mailinglist.name + '] '  
42 - title += item.latest_message.subject_clean  
43 - return title  
44 -  
45 - def item_description(self, item):  
46 - return item.latest_message.body  
47 -  
48 -  
49 -class LatestColabFeeds(Feed):  
50 - title = _(u'Latest collaborations')  
51 - link = '/rss/colab/latest/'  
52 -  
53 - def items(self):  
54 - items = solrutils.get_latest_collaborations(20)  
55 - return items  
56 -  
57 - def item_title(self, item):  
58 - type_ = item.get('Type') + ': '  
59 - mailinglist = item.get('mailinglist')  
60 -  
61 - if mailinglist:  
62 - prefix = type_ + mailinglist + ' - '  
63 - else:  
64 - prefix = type_  
65 -  
66 - return prefix + item.get('Title')  
67 -  
68 - def item_description(self, item):  
69 - return item.get('Description')  
70 -  
71 - def item_link(self, item):  
72 - if item.get('Type') != 'thread':  
73 - url = item.get('url')  
74 - else:  
75 - url = 'http://colab.interlegis.leg.br'  
76 - url += item.get('url')  
77 - return url  
78 -  
colab/rss/urls.py
@@ -1,9 +0,0 @@ @@ -1,9 +0,0 @@
1 -from django.conf.urls.defaults import patterns, url  
2 -import feeds  
3 -  
4 -urlpatterns = patterns('',  
5 - url(r'threads/latest/$', feeds.LatestThreadsFeeds(), name='rss_latest_threads'),  
6 - url(r'colab/latest/$', feeds.LatestColabFeeds(), name='rss_latest_colab'),  
7 - url(r'threads/hottest/$', feeds.HottestThreadsFeeds(), name='rss_hottest_threads'),  
8 -)  
9 -  
colab/super_archives/__init__.py
colab/super_archives/admin.py
@@ -1,54 +0,0 @@ @@ -1,54 +0,0 @@
1 -  
2 -from django.contrib import admin  
3 -from colab.super_archives.models import Message, Thread, UserProfile  
4 -  
5 -class MessageAdmin(admin.ModelAdmin):  
6 - list_filter = ('spam', 'thread__mailinglist', 'received_time', )  
7 - search_fields = (  
8 - 'id',  
9 - 'subject',  
10 - 'subject_clean',  
11 - 'body',  
12 - 'from_address__real_name',  
13 - 'from_address__address',  
14 - 'from_address__user__first_name',  
15 - 'from_address__user__last_name',  
16 - 'from_address__user__username',  
17 - )  
18 - readonly_fields = ('thread', 'from_address', 'mailinglist')  
19 -  
20 -  
21 -class ThreadAdmin(admin.ModelAdmin):  
22 - list_filter = ('spam', 'mailinglist', 'message__received_time',)  
23 - search_fields = (  
24 - 'id',  
25 - 'subject_token',  
26 - 'message__subject',  
27 - 'message__subject_clean',  
28 - 'message__from_address__real_name',  
29 - 'message__from_address__address',  
30 - 'message__from_address__user__first_name',  
31 - 'message__from_address__user__last_name',  
32 - 'message__from_address__user__username',  
33 - )  
34 -  
35 - readonly_fields = (  
36 - 'mailinglist',  
37 - 'subject_token',  
38 - 'latest_message',  
39 - 'score',  
40 - )  
41 -  
42 - fields = (  
43 - 'mailinglist',  
44 - 'subject_token',  
45 - 'latest_message',  
46 - 'score',  
47 - 'spam',  
48 - )  
49 -  
50 -  
51 -admin.site.register(UserProfile)  
52 -admin.site.register(Thread, ThreadAdmin)  
53 -admin.site.register(Message, MessageAdmin)  
54 -  
colab/super_archives/fixtures/initial_data.json
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -[  
2 - {  
3 - "pk": 1,  
4 - "model": "auth.group",  
5 - "fields": {  
6 - "name": "developer",  
7 - "permissions": []  
8 - }  
9 - }  
10 -]  
colab/super_archives/forms.py
@@ -1,66 +0,0 @@ @@ -1,66 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -  
3 -from django import forms  
4 -from django.core.exceptions import ValidationError  
5 -from django.contrib.auth.models import User  
6 -from django.contrib.auth.forms import UserCreationForm as UserCreationForm_  
7 -from django.utils.translation import ugettext_lazy as _  
8 -  
9 -from colab.super_archives.models import MailingList  
10 -from colab.super_archives.validators import UniqueValidator  
11 -  
12 -# XXX: I know that this code does not look nice AT ALL.  
13 -# probably it should be implemented using formsets instead of  
14 -# the hack below. Feel free to improve it! :)  
15 -  
16 -# User fields  
17 -username_field = UserCreationForm_().fields.get(u'username')  
18 -first_name_field = forms.CharField(max_length=30, label=_(u'Name'))  
19 -last_name_field = forms.CharField(max_length=30, label=_(u'Last name'))  
20 -email_field = forms.EmailField(validators=[UniqueValidator(User, 'email')])  
21 -  
22 -# UserProfile fields  
23 -institution_field = forms.CharField(max_length=120, label=_(u'Institution'),  
24 - required=False)  
25 -role_field = forms.CharField(max_length=60, label=_(u'Function'), required=False)  
26 -twitter_field = forms.URLField(label=_(u'Twitter'), required=False)  
27 -facebook_field = forms.URLField(label=_(u'Facebook'), required=False)  
28 -google_talk_field = forms.EmailField(label=_(u'Google Talk'), required=False)  
29 -webpage_field = forms.URLField(label=_(u'Personal Website/Blog'), required=False)  
30 -  
31 -all_lists = MailingList.objects.all()  
32 -lists_names = []  
33 -for list_ in all_lists:  
34 - choice = (list_.name, list_.name)  
35 - lists_names.append(choice)  
36 -  
37 -lists_field = forms.MultipleChoiceField(  
38 - label=u'Listas',  
39 - required=False,  
40 - widget=forms.CheckboxSelectMultiple,  
41 - choices=lists_names  
42 -)  
43 -  
44 -  
45 -class UserCreationForm(UserCreationForm_):  
46 - first_name = first_name_field  
47 - last_name = last_name_field  
48 - email = email_field  
49 - institution = institution_field  
50 - role = role_field  
51 - twitter = twitter_field  
52 - facebook = facebook_field  
53 - google_talk = google_talk_field  
54 - webpage = webpage_field  
55 - lists = lists_field  
56 -  
57 -  
58 -class UserUpdateForm(forms.Form):  
59 - username = username_field  
60 - username.required = False  
61 - institution = institution_field  
62 - role = role_field  
63 - twitter = twitter_field  
64 - facebook = facebook_field  
65 - google_talk = google_talk_field  
66 - webpage = webpage_field  
colab/super_archives/management/__init__.py
colab/super_archives/management/commands/__init__.py
colab/super_archives/management/commands/import_emails.py
@@ -1,258 +0,0 @@ @@ -1,258 +0,0 @@
1 -#!/usr/bin/env python  
2 -# -*- encoding: utf-8 -*-  
3 -  
4 -"""Import emails from a mailman storage to the django database."""  
5 -  
6 -import os  
7 -import re  
8 -import sys  
9 -import mailbox  
10 -from optparse import make_option  
11 -  
12 -from django.db import transaction  
13 -from django.template.defaultfilters import slugify  
14 -from django.core.management.base import BaseCommand, CommandError  
15 -  
16 -from colab.super_archives.models import MailingList, Message, \  
17 - Thread, EmailAddress  
18 -from colab.super_archives.management.commands.message import Message as \  
19 - CustomMessage  
20 -  
21 -  
22 -class Command(BaseCommand, object):  
23 - """Get emails from mailman archives and import them in the django db. """  
24 -  
25 - help = __doc__  
26 -  
27 - default_archives_path = '/var/lib/mailman/archives/private'  
28 - RE_SUBJECT_CLEAN = re.compile('((re|res|fw|fwd|en|enc):)|\[.*?\]',  
29 - re.IGNORECASE)  
30 - THREAD_CACHE = {}  
31 - EMAIL_ADDR_CACHE = {}  
32 -  
33 - # A new command line option to get the dump file to parse.  
34 - option_list = BaseCommand.option_list + (  
35 - make_option('--archives_path',  
36 - dest='archives_path',  
37 - help='Path of email archives to be imported. (default: %s)' %  
38 - default_archives_path,  
39 - default=default_archives_path),  
40 -  
41 - make_option('--exclude-list',  
42 - dest='exclude_lists',  
43 - help=("Mailing list that won't be imported. It can be used many"  
44 - "times for more than one list."),  
45 - action='append',  
46 - default=None),  
47 -  
48 - make_option('--all',  
49 - dest='all',  
50 - help='Import all messages (default: False)',  
51 - action="store_true",  
52 - default=False),  
53 - )  
54 -  
55 - def __init__(self, *args, **kwargs):  
56 - super(Command, self).__init__(*args, **kwargs)  
57 -  
58 - def log(self, msg, error=False):  
59 - """Log message helper."""  
60 - output = self.stdout  
61 - if error:  
62 - output = self.stderr  
63 -  
64 - output.write(msg)  
65 - output.write('\n')  
66 -  
67 - def parse_emails(self, email_filename, index=0):  
68 - """Generator function that parse and extract emails from the file  
69 - `email_filename` starting from the position `index`.  
70 -  
71 - Yield: An instance of `mailbox.mboxMessage` for each email in the  
72 - file.  
73 -  
74 - """  
75 - self.log("Parsing email dump: %s." % email_filename)  
76 - mbox = mailbox.mbox(email_filename, factory=CustomMessage)  
77 -  
78 - # Get each email from mbox file  
79 - #  
80 - # The following implementation was used because the object  
81 - # mbox does not support slicing. Converting the object to a  
82 - # tuple (as represented in the code down here) was a valid  
83 - # option but its performance was too poor.  
84 - #  
85 - #for message in tuple(mbox)[index:]:  
86 - # yield message  
87 - #  
88 - key = index  
89 - while mbox.has_key(key):  
90 - key += 1  
91 - yield key-1, mbox[key-1]  
92 -  
93 - def get_emails(self, mailinglist_dir, all, exclude_lists):  
94 - """Generator function that get the emails from each mailing  
95 - list dump dirctory. If `all` is set to True all the emails in the  
96 - mbox will be imported if not it will just resume from the last  
97 - message previously imported. The lists set in `exclude_lists`  
98 - won't be imported.  
99 -  
100 - Yield: A tuple in the form: (mailing list name, email message).  
101 -  
102 - """  
103 - self.log("Getting emails dumps from: %s" % mailinglist_dir)  
104 -  
105 - # Get the list of directories ending with .mbox  
106 - mailing_lists_mboxes = (mbox for mbox in os.listdir(mailinglist_dir)  
107 - if mbox.endswith('.mbox'))  
108 -  
109 - # Get messages from each mbox  
110 - for mbox in mailing_lists_mboxes:  
111 - mbox_path = os.path.join(mailinglist_dir, mbox, mbox)  
112 - mailinglist_name = mbox.split('.')[0]  
113 -  
114 - # Check if the mailinglist is set not to be imported  
115 - if exclude_lists and mailinglist_name in exclude_lists:  
116 - continue  
117 -  
118 - # Find the index of the last imported message  
119 - if all:  
120 - n_msgs = 0  
121 - else:  
122 - try:  
123 - mailinglist = MailingList.objects.get(  
124 - name=mailinglist_name)  
125 - n_msgs = mailinglist.last_imported_index  
126 - except MailingList.DoesNotExist:  
127 - n_msgs = 0  
128 -  
129 - for index, msg in self.parse_emails(mbox_path, n_msgs):  
130 - yield mailinglist_name, msg, index  
131 -  
132 - def get_thread(self, email, mailinglist):  
133 - """Group messages by thread looking for similar subjects"""  
134 -  
135 - subject_slug = slugify(email.subject_clean)  
136 - thread = self.THREAD_CACHE.get(subject_slug, {}).get(mailinglist.id)  
137 - if thread is None:  
138 - thread = Thread.objects.get_or_create(  
139 - mailinglist=mailinglist,  
140 - subject_token=subject_slug  
141 - )[0]  
142 -  
143 - if self.THREAD_CACHE.get(subject_slug) is None:  
144 - self.THREAD_CACHE[subject_slug] = dict()  
145 - self.THREAD_CACHE[subject_slug][mailinglist.id] = thread  
146 -  
147 - thread.latest_message = email  
148 - thread.save()  
149 - return thread  
150 -  
151 - def save_email(self, list_name, email_msg, index):  
152 - """Save email message into the database."""  
153 -  
154 - # Update last imported message into the DB  
155 - mailinglist, created = MailingList.objects.get_or_create(name=list_name)  
156 - mailinglist.last_imported_index = index  
157 -  
158 - if created:  
159 - # if the mailinglist is newly created it's sure that the message  
160 - # is not in the DB yet.  
161 - self.create_email(mailinglist, email_msg)  
162 -  
163 - else:  
164 - # If the message is already at the database don't do anything  
165 - try:  
166 - messages = Message.objects.get(  
167 - message_id=email_msg.get('Message-ID'),  
168 - thread__mailinglist=mailinglist  
169 - )  
170 -  
171 - except Message.DoesNotExist:  
172 - self.create_email(mailinglist, email_msg)  
173 -  
174 - mailinglist.save()  
175 -  
176 - def create_email(self, mailinglist, email_msg):  
177 -  
178 - real_name, from_ = email_msg.get_from_addr()  
179 -  
180 - email_addr = self.EMAIL_ADDR_CACHE.get(from_)  
181 - if email_addr is None:  
182 - email_addr = EmailAddress.objects.get_or_create(  
183 - address=from_)[0]  
184 - self.EMAIL_ADDR_CACHE[from_] = email_addr  
185 -  
186 - if not email_addr.real_name and real_name:  
187 - email_addr.real_name = real_name[:64]  
188 - email_addr.save()  
189 -  
190 - subject = email_msg.get_subject()  
191 -  
192 - email = Message.objects.create(  
193 - message_id=email_msg.get('Message-ID'),  
194 - from_address=email_addr,  
195 - subject=subject,  
196 - subject_clean=self.RE_SUBJECT_CLEAN.sub('', subject).strip(),  
197 - body=email_msg.get_body(),  
198 - received_time=email_msg.get_received_datetime(),  
199 - )  
200 - email.thread = self.get_thread(email, mailinglist)  
201 - email.save()  
202 -  
203 - @transaction.commit_manually  
204 - def import_emails(self, archives_path, all, exclude_lists=None):  
205 - """Get emails from the filesystem from the `archives_path`  
206 - and store them into the database. If `all` is set to True all  
207 - the filesystem storage will be imported otherwise the  
208 - importation will resume from the last message previously  
209 - imported. The lists set in `exclude_lists` won't be imported.  
210 -  
211 - """  
212 -  
213 - count = 0  
214 - email_generator = self.get_emails(archives_path, all, exclude_lists)  
215 - for mailinglist_name, msg, index in email_generator:  
216 - try:  
217 - self.save_email(mailinglist_name, msg, index)  
218 - except:  
219 - # This anti-pattern is needed to avoid the transations to  
220 - # get stuck in case of errors.  
221 - transaction.rollback()  
222 - raise  
223 -  
224 - count += 1  
225 - if count % 1000 == 0:  
226 - transaction.commit()  
227 -  
228 - transaction.commit()  
229 -  
230 - def handle(self, *args, **options):  
231 - """Main command method."""  
232 -  
233 - lock_file = '/var/lock/colab/import_emails.lock'  
234 -  
235 - # Already running, so quit  
236 - if os.path.exists(lock_file):  
237 - self.log(("This script is already running. (If your are sure it's "  
238 - "not please delete the lock file in %s')") % lock_file)  
239 - sys.exit(0)  
240 -  
241 - if not os.path.exists(os.path.dirname(lock_file)):  
242 - os.mkdir(os.path.dirname(lock_file), 0755)  
243 -  
244 - run_lock = file(lock_file, 'w')  
245 - run_lock.close()  
246 -  
247 - archives_path = options.get('archives_path')  
248 - self.log('Using archives_path `%s`' % self.default_archives_path)  
249 -  
250 - if not os.path.exists(archives_path):  
251 - raise CommandError('archives_path (%s) does not exist' %  
252 - archives_path)  
253 -  
254 - self.import_emails(archives_path,  
255 - options.get('all'), options.get('exclude_lists'))  
256 -  
257 - os.remove(lock_file)  
258 -  
colab/super_archives/management/commands/message.py
@@ -1,101 +0,0 @@ @@ -1,101 +0,0 @@
1 -  
2 -import re  
3 -import pytz  
4 -import email  
5 -import codecs  
6 -import mailbox  
7 -import datetime  
8 -from email.iterators import typed_subpart_iterator  
9 -  
10 -import chardet  
11 -  
12 -  
13 -def get_charset(message, default='ASCII'):  
14 - """Get the message charset"""  
15 -  
16 - charset = message.get_content_charset()  
17 -  
18 - if not charset:  
19 - charset = message.get_charset()  
20 -  
21 - if not charset:  
22 - charset = default  
23 -  
24 - try:  
25 - codecs.lookup(charset)  
26 - except LookupError:  
27 - charset = default  
28 -  
29 - return charset  
30 -  
31 -  
32 -class Message(mailbox.mboxMessage):  
33 -  
34 - RECEIVED_DELIMITER = re.compile('\n|;')  
35 -  
36 - def get_subject(self):  
37 - subject = email.header.decode_header(self['Subject'])  
38 -  
39 - if isinstance(subject, list):  
40 - new_subject = u''  
41 - for text_part, encoding in subject:  
42 - if not encoding:  
43 - encoding = get_charset(self)  
44 -  
45 - try:  
46 - new_subject += unicode(text_part, encoding)  
47 - except (UnicodeDecodeError, LookupError):  
48 - try:  
49 - new_subject += unicode(text_part, get_charset(self))  
50 - except (UnicodeDecodeError, LookupError):  
51 - encoding = chardet.detect(text_part)['encoding']  
52 - new_subject += unicode(text_part, encoding)  
53 -  
54 - return ''.join(new_subject)  
55 -  
56 - def get_body(self):  
57 - """Get the body of the email message"""  
58 -  
59 - if self.is_multipart():  
60 - #get the plain text version only  
61 - text_parts = [part  
62 - for part in typed_subpart_iterator(self,  
63 - 'text',  
64 - 'plain')]  
65 - body = []  
66 - for part in text_parts:  
67 - charset = get_charset(part, get_charset(self))  
68 - body.append(unicode(part.get_payload(decode=True),  
69 - charset,  
70 - "replace"))  
71 -  
72 - return u"\n".join(body).strip()  
73 -  
74 - else: # if it is not multipart, the payload will be a string  
75 - # representing the message body  
76 - body = unicode(self.get_payload(decode=True),  
77 - get_charset(self),  
78 - "replace")  
79 - return body.strip()  
80 -  
81 - def get_received_datetime(self):  
82 - # The time received should always be the last element  
83 - # in the `Received` attribute from the message headers  
84 - received_header = self.RECEIVED_DELIMITER.split(self['Received'])  
85 - received_time_header = received_header[-1].strip()  
86 -  
87 - date_tuple = email.utils.parsedate_tz(received_time_header)  
88 - utc_timestamp = email.utils.mktime_tz(date_tuple)  
89 - utc_datetime = datetime.datetime.fromtimestamp(utc_timestamp,  
90 - pytz.utc)  
91 -  
92 - return utc_datetime  
93 -  
94 - def get_from_addr(self):  
95 - real_name_raw, from_ = email.utils.parseaddr(self['From'])  
96 - real_name_str, encoding = email.header.decode_header(real_name_raw)[0]  
97 - if not encoding:  
98 - encoding = 'ascii'  
99 -  
100 - real_name = unicode(real_name_str, encoding, errors='replace')  
101 - return real_name, from_  
colab/super_archives/migrations/0001_initial.py
@@ -1,255 +0,0 @@ @@ -1,255 +0,0 @@
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 - # Adding model 'PageHit'  
12 - db.create_table('super_archives_pagehit', (  
13 - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),  
14 - ('url_path', self.gf('django.db.models.fields.CharField')(unique=True, max_length=2048, db_index=True)),  
15 - ('hit_count', self.gf('django.db.models.fields.IntegerField')(default=0)),  
16 - ))  
17 - db.send_create_signal('super_archives', ['PageHit'])  
18 -  
19 - # Adding model 'EmailAddress'  
20 - db.create_table('super_archives_emailaddress', (  
21 - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),  
22 - ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='emails', null=True, to=orm['auth.User'])),  
23 - ('address', self.gf('django.db.models.fields.EmailField')(unique=True, max_length=75)),  
24 - ('real_name', self.gf('django.db.models.fields.CharField')(max_length=64, blank=True)),  
25 - ('md5', self.gf('django.db.models.fields.CharField')(max_length=32, null=True)),  
26 - ))  
27 - db.send_create_signal('super_archives', ['EmailAddress'])  
28 -  
29 - # Adding model 'UserProfile'  
30 - db.create_table('super_archives_userprofile', (  
31 - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),  
32 - ('user', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.User'], unique=True)),  
33 - ('institution', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),  
34 - ('role', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),  
35 - ('twitter', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),  
36 - ('facebook', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),  
37 - ('google_talk', self.gf('django.db.models.fields.EmailField')(max_length=75, null=True)),  
38 - ('webpage', self.gf('django.db.models.fields.CharField')(max_length=256)),  
39 - ))  
40 - db.send_create_signal('super_archives', ['UserProfile'])  
41 -  
42 - # Adding model 'MailingList'  
43 - db.create_table('super_archives_mailinglist', (  
44 - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),  
45 - ('name', self.gf('django.db.models.fields.CharField')(max_length=80)),  
46 - ('email', self.gf('django.db.models.fields.EmailField')(max_length=75)),  
47 - ('description', self.gf('django.db.models.fields.TextField')()),  
48 - ('logo', self.gf('django.db.models.fields.files.FileField')(max_length=100)),  
49 - ('last_imported_index', self.gf('django.db.models.fields.IntegerField')(default=0)),  
50 - ))  
51 - db.send_create_signal('super_archives', ['MailingList'])  
52 -  
53 - # Adding model 'MailingListMembership'  
54 - db.create_table('super_archives_mailinglistmembership', (  
55 - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),  
56 - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),  
57 - ('mailinglist', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.MailingList'])),  
58 - ))  
59 - db.send_create_signal('super_archives', ['MailingListMembership'])  
60 -  
61 - # Adding model 'Thread'  
62 - db.create_table('super_archives_thread', (  
63 - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),  
64 - ('subject_token', self.gf('django.db.models.fields.CharField')(max_length=512)),  
65 - ('mailinglist', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.MailingList'])),  
66 - ('latest_message', self.gf('django.db.models.fields.related.OneToOneField')(related_name='+', unique=True, null=True, to=orm['super_archives.Message'])),  
67 - ))  
68 - db.send_create_signal('super_archives', ['Thread'])  
69 -  
70 - # Adding unique constraint on 'Thread', fields ['subject_token', 'mailinglist']  
71 - db.create_unique('super_archives_thread', ['subject_token', 'mailinglist_id'])  
72 -  
73 - # Adding model 'Vote'  
74 - db.create_table('super_archives_vote', (  
75 - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),  
76 - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),  
77 - ('message', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.Message'])),  
78 - ))  
79 - db.send_create_signal('super_archives', ['Vote'])  
80 -  
81 - # Adding unique constraint on 'Vote', fields ['user', 'message']  
82 - db.create_unique('super_archives_vote', ['user_id', 'message_id'])  
83 -  
84 - # Adding model 'Message'  
85 - db.create_table('super_archives_message', (  
86 - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),  
87 - ('from_address', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.EmailAddress'])),  
88 - ('mailinglist', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.MailingList'])),  
89 - ('thread', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.Thread'], null=True)),  
90 - ('subject', self.gf('django.db.models.fields.CharField')(max_length=512)),  
91 - ('subject_clean', self.gf('django.db.models.fields.CharField')(max_length=512)),  
92 - ('body', self.gf('django.db.models.fields.TextField')(default='')),  
93 - ('received_time', self.gf('django.db.models.fields.DateTimeField')()),  
94 - ('message_id', self.gf('django.db.models.fields.CharField')(max_length=512)),  
95 - ))  
96 - db.send_create_signal('super_archives', ['Message'])  
97 -  
98 - # Adding model 'MessageMetadata'  
99 - db.create_table('super_archives_messagemetadata', (  
100 - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),  
101 - ('Message', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.Message'])),  
102 - ('name', self.gf('django.db.models.fields.CharField')(max_length=512)),  
103 - ('value', self.gf('django.db.models.fields.TextField')()),  
104 - ))  
105 - db.send_create_signal('super_archives', ['MessageMetadata'])  
106 -  
107 -  
108 - def backwards(self, orm):  
109 -  
110 - # Removing unique constraint on 'Vote', fields ['user', 'message']  
111 - db.delete_unique('super_archives_vote', ['user_id', 'message_id'])  
112 -  
113 - # Removing unique constraint on 'Thread', fields ['subject_token', 'mailinglist']  
114 - db.delete_unique('super_archives_thread', ['subject_token', 'mailinglist_id'])  
115 -  
116 - # Deleting model 'PageHit'  
117 - db.delete_table('super_archives_pagehit')  
118 -  
119 - # Deleting model 'EmailAddress'  
120 - db.delete_table('super_archives_emailaddress')  
121 -  
122 - # Deleting model 'UserProfile'  
123 - db.delete_table('super_archives_userprofile')  
124 -  
125 - # Deleting model 'MailingList'  
126 - db.delete_table('super_archives_mailinglist')  
127 -  
128 - # Deleting model 'MailingListMembership'  
129 - db.delete_table('super_archives_mailinglistmembership')  
130 -  
131 - # Deleting model 'Thread'  
132 - db.delete_table('super_archives_thread')  
133 -  
134 - # Deleting model 'Vote'  
135 - db.delete_table('super_archives_vote')  
136 -  
137 - # Deleting model 'Message'  
138 - db.delete_table('super_archives_message')  
139 -  
140 - # Deleting model 'MessageMetadata'  
141 - db.delete_table('super_archives_messagemetadata')  
142 -  
143 -  
144 - models = {  
145 - 'auth.group': {  
146 - 'Meta': {'object_name': 'Group'},  
147 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
148 - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),  
149 - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})  
150 - },  
151 - 'auth.permission': {  
152 - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},  
153 - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),  
154 - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),  
155 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
156 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})  
157 - },  
158 - 'auth.user': {  
159 - 'Meta': {'object_name': 'User'},  
160 - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),  
161 - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),  
162 - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),  
163 - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),  
164 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
165 - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),  
166 - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
167 - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
168 - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),  
169 - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),  
170 - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),  
171 - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),  
172 - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})  
173 - },  
174 - 'contenttypes.contenttype': {  
175 - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},  
176 - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),  
177 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
178 - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),  
179 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})  
180 - },  
181 - 'super_archives.emailaddress': {  
182 - 'Meta': {'object_name': 'EmailAddress'},  
183 - 'address': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}),  
184 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
185 - 'md5': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),  
186 - 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),  
187 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emails'", 'null': 'True', 'to': "orm['auth.User']"})  
188 - },  
189 - 'super_archives.mailinglist': {  
190 - 'Meta': {'object_name': 'MailingList'},  
191 - 'description': ('django.db.models.fields.TextField', [], {}),  
192 - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),  
193 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
194 - 'last_imported_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
195 - 'logo': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),  
196 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'})  
197 - },  
198 - 'super_archives.mailinglistmembership': {  
199 - 'Meta': {'object_name': 'MailingListMembership'},  
200 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
201 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
202 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
203 - },  
204 - 'super_archives.message': {  
205 - 'Meta': {'object_name': 'Message'},  
206 - 'body': ('django.db.models.fields.TextField', [], {'default': "''"}),  
207 - 'from_address': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.EmailAddress']"}),  
208 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
209 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
210 - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
211 - 'received_time': ('django.db.models.fields.DateTimeField', [], {}),  
212 - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
213 - 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
214 - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'})  
215 - },  
216 - 'super_archives.messagemetadata': {  
217 - 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
218 - 'Meta': {'object_name': 'MessageMetadata'},  
219 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
220 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
221 - 'value': ('django.db.models.fields.TextField', [], {})  
222 - },  
223 - 'super_archives.pagehit': {  
224 - 'Meta': {'object_name': 'PageHit'},  
225 - 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
226 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
227 - 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'})  
228 - },  
229 - 'super_archives.thread': {  
230 - 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'},  
231 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
232 - 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}),  
233 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
234 - 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})  
235 - },  
236 - 'super_archives.userprofile': {  
237 - 'Meta': {'object_name': 'UserProfile'},  
238 - 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
239 - 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),  
240 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
241 - 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
242 - 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
243 - 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
244 - 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),  
245 - 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})  
246 - },  
247 - 'super_archives.vote': {  
248 - 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},  
249 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
250 - 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
251 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
252 - }  
253 - }  
254 -  
255 - complete_apps = ['super_archives']  
colab/super_archives/migrations/0002_auto__add_field_userprofile_verification_hash.py
@@ -1,133 +0,0 @@ @@ -1,133 +0,0 @@
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 - # Adding field 'UserProfile.verification_hash'  
12 - db.add_column('super_archives_userprofile', 'verification_hash', self.gf('django.db.models.fields.CharField')(max_length=32, null=True), keep_default=False)  
13 -  
14 -  
15 - def backwards(self, orm):  
16 -  
17 - # Deleting field 'UserProfile.verification_hash'  
18 - db.delete_column('super_archives_userprofile', 'verification_hash')  
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', [], {'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 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
87 - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
88 - 'received_time': ('django.db.models.fields.DateTimeField', [], {}),  
89 - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
90 - 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
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 - 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})  
112 - },  
113 - 'super_archives.userprofile': {  
114 - 'Meta': {'object_name': 'UserProfile'},  
115 - 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
116 - 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),  
117 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
118 - 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
119 - 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
120 - 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
121 - 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),  
122 - 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),  
123 - 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})  
124 - },  
125 - 'super_archives.vote': {  
126 - 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},  
127 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
128 - 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
129 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
130 - }  
131 - }  
132 -  
133 - complete_apps = ['super_archives']  
colab/super_archives/migrations/0003_auto__add_field_thread_score.py
@@ -1,134 +0,0 @@ @@ -1,134 +0,0 @@
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 - # Adding field 'Thread.score'  
12 - db.add_column('super_archives_thread', 'score', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)  
13 -  
14 -  
15 - def backwards(self, orm):  
16 -  
17 - # Deleting field 'Thread.score'  
18 - db.delete_column('super_archives_thread', 'score')  
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', [], {'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 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
87 - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
88 - 'received_time': ('django.db.models.fields.DateTimeField', [], {}),  
89 - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
90 - 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
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 - 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})  
113 - },  
114 - 'super_archives.userprofile': {  
115 - 'Meta': {'object_name': 'UserProfile'},  
116 - 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
117 - 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),  
118 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
119 - 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
120 - 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
121 - 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
122 - 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),  
123 - 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),  
124 - 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})  
125 - },  
126 - 'super_archives.vote': {  
127 - 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},  
128 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
129 - 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
130 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
131 - }  
132 - }  
133 -  
134 - complete_apps = ['super_archives']  
colab/super_archives/migrations/0004_auto__add_field_vote_created.py
@@ -1,135 +0,0 @@ @@ -1,135 +0,0 @@
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 - # Adding field 'Vote.created'  
12 - db.add_column('super_archives_vote', 'created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, default=datetime.datetime(2012, 1, 19, 18, 8, 46, 813949), blank=True), keep_default=False)  
13 -  
14 -  
15 - def backwards(self, orm):  
16 -  
17 - # Deleting field 'Vote.created'  
18 - db.delete_column('super_archives_vote', 'created')  
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', [], {'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 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
87 - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
88 - 'received_time': ('django.db.models.fields.DateTimeField', [], {}),  
89 - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
90 - 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
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 - 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})  
113 - },  
114 - 'super_archives.userprofile': {  
115 - 'Meta': {'object_name': 'UserProfile'},  
116 - 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
117 - 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),  
118 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
119 - 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
120 - 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
121 - 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
122 - 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),  
123 - 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),  
124 - 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})  
125 - },  
126 - 'super_archives.vote': {  
127 - 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},  
128 - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),  
129 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
130 - 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
131 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
132 - }  
133 - }  
134 -  
135 - complete_apps = ['super_archives']  
colab/super_archives/migrations/0005_auto__add_field_message_spam__add_field_thread_spam.py
@@ -1,143 +0,0 @@ @@ -1,143 +0,0 @@
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 - # Adding field 'Message.spam'  
12 - db.add_column('super_archives_message', 'spam', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)  
13 -  
14 - # Adding field 'Thread.spam'  
15 - db.add_column('super_archives_thread', 'spam', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)  
16 -  
17 -  
18 - def backwards(self, orm):  
19 -  
20 - # Deleting field 'Message.spam'  
21 - db.delete_column('super_archives_message', 'spam')  
22 -  
23 - # Deleting field 'Thread.spam'  
24 - db.delete_column('super_archives_thread', 'spam')  
25 -  
26 -  
27 - models = {  
28 - 'auth.group': {  
29 - 'Meta': {'object_name': 'Group'},  
30 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
31 - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),  
32 - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})  
33 - },  
34 - 'auth.permission': {  
35 - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},  
36 - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),  
37 - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),  
38 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
39 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})  
40 - },  
41 - 'auth.user': {  
42 - 'Meta': {'object_name': 'User'},  
43 - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),  
44 - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),  
45 - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),  
46 - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),  
47 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
48 - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),  
49 - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
50 - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
51 - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),  
52 - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),  
53 - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),  
54 - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),  
55 - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})  
56 - },  
57 - 'contenttypes.contenttype': {  
58 - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},  
59 - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),  
60 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
61 - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),  
62 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})  
63 - },  
64 - 'super_archives.emailaddress': {  
65 - 'Meta': {'object_name': 'EmailAddress'},  
66 - 'address': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}),  
67 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
68 - 'md5': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),  
69 - 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),  
70 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emails'", 'null': 'True', 'to': "orm['auth.User']"})  
71 - },  
72 - 'super_archives.mailinglist': {  
73 - 'Meta': {'object_name': 'MailingList'},  
74 - 'description': ('django.db.models.fields.TextField', [], {}),  
75 - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),  
76 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
77 - 'last_imported_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
78 - 'logo': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),  
79 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'})  
80 - },  
81 - 'super_archives.mailinglistmembership': {  
82 - 'Meta': {'object_name': 'MailingListMembership'},  
83 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
84 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
85 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
86 - },  
87 - 'super_archives.message': {  
88 - 'Meta': {'object_name': 'Message'},  
89 - 'body': ('django.db.models.fields.TextField', [], {'default': "''"}),  
90 - 'from_address': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.EmailAddress']"}),  
91 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
92 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
93 - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
94 - 'received_time': ('django.db.models.fields.DateTimeField', [], {}),  
95 - 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
96 - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
97 - 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
98 - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'})  
99 - },  
100 - 'super_archives.messagemetadata': {  
101 - 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
102 - 'Meta': {'object_name': 'MessageMetadata'},  
103 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
104 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
105 - 'value': ('django.db.models.fields.TextField', [], {})  
106 - },  
107 - 'super_archives.pagehit': {  
108 - 'Meta': {'object_name': 'PageHit'},  
109 - 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
110 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
111 - 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'})  
112 - },  
113 - 'super_archives.thread': {  
114 - 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'},  
115 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
116 - 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}),  
117 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
118 - 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
119 - 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
120 - 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})  
121 - },  
122 - 'super_archives.userprofile': {  
123 - 'Meta': {'object_name': 'UserProfile'},  
124 - 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
125 - 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),  
126 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
127 - 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
128 - 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
129 - 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
130 - 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),  
131 - 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),  
132 - 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})  
133 - },  
134 - 'super_archives.vote': {  
135 - 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},  
136 - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),  
137 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
138 - 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
139 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
140 - }  
141 - }  
142 -  
143 - complete_apps = ['super_archives']  
colab/super_archives/migrations/0006_auto.py
@@ -1,143 +0,0 @@ @@ -1,143 +0,0 @@
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 - # Adding index on 'Message', fields ['subject_clean']  
12 - db.create_index('super_archives_message', ['subject_clean'])  
13 -  
14 - # Adding index on 'Message', fields ['subject']  
15 - db.create_index('super_archives_message', ['subject'])  
16 -  
17 -  
18 - def backwards(self, orm):  
19 -  
20 - # Removing index on 'Message', fields ['subject']  
21 - db.delete_index('super_archives_message', ['subject'])  
22 -  
23 - # Removing index on 'Message', fields ['subject_clean']  
24 - db.delete_index('super_archives_message', ['subject_clean'])  
25 -  
26 -  
27 - models = {  
28 - 'auth.group': {  
29 - 'Meta': {'object_name': 'Group'},  
30 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
31 - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),  
32 - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})  
33 - },  
34 - 'auth.permission': {  
35 - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},  
36 - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),  
37 - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),  
38 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
39 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})  
40 - },  
41 - 'auth.user': {  
42 - 'Meta': {'object_name': 'User'},  
43 - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),  
44 - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),  
45 - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),  
46 - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),  
47 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
48 - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),  
49 - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
50 - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
51 - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),  
52 - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),  
53 - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),  
54 - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),  
55 - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})  
56 - },  
57 - 'contenttypes.contenttype': {  
58 - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},  
59 - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),  
60 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
61 - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),  
62 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})  
63 - },  
64 - 'super_archives.emailaddress': {  
65 - 'Meta': {'object_name': 'EmailAddress'},  
66 - 'address': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}),  
67 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
68 - 'md5': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),  
69 - 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),  
70 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emails'", 'null': 'True', 'to': "orm['auth.User']"})  
71 - },  
72 - 'super_archives.mailinglist': {  
73 - 'Meta': {'object_name': 'MailingList'},  
74 - 'description': ('django.db.models.fields.TextField', [], {}),  
75 - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),  
76 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
77 - 'last_imported_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
78 - 'logo': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),  
79 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'})  
80 - },  
81 - 'super_archives.mailinglistmembership': {  
82 - 'Meta': {'object_name': 'MailingListMembership'},  
83 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
84 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
85 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
86 - },  
87 - 'super_archives.message': {  
88 - 'Meta': {'object_name': 'Message'},  
89 - 'body': ('django.db.models.fields.TextField', [], {'default': "''"}),  
90 - 'from_address': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.EmailAddress']"}),  
91 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
92 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
93 - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
94 - 'received_time': ('django.db.models.fields.DateTimeField', [], {}),  
95 - 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
96 - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}),  
97 - 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}),  
98 - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'})  
99 - },  
100 - 'super_archives.messagemetadata': {  
101 - 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
102 - 'Meta': {'object_name': 'MessageMetadata'},  
103 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
104 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
105 - 'value': ('django.db.models.fields.TextField', [], {})  
106 - },  
107 - 'super_archives.pagehit': {  
108 - 'Meta': {'object_name': 'PageHit'},  
109 - 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
110 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
111 - 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'})  
112 - },  
113 - 'super_archives.thread': {  
114 - 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'},  
115 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
116 - 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}),  
117 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
118 - 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
119 - 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
120 - 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})  
121 - },  
122 - 'super_archives.userprofile': {  
123 - 'Meta': {'object_name': 'UserProfile'},  
124 - 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
125 - 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),  
126 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
127 - 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
128 - 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
129 - 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
130 - 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),  
131 - 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),  
132 - 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})  
133 - },  
134 - 'super_archives.vote': {  
135 - 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},  
136 - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),  
137 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
138 - 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
139 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
140 - }  
141 - }  
142 -  
143 - complete_apps = ['super_archives']  
colab/super_archives/migrations/0007_auto.py
@@ -1,137 +0,0 @@ @@ -1,137 +0,0 @@
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 - # Adding index on 'EmailAddress', fields ['real_name']  
12 - db.create_index('super_archives_emailaddress', ['real_name'])  
13 -  
14 -  
15 - def backwards(self, orm):  
16 -  
17 - # Removing index on 'EmailAddress', fields ['real_name']  
18 - db.delete_index('super_archives_emailaddress', ['real_name'])  
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 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
87 - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
88 - 'received_time': ('django.db.models.fields.DateTimeField', [], {}),  
89 - 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
90 - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}),  
91 - 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}),  
92 - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'})  
93 - },  
94 - 'super_archives.messagemetadata': {  
95 - 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
96 - 'Meta': {'object_name': 'MessageMetadata'},  
97 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
98 - 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),  
99 - 'value': ('django.db.models.fields.TextField', [], {})  
100 - },  
101 - 'super_archives.pagehit': {  
102 - 'Meta': {'object_name': 'PageHit'},  
103 - 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
104 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
105 - 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'})  
106 - },  
107 - 'super_archives.thread': {  
108 - 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'},  
109 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
110 - 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}),  
111 - 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),  
112 - 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),  
113 - 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),  
114 - 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})  
115 - },  
116 - 'super_archives.userprofile': {  
117 - 'Meta': {'object_name': 'UserProfile'},  
118 - 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
119 - 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),  
120 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
121 - 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
122 - 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
123 - 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),  
124 - 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),  
125 - 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),  
126 - 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})  
127 - },  
128 - 'super_archives.vote': {  
129 - 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},  
130 - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),  
131 - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),  
132 - 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),  
133 - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})  
134 - }  
135 - }  
136 -  
137 - complete_apps = ['super_archives']  
colab/super_archives/migrations/0008_add_mailinglist_name_to_url.py
@@ -1,142 +0,0 @@ @@ -1,142 +0,0 @@
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/migrations/0009_auto__del_field_message_mailinglist.py
@@ -1,136 +0,0 @@ @@ -1,136 +0,0 @@
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/migrations/0010_auto__add_unique_message_message_id_thread.py
@@ -1,136 +0,0 @@ @@ -1,136 +0,0 @@
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 - # Adding unique constraint on 'Message', fields ['message_id', 'thread']  
12 - db.create_unique('super_archives_message', ['message_id', 'thread_id'])  
13 -  
14 -  
15 - def backwards(self, orm):  
16 -  
17 - # Removing unique constraint on 'Message', fields ['message_id', 'thread']  
18 - db.delete_unique('super_archives_message', ['message_id', 'thread_id'])  
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': {'unique_together': "(('thread', 'message_id'),)", '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/migrations/__init__.py
colab/super_archives/models.py
@@ -1,279 +0,0 @@ @@ -1,279 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -  
3 -import datetime  
4 -from hashlib import md5  
5 -  
6 -from django.db import models  
7 -from django.conf import settings  
8 -from django.contrib.auth.models import User  
9 -from django.core.urlresolvers import reverse, NoReverseMatch  
10 -from django.utils.translation import ugettext_lazy as _  
11 -  
12 -  
13 -class NotSpamManager(models.Manager):  
14 - """Only return objects which are not marked as spam."""  
15 -  
16 - def get_query_set(self):  
17 - return super(NotSpamManager, self).get_query_set().exclude(spam=True)  
18 -  
19 -  
20 -class PageHit(models.Model):  
21 - url_path = models.CharField(max_length=2048, unique=True, db_index=True)  
22 - hit_count = models.IntegerField(default=0)  
23 -  
24 -  
25 -class EmailAddress(models.Model):  
26 - user = models.ForeignKey(User, null=True, related_name='emails')  
27 - address = models.EmailField(unique=True)  
28 - real_name = models.CharField(max_length=64, blank=True, db_index=True)  
29 - md5 = models.CharField(max_length=32, null=True)  
30 -  
31 - def save(self, *args, **kwargs):  
32 - self.md5 = md5(self.address).hexdigest()  
33 - super(EmailAddress, self).save(*args, **kwargs)  
34 -  
35 - def get_full_name(self):  
36 - if self.user and self.user.get_full_name():  
37 - return self.user.get_full_name()  
38 - elif self.user and self.username:  
39 - return self.username  
40 - elif self.real_name:  
41 - return self.real_name  
42 -  
43 - def get_profile_link(self):  
44 - if self.user:  
45 - return reverse('user_profile', args=[self.user.username])  
46 - else:  
47 - return reverse('colab.views.userprofile.by_emailhash',  
48 - args=[self.md5])  
49 -  
50 - def __unicode__(self):  
51 - return '"%s" <%s>' % (self.get_full_name(), self.address)  
52 -  
53 -  
54 -class UserProfile(models.Model):  
55 -  
56 - user = models.OneToOneField(User, unique=True)  
57 - institution = models.CharField(max_length=128, null=True)  
58 - role = models.CharField(max_length=128, null=True)  
59 - twitter = models.CharField(max_length=128, null=True)  
60 - facebook = models.CharField(max_length=128, null=True)  
61 - google_talk = models.EmailField(null=True)  
62 - webpage = models.CharField(max_length=256)  
63 - verification_hash = models.CharField(max_length=32, null=True)  
64 -  
65 - class Meta:  
66 - verbose_name = _(u"User Profile")  
67 - verbose_name_plural = _(u"Users Profiles")  
68 -  
69 - def __unicode__(self):  
70 - return '%s (%s)' % (self.user.get_full_name(), self.user.username)  
71 -  
72 -# This does the same the same than related_name argument but it also creates  
73 -# a profile in the case it doesn't exist yet.  
74 -User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])  
75 -  
76 -  
77 -class MailingList(models.Model):  
78 - name = models.CharField(max_length=80)  
79 - email = models.EmailField()  
80 - description = models.TextField()  
81 - logo = models.FileField(upload_to='list_logo') #TODO  
82 - last_imported_index = models.IntegerField(default=0)  
83 -  
84 - def __unicode__(self):  
85 - return self.name  
86 -  
87 -  
88 -class MailingListMembership(models.Model):  
89 - user = models.ForeignKey(User)  
90 - mailinglist = models.ForeignKey(MailingList)  
91 -  
92 - def __unicode__(self):  
93 - return '%s on %s' % (self.user.username, self.mailinglist.name)  
94 -  
95 -  
96 -class Thread(models.Model):  
97 -  
98 - subject_token = models.CharField(max_length=512)  
99 - mailinglist = models.ForeignKey(MailingList,  
100 - verbose_name=_(u"Mailing List"),  
101 - help_text=_(u"The Mailing List where is the thread"))  
102 - latest_message = models.OneToOneField('Message', null=True,  
103 - related_name='+',  
104 - verbose_name=_(u"Latest message"),  
105 - help_text=_(u"Latest message posted"))  
106 - score = models.IntegerField(default=0, verbose_name=_(u"Score"), help_text=_(u"Thread score"))  
107 - spam = models.BooleanField(default=False)  
108 -  
109 - all_objects = models.Manager()  
110 - objects = NotSpamManager()  
111 -  
112 - class Meta:  
113 - verbose_name = _(u"Thread")  
114 - verbose_name_plural = _(u"Threads")  
115 - unique_together = ('subject_token', 'mailinglist')  
116 -  
117 - def __unicode__(self):  
118 - return '%s - %s (%s)' % (self.id,  
119 - self.subject_token,  
120 - self.message_set.count())  
121 -  
122 - def update_score(self):  
123 - """Update the relevance score for this thread.  
124 -  
125 - The score is calculated with the following variables:  
126 -  
127 - * vote_weight: 100 - (minus) 1 for each 3 days since  
128 - voted with minimum of 5.  
129 - * replies_weight: 300 - (minus) 1 for each 3 days since  
130 - replied with minimum of 5.  
131 - * page_view_weight: 10.  
132 -  
133 - * vote_score: sum(vote_weight)  
134 - * replies_score: sum(replies_weight)  
135 - * page_view_score: sum(page_view_weight)  
136 -  
137 - * score = (vote_score + replies_score + page_view_score) // 10  
138 - with minimum of 0 and maximum of 5000  
139 -  
140 - """  
141 -  
142 - if not self.subject_token:  
143 - return  
144 -  
145 - # Save this pseudo now to avoid calling the  
146 - # function N times in the loops below  
147 - now = datetime.datetime.now()  
148 - days_ago = lambda date: (now - date).days  
149 - get_score = lambda weight, created: \  
150 - max(weight - (days_ago(created) // 3), 5)  
151 -  
152 - vote_score = 0  
153 - replies_score = 0  
154 - for msg in self.message_set.all():  
155 - # Calculate replies_score  
156 - replies_score += get_score(300, msg.received_time)  
157 -  
158 - # Calculate vote_score  
159 - for vote in msg.vote_set.all():  
160 - vote_score += get_score(100, vote.created)  
161 -  
162 - # Calculate page_view_score  
163 - try:  
164 - url = reverse('thread_view', args=[self.mailinglist.name,  
165 - self.subject_token])  
166 - pagehit = PageHit.objects.get(url_path=url)  
167 - page_view_score = pagehit.hit_count * 10  
168 - except (NoReverseMatch, PageHit.DoesNotExist):  
169 - page_view_score = 0  
170 -  
171 - self.score = (page_view_score + vote_score + replies_score) // 10  
172 - self.save()  
173 -  
174 -  
175 -class Vote(models.Model):  
176 - user = models.ForeignKey(User)  
177 - message = models.ForeignKey('Message')  
178 - created = models.DateTimeField(auto_now_add=True)  
179 -  
180 - class Meta:  
181 - unique_together = ('user', 'message')  
182 -  
183 - def __unicode__(self):  
184 - return 'Vote on %s by %s' % (self.Message.id,  
185 - self.user.username)  
186 -  
187 -  
188 -class Message(models.Model):  
189 -  
190 - from_address = models.ForeignKey(EmailAddress, db_index=True)  
191 - thread = models.ForeignKey(Thread, null=True, db_index=True)  
192 - # RFC 2822 recommends to use 78 chars + CRLF (so 80 chars) for  
193 - # the max_length of a subject but most of implementations  
194 - # goes for 256. We use 512 just in case.  
195 - subject = models.CharField(max_length=512, db_index=True,  
196 - verbose_name=_(u"Subject"),  
197 - help_text=_(u"Please enter a message subject"))  
198 - subject_clean = models.CharField(max_length=512, db_index=True)  
199 - body = models.TextField(default='',  
200 - verbose_name=_(u"Message body"),  
201 - help_text=_(u"Please enter a message body"))  
202 - received_time = models.DateTimeField()  
203 - message_id = models.CharField(max_length=512)  
204 - spam = models.BooleanField(default=False)  
205 -  
206 - all_objects = models.Manager()  
207 - objects = NotSpamManager()  
208 -  
209 - class Meta:  
210 - verbose_name = _(u"Message")  
211 - verbose_name_plural = _(u"Messages")  
212 - unique_together = ('thread', 'message_id')  
213 -  
214 - def __unicode__(self):  
215 - return '(%s) %s: %s' % (self.id,  
216 - self.from_address.get_full_name(),  
217 - self.subject_clean)  
218 -  
219 - @property  
220 - def mailinglist(self):  
221 - if not self.thread or not self.thread.mailinglist:  
222 - return None  
223 -  
224 - return self.thread.mailinglist  
225 -  
226 -  
227 - def vote_list(self):  
228 - """Return a list of user that voted in this message."""  
229 -  
230 - return [vote.user for vote in self.vote_set.all()]  
231 -  
232 - def votes_count(self):  
233 - return len(self.vote_list())  
234 -  
235 - def vote(self, user):  
236 - Vote.objects.create(  
237 - message=self,  
238 - user=user  
239 - )  
240 -  
241 - def unvote(self, user):  
242 - Vote.objects.get(  
243 - message=self,  
244 - user=user  
245 - ).delete()  
246 -  
247 - @property  
248 - def url(self):  
249 - """Shortcut to get thread url"""  
250 - return reverse('thread_view', args=[self.mailinglist.name,  
251 - self.thread.subject_token])  
252 -  
253 - @property  
254 - def Description(self):  
255 - """Alias to self.body"""  
256 - return self.body  
257 -  
258 - @property  
259 - def Title(self):  
260 - """Alias to self.subject_clean"""  
261 - return self.subject_clean  
262 -  
263 - @property  
264 - def modified(self):  
265 - """Alias to self.modified"""  
266 - return self.received_time  
267 -  
268 -  
269 -class MessageMetadata(models.Model):  
270 - Message = models.ForeignKey(Message)  
271 - # Same problem here than on subjects. Read comment above  
272 - # on Message.subject  
273 - name = models.CharField(max_length=512)  
274 - value = models.TextField()  
275 -  
276 - def __unicode__(self):  
277 - return 'Email Message Id: %s - %s: %s' % (self.Message.id,  
278 - self.name, self.value)  
279 -  
colab/super_archives/queries.py
@@ -1,54 +0,0 @@ @@ -1,54 +0,0 @@
1 -  
2 -from django.core.exceptions import ObjectDoesNotExist  
3 -from colab.super_archives.models import Thread, Vote, Message, PageHit  
4 -  
5 -  
6 -def get_messages_by_date():  
7 - return Message.objects.order_by('received_time')  
8 -  
9 -  
10 -def get_messages_by_voted():  
11 - """Query for the most voted messages sorting by the sum of  
12 - voted and after by date."""  
13 -  
14 - sql = """  
15 - SELECT  
16 - count(sav.id)  
17 - FROM  
18 - super_archives_vote AS sav  
19 - WHERE  
20 - super_archives_message.id = sav.message_id  
21 - """  
22 - messages = Message.objects.extra(  
23 - select={  
24 - 'vote_count': sql,  
25 - }  
26 - )  
27 - return messages.order_by('-vote_count', 'received_time')  
28 -  
29 -  
30 -def get_first_message_in_thread(mailinglist, thread_token):  
31 - query = get_messages_by_date()  
32 - query = query.filter(thread__mailinglist__name=mailinglist)  
33 - try:  
34 - query = query.filter(thread__subject_token=thread_token)[0]  
35 - except IndexError:  
36 - raise ObjectDoesNotExist  
37 - return query  
38 -  
39 -  
40 -def get_latest_threads():  
41 - return Thread.objects.order_by('-latest_message__received_time')  
42 -  
43 -  
44 -def get_hottest_threads():  
45 - return Thread.objects.order_by('-score', '-latest_message__received_time')  
46 -  
47 -  
48 -def get_page_hits(path_info):  
49 - pagehit = PageHit.objects.filter(url_path=path_info)  
50 -  
51 - if pagehit:  
52 - return pagehit[0].hit_count  
53 - return 0  
54 -  
colab/super_archives/templates/message-list.html
@@ -1,68 +0,0 @@ @@ -1,68 +0,0 @@
1 -{% extends "base.html" %}  
2 -{% load i18n %}  
3 -{% load append_to_get %}  
4 -{% block main-content %}  
5 -<div id="message-list">  
6 - <h2 class="span-5">{% trans "Discussions" %}</h2>  
7 - <hr/>  
8 -  
9 - <div class="span-5 border filters">  
10 - <h3>{% trans "Filters" %}</h3>  
11 -  
12 - <h4>{% trans "Sort by" %}</h4>  
13 - <ul>  
14 - <li {% ifequal order_by "hottest" %} class="selected" title="{% trans "Remove filter" %}" {% endifequal %}>  
15 - <a href="{% ifequal order_by "hottest" %} {% append_to_get order="",p=1 %} {% else %} {% append_to_get order='hottest',p=1 %} {% endifequal %}">  
16 - {% trans "Relevance" %}</a></li>  
17 - <li {% ifequal order_by "latest" %} class="selected" title="{% trans "Remove filter" %}" {% endifequal %}>  
18 - <a href="{% ifequal order_by "latest" %} {% append_to_get order="",p=1 %} {% else %} {% append_to_get order='latest',p=1 %} {% endifequal %}">  
19 - {% trans "Recent activity" %}</a></li>  
20 - </ul>  
21 -  
22 - <hr class="space" />  
23 -  
24 - <h4>{% trans "Lists" %}</h4>  
25 - <ul>  
26 - {% for list in lists %}  
27 - <li {% ifequal list.name selected_list %} class="selected" title="{% trans "Remove filter" %}" {% endifequal %}>  
28 - <a href="{% ifnotequal list.name selected_list %} {% append_to_get list=list.name,p=1 %} {% else %} {% append_to_get list="",p=1 %}  
29 - {% endifnotequal %}">{{ list.name }}</a></li>  
30 - {% endfor %}  
31 - </ul>  
32 - </div>  
33 -  
34 - <div class="span-17 prepend-1 last">  
35 - <ul>  
36 - {% for thread in threads.object_list %}  
37 - {% include "message-preview.html" with doc=thread.latest_message %}  
38 - {% empty %}  
39 - <br/><br/>  
40 - <span class="span-18 center large">  
41 - <b>{% trans "No discussion found" %}</b>  
42 - </span>  
43 - {% endfor %}  
44 - </ul>  
45 - <hr class="space"/>  
46 -  
47 - {% if n_results %}  
48 - <div class="pagination center">  
49 - <span class="step-links">  
50 - {% if threads.has_previous %}  
51 - <a href="{% append_to_get p=threads.previous_page_number %}">{% trans "Previous" %}</a>  
52 - {% endif %}  
53 -  
54 - <span class="current">  
55 - {% trans "Page" %} {{ threads.number }} {% trans "of" %} {{ threads.paginator.num_pages }}  
56 - </span>  
57 -  
58 - {% if threads.has_next %}  
59 - <a href="{% append_to_get p=threads.next_page_number %}">{% trans "Next" %}</a>  
60 - {% endif %}  
61 - </span>  
62 - </div>  
63 - {% endif %}  
64 -  
65 - </div>  
66 -</div>  
67 -  
68 -{% endblock %}  
colab/super_archives/templates/message-preview.html
@@ -1,51 +0,0 @@ @@ -1,51 +0,0 @@
1 -{% load i18n %}  
2 -  
3 -{% if doc.Title %}  
4 -<li class="preview-message">  
5 - {% if doc.Type %}  
6 - <img alt="{{ doc.Type }}" title="{{ doc.Type }}"  
7 - src="{{ STATIC_URL }}img/{{ doc.Type }}.png" />  
8 - {% else %}  
9 - <img alt="thread" title="thread"  
10 - src="{{ STATIC_URL }}img/thread.png" />  
11 - {% endif %}  
12 -  
13 - {% if doc.mailinglist %}  
14 - <a href="{% url super_archives.views.list_messages %}?list={{ doc.mailinglist }}">  
15 - <span class="tag">{{ doc.mailinglist }}</span>  
16 - </a>  
17 - {% endif %}  
18 -  
19 - <span class="subject">  
20 - <a href="{{ doc.url }}"  
21 - {% if  
22 - title="{% filter striptags|truncatewords:50 %}  
23 - {{ doc.Description|escape }}  
24 - {% endfilter %}">  
25 - {{ doc.Title }}  
26 - </a>  
27 - </span>  
28 -  
29 - <span class="quiet">-  
30 - {{ doc.Description|striptags }}  
31 - </span>  
32 -  
33 - <div class="quiet">  
34 - <span class="left">  
35 - {% trans "by" %}  
36 - {% if doc.from_address.get_full_name %}  
37 - <a href="{{ doc.from_address.get_profile_link }}">  
38 - {{ doc.from_address.get_full_name }}  
39 - </a>  
40 - {% else %}  
41 - {% firstof doc.last_author doc.Creator _("anônimo") %}  
42 - {% endif %}  
43 - </span>  
44 -  
45 - <span class="right">  
46 - {{ doc.modified|timesince }}  
47 - {% trans "back" %}  
48 - </span>  
49 - </div>  
50 -</li>  
51 -{% endif %}  
colab/super_archives/templates/message-thread.html
@@ -1,77 +0,0 @@ @@ -1,77 +0,0 @@
1 -{% extends "base.html" %}  
2 -{% load i18n %}  
3 -{% load append_to_get %}  
4 -{% block main-content %}  
5 - <div id="vote-notification" class="error hide"></div>  
6 -  
7 - <h2>{{ first_msg.subject_clean }}</h2>  
8 - <hr/>  
9 - <div class="span-17 border">  
10 - <ul>  
11 - {% for email in emails %}  
12 - <li>  
13 - <div id="msg-{{ email.id }}" class="email_message">  
14 - <div class="span-3 center">  
15 - <div>  
16 - <a href="{{ email.from_address.get_profile_link }}">  
17 - <img class="avatar" width="80px" heigth="80px"  
18 - src="http://www.gravatar.com/avatar/{{ email.from_address.md5 }}?s=80&d=identicon" />  
19 - <span>{% firstof email.from_address.get_full_name "Anônimo" %}</span>  
20 - </a>  
21 - </div>  
22 - <p>{{ email.received_time|date:"SHORT_DATETIME_FORMAT" }}</p>  
23 -  
24 - <div class="plus">  
25 - <span>{{ email.votes_count }}</span>  
26 - <img title="{% trans 'Vote' %}" class="right" src="{{ STATIC_URL }}img/plus.png">  
27 - </div>  
28 -  
29 - <p class="minus {% if not user in email.vote_list %}hide{% endif %}">  
30 - <a href="#">{% trans "Remove votes" %}</a>  
31 - </p>  
32 - </div>  
33 -  
34 - <div class="span-13">  
35 - <pre>{{ email.body }}</pre>  
36 - </div>  
37 - </div>  
38 - {% if not forloop.last %}  
39 - <hr/>  
40 - {% endif %}  
41 - </li>  
42 - {% endfor %}  
43 - </ul>  
44 - </div>  
45 - <div class="span-6 filters last">  
46 - <h4><b>{% trans "Order by" %}:</b></h4>  
47 - <ul>  
48 - <li><a href="{% append_to_get order='voted' %}">{% trans "Votes" %}</a></li>  
49 - <li><a href="{% append_to_get order='date' %}">{% trans "Data" %}</a></li>  
50 - </ul>  
51 -  
52 - <hr class="space"/>  
53 -  
54 - <h4><b>{% trans "Statistics:" %}</b></h4>  
55 -  
56 - <ul>  
57 - <li class="quiet">{% trans "started at" %}  
58 - <h4>{{ first_msg.received_time|timesince }} {% trans "back" %}</h4>  
59 - </li>  
60 - <li class="quiet">{% trans "viewed" %}  
61 - <h4>{{ pagehits }} {% trans "times" %}</h4>  
62 - </li>  
63 - <li class="quiet">{% trans "answered" %}  
64 - <h4>{{ emails|length }} {% trans "times" %}</h4>  
65 - </li>  
66 - <li class="quiet">{% trans "voted" %}  
67 - <h4>{{ total_votes }} {% trans "times" %}</h4>  
68 - </li>  
69 - </ul>  
70 -  
71 - </div>  
72 -  
73 - <script type="text/javascript" charset="utf-8">  
74 - pagehit("{{ request.path_info }}");  
75 - </script>  
76 -  
77 -{% endblock %}  
colab/super_archives/templatetags/__init__.py
colab/super_archives/templatetags/append_to_get.py
@@ -1,56 +0,0 @@ @@ -1,56 +0,0 @@
1 -  
2 -import urllib  
3 -from django import template  
4 -  
5 -register = template.Library()  
6 -  
7 -"""  
8 -Decorator to facilitate template tag creation  
9 -"""  
10 -def easy_tag(func):  
11 - """deal with the repetitive parts of parsing template tags"""  
12 - def inner(parser, token):  
13 - #print token  
14 - try:  
15 - return func(*token.split_contents())  
16 - except TypeError:  
17 - raise template.TemplateSyntaxError('Bad arguments for tag "%s"' %  
18 - token.split_contents()[0])  
19 - inner.__name__ = func.__name__  
20 - inner.__doc__ = inner.__doc__  
21 - return inner  
22 -  
23 -  
24 -class AppendGetNode(template.Node):  
25 - def __init__(self, dict):  
26 - self.dict_pairs = {}  
27 - for pair in dict.split(','):  
28 - pair = pair.split('=')  
29 - self.dict_pairs[pair[0]] = template.Variable(pair[1])  
30 -  
31 - def render(self, context):  
32 - get = context['request'].GET.copy()  
33 -  
34 - for key in self.dict_pairs:  
35 - get[key] = self.dict_pairs[key].resolve(context)  
36 -  
37 - path = context['request'].META['PATH_INFO']  
38 -  
39 - if len(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)  
50 -  
51 - return path  
52 -  
53 -@register.tag()  
54 -@easy_tag  
55 -def append_to_get(_tag_name, dict):  
56 - return AppendGetNode(dict)  
colab/super_archives/templatetags/form_field.py
@@ -1,64 +0,0 @@ @@ -1,64 +0,0 @@
1 -from django import template  
2 -from django import forms  
3 -  
4 -def render_form_field(parser, token):  
5 - variables = token.split_contents()  
6 -  
7 - if len(variables) == 2:  
8 - tag_name, form_field = variables  
9 - default_value = 'None'  
10 - elif len(variables) == 3:  
11 - tag_name, form_field, default_value = variables  
12 - else:  
13 - raise template.TemplateSyntaxError  
14 -  
15 - return RenderFormField(form_field, default_value)  
16 -  
17 -  
18 -class RenderFormField(template.Node):  
19 -  
20 - def __init__(self, form_field, default_value):  
21 - self.form_field_nocontext = template.Variable(form_field)  
22 - self.default_value_nocontext = template.Variable(default_value)  
23 -  
24 - def render(self, context):  
25 - editable = context.get('editable', True)  
26 -  
27 - class_ = u''  
28 - errors = u''  
29 - form_field_tag = u''  
30 - try:  
31 - form_field = self.form_field_nocontext.resolve(context)  
32 - except template.VariableDoesNotExist:  
33 - return u''  
34 -  
35 - if form_field.errors:  
36 - class_ += u'error'  
37 - if form_field.field.required:  
38 - class_ += u' required'  
39 - if form_field.errors:  
40 - errors = u'<br/>' + form_field.errors.as_text()  
41 -  
42 - try:  
43 - default_value = self.default_value_nocontext.resolve(context)  
44 - except template.VariableDoesNotExist:  
45 - default_value = u''  
46 -  
47 - if editable:  
48 - form_field_tag = u'<br/>' + unicode(form_field)  
49 - elif isinstance(form_field.field, forms.URLField):  
50 - form_field_tag = u"""<a href="%s" target="_blank">%s</a>""" % (  
51 - default_value, default_value)  
52 - else:  
53 - form_field_tag = default_value  
54 -  
55 - return u"""<p class="%s">%s: %s %s</p>""" % (  
56 - class_,  
57 - form_field.label_tag(),  
58 - form_field_tag,  
59 - errors  
60 - )  
61 -  
62 -  
63 -register = template.Library()  
64 -register.tag('render_form_field', render_form_field)  
colab/super_archives/tests.py
@@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
1 -"""  
2 -This file demonstrates writing tests using the unittest module. These will pass  
3 -when you run "manage.py test".  
4 -  
5 -Replace this with more appropriate tests for your application.  
6 -"""  
7 -  
8 -from django.test import TestCase  
9 -  
10 -  
11 -class SimpleTest(TestCase):  
12 - def test_basic_addition(self):  
13 - """  
14 - Tests that 1 + 1 always equals 2.  
15 - """  
16 - self.assertEqual(1 + 1, 2)  
colab/super_archives/urls.py
@@ -1,9 +0,0 @@ @@ -1,9 +0,0 @@
1 -from django.conf.urls.defaults import patterns, include, url  
2 -  
3 -urlpatterns = patterns('',  
4 -# url(r'thread/(?P<thread>\d+)/$', 'super_archives.views.thread', name='thread'),  
5 - url(r'thread/(?P<mailinglist>[-\w]+)/(?P<thread_token>[-\w]+)$',  
6 - 'colab.super_archives.views.thread', name="thread_view"),  
7 - url(r'thread/$',  
8 - 'colab.super_archives.views.list_messages', name='thread_list')  
9 -)  
colab/super_archives/validators.py
@@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -  
3 -from django.core.exceptions import ValidationError  
4 -  
5 -class UniqueValidator(object):  
6 -  
7 - def __init__(self, model, field_name):  
8 - self.model = model  
9 - self.field_name = field_name  
10 -  
11 - def __call__(self, value):  
12 - result = self.model.objects.filter(**{self.field_name: value})  
13 - if result:  
14 - msg = u'Já existente. Escolha outro.'  
15 - raise ValidationError(msg)  
colab/super_archives/views.py
@@ -1,80 +0,0 @@ @@ -1,80 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -  
3 -from django.http import Http404  
4 -from django.template import RequestContext  
5 -from django.core.paginator import Paginator  
6 -from django.core.exceptions import ObjectDoesNotExist  
7 -from django.shortcuts import render_to_response, get_list_or_404  
8 -  
9 -from colab.super_archives import queries  
10 -from colab.super_archives.models import MailingList, Thread  
11 -  
12 -  
13 -def thread(request, mailinglist, thread_token):  
14 -  
15 - try:  
16 - first_message = queries.get_first_message_in_thread(mailinglist, thread_token)  
17 - except ObjectDoesNotExist:  
18 - raise Http404  
19 - order_by = request.GET.get('order')  
20 - if order_by == 'voted':  
21 - msgs_query = queries.get_messages_by_voted()  
22 - else:  
23 - msgs_query = queries.get_messages_by_date()  
24 -  
25 - msgs_query = msgs_query.filter(thread__subject_token=thread_token)  
26 - msgs_query = msgs_query.filter(thread__mailinglist__name=mailinglist)  
27 - emails = msgs_query.exclude(id=first_message.id)  
28 -  
29 - total_votes = first_message.votes_count()  
30 - for email in emails:  
31 - total_votes += email.votes_count()  
32 -  
33 - # Update relevance score  
34 - query = Thread.objects.filter(mailinglist__name=mailinglist)  
35 - thread = query.get(subject_token=thread_token)  
36 - thread.update_score()  
37 -  
38 - template_data = {  
39 - 'first_msg': first_message,  
40 - 'emails': [first_message] + list(emails),  
41 - 'pagehits': queries.get_page_hits(request.path_info),  
42 - 'total_votes': total_votes,  
43 - }  
44 -  
45 - return render_to_response('message-thread.html', template_data,  
46 - RequestContext(request))  
47 -  
48 -  
49 -def list_messages(request):  
50 -  
51 - selected_list = request.GET.get('list')  
52 -  
53 - order_by = request.GET.get('order')  
54 - if order_by == 'hottest':  
55 - threads = queries.get_hottest_threads()  
56 - else:  
57 - threads = queries.get_latest_threads()  
58 -  
59 - mail_list = request.GET.get('list')  
60 - if mail_list:  
61 - threads = threads.filter(mailinglist__name=mail_list)  
62 -  
63 - paginator = Paginator(threads, 16)  
64 - try:  
65 - page = int(request.GET.get('p', '1'))  
66 - except ValueError:  
67 - page = 1  
68 - threads = paginator.page(page)  
69 -  
70 - lists = MailingList.objects.all()  
71 -  
72 - template_data = {  
73 - 'lists': lists,  
74 - 'n_results': paginator.count,  
75 - 'threads': threads,  
76 - 'selected_list': selected_list,  
77 - 'order_by': order_by,  
78 - }  
79 - return render_to_response('message-list.html', template_data,  
80 - RequestContext(request))  
src/api/__init__.py 0 → 100644
src/api/handlers.py 0 → 100644
@@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
  1 +
  2 +from django.core.cache import cache
  3 +from django.db import IntegrityError
  4 +from django.core.exceptions import ObjectDoesNotExist
  5 +from django.contrib.auth.decorators import login_required
  6 +
  7 +from piston.utils import rc
  8 +from piston.handler import BaseHandler
  9 +
  10 +from colab import solrutils
  11 +from colab.super_archives.models import Message, PageHit
  12 +
  13 +
  14 +class VoteHandler(BaseHandler):
  15 + allowed_methods = ('GET', 'POST', 'DELETE')
  16 +
  17 + def create(self, request, message_id):
  18 + if not request.user.is_authenticated():
  19 + return rc.FORBIDDEN
  20 +
  21 + try:
  22 + Message.objects.get(id=message_id).vote(request.user)
  23 + except IntegrityError:
  24 + return rc.DUPLICATE_ENTRY
  25 +
  26 + return rc.CREATED
  27 +
  28 + def read(self, request, message_id):
  29 + return Message.objects.get(id=message_id).votes_count()
  30 +
  31 + def delete(self, request, message_id):
  32 + if not request.user.is_authenticated():
  33 + return rc.FORBIDDEN
  34 +
  35 + try:
  36 + Message.objects.get(id=message_id).unvote(request.user)
  37 + except ObjectDoesNotExist:
  38 + return rc.NOT_HERE
  39 +
  40 + return rc.DELETED
  41 +
  42 +
  43 +class CountHandler(BaseHandler):
  44 + allowed_methods = ('POST')
  45 +
  46 + def create(self, request):
  47 + """Add one page view for the given url"""
  48 +
  49 + # If missing the path_info argument we can't do anything
  50 + path_info = request.POST.get('path_info')
  51 + if not path_info:
  52 + return rc.BAD_REQUEST
  53 +
  54 + # Here we cache the user's IP to ensure that the same
  55 + # IP won't hit the same page again for while
  56 + ip_addr = request.META.get('REMOTE_ADDR')
  57 + page_hits_cache = cache.get('page_hits', {})
  58 + duplicate = page_hits_cache.get(path_info, {}).get(ip_addr)
  59 +
  60 + if duplicate:
  61 + return rc.DUPLICATE_ENTRY
  62 + else:
  63 + page_hits_cache.update({path_info: {ip_addr: True }})
  64 + cache.set('page_hits', page_hits_cache)
  65 +
  66 + # Everything ok, so just increment the page count
  67 + page_hit = PageHit.objects.get_or_create(url_path=path_info)[0]
  68 + page_hit.hit_count += 1
  69 + page_hit.save()
  70 +
  71 + return rc.CREATED
  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)
src/api/urls.py 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +from django.conf.urls.defaults import patterns, include, url
  2 +
  3 +from piston.resource import Resource
  4 +
  5 +from colab.api.handlers import VoteHandler, CountHandler, SearchHandler
  6 +
  7 +
  8 +vote_handler = Resource(VoteHandler)
  9 +count_handler = Resource(CountHandler)
  10 +search_handler = Resource(SearchHandler)
  11 +
  12 +urlpatterns = patterns('',
  13 + url(r'message/(?P<message_id>\d+)/vote$', vote_handler),
  14 + url(r'hit/$', count_handler),
  15 + url(r'search/$', search_handler),
  16 +)
src/rss/__init__.py 0 → 100644
src/rss/feeds.py 0 → 100644
@@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
  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'Latest Discussions')
  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 + title = '[' + item.mailinglist.name + '] '
  23 + title += item.latest_message.subject_clean
  24 + return title
  25 +
  26 + def item_description(self, item):
  27 + return item.latest_message.body
  28 +
  29 +
  30 +class HottestThreadsFeeds(Feed):
  31 + title = _(u'Discussions Most Relevance')
  32 + link = '/rss/threads/hottest/'
  33 +
  34 + def items(self):
  35 + return queries.get_hottest_threads()[:20]
  36 +
  37 + def item_link(self, item):
  38 + return item.latest_message.url
  39 +
  40 + def item_title(self, item):
  41 + title = '[' + item.mailinglist.name + '] '
  42 + title += item.latest_message.subject_clean
  43 + return title
  44 +
  45 + def item_description(self, item):
  46 + return item.latest_message.body
  47 +
  48 +
  49 +class LatestColabFeeds(Feed):
  50 + title = _(u'Latest collaborations')
  51 + link = '/rss/colab/latest/'
  52 +
  53 + def items(self):
  54 + items = solrutils.get_latest_collaborations(20)
  55 + return items
  56 +
  57 + def item_title(self, item):
  58 + type_ = item.get('Type') + ': '
  59 + mailinglist = item.get('mailinglist')
  60 +
  61 + if mailinglist:
  62 + prefix = type_ + mailinglist + ' - '
  63 + else:
  64 + prefix = type_
  65 +
  66 + return prefix + item.get('Title')
  67 +
  68 + def item_description(self, item):
  69 + return item.get('Description')
  70 +
  71 + def item_link(self, item):
  72 + if item.get('Type') != 'thread':
  73 + url = item.get('url')
  74 + else:
  75 + url = 'http://colab.interlegis.leg.br'
  76 + url += item.get('url')
  77 + return url
  78 +
src/rss/urls.py 0 → 100644
@@ -0,0 +1,9 @@ @@ -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(), name='rss_latest_threads'),
  6 + url(r'colab/latest/$', feeds.LatestColabFeeds(), name='rss_latest_colab'),
  7 + url(r'threads/hottest/$', feeds.HottestThreadsFeeds(), name='rss_hottest_threads'),
  8 +)
  9 +
src/super_archives/__init__.py 0 → 100644
src/super_archives/admin.py 0 → 100644
@@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
  1 +
  2 +from django.contrib import admin
  3 +from colab.super_archives.models import Message, Thread, UserProfile
  4 +
  5 +class MessageAdmin(admin.ModelAdmin):
  6 + list_filter = ('spam', 'thread__mailinglist', 'received_time', )
  7 + search_fields = (
  8 + 'id',
  9 + 'subject',
  10 + 'subject_clean',
  11 + 'body',
  12 + 'from_address__real_name',
  13 + 'from_address__address',
  14 + 'from_address__user__first_name',
  15 + 'from_address__user__last_name',
  16 + 'from_address__user__username',
  17 + )
  18 + readonly_fields = ('thread', 'from_address', 'mailinglist')
  19 +
  20 +
  21 +class ThreadAdmin(admin.ModelAdmin):
  22 + list_filter = ('spam', 'mailinglist', 'message__received_time',)
  23 + search_fields = (
  24 + 'id',
  25 + 'subject_token',
  26 + 'message__subject',
  27 + 'message__subject_clean',
  28 + 'message__from_address__real_name',
  29 + 'message__from_address__address',
  30 + 'message__from_address__user__first_name',
  31 + 'message__from_address__user__last_name',
  32 + 'message__from_address__user__username',
  33 + )
  34 +
  35 + readonly_fields = (
  36 + 'mailinglist',
  37 + 'subject_token',
  38 + 'latest_message',
  39 + 'score',
  40 + )
  41 +
  42 + fields = (
  43 + 'mailinglist',
  44 + 'subject_token',
  45 + 'latest_message',
  46 + 'score',
  47 + 'spam',
  48 + )
  49 +
  50 +
  51 +admin.site.register(UserProfile)
  52 +admin.site.register(Thread, ThreadAdmin)
  53 +admin.site.register(Message, MessageAdmin)
  54 +
src/super_archives/fixtures/initial_data.json 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +[
  2 + {
  3 + "pk": 1,
  4 + "model": "auth.group",
  5 + "fields": {
  6 + "name": "developer",
  7 + "permissions": []
  8 + }
  9 + }
  10 +]
src/super_archives/forms.py 0 → 100644
@@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
  1 +# -*- coding: utf-8 -*-
  2 +
  3 +from django import forms
  4 +from django.core.exceptions import ValidationError
  5 +from django.contrib.auth.models import User
  6 +from django.contrib.auth.forms import UserCreationForm as UserCreationForm_
  7 +from django.utils.translation import ugettext_lazy as _
  8 +
  9 +from colab.super_archives.models import MailingList
  10 +from colab.super_archives.validators import UniqueValidator
  11 +
  12 +# XXX: I know that this code does not look nice AT ALL.
  13 +# probably it should be implemented using formsets instead of
  14 +# the hack below. Feel free to improve it! :)
  15 +
  16 +# User fields
  17 +username_field = UserCreationForm_().fields.get(u'username')
  18 +first_name_field = forms.CharField(max_length=30, label=_(u'Name'))
  19 +last_name_field = forms.CharField(max_length=30, label=_(u'Last name'))
  20 +email_field = forms.EmailField(validators=[UniqueValidator(User, 'email')])
  21 +
  22 +# UserProfile fields
  23 +institution_field = forms.CharField(max_length=120, label=_(u'Institution'),
  24 + required=False)
  25 +role_field = forms.CharField(max_length=60, label=_(u'Function'), required=False)
  26 +twitter_field = forms.URLField(label=_(u'Twitter'), required=False)
  27 +facebook_field = forms.URLField(label=_(u'Facebook'), required=False)
  28 +google_talk_field = forms.EmailField(label=_(u'Google Talk'), required=False)
  29 +webpage_field = forms.URLField(label=_(u'Personal Website/Blog'), required=False)
  30 +
  31 +all_lists = MailingList.objects.all()
  32 +lists_names = []
  33 +for list_ in all_lists:
  34 + choice = (list_.name, list_.name)
  35 + lists_names.append(choice)
  36 +
  37 +lists_field = forms.MultipleChoiceField(
  38 + label=u'Listas',
  39 + required=False,
  40 + widget=forms.CheckboxSelectMultiple,
  41 + choices=lists_names
  42 +)
  43 +
  44 +
  45 +class UserCreationForm(UserCreationForm_):
  46 + first_name = first_name_field
  47 + last_name = last_name_field
  48 + email = email_field
  49 + institution = institution_field
  50 + role = role_field
  51 + twitter = twitter_field
  52 + facebook = facebook_field
  53 + google_talk = google_talk_field
  54 + webpage = webpage_field
  55 + lists = lists_field
  56 +
  57 +
  58 +class UserUpdateForm(forms.Form):
  59 + username = username_field
  60 + username.required = False
  61 + institution = institution_field
  62 + role = role_field
  63 + twitter = twitter_field
  64 + facebook = facebook_field
  65 + google_talk = google_talk_field
  66 + webpage = webpage_field
src/super_archives/management/__init__.py 0 → 100644
src/super_archives/management/commands/__init__.py 0 → 100644
src/super_archives/management/commands/import_emails.py 0 → 100644
@@ -0,0 +1,258 @@ @@ -0,0 +1,258 @@
  1 +#!/usr/bin/env python
  2 +# -*- encoding: utf-8 -*-
  3 +
  4 +"""Import emails from a mailman storage to the django database."""
  5 +
  6 +import os
  7 +import re
  8 +import sys
  9 +import mailbox
  10 +from optparse import make_option
  11 +
  12 +from django.db import transaction
  13 +from django.template.defaultfilters import slugify
  14 +from django.core.management.base import BaseCommand, CommandError
  15 +
  16 +from colab.super_archives.models import MailingList, Message, \
  17 + Thread, EmailAddress
  18 +from colab.super_archives.management.commands.message import Message as \
  19 + CustomMessage
  20 +
  21 +
  22 +class Command(BaseCommand, object):
  23 + """Get emails from mailman archives and import them in the django db. """
  24 +
  25 + help = __doc__
  26 +
  27 + default_archives_path = '/var/lib/mailman/archives/private'
  28 + RE_SUBJECT_CLEAN = re.compile('((re|res|fw|fwd|en|enc):)|\[.*?\]',
  29 + re.IGNORECASE)
  30 + THREAD_CACHE = {}
  31 + EMAIL_ADDR_CACHE = {}
  32 +
  33 + # A new command line option to get the dump file to parse.
  34 + option_list = BaseCommand.option_list + (
  35 + make_option('--archives_path',
  36 + dest='archives_path',
  37 + help='Path of email archives to be imported. (default: %s)' %
  38 + default_archives_path,
  39 + default=default_archives_path),
  40 +
  41 + make_option('--exclude-list',
  42 + dest='exclude_lists',
  43 + help=("Mailing list that won't be imported. It can be used many"
  44 + "times for more than one list."),
  45 + action='append',
  46 + default=None),
  47 +
  48 + make_option('--all',
  49 + dest='all',
  50 + help='Import all messages (default: False)',
  51 + action="store_true",
  52 + default=False),
  53 + )
  54 +
  55 + def __init__(self, *args, **kwargs):
  56 + super(Command, self).__init__(*args, **kwargs)
  57 +
  58 + def log(self, msg, error=False):
  59 + """Log message helper."""
  60 + output = self.stdout
  61 + if error:
  62 + output = self.stderr
  63 +
  64 + output.write(msg)
  65 + output.write('\n')
  66 +
  67 + def parse_emails(self, email_filename, index=0):
  68 + """Generator function that parse and extract emails from the file
  69 + `email_filename` starting from the position `index`.
  70 +
  71 + Yield: An instance of `mailbox.mboxMessage` for each email in the
  72 + file.
  73 +
  74 + """
  75 + self.log("Parsing email dump: %s." % email_filename)
  76 + mbox = mailbox.mbox(email_filename, factory=CustomMessage)
  77 +
  78 + # Get each email from mbox file
  79 + #
  80 + # The following implementation was used because the object
  81 + # mbox does not support slicing. Converting the object to a
  82 + # tuple (as represented in the code down here) was a valid
  83 + # option but its performance was too poor.
  84 + #
  85 + #for message in tuple(mbox)[index:]:
  86 + # yield message
  87 + #
  88 + key = index
  89 + while mbox.has_key(key):
  90 + key += 1
  91 + yield key-1, mbox[key-1]
  92 +
  93 + def get_emails(self, mailinglist_dir, all, exclude_lists):
  94 + """Generator function that get the emails from each mailing
  95 + list dump dirctory. If `all` is set to True all the emails in the
  96 + mbox will be imported if not it will just resume from the last
  97 + message previously imported. The lists set in `exclude_lists`
  98 + won't be imported.
  99 +
  100 + Yield: A tuple in the form: (mailing list name, email message).
  101 +
  102 + """
  103 + self.log("Getting emails dumps from: %s" % mailinglist_dir)
  104 +
  105 + # Get the list of directories ending with .mbox
  106 + mailing_lists_mboxes = (mbox for mbox in os.listdir(mailinglist_dir)
  107 + if mbox.endswith('.mbox'))
  108 +
  109 + # Get messages from each mbox
  110 + for mbox in mailing_lists_mboxes:
  111 + mbox_path = os.path.join(mailinglist_dir, mbox, mbox)
  112 + mailinglist_name = mbox.split('.')[0]
  113 +
  114 + # Check if the mailinglist is set not to be imported
  115 + if exclude_lists and mailinglist_name in exclude_lists:
  116 + continue
  117 +
  118 + # Find the index of the last imported message
  119 + if all:
  120 + n_msgs = 0
  121 + else:
  122 + try:
  123 + mailinglist = MailingList.objects.get(
  124 + name=mailinglist_name)
  125 + n_msgs = mailinglist.last_imported_index
  126 + except MailingList.DoesNotExist:
  127 + n_msgs = 0
  128 +
  129 + for index, msg in self.parse_emails(mbox_path, n_msgs):
  130 + yield mailinglist_name, msg, index
  131 +
  132 + def get_thread(self, email, mailinglist):
  133 + """Group messages by thread looking for similar subjects"""
  134 +
  135 + subject_slug = slugify(email.subject_clean)
  136 + thread = self.THREAD_CACHE.get(subject_slug, {}).get(mailinglist.id)
  137 + if thread is None:
  138 + thread = Thread.objects.get_or_create(
  139 + mailinglist=mailinglist,
  140 + subject_token=subject_slug
  141 + )[0]
  142 +
  143 + if self.THREAD_CACHE.get(subject_slug) is None:
  144 + self.THREAD_CACHE[subject_slug] = dict()
  145 + self.THREAD_CACHE[subject_slug][mailinglist.id] = thread
  146 +
  147 + thread.latest_message = email
  148 + thread.save()
  149 + return thread
  150 +
  151 + def save_email(self, list_name, email_msg, index):
  152 + """Save email message into the database."""
  153 +
  154 + # Update last imported message into the DB
  155 + mailinglist, created = MailingList.objects.get_or_create(name=list_name)
  156 + mailinglist.last_imported_index = index
  157 +
  158 + if created:
  159 + # if the mailinglist is newly created it's sure that the message
  160 + # is not in the DB yet.
  161 + self.create_email(mailinglist, email_msg)
  162 +
  163 + else:
  164 + # If the message is already at the database don't do anything
  165 + try:
  166 + messages = Message.objects.get(
  167 + message_id=email_msg.get('Message-ID'),
  168 + thread__mailinglist=mailinglist
  169 + )
  170 +
  171 + except Message.DoesNotExist:
  172 + self.create_email(mailinglist, email_msg)
  173 +
  174 + mailinglist.save()
  175 +
  176 + def create_email(self, mailinglist, email_msg):
  177 +
  178 + real_name, from_ = email_msg.get_from_addr()
  179 +
  180 + email_addr = self.EMAIL_ADDR_CACHE.get(from_)
  181 + if email_addr is None:
  182 + email_addr = EmailAddress.objects.get_or_create(
  183 + address=from_)[0]
  184 + self.EMAIL_ADDR_CACHE[from_] = email_addr
  185 +
  186 + if not email_addr.real_name and real_name:
  187 + email_addr.real_name = real_name[:64]
  188 + email_addr.save()
  189 +
  190 + subject = email_msg.get_subject()
  191 +
  192 + email = Message.objects.create(
  193 + message_id=email_msg.get('Message-ID'),
  194 + from_address=email_addr,
  195 + subject=subject,
  196 + subject_clean=self.RE_SUBJECT_CLEAN.sub('', subject).strip(),
  197 + body=email_msg.get_body(),
  198 + received_time=email_msg.get_received_datetime(),
  199 + )
  200 + email.thread = self.get_thread(email, mailinglist)
  201 + email.save()
  202 +
  203 + @transaction.commit_manually
  204 + def import_emails(self, archives_path, all, exclude_lists=None):
  205 + """Get emails from the filesystem from the `archives_path`
  206 + and store them into the database. If `all` is set to True all
  207 + the filesystem storage will be imported otherwise the
  208 + importation will resume from the last message previously
  209 + imported. The lists set in `exclude_lists` won't be imported.
  210 +
  211 + """
  212 +
  213 + count = 0
  214 + email_generator = self.get_emails(archives_path, all, exclude_lists)
  215 + for mailinglist_name, msg, index in email_generator:
  216 + try:
  217 + self.save_email(mailinglist_name, msg, index)
  218 + except:
  219 + # This anti-pattern is needed to avoid the transations to
  220 + # get stuck in case of errors.
  221 + transaction.rollback()
  222 + raise
  223 +
  224 + count += 1
  225 + if count % 1000 == 0:
  226 + transaction.commit()
  227 +
  228 + transaction.commit()
  229 +
  230 + def handle(self, *args, **options):
  231 + """Main command method."""
  232 +
  233 + lock_file = '/var/lock/colab/import_emails.lock'
  234 +
  235 + # Already running, so quit
  236 + if os.path.exists(lock_file):
  237 + self.log(("This script is already running. (If your are sure it's "
  238 + "not please delete the lock file in %s')") % lock_file)
  239 + sys.exit(0)
  240 +
  241 + if not os.path.exists(os.path.dirname(lock_file)):
  242 + os.mkdir(os.path.dirname(lock_file), 0755)
  243 +
  244 + run_lock = file(lock_file, 'w')
  245 + run_lock.close()
  246 +
  247 + archives_path = options.get('archives_path')
  248 + self.log('Using archives_path `%s`' % self.default_archives_path)
  249 +
  250 + if not os.path.exists(archives_path):
  251 + raise CommandError('archives_path (%s) does not exist' %
  252 + archives_path)
  253 +
  254 + self.import_emails(archives_path,
  255 + options.get('all'), options.get('exclude_lists'))
  256 +
  257 + os.remove(lock_file)
  258 +
src/super_archives/management/commands/message.py 0 → 100644
@@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
  1 +
  2 +import re
  3 +import pytz
  4 +import email
  5 +import codecs
  6 +import mailbox
  7 +import datetime
  8 +from email.iterators import typed_subpart_iterator
  9 +
  10 +import chardet
  11 +
  12 +
  13 +def get_charset(message, default='ASCII'):
  14 + """Get the message charset"""
  15 +
  16 + charset = message.get_content_charset()
  17 +
  18 + if not charset:
  19 + charset = message.get_charset()
  20 +
  21 + if not charset:
  22 + charset = default
  23 +
  24 + try:
  25 + codecs.lookup(charset)
  26 + except LookupError:
  27 + charset = default
  28 +
  29 + return charset
  30 +
  31 +
  32 +class Message(mailbox.mboxMessage):
  33 +
  34 + RECEIVED_DELIMITER = re.compile('\n|;')
  35 +
  36 + def get_subject(self):
  37 + subject = email.header.decode_header(self['Subject'])
  38 +
  39 + if isinstance(subject, list):
  40 + new_subject = u''
  41 + for text_part, encoding in subject:
  42 + if not encoding:
  43 + encoding = get_charset(self)
  44 +
  45 + try:
  46 + new_subject += unicode(text_part, encoding)
  47 + except (UnicodeDecodeError, LookupError):
  48 + try:
  49 + new_subject += unicode(text_part, get_charset(self))
  50 + except (UnicodeDecodeError, LookupError):
  51 + encoding = chardet.detect(text_part)['encoding']
  52 + new_subject += unicode(text_part, encoding)
  53 +
  54 + return ''.join(new_subject)
  55 +
  56 + def get_body(self):
  57 + """Get the body of the email message"""
  58 +
  59 + if self.is_multipart():
  60 + #get the plain text version only
  61 + text_parts = [part
  62 + for part in typed_subpart_iterator(self,
  63 + 'text',
  64 + 'plain')]
  65 + body = []
  66 + for part in text_parts:
  67 + charset = get_charset(part, get_charset(self))
  68 + body.append(unicode(part.get_payload(decode=True),
  69 + charset,
  70 + "replace"))
  71 +
  72 + return u"\n".join(body).strip()
  73 +
  74 + else: # if it is not multipart, the payload will be a string
  75 + # representing the message body
  76 + body = unicode(self.get_payload(decode=True),
  77 + get_charset(self),
  78 + "replace")
  79 + return body.strip()
  80 +
  81 + def get_received_datetime(self):
  82 + # The time received should always be the last element
  83 + # in the `Received` attribute from the message headers
  84 + received_header = self.RECEIVED_DELIMITER.split(self['Received'])
  85 + received_time_header = received_header[-1].strip()
  86 +
  87 + date_tuple = email.utils.parsedate_tz(received_time_header)
  88 + utc_timestamp = email.utils.mktime_tz(date_tuple)
  89 + utc_datetime = datetime.datetime.fromtimestamp(utc_timestamp,
  90 + pytz.utc)
  91 +
  92 + return utc_datetime
  93 +
  94 + def get_from_addr(self):
  95 + real_name_raw, from_ = email.utils.parseaddr(self['From'])
  96 + real_name_str, encoding = email.header.decode_header(real_name_raw)[0]
  97 + if not encoding:
  98 + encoding = 'ascii'
  99 +
  100 + real_name = unicode(real_name_str, encoding, errors='replace')
  101 + return real_name, from_
src/super_archives/migrations/0001_initial.py 0 → 100644
@@ -0,0 +1,255 @@ @@ -0,0 +1,255 @@
  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 + # Adding model 'PageHit'
  12 + db.create_table('super_archives_pagehit', (
  13 + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  14 + ('url_path', self.gf('django.db.models.fields.CharField')(unique=True, max_length=2048, db_index=True)),
  15 + ('hit_count', self.gf('django.db.models.fields.IntegerField')(default=0)),
  16 + ))
  17 + db.send_create_signal('super_archives', ['PageHit'])
  18 +
  19 + # Adding model 'EmailAddress'
  20 + db.create_table('super_archives_emailaddress', (
  21 + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  22 + ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='emails', null=True, to=orm['auth.User'])),
  23 + ('address', self.gf('django.db.models.fields.EmailField')(unique=True, max_length=75)),
  24 + ('real_name', self.gf('django.db.models.fields.CharField')(max_length=64, blank=True)),
  25 + ('md5', self.gf('django.db.models.fields.CharField')(max_length=32, null=True)),
  26 + ))
  27 + db.send_create_signal('super_archives', ['EmailAddress'])
  28 +
  29 + # Adding model 'UserProfile'
  30 + db.create_table('super_archives_userprofile', (
  31 + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  32 + ('user', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.User'], unique=True)),
  33 + ('institution', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
  34 + ('role', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
  35 + ('twitter', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
  36 + ('facebook', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
  37 + ('google_talk', self.gf('django.db.models.fields.EmailField')(max_length=75, null=True)),
  38 + ('webpage', self.gf('django.db.models.fields.CharField')(max_length=256)),
  39 + ))
  40 + db.send_create_signal('super_archives', ['UserProfile'])
  41 +
  42 + # Adding model 'MailingList'
  43 + db.create_table('super_archives_mailinglist', (
  44 + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  45 + ('name', self.gf('django.db.models.fields.CharField')(max_length=80)),
  46 + ('email', self.gf('django.db.models.fields.EmailField')(max_length=75)),
  47 + ('description', self.gf('django.db.models.fields.TextField')()),
  48 + ('logo', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
  49 + ('last_imported_index', self.gf('django.db.models.fields.IntegerField')(default=0)),
  50 + ))
  51 + db.send_create_signal('super_archives', ['MailingList'])
  52 +
  53 + # Adding model 'MailingListMembership'
  54 + db.create_table('super_archives_mailinglistmembership', (
  55 + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  56 + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
  57 + ('mailinglist', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.MailingList'])),
  58 + ))
  59 + db.send_create_signal('super_archives', ['MailingListMembership'])
  60 +
  61 + # Adding model 'Thread'
  62 + db.create_table('super_archives_thread', (
  63 + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  64 + ('subject_token', self.gf('django.db.models.fields.CharField')(max_length=512)),
  65 + ('mailinglist', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.MailingList'])),
  66 + ('latest_message', self.gf('django.db.models.fields.related.OneToOneField')(related_name='+', unique=True, null=True, to=orm['super_archives.Message'])),
  67 + ))
  68 + db.send_create_signal('super_archives', ['Thread'])
  69 +
  70 + # Adding unique constraint on 'Thread', fields ['subject_token', 'mailinglist']
  71 + db.create_unique('super_archives_thread', ['subject_token', 'mailinglist_id'])
  72 +
  73 + # Adding model 'Vote'
  74 + db.create_table('super_archives_vote', (
  75 + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  76 + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
  77 + ('message', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.Message'])),
  78 + ))
  79 + db.send_create_signal('super_archives', ['Vote'])
  80 +
  81 + # Adding unique constraint on 'Vote', fields ['user', 'message']
  82 + db.create_unique('super_archives_vote', ['user_id', 'message_id'])
  83 +
  84 + # Adding model 'Message'
  85 + db.create_table('super_archives_message', (
  86 + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  87 + ('from_address', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.EmailAddress'])),
  88 + ('mailinglist', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.MailingList'])),
  89 + ('thread', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.Thread'], null=True)),
  90 + ('subject', self.gf('django.db.models.fields.CharField')(max_length=512)),
  91 + ('subject_clean', self.gf('django.db.models.fields.CharField')(max_length=512)),
  92 + ('body', self.gf('django.db.models.fields.TextField')(default='')),
  93 + ('received_time', self.gf('django.db.models.fields.DateTimeField')()),
  94 + ('message_id', self.gf('django.db.models.fields.CharField')(max_length=512)),
  95 + ))
  96 + db.send_create_signal('super_archives', ['Message'])
  97 +
  98 + # Adding model 'MessageMetadata'
  99 + db.create_table('super_archives_messagemetadata', (
  100 + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  101 + ('Message', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['super_archives.Message'])),
  102 + ('name', self.gf('django.db.models.fields.CharField')(max_length=512)),
  103 + ('value', self.gf('django.db.models.fields.TextField')()),
  104 + ))
  105 + db.send_create_signal('super_archives', ['MessageMetadata'])
  106 +
  107 +
  108 + def backwards(self, orm):
  109 +
  110 + # Removing unique constraint on 'Vote', fields ['user', 'message']
  111 + db.delete_unique('super_archives_vote', ['user_id', 'message_id'])
  112 +
  113 + # Removing unique constraint on 'Thread', fields ['subject_token', 'mailinglist']
  114 + db.delete_unique('super_archives_thread', ['subject_token', 'mailinglist_id'])
  115 +
  116 + # Deleting model 'PageHit'
  117 + db.delete_table('super_archives_pagehit')
  118 +
  119 + # Deleting model 'EmailAddress'
  120 + db.delete_table('super_archives_emailaddress')
  121 +
  122 + # Deleting model 'UserProfile'
  123 + db.delete_table('super_archives_userprofile')
  124 +
  125 + # Deleting model 'MailingList'
  126 + db.delete_table('super_archives_mailinglist')
  127 +
  128 + # Deleting model 'MailingListMembership'
  129 + db.delete_table('super_archives_mailinglistmembership')
  130 +
  131 + # Deleting model 'Thread'
  132 + db.delete_table('super_archives_thread')
  133 +
  134 + # Deleting model 'Vote'
  135 + db.delete_table('super_archives_vote')
  136 +
  137 + # Deleting model 'Message'
  138 + db.delete_table('super_archives_message')
  139 +
  140 + # Deleting model 'MessageMetadata'
  141 + db.delete_table('super_archives_messagemetadata')
  142 +
  143 +
  144 + models = {
  145 + 'auth.group': {
  146 + 'Meta': {'object_name': 'Group'},
  147 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  148 + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
  149 + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
  150 + },
  151 + 'auth.permission': {
  152 + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
  153 + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  154 + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
  155 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  156 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
  157 + },
  158 + 'auth.user': {
  159 + 'Meta': {'object_name': 'User'},
  160 + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
  161 + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
  162 + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
  163 + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
  164 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  165 + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
  166 + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  167 + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  168 + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
  169 + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
  170 + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
  171 + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
  172 + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
  173 + },
  174 + 'contenttypes.contenttype': {
  175 + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
  176 + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  177 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  178 + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  179 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
  180 + },
  181 + 'super_archives.emailaddress': {
  182 + 'Meta': {'object_name': 'EmailAddress'},
  183 + 'address': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}),
  184 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  185 + 'md5': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
  186 + 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
  187 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emails'", 'null': 'True', 'to': "orm['auth.User']"})
  188 + },
  189 + 'super_archives.mailinglist': {
  190 + 'Meta': {'object_name': 'MailingList'},
  191 + 'description': ('django.db.models.fields.TextField', [], {}),
  192 + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
  193 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  194 + 'last_imported_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  195 + 'logo': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
  196 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'})
  197 + },
  198 + 'super_archives.mailinglistmembership': {
  199 + 'Meta': {'object_name': 'MailingListMembership'},
  200 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  201 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  202 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  203 + },
  204 + 'super_archives.message': {
  205 + 'Meta': {'object_name': 'Message'},
  206 + 'body': ('django.db.models.fields.TextField', [], {'default': "''"}),
  207 + 'from_address': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.EmailAddress']"}),
  208 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  209 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  210 + 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  211 + 'received_time': ('django.db.models.fields.DateTimeField', [], {}),
  212 + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  213 + 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  214 + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'})
  215 + },
  216 + 'super_archives.messagemetadata': {
  217 + 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  218 + 'Meta': {'object_name': 'MessageMetadata'},
  219 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  220 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  221 + 'value': ('django.db.models.fields.TextField', [], {})
  222 + },
  223 + 'super_archives.pagehit': {
  224 + 'Meta': {'object_name': 'PageHit'},
  225 + 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  226 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  227 + 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'})
  228 + },
  229 + 'super_archives.thread': {
  230 + 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'},
  231 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  232 + 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}),
  233 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  234 + 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})
  235 + },
  236 + 'super_archives.userprofile': {
  237 + 'Meta': {'object_name': 'UserProfile'},
  238 + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  239 + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
  240 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  241 + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  242 + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  243 + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  244 + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),
  245 + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})
  246 + },
  247 + 'super_archives.vote': {
  248 + 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},
  249 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  250 + 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  251 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  252 + }
  253 + }
  254 +
  255 + complete_apps = ['super_archives']
src/super_archives/migrations/0002_auto__add_field_userprofile_verification_hash.py 0 → 100644
@@ -0,0 +1,133 @@ @@ -0,0 +1,133 @@
  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 + # Adding field 'UserProfile.verification_hash'
  12 + db.add_column('super_archives_userprofile', 'verification_hash', self.gf('django.db.models.fields.CharField')(max_length=32, null=True), keep_default=False)
  13 +
  14 +
  15 + def backwards(self, orm):
  16 +
  17 + # Deleting field 'UserProfile.verification_hash'
  18 + db.delete_column('super_archives_userprofile', 'verification_hash')
  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', [], {'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 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  87 + 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  88 + 'received_time': ('django.db.models.fields.DateTimeField', [], {}),
  89 + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  90 + 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  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 + 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})
  112 + },
  113 + 'super_archives.userprofile': {
  114 + 'Meta': {'object_name': 'UserProfile'},
  115 + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  116 + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
  117 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  118 + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  119 + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  120 + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  121 + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),
  122 + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
  123 + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})
  124 + },
  125 + 'super_archives.vote': {
  126 + 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},
  127 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  128 + 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  129 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  130 + }
  131 + }
  132 +
  133 + complete_apps = ['super_archives']
src/super_archives/migrations/0003_auto__add_field_thread_score.py 0 → 100644
@@ -0,0 +1,134 @@ @@ -0,0 +1,134 @@
  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 + # Adding field 'Thread.score'
  12 + db.add_column('super_archives_thread', 'score', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)
  13 +
  14 +
  15 + def backwards(self, orm):
  16 +
  17 + # Deleting field 'Thread.score'
  18 + db.delete_column('super_archives_thread', 'score')
  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', [], {'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 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  87 + 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  88 + 'received_time': ('django.db.models.fields.DateTimeField', [], {}),
  89 + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  90 + 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  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 + 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})
  113 + },
  114 + 'super_archives.userprofile': {
  115 + 'Meta': {'object_name': 'UserProfile'},
  116 + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  117 + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
  118 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  119 + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  120 + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  121 + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  122 + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),
  123 + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
  124 + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})
  125 + },
  126 + 'super_archives.vote': {
  127 + 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},
  128 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  129 + 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  130 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  131 + }
  132 + }
  133 +
  134 + complete_apps = ['super_archives']
src/super_archives/migrations/0004_auto__add_field_vote_created.py 0 → 100644
@@ -0,0 +1,135 @@ @@ -0,0 +1,135 @@
  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 + # Adding field 'Vote.created'
  12 + db.add_column('super_archives_vote', 'created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, default=datetime.datetime(2012, 1, 19, 18, 8, 46, 813949), blank=True), keep_default=False)
  13 +
  14 +
  15 + def backwards(self, orm):
  16 +
  17 + # Deleting field 'Vote.created'
  18 + db.delete_column('super_archives_vote', 'created')
  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', [], {'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 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  87 + 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  88 + 'received_time': ('django.db.models.fields.DateTimeField', [], {}),
  89 + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  90 + 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  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 + 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})
  113 + },
  114 + 'super_archives.userprofile': {
  115 + 'Meta': {'object_name': 'UserProfile'},
  116 + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  117 + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
  118 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  119 + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  120 + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  121 + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  122 + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),
  123 + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
  124 + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})
  125 + },
  126 + 'super_archives.vote': {
  127 + 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},
  128 + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
  129 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  130 + 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  131 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  132 + }
  133 + }
  134 +
  135 + complete_apps = ['super_archives']
src/super_archives/migrations/0005_auto__add_field_message_spam__add_field_thread_spam.py 0 → 100644
@@ -0,0 +1,143 @@ @@ -0,0 +1,143 @@
  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 + # Adding field 'Message.spam'
  12 + db.add_column('super_archives_message', 'spam', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
  13 +
  14 + # Adding field 'Thread.spam'
  15 + db.add_column('super_archives_thread', 'spam', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
  16 +
  17 +
  18 + def backwards(self, orm):
  19 +
  20 + # Deleting field 'Message.spam'
  21 + db.delete_column('super_archives_message', 'spam')
  22 +
  23 + # Deleting field 'Thread.spam'
  24 + db.delete_column('super_archives_thread', 'spam')
  25 +
  26 +
  27 + models = {
  28 + 'auth.group': {
  29 + 'Meta': {'object_name': 'Group'},
  30 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  31 + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
  32 + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
  33 + },
  34 + 'auth.permission': {
  35 + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
  36 + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  37 + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
  38 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  39 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
  40 + },
  41 + 'auth.user': {
  42 + 'Meta': {'object_name': 'User'},
  43 + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
  44 + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
  45 + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
  46 + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
  47 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  48 + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
  49 + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  50 + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  51 + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
  52 + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
  53 + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
  54 + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
  55 + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
  56 + },
  57 + 'contenttypes.contenttype': {
  58 + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
  59 + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  60 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  61 + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  62 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
  63 + },
  64 + 'super_archives.emailaddress': {
  65 + 'Meta': {'object_name': 'EmailAddress'},
  66 + 'address': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}),
  67 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  68 + 'md5': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
  69 + 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
  70 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emails'", 'null': 'True', 'to': "orm['auth.User']"})
  71 + },
  72 + 'super_archives.mailinglist': {
  73 + 'Meta': {'object_name': 'MailingList'},
  74 + 'description': ('django.db.models.fields.TextField', [], {}),
  75 + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
  76 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  77 + 'last_imported_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  78 + 'logo': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
  79 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'})
  80 + },
  81 + 'super_archives.mailinglistmembership': {
  82 + 'Meta': {'object_name': 'MailingListMembership'},
  83 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  84 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  85 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  86 + },
  87 + 'super_archives.message': {
  88 + 'Meta': {'object_name': 'Message'},
  89 + 'body': ('django.db.models.fields.TextField', [], {'default': "''"}),
  90 + 'from_address': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.EmailAddress']"}),
  91 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  92 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  93 + 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  94 + 'received_time': ('django.db.models.fields.DateTimeField', [], {}),
  95 + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  96 + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  97 + 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  98 + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'})
  99 + },
  100 + 'super_archives.messagemetadata': {
  101 + 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  102 + 'Meta': {'object_name': 'MessageMetadata'},
  103 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  104 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  105 + 'value': ('django.db.models.fields.TextField', [], {})
  106 + },
  107 + 'super_archives.pagehit': {
  108 + 'Meta': {'object_name': 'PageHit'},
  109 + 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  110 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  111 + 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'})
  112 + },
  113 + 'super_archives.thread': {
  114 + 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'},
  115 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  116 + 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}),
  117 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  118 + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  119 + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  120 + 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})
  121 + },
  122 + 'super_archives.userprofile': {
  123 + 'Meta': {'object_name': 'UserProfile'},
  124 + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  125 + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
  126 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  127 + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  128 + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  129 + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  130 + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),
  131 + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
  132 + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})
  133 + },
  134 + 'super_archives.vote': {
  135 + 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},
  136 + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
  137 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  138 + 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  139 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  140 + }
  141 + }
  142 +
  143 + complete_apps = ['super_archives']
src/super_archives/migrations/0006_auto.py 0 → 100644
@@ -0,0 +1,143 @@ @@ -0,0 +1,143 @@
  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 + # Adding index on 'Message', fields ['subject_clean']
  12 + db.create_index('super_archives_message', ['subject_clean'])
  13 +
  14 + # Adding index on 'Message', fields ['subject']
  15 + db.create_index('super_archives_message', ['subject'])
  16 +
  17 +
  18 + def backwards(self, orm):
  19 +
  20 + # Removing index on 'Message', fields ['subject']
  21 + db.delete_index('super_archives_message', ['subject'])
  22 +
  23 + # Removing index on 'Message', fields ['subject_clean']
  24 + db.delete_index('super_archives_message', ['subject_clean'])
  25 +
  26 +
  27 + models = {
  28 + 'auth.group': {
  29 + 'Meta': {'object_name': 'Group'},
  30 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  31 + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
  32 + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
  33 + },
  34 + 'auth.permission': {
  35 + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
  36 + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  37 + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
  38 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  39 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
  40 + },
  41 + 'auth.user': {
  42 + 'Meta': {'object_name': 'User'},
  43 + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
  44 + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
  45 + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
  46 + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
  47 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  48 + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
  49 + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  50 + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  51 + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
  52 + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
  53 + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
  54 + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
  55 + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
  56 + },
  57 + 'contenttypes.contenttype': {
  58 + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
  59 + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  60 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  61 + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  62 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
  63 + },
  64 + 'super_archives.emailaddress': {
  65 + 'Meta': {'object_name': 'EmailAddress'},
  66 + 'address': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}),
  67 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  68 + 'md5': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
  69 + 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
  70 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emails'", 'null': 'True', 'to': "orm['auth.User']"})
  71 + },
  72 + 'super_archives.mailinglist': {
  73 + 'Meta': {'object_name': 'MailingList'},
  74 + 'description': ('django.db.models.fields.TextField', [], {}),
  75 + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
  76 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  77 + 'last_imported_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  78 + 'logo': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
  79 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'})
  80 + },
  81 + 'super_archives.mailinglistmembership': {
  82 + 'Meta': {'object_name': 'MailingListMembership'},
  83 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  84 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  85 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  86 + },
  87 + 'super_archives.message': {
  88 + 'Meta': {'object_name': 'Message'},
  89 + 'body': ('django.db.models.fields.TextField', [], {'default': "''"}),
  90 + 'from_address': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.EmailAddress']"}),
  91 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  92 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  93 + 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  94 + 'received_time': ('django.db.models.fields.DateTimeField', [], {}),
  95 + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  96 + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}),
  97 + 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}),
  98 + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'})
  99 + },
  100 + 'super_archives.messagemetadata': {
  101 + 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  102 + 'Meta': {'object_name': 'MessageMetadata'},
  103 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  104 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  105 + 'value': ('django.db.models.fields.TextField', [], {})
  106 + },
  107 + 'super_archives.pagehit': {
  108 + 'Meta': {'object_name': 'PageHit'},
  109 + 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  110 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  111 + 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'})
  112 + },
  113 + 'super_archives.thread': {
  114 + 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'},
  115 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  116 + 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}),
  117 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  118 + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  119 + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  120 + 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})
  121 + },
  122 + 'super_archives.userprofile': {
  123 + 'Meta': {'object_name': 'UserProfile'},
  124 + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  125 + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
  126 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  127 + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  128 + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  129 + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  130 + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),
  131 + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
  132 + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})
  133 + },
  134 + 'super_archives.vote': {
  135 + 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},
  136 + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
  137 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  138 + 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  139 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  140 + }
  141 + }
  142 +
  143 + complete_apps = ['super_archives']
src/super_archives/migrations/0007_auto.py 0 → 100644
@@ -0,0 +1,137 @@ @@ -0,0 +1,137 @@
  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 + # Adding index on 'EmailAddress', fields ['real_name']
  12 + db.create_index('super_archives_emailaddress', ['real_name'])
  13 +
  14 +
  15 + def backwards(self, orm):
  16 +
  17 + # Removing index on 'EmailAddress', fields ['real_name']
  18 + db.delete_index('super_archives_emailaddress', ['real_name'])
  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 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  87 + 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  88 + 'received_time': ('django.db.models.fields.DateTimeField', [], {}),
  89 + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  90 + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}),
  91 + 'subject_clean': ('django.db.models.fields.CharField', [], {'max_length': '512', 'db_index': 'True'}),
  92 + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Thread']", 'null': 'True'})
  93 + },
  94 + 'super_archives.messagemetadata': {
  95 + 'Message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  96 + 'Meta': {'object_name': 'MessageMetadata'},
  97 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  98 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
  99 + 'value': ('django.db.models.fields.TextField', [], {})
  100 + },
  101 + 'super_archives.pagehit': {
  102 + 'Meta': {'object_name': 'PageHit'},
  103 + 'hit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  104 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  105 + 'url_path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048', 'db_index': 'True'})
  106 + },
  107 + 'super_archives.thread': {
  108 + 'Meta': {'unique_together': "(('subject_token', 'mailinglist'),)", 'object_name': 'Thread'},
  109 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  110 + 'latest_message': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'unique': 'True', 'null': 'True', 'to': "orm['super_archives.Message']"}),
  111 + 'mailinglist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.MailingList']"}),
  112 + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
  113 + 'spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
  114 + 'subject_token': ('django.db.models.fields.CharField', [], {'max_length': '512'})
  115 + },
  116 + 'super_archives.userprofile': {
  117 + 'Meta': {'object_name': 'UserProfile'},
  118 + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  119 + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
  120 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  121 + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  122 + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  123 + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
  124 + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),
  125 + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
  126 + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256'})
  127 + },
  128 + 'super_archives.vote': {
  129 + 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'Vote'},
  130 + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
  131 + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  132 + 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['super_archives.Message']"}),
  133 + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
  134 + }
  135 + }
  136 +
  137 + complete_apps = ['super_archives']
src/super_archives/migrations/0008_add_mailinglist_name_to_url.py 0 → 100644
@@ -0,0 +1,142 @@ @@ -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']
src/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']
src/super_archives/migrations/0010_auto__add_unique_message_message_id_thread.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 + # Adding unique constraint on 'Message', fields ['message_id', 'thread']
  12 + db.create_unique('super_archives_message', ['message_id', 'thread_id'])
  13 +
  14 +
  15 + def backwards(self, orm):
  16 +
  17 + # Removing unique constraint on 'Message', fields ['message_id', 'thread']
  18 + db.delete_unique('super_archives_message', ['message_id', 'thread_id'])
  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': {'unique_together': "(('thread', 'message_id'),)", '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']
src/super_archives/migrations/__init__.py 0 → 100644
src/super_archives/models.py 0 → 100644
@@ -0,0 +1,279 @@ @@ -0,0 +1,279 @@
  1 +# -*- coding: utf-8 -*-
  2 +
  3 +import datetime
  4 +from hashlib import md5
  5 +
  6 +from django.db import models
  7 +from django.conf import settings
  8 +from django.contrib.auth.models import User
  9 +from django.core.urlresolvers import reverse, NoReverseMatch
  10 +from django.utils.translation import ugettext_lazy as _
  11 +
  12 +
  13 +class NotSpamManager(models.Manager):
  14 + """Only return objects which are not marked as spam."""
  15 +
  16 + def get_query_set(self):
  17 + return super(NotSpamManager, self).get_query_set().exclude(spam=True)
  18 +
  19 +
  20 +class PageHit(models.Model):
  21 + url_path = models.CharField(max_length=2048, unique=True, db_index=True)
  22 + hit_count = models.IntegerField(default=0)
  23 +
  24 +
  25 +class EmailAddress(models.Model):
  26 + user = models.ForeignKey(User, null=True, related_name='emails')
  27 + address = models.EmailField(unique=True)
  28 + real_name = models.CharField(max_length=64, blank=True, db_index=True)
  29 + md5 = models.CharField(max_length=32, null=True)
  30 +
  31 + def save(self, *args, **kwargs):
  32 + self.md5 = md5(self.address).hexdigest()
  33 + super(EmailAddress, self).save(*args, **kwargs)
  34 +
  35 + def get_full_name(self):
  36 + if self.user and self.user.get_full_name():
  37 + return self.user.get_full_name()
  38 + elif self.user and self.username:
  39 + return self.username
  40 + elif self.real_name:
  41 + return self.real_name
  42 +
  43 + def get_profile_link(self):
  44 + if self.user:
  45 + return reverse('user_profile', args=[self.user.username])
  46 + else:
  47 + return reverse('colab.views.userprofile.by_emailhash',
  48 + args=[self.md5])
  49 +
  50 + def __unicode__(self):
  51 + return '"%s" <%s>' % (self.get_full_name(), self.address)
  52 +
  53 +
  54 +class UserProfile(models.Model):
  55 +
  56 + user = models.OneToOneField(User, unique=True)
  57 + institution = models.CharField(max_length=128, null=True)
  58 + role = models.CharField(max_length=128, null=True)
  59 + twitter = models.CharField(max_length=128, null=True)
  60 + facebook = models.CharField(max_length=128, null=True)
  61 + google_talk = models.EmailField(null=True)
  62 + webpage = models.CharField(max_length=256)
  63 + verification_hash = models.CharField(max_length=32, null=True)
  64 +
  65 + class Meta:
  66 + verbose_name = _(u"User Profile")
  67 + verbose_name_plural = _(u"Users Profiles")
  68 +
  69 + def __unicode__(self):
  70 + return '%s (%s)' % (self.user.get_full_name(), self.user.username)
  71 +
  72 +# This does the same the same than related_name argument but it also creates
  73 +# a profile in the case it doesn't exist yet.
  74 +User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
  75 +
  76 +
  77 +class MailingList(models.Model):
  78 + name = models.CharField(max_length=80)
  79 + email = models.EmailField()
  80 + description = models.TextField()
  81 + logo = models.FileField(upload_to='list_logo') #TODO
  82 + last_imported_index = models.IntegerField(default=0)
  83 +
  84 + def __unicode__(self):
  85 + return self.name
  86 +
  87 +
  88 +class MailingListMembership(models.Model):
  89 + user = models.ForeignKey(User)
  90 + mailinglist = models.ForeignKey(MailingList)
  91 +
  92 + def __unicode__(self):
  93 + return '%s on %s' % (self.user.username, self.mailinglist.name)
  94 +
  95 +
  96 +class Thread(models.Model):
  97 +
  98 + subject_token = models.CharField(max_length=512)
  99 + mailinglist = models.ForeignKey(MailingList,
  100 + verbose_name=_(u"Mailing List"),
  101 + help_text=_(u"The Mailing List where is the thread"))
  102 + latest_message = models.OneToOneField('Message', null=True,
  103 + related_name='+',
  104 + verbose_name=_(u"Latest message"),
  105 + help_text=_(u"Latest message posted"))
  106 + score = models.IntegerField(default=0, verbose_name=_(u"Score"), help_text=_(u"Thread score"))
  107 + spam = models.BooleanField(default=False)
  108 +
  109 + all_objects = models.Manager()
  110 + objects = NotSpamManager()
  111 +
  112 + class Meta:
  113 + verbose_name = _(u"Thread")
  114 + verbose_name_plural = _(u"Threads")
  115 + unique_together = ('subject_token', 'mailinglist')
  116 +
  117 + def __unicode__(self):
  118 + return '%s - %s (%s)' % (self.id,
  119 + self.subject_token,
  120 + self.message_set.count())
  121 +
  122 + def update_score(self):
  123 + """Update the relevance score for this thread.
  124 +
  125 + The score is calculated with the following variables:
  126 +
  127 + * vote_weight: 100 - (minus) 1 for each 3 days since
  128 + voted with minimum of 5.
  129 + * replies_weight: 300 - (minus) 1 for each 3 days since
  130 + replied with minimum of 5.
  131 + * page_view_weight: 10.
  132 +
  133 + * vote_score: sum(vote_weight)
  134 + * replies_score: sum(replies_weight)
  135 + * page_view_score: sum(page_view_weight)
  136 +
  137 + * score = (vote_score + replies_score + page_view_score) // 10
  138 + with minimum of 0 and maximum of 5000
  139 +
  140 + """
  141 +
  142 + if not self.subject_token:
  143 + return
  144 +
  145 + # Save this pseudo now to avoid calling the
  146 + # function N times in the loops below
  147 + now = datetime.datetime.now()
  148 + days_ago = lambda date: (now - date).days
  149 + get_score = lambda weight, created: \
  150 + max(weight - (days_ago(created) // 3), 5)
  151 +
  152 + vote_score = 0
  153 + replies_score = 0
  154 + for msg in self.message_set.all():
  155 + # Calculate replies_score
  156 + replies_score += get_score(300, msg.received_time)
  157 +
  158 + # Calculate vote_score
  159 + for vote in msg.vote_set.all():
  160 + vote_score += get_score(100, vote.created)
  161 +
  162 + # Calculate page_view_score
  163 + try:
  164 + url = reverse('thread_view', args=[self.mailinglist.name,
  165 + self.subject_token])
  166 + pagehit = PageHit.objects.get(url_path=url)
  167 + page_view_score = pagehit.hit_count * 10
  168 + except (NoReverseMatch, PageHit.DoesNotExist):
  169 + page_view_score = 0
  170 +
  171 + self.score = (page_view_score + vote_score + replies_score) // 10
  172 + self.save()
  173 +
  174 +
  175 +class Vote(models.Model):
  176 + user = models.ForeignKey(User)
  177 + message = models.ForeignKey('Message')
  178 + created = models.DateTimeField(auto_now_add=True)
  179 +
  180 + class Meta:
  181 + unique_together = ('user', 'message')
  182 +
  183 + def __unicode__(self):
  184 + return 'Vote on %s by %s' % (self.Message.id,
  185 + self.user.username)
  186 +
  187 +
  188 +class Message(models.Model):
  189 +
  190 + from_address = models.ForeignKey(EmailAddress, db_index=True)
  191 + thread = models.ForeignKey(Thread, null=True, db_index=True)
  192 + # RFC 2822 recommends to use 78 chars + CRLF (so 80 chars) for
  193 + # the max_length of a subject but most of implementations
  194 + # goes for 256. We use 512 just in case.
  195 + subject = models.CharField(max_length=512, db_index=True,
  196 + verbose_name=_(u"Subject"),
  197 + help_text=_(u"Please enter a message subject"))
  198 + subject_clean = models.CharField(max_length=512, db_index=True)
  199 + body = models.TextField(default='',
  200 + verbose_name=_(u"Message body"),
  201 + help_text=_(u"Please enter a message body"))
  202 + received_time = models.DateTimeField()
  203 + message_id = models.CharField(max_length=512)
  204 + spam = models.BooleanField(default=False)
  205 +
  206 + all_objects = models.Manager()
  207 + objects = NotSpamManager()
  208 +
  209 + class Meta:
  210 + verbose_name = _(u"Message")
  211 + verbose_name_plural = _(u"Messages")
  212 + unique_together = ('thread', 'message_id')
  213 +
  214 + def __unicode__(self):
  215 + return '(%s) %s: %s' % (self.id,
  216 + self.from_address.get_full_name(),
  217 + self.subject_clean)
  218 +
  219 + @property
  220 + def mailinglist(self):
  221 + if not self.thread or not self.thread.mailinglist:
  222 + return None
  223 +
  224 + return self.thread.mailinglist
  225 +
  226 +
  227 + def vote_list(self):
  228 + """Return a list of user that voted in this message."""
  229 +
  230 + return [vote.user for vote in self.vote_set.all()]
  231 +
  232 + def votes_count(self):
  233 + return len(self.vote_list())
  234 +
  235 + def vote(self, user):
  236 + Vote.objects.create(
  237 + message=self,
  238 + user=user
  239 + )
  240 +
  241 + def unvote(self, user):
  242 + Vote.objects.get(
  243 + message=self,
  244 + user=user
  245 + ).delete()
  246 +
  247 + @property
  248 + def url(self):
  249 + """Shortcut to get thread url"""
  250 + return reverse('thread_view', args=[self.mailinglist.name,
  251 + self.thread.subject_token])
  252 +
  253 + @property
  254 + def Description(self):
  255 + """Alias to self.body"""
  256 + return self.body
  257 +
  258 + @property
  259 + def Title(self):
  260 + """Alias to self.subject_clean"""
  261 + return self.subject_clean
  262 +
  263 + @property
  264 + def modified(self):
  265 + """Alias to self.modified"""
  266 + return self.received_time
  267 +
  268 +
  269 +class MessageMetadata(models.Model):
  270 + Message = models.ForeignKey(Message)
  271 + # Same problem here than on subjects. Read comment above
  272 + # on Message.subject
  273 + name = models.CharField(max_length=512)
  274 + value = models.TextField()
  275 +
  276 + def __unicode__(self):
  277 + return 'Email Message Id: %s - %s: %s' % (self.Message.id,
  278 + self.name, self.value)
  279 +
src/super_archives/queries.py 0 → 100644
@@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
  1 +
  2 +from django.core.exceptions import ObjectDoesNotExist
  3 +from colab.super_archives.models import Thread, Vote, Message, PageHit
  4 +
  5 +
  6 +def get_messages_by_date():
  7 + return Message.objects.order_by('received_time')
  8 +
  9 +
  10 +def get_messages_by_voted():
  11 + """Query for the most voted messages sorting by the sum of
  12 + voted and after by date."""
  13 +
  14 + sql = """
  15 + SELECT
  16 + count(sav.id)
  17 + FROM
  18 + super_archives_vote AS sav
  19 + WHERE
  20 + super_archives_message.id = sav.message_id
  21 + """
  22 + messages = Message.objects.extra(
  23 + select={
  24 + 'vote_count': sql,
  25 + }
  26 + )
  27 + return messages.order_by('-vote_count', 'received_time')
  28 +
  29 +
  30 +def get_first_message_in_thread(mailinglist, thread_token):
  31 + query = get_messages_by_date()
  32 + query = query.filter(thread__mailinglist__name=mailinglist)
  33 + try:
  34 + query = query.filter(thread__subject_token=thread_token)[0]
  35 + except IndexError:
  36 + raise ObjectDoesNotExist
  37 + return query
  38 +
  39 +
  40 +def get_latest_threads():
  41 + return Thread.objects.order_by('-latest_message__received_time')
  42 +
  43 +
  44 +def get_hottest_threads():
  45 + return Thread.objects.order_by('-score', '-latest_message__received_time')
  46 +
  47 +
  48 +def get_page_hits(path_info):
  49 + pagehit = PageHit.objects.filter(url_path=path_info)
  50 +
  51 + if pagehit:
  52 + return pagehit[0].hit_count
  53 + return 0
  54 +
src/super_archives/templates/message-list.html 0 → 100644
@@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
  1 +{% extends "base.html" %}
  2 +{% load i18n %}
  3 +{% load append_to_get %}
  4 +{% block main-content %}
  5 +<div id="message-list">
  6 + <h2 class="span-5">{% trans "Discussions" %}</h2>
  7 + <hr/>
  8 +
  9 + <div class="span-5 border filters">
  10 + <h3>{% trans "Filters" %}</h3>
  11 +
  12 + <h4>{% trans "Sort by" %}</h4>
  13 + <ul>
  14 + <li {% ifequal order_by "hottest" %} class="selected" title="{% trans "Remove filter" %}" {% endifequal %}>
  15 + <a href="{% ifequal order_by "hottest" %} {% append_to_get order="",p=1 %} {% else %} {% append_to_get order='hottest',p=1 %} {% endifequal %}">
  16 + {% trans "Relevance" %}</a></li>
  17 + <li {% ifequal order_by "latest" %} class="selected" title="{% trans "Remove filter" %}" {% endifequal %}>
  18 + <a href="{% ifequal order_by "latest" %} {% append_to_get order="",p=1 %} {% else %} {% append_to_get order='latest',p=1 %} {% endifequal %}">
  19 + {% trans "Recent activity" %}</a></li>
  20 + </ul>
  21 +
  22 + <hr class="space" />
  23 +
  24 + <h4>{% trans "Lists" %}</h4>
  25 + <ul>
  26 + {% for list in lists %}
  27 + <li {% ifequal list.name selected_list %} class="selected" title="{% trans "Remove filter" %}" {% endifequal %}>
  28 + <a href="{% ifnotequal list.name selected_list %} {% append_to_get list=list.name,p=1 %} {% else %} {% append_to_get list="",p=1 %}
  29 + {% endifnotequal %}">{{ list.name }}</a></li>
  30 + {% endfor %}
  31 + </ul>
  32 + </div>
  33 +
  34 + <div class="span-17 prepend-1 last">
  35 + <ul>
  36 + {% for thread in threads.object_list %}
  37 + {% include "message-preview.html" with doc=thread.latest_message %}
  38 + {% empty %}
  39 + <br/><br/>
  40 + <span class="span-18 center large">
  41 + <b>{% trans "No discussion found" %}</b>
  42 + </span>
  43 + {% endfor %}
  44 + </ul>
  45 + <hr class="space"/>
  46 +
  47 + {% if n_results %}
  48 + <div class="pagination center">
  49 + <span class="step-links">
  50 + {% if threads.has_previous %}
  51 + <a href="{% append_to_get p=threads.previous_page_number %}">{% trans "Previous" %}</a>
  52 + {% endif %}
  53 +
  54 + <span class="current">
  55 + {% trans "Page" %} {{ threads.number }} {% trans "of" %} {{ threads.paginator.num_pages }}
  56 + </span>
  57 +
  58 + {% if threads.has_next %}
  59 + <a href="{% append_to_get p=threads.next_page_number %}">{% trans "Next" %}</a>
  60 + {% endif %}
  61 + </span>
  62 + </div>
  63 + {% endif %}
  64 +
  65 + </div>
  66 +</div>
  67 +
  68 +{% endblock %}
src/super_archives/templates/message-preview.html 0 → 100644
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  1 +{% load i18n %}
  2 +
  3 +{% if doc.Title %}
  4 +<li class="preview-message">
  5 + {% if doc.Type %}
  6 + <img alt="{{ doc.Type }}" title="{{ doc.Type }}"
  7 + src="{{ STATIC_URL }}img/{{ doc.Type }}.png" />
  8 + {% else %}
  9 + <img alt="thread" title="thread"
  10 + src="{{ STATIC_URL }}img/thread.png" />
  11 + {% endif %}
  12 +
  13 + {% if doc.mailinglist %}
  14 + <a href="{% url super_archives.views.list_messages %}?list={{ doc.mailinglist }}">
  15 + <span class="tag">{{ doc.mailinglist }}</span>
  16 + </a>
  17 + {% endif %}
  18 +
  19 + <span class="subject">
  20 + <a href="{{ doc.url }}"
  21 + {% if
  22 + title="{% filter striptags|truncatewords:50 %}
  23 + {{ doc.Description|escape }}
  24 + {% endfilter %}">
  25 + {{ doc.Title }}
  26 + </a>
  27 + </span>
  28 +
  29 + <span class="quiet">-
  30 + {{ doc.Description|striptags }}
  31 + </span>
  32 +
  33 + <div class="quiet">
  34 + <span class="left">
  35 + {% trans "by" %}
  36 + {% if doc.from_address.get_full_name %}
  37 + <a href="{{ doc.from_address.get_profile_link }}">
  38 + {{ doc.from_address.get_full_name }}
  39 + </a>
  40 + {% else %}
  41 + {% firstof doc.last_author doc.Creator _("anônimo") %}
  42 + {% endif %}
  43 + </span>
  44 +
  45 + <span class="right">
  46 + {{ doc.modified|timesince }}
  47 + {% trans "back" %}
  48 + </span>
  49 + </div>
  50 +</li>
  51 +{% endif %}
src/super_archives/templates/message-thread.html 0 → 100644
@@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
  1 +{% extends "base.html" %}
  2 +{% load i18n %}
  3 +{% load append_to_get %}
  4 +{% block main-content %}
  5 + <div id="vote-notification" class="error hide"></div>
  6 +
  7 + <h2>{{ first_msg.subject_clean }}</h2>
  8 + <hr/>
  9 + <div class="span-17 border">
  10 + <ul>
  11 + {% for email in emails %}
  12 + <li>
  13 + <div id="msg-{{ email.id }}" class="email_message">
  14 + <div class="span-3 center">
  15 + <div>
  16 + <a href="{{ email.from_address.get_profile_link }}">
  17 + <img class="avatar" width="80px" heigth="80px"
  18 + src="http://www.gravatar.com/avatar/{{ email.from_address.md5 }}?s=80&d=identicon" />
  19 + <span>{% firstof email.from_address.get_full_name "Anônimo" %}</span>
  20 + </a>
  21 + </div>
  22 + <p>{{ email.received_time|date:"SHORT_DATETIME_FORMAT" }}</p>
  23 +
  24 + <div class="plus">
  25 + <span>{{ email.votes_count }}</span>
  26 + <img title="{% trans 'Vote' %}" class="right" src="{{ STATIC_URL }}img/plus.png">
  27 + </div>
  28 +
  29 + <p class="minus {% if not user in email.vote_list %}hide{% endif %}">
  30 + <a href="#">{% trans "Remove votes" %}</a>
  31 + </p>
  32 + </div>
  33 +
  34 + <div class="span-13">
  35 + <pre>{{ email.body }}</pre>
  36 + </div>
  37 + </div>
  38 + {% if not forloop.last %}
  39 + <hr/>
  40 + {% endif %}
  41 + </li>
  42 + {% endfor %}
  43 + </ul>
  44 + </div>
  45 + <div class="span-6 filters last">
  46 + <h4><b>{% trans "Order by" %}:</b></h4>
  47 + <ul>
  48 + <li><a href="{% append_to_get order='voted' %}">{% trans "Votes" %}</a></li>
  49 + <li><a href="{% append_to_get order='date' %}">{% trans "Data" %}</a></li>
  50 + </ul>
  51 +
  52 + <hr class="space"/>
  53 +
  54 + <h4><b>{% trans "Statistics:" %}</b></h4>
  55 +
  56 + <ul>
  57 + <li class="quiet">{% trans "started at" %}
  58 + <h4>{{ first_msg.received_time|timesince }} {% trans "back" %}</h4>
  59 + </li>
  60 + <li class="quiet">{% trans "viewed" %}
  61 + <h4>{{ pagehits }} {% trans "times" %}</h4>
  62 + </li>
  63 + <li class="quiet">{% trans "answered" %}
  64 + <h4>{{ emails|length }} {% trans "times" %}</h4>
  65 + </li>
  66 + <li class="quiet">{% trans "voted" %}
  67 + <h4>{{ total_votes }} {% trans "times" %}</h4>
  68 + </li>
  69 + </ul>
  70 +
  71 + </div>
  72 +
  73 + <script type="text/javascript" charset="utf-8">
  74 + pagehit("{{ request.path_info }}");
  75 + </script>
  76 +
  77 +{% endblock %}
src/super_archives/templatetags/__init__.py 0 → 100644
src/super_archives/templatetags/append_to_get.py 0 → 100644
@@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
  1 +
  2 +import urllib
  3 +from django import template
  4 +
  5 +register = template.Library()
  6 +
  7 +"""
  8 +Decorator to facilitate template tag creation
  9 +"""
  10 +def easy_tag(func):
  11 + """deal with the repetitive parts of parsing template tags"""
  12 + def inner(parser, token):
  13 + #print token
  14 + try:
  15 + return func(*token.split_contents())
  16 + except TypeError:
  17 + raise template.TemplateSyntaxError('Bad arguments for tag "%s"' %
  18 + token.split_contents()[0])
  19 + inner.__name__ = func.__name__
  20 + inner.__doc__ = inner.__doc__
  21 + return inner
  22 +
  23 +
  24 +class AppendGetNode(template.Node):
  25 + def __init__(self, dict):
  26 + self.dict_pairs = {}
  27 + for pair in dict.split(','):
  28 + pair = pair.split('=')
  29 + self.dict_pairs[pair[0]] = template.Variable(pair[1])
  30 +
  31 + def render(self, context):
  32 + get = context['request'].GET.copy()
  33 +
  34 + for key in self.dict_pairs:
  35 + get[key] = self.dict_pairs[key].resolve(context)
  36 +
  37 + path = context['request'].META['PATH_INFO']
  38 +
  39 + if len(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)
  50 +
  51 + return path
  52 +
  53 +@register.tag()
  54 +@easy_tag
  55 +def append_to_get(_tag_name, dict):
  56 + return AppendGetNode(dict)
src/super_archives/templatetags/form_field.py 0 → 100644
@@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
  1 +from django import template
  2 +from django import forms
  3 +
  4 +def render_form_field(parser, token):
  5 + variables = token.split_contents()
  6 +
  7 + if len(variables) == 2:
  8 + tag_name, form_field = variables
  9 + default_value = 'None'
  10 + elif len(variables) == 3:
  11 + tag_name, form_field, default_value = variables
  12 + else:
  13 + raise template.TemplateSyntaxError
  14 +
  15 + return RenderFormField(form_field, default_value)
  16 +
  17 +
  18 +class RenderFormField(template.Node):
  19 +
  20 + def __init__(self, form_field, default_value):
  21 + self.form_field_nocontext = template.Variable(form_field)
  22 + self.default_value_nocontext = template.Variable(default_value)
  23 +
  24 + def render(self, context):
  25 + editable = context.get('editable', True)
  26 +
  27 + class_ = u''
  28 + errors = u''
  29 + form_field_tag = u''
  30 + try:
  31 + form_field = self.form_field_nocontext.resolve(context)
  32 + except template.VariableDoesNotExist:
  33 + return u''
  34 +
  35 + if form_field.errors:
  36 + class_ += u'error'
  37 + if form_field.field.required:
  38 + class_ += u' required'
  39 + if form_field.errors:
  40 + errors = u'<br/>' + form_field.errors.as_text()
  41 +
  42 + try:
  43 + default_value = self.default_value_nocontext.resolve(context)
  44 + except template.VariableDoesNotExist:
  45 + default_value = u''
  46 +
  47 + if editable:
  48 + form_field_tag = u'<br/>' + unicode(form_field)
  49 + elif isinstance(form_field.field, forms.URLField):
  50 + form_field_tag = u"""<a href="%s" target="_blank">%s</a>""" % (
  51 + default_value, default_value)
  52 + else:
  53 + form_field_tag = default_value
  54 +
  55 + return u"""<p class="%s">%s: %s %s</p>""" % (
  56 + class_,
  57 + form_field.label_tag(),
  58 + form_field_tag,
  59 + errors
  60 + )
  61 +
  62 +
  63 +register = template.Library()
  64 +register.tag('render_form_field', render_form_field)
src/super_archives/tests.py 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +"""
  2 +This file demonstrates writing tests using the unittest module. These will pass
  3 +when you run "manage.py test".
  4 +
  5 +Replace this with more appropriate tests for your application.
  6 +"""
  7 +
  8 +from django.test import TestCase
  9 +
  10 +
  11 +class SimpleTest(TestCase):
  12 + def test_basic_addition(self):
  13 + """
  14 + Tests that 1 + 1 always equals 2.
  15 + """
  16 + self.assertEqual(1 + 1, 2)
src/super_archives/urls.py 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +from django.conf.urls.defaults import patterns, include, url
  2 +
  3 +urlpatterns = patterns('',
  4 +# url(r'thread/(?P<thread>\d+)/$', 'super_archives.views.thread', name='thread'),
  5 + url(r'thread/(?P<mailinglist>[-\w]+)/(?P<thread_token>[-\w]+)$',
  6 + 'colab.super_archives.views.thread', name="thread_view"),
  7 + url(r'thread/$',
  8 + 'colab.super_archives.views.list_messages', name='thread_list')
  9 +)
src/super_archives/validators.py 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +# -*- coding: utf-8 -*-
  2 +
  3 +from django.core.exceptions import ValidationError
  4 +
  5 +class UniqueValidator(object):
  6 +
  7 + def __init__(self, model, field_name):
  8 + self.model = model
  9 + self.field_name = field_name
  10 +
  11 + def __call__(self, value):
  12 + result = self.model.objects.filter(**{self.field_name: value})
  13 + if result:
  14 + msg = u'Já existente. Escolha outro.'
  15 + raise ValidationError(msg)
src/super_archives/views.py 0 → 100644
@@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
  1 +# -*- coding: utf-8 -*-
  2 +
  3 +from django.http import Http404
  4 +from django.template import RequestContext
  5 +from django.core.paginator import Paginator
  6 +from django.core.exceptions import ObjectDoesNotExist
  7 +from django.shortcuts import render_to_response, get_list_or_404
  8 +
  9 +from colab.super_archives import queries
  10 +from colab.super_archives.models import MailingList, Thread
  11 +
  12 +
  13 +def thread(request, mailinglist, thread_token):
  14 +
  15 + try:
  16 + first_message = queries.get_first_message_in_thread(mailinglist, thread_token)
  17 + except ObjectDoesNotExist:
  18 + raise Http404
  19 + order_by = request.GET.get('order')
  20 + if order_by == 'voted':
  21 + msgs_query = queries.get_messages_by_voted()
  22 + else:
  23 + msgs_query = queries.get_messages_by_date()
  24 +
  25 + msgs_query = msgs_query.filter(thread__subject_token=thread_token)
  26 + msgs_query = msgs_query.filter(thread__mailinglist__name=mailinglist)
  27 + emails = msgs_query.exclude(id=first_message.id)
  28 +
  29 + total_votes = first_message.votes_count()
  30 + for email in emails:
  31 + total_votes += email.votes_count()
  32 +
  33 + # Update relevance score
  34 + query = Thread.objects.filter(mailinglist__name=mailinglist)
  35 + thread = query.get(subject_token=thread_token)
  36 + thread.update_score()
  37 +
  38 + template_data = {
  39 + 'first_msg': first_message,
  40 + 'emails': [first_message] + list(emails),
  41 + 'pagehits': queries.get_page_hits(request.path_info),
  42 + 'total_votes': total_votes,
  43 + }
  44 +
  45 + return render_to_response('message-thread.html', template_data,
  46 + RequestContext(request))
  47 +
  48 +
  49 +def list_messages(request):
  50 +
  51 + selected_list = request.GET.get('list')
  52 +
  53 + order_by = request.GET.get('order')
  54 + if order_by == 'hottest':
  55 + threads = queries.get_hottest_threads()
  56 + else:
  57 + threads = queries.get_latest_threads()
  58 +
  59 + mail_list = request.GET.get('list')
  60 + if mail_list:
  61 + threads = threads.filter(mailinglist__name=mail_list)
  62 +
  63 + paginator = Paginator(threads, 16)
  64 + try:
  65 + page = int(request.GET.get('p', '1'))
  66 + except ValueError:
  67 + page = 1
  68 + threads = paginator.page(page)
  69 +
  70 + lists = MailingList.objects.all()
  71 +
  72 + template_data = {
  73 + 'lists': lists,
  74 + 'n_results': paginator.count,
  75 + 'threads': threads,
  76 + 'selected_list': selected_list,
  77 + 'order_by': order_by,
  78 + }
  79 + return render_to_response('message-list.html', template_data,
  80 + RequestContext(request))