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   -
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   -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   -#!/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   -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   -
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   -[
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   -# -*- 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   -#!/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   -
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   -# 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   -# 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   -# 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   -# 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   -# 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   -# 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   -# 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   -# 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   -# 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   -# 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   -# -*- 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   -
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   -{% 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   -{% 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   -{% 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   -
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   -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   -"""
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   -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   -# -*- 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   -# -*- 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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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))
... ...