summaryrefslogtreecommitdiffstats
path: root/hyperkitty/views
diff options
context:
space:
mode:
authorAamir Khan <syst3m.w0rm@gmail.com>2012-07-24 17:00:25 -0400
committerAamir Khan <syst3m.w0rm@gmail.com>2012-07-24 17:00:25 -0400
commit9f18a590819a01017c15169d82763680a72848fb (patch)
tree9c781cd677eeae9b1e50e986647e1929e99bdac7 /hyperkitty/views
parentae77d9901e2a466622818f95d784fb85b5296727 (diff)
downloadhyperkitty-9f18a590819a01017c15169d82763680a72848fb.tar.gz
hyperkitty-9f18a590819a01017c15169d82763680a72848fb.tar.xz
hyperkitty-9f18a590819a01017c15169d82763680a72848fb.zip
Packaging hyperkitty
Diffstat (limited to 'hyperkitty/views')
-rw-r--r--hyperkitty/views/__init__.py0
-rw-r--r--hyperkitty/views/accounts.py114
-rw-r--r--hyperkitty/views/api.py27
-rw-r--r--hyperkitty/views/forms.py59
-rw-r--r--hyperkitty/views/list.py291
-rw-r--r--hyperkitty/views/message.py82
-rw-r--r--hyperkitty/views/pages.py38
-rw-r--r--hyperkitty/views/thread.py113
8 files changed, 724 insertions, 0 deletions
diff --git a/hyperkitty/views/__init__.py b/hyperkitty/views/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hyperkitty/views/__init__.py
diff --git a/hyperkitty/views/accounts.py b/hyperkitty/views/accounts.py
new file mode 100644
index 0000000..3154563
--- /dev/null
+++ b/hyperkitty/views/accounts.py
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 1998-2012 by the Free Software Foundation, Inc.
+#
+# This file is part of HyperKitty.
+#
+# HyperKitty is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# HyperKitty is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# HyperKitty. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Aamir Khan <syst3m.w0rm@gmail.com>
+#
+
+import re
+import sys
+
+from django.conf import settings
+from django.contrib import messages
+from django.contrib.auth import logout, authenticate, login
+from django.contrib.auth.decorators import (login_required,
+ permission_required,
+ user_passes_test)
+from django.contrib.auth.forms import AuthenticationForm
+from gsoc.models import UserProfile
+from django.contrib.auth.models import User
+from django.core.urlresolvers import reverse
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import render_to_response, redirect
+from django.template import Context, loader, RequestContext
+from django.utils.translation import gettext as _
+from urllib2 import HTTPError
+from urlparse import urlparse
+
+from forms import RegistrationForm
+from gsoc.utils import log
+
+def user_logout(request):
+ logout(request)
+ return redirect('user_login')
+
+def user_login(request,template = 'login.html'):
+
+ parse_r = urlparse(request.META.get('HTTP_REFERER', 'index'))
+ previous = '%s%s' % (parse_r.path, parse_r.query)
+
+ next_var = request.POST.get('next', request.GET.get('next', previous))
+
+ if request.method == 'POST':
+ form = AuthenticationForm(request.POST)
+ user = authenticate(username=request.POST.get('username'),
+ password=request.POST.get('password'))
+
+ if user is not None:
+ log('debug', user)
+ if user.is_active:
+ login(request,user)
+ return redirect(next_var)
+
+ else:
+ form = AuthenticationForm()
+ return render_to_response(template, {'form': form, 'next' : next_var},
+ context_instance=RequestContext(request))
+
+@login_required
+def user_profile(request, user_email = None):
+ if not request.user.is_authenticated():
+ return redirect('user_login')
+ # try to render the user profile.
+ try:
+ user_profile = request.user.get_profile()
+ # @TODO: Include the error name e.g, ProfileDoesNotExist?
+ except:
+ user_profile = UserProfile.objects.create(user=request.user)
+
+ t = loader.get_template('user_profile.html')
+
+ c = RequestContext(request, {
+ 'user_profile' : user_profile,
+ })
+
+ return HttpResponse(t.render(c))
+
+
+def user_registration(request):
+ if request.user.is_authenticated():
+ # Already registered, redirect back to index page
+ return redirect('index')
+
+ if request.POST:
+ form = RegistrationForm(request.POST)
+ if form.is_valid():
+ # Save the user data.
+ form.save(form.cleaned_data)
+ user = authenticate(username=form.cleaned_data['username'],
+ password=form.cleaned_data['password1'])
+
+ if user is not None:
+ log('debug', user)
+ if user.is_active:
+ login(request,user)
+ return redirect('index')
+ else:
+ form = RegistrationForm()
+
+ return render_to_response('register.html', {'form': form}, context_instance=RequestContext(request))
+
diff --git a/hyperkitty/views/api.py b/hyperkitty/views/api.py
new file mode 100644
index 0000000..3a764db
--- /dev/null
+++ b/hyperkitty/views/api.py
@@ -0,0 +1,27 @@
+import re
+import os
+import json
+import urllib
+import django.utils.simplejson as simplejson
+
+from calendar import timegm
+from datetime import datetime, timedelta
+
+from urlparse import urljoin
+from django.http import HttpResponse, HttpResponseRedirect
+from django.template import RequestContext, loader
+from django.conf import settings
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger, InvalidPage
+from django.contrib.auth.decorators import (login_required,
+ permission_required,
+ user_passes_test)
+from gsoc.utils import log
+
+
+def api(request):
+ t = loader.get_template('api.html')
+ c = RequestContext(request, {
+ })
+ return HttpResponse(t.render(c))
+
+
diff --git a/hyperkitty/views/forms.py b/hyperkitty/views/forms.py
new file mode 100644
index 0000000..97e5550
--- /dev/null
+++ b/hyperkitty/views/forms.py
@@ -0,0 +1,59 @@
+from django import forms
+from django.core import validators
+from django.contrib.auth.models import User
+
+def isValidUsername(username):
+ try:
+ User.objects.get(username=username)
+ except User.DoesNotExist:
+ return
+ raise validators.ValidationError('The username "%s" is already taken.' % username)
+
+class RegistrationForm(forms.Form):
+
+ username = forms.CharField(label='username', help_text=None,
+ widget=forms.TextInput(
+ attrs={'placeholder': 'username...'}
+ ), required = True, validators=[isValidUsername]
+ )
+
+ email = forms.EmailField(required=True)
+
+ password1 = forms.CharField(widget=forms.PasswordInput)
+
+ password2 = forms.CharField(widget=forms.PasswordInput)
+
+ def save(self, new_user_data):
+ u = User.objects.create_user(new_user_data['username'],
+ new_user_data['email'],
+ new_user_data['password1'])
+ u.is_active = True
+ u.save()
+ return u
+
+
+class AddTagForm(forms.Form):
+ tag = forms.CharField(label='', help_text=None,
+ widget=forms.TextInput(
+ attrs={'placeholder': 'Add a tag...'}
+ )
+ )
+ from_url = forms.CharField(widget=forms.HiddenInput, required=False)
+
+class SearchForm(forms.Form):
+ target = forms.CharField(label='', help_text=None,
+ widget=forms.Select(
+ choices=(('Subject', 'Subject'),
+ ('Content', 'Content'),
+ ('SubjectContent', 'Subject & Content'),
+ ('From', 'From'))
+ )
+ )
+
+ keyword = forms.CharField(max_length=100,label='', help_text=None,
+ widget=forms.TextInput(
+ attrs={'placeholder': 'Search this list.'}
+ )
+ )
+
+
diff --git a/hyperkitty/views/list.py b/hyperkitty/views/list.py
new file mode 100644
index 0000000..17da2c6
--- /dev/null
+++ b/hyperkitty/views/list.py
@@ -0,0 +1,291 @@
+import re
+import os
+import json
+import urllib
+import django.utils.simplejson as simplejson
+
+from calendar import timegm
+from datetime import datetime, timedelta
+
+from urlparse import urljoin
+from django.http import HttpResponse, HttpResponseRedirect
+from django.template import RequestContext, loader
+from django.conf import settings
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger, InvalidPage
+from django.contrib.auth.decorators import (login_required,
+ permission_required,
+ user_passes_test)
+from kittystore.kittysastore import KittySAStore
+
+from gsoc.models import Rating
+from lib.mockup import *
+from forms import *
+from gsoc.utils import log
+
+
+STORE = KittySAStore(settings.KITTYSTORE_URL)
+
+
+# @TODO : Move this into settings.py
+MONTH_PARTICIPANTS = 284
+MONTH_DISCUSSIONS = 82
+
+
+
+def archives(request, mlist_fqdn, year=None, month=None, day=None):
+ # No year/month: past 32 days
+ # year and month: find the 32 days for that month
+ # @TODO : modify url.py to account for page number
+
+ end_date = None
+ if year or month or day:
+ try:
+ start_day = 1
+ end_day = 1
+ start_month = int(month)
+ end_month = int(month) + 1
+ start_year = int(year)
+ end_year = int(year)
+ if day:
+ start_day = int(day)
+ end_day = start_day + 1
+ end_month = start_month
+ if start_month == 12:
+ end_month = 1
+ end_year = start_year + 1
+
+ begin_date = datetime(start_year, start_month, start_day)
+ end_date = datetime(end_year, end_month, end_day)
+ month_string = begin_date.strftime('%B %Y')
+ except ValueError, err:
+ print err
+ logger.error('Wrong format given for the date')
+
+ if not end_date:
+ today = datetime.utcnow()
+ begin_date = datetime(today.year, today.month, 1)
+ end_date = datetime(today.year, today.month+1, 1)
+ month_string = 'Past thirty days'
+ list_name = mlist_fqdn.split('@')[0]
+
+ search_form = SearchForm(auto_id=False)
+ t = loader.get_template('month_view.html')
+ threads = STORE.get_archives(list_name, start=begin_date,
+ end=end_date)
+
+ participants = set()
+ cnt = 0
+ for msg in threads:
+ # Statistics on how many participants and threads this month
+ participants.add(msg.sender)
+ msg.participants = STORE.get_thread_participants(list_name,
+ msg.thread_id)
+ msg.answers = STORE.get_thread_length(list_name,
+ msg.thread_id)
+ threads[cnt] = msg
+ cnt = cnt + 1
+ #print msg
+
+ paginator = Paginator(threads, 10)
+ pageNo = request.GET.get('page')
+
+ try:
+ threads = paginator.page(pageNo)
+ except PageNotAnInteger:
+ # If page is not an integer, deliver first page.
+ threads = paginator.page(1)
+ except EmptyPage:
+ # If page is out of range (e.g. 9999), deliver last page of results.
+ threads = paginator.page(paginator.num_pages)
+
+
+ archives_length = STORE.get_archives_length(list_name)
+
+ c = RequestContext(request, {
+ 'list_name' : list_name,
+ 'list_address': mlist_fqdn,
+ 'search_form': search_form,
+ 'month': month_string,
+ 'month_participants': len(participants),
+ 'month_discussions': len(threads),
+ 'threads': threads,
+ 'archives_length': archives_length,
+ })
+ return HttpResponse(t.render(c))
+
+def list(request, mlist_fqdn=None):
+ if not mlist_fqdn:
+ return HttpResponseRedirect('/')
+ t = loader.get_template('recent_activities.html')
+ search_form = SearchForm(auto_id=False)
+ list_name = mlist_fqdn.split('@')[0]
+
+ # Get stats for last 30 days
+ today = datetime.utcnow()
+ end_date = datetime(today.year, today.month, today.day)
+ begin_date = end_date - timedelta(days=32)
+
+ threads = STORE.get_archives(list_name=list_name,start=begin_date,
+ end=end_date)
+
+ participants = set()
+ dates = {}
+ cnt = 0
+ for msg in threads:
+ month = msg.date.month
+ if month < 10:
+ month = '0%s' % month
+ day = msg.date.day
+ if day < 10:
+ day = '0%s' % day
+ key = '%s%s%s' % (msg.date.year, month, day)
+ if key in dates:
+ dates[key] = dates[key] + 1
+ else:
+ dates[key] = 1
+ # Statistics on how many participants and threads this month
+ participants.add(msg.sender)
+ msg.participants = STORE.get_thread_participants(list_name,
+ msg.thread_id)
+ msg.answers = STORE.get_thread_length(list_name,
+ msg.thread_id)
+ threads[cnt] = msg
+ cnt = cnt + 1
+
+ # top threads are the one with the most answers
+ top_threads = sorted(threads, key=lambda entry: entry.answers, reverse=True)
+
+ # active threads are the ones that have the most recent posting
+ active_threads = sorted(threads, key=lambda entry: entry.date, reverse=True)
+
+ archives_length = STORE.get_archives_length(list_name)
+
+ # top authors are the ones that have the most kudos. How do we determine
+ # that? Most likes for their post?
+ authors = generate_top_author()
+ authors = sorted(authors, key=lambda author: author.kudos)
+ authors.reverse()
+
+ # Get the list activity per day
+ days = dates.keys()
+ days.sort()
+ dates_string = ["%s/%s/%s" % (key[0:4], key[4:6], key[6:8]) for key in days]
+ #print days
+ #print dates_string
+ evolution = [dates[key] for key in days]
+ if not evolution:
+ evolution.append(0)
+
+ # threads per category is the top thread titles in each category
+ threads_per_category = generate_thread_per_category()
+ c = RequestContext(request, {
+ 'list_name' : list_name,
+ 'list_address': mlist_fqdn,
+ 'search_form': search_form,
+ 'month': 'Recent activity',
+ 'month_participants': len(participants),
+ 'month_discussions': len(threads),
+ 'top_threads': top_threads[:5],
+ 'most_active_threads': active_threads[:5],
+ 'top_author': authors,
+ 'threads_per_category': threads_per_category,
+ 'archives_length': archives_length,
+ 'evolution': evolution,
+ 'dates_string': dates_string,
+ })
+ return HttpResponse(t.render(c))
+
+
+def _search_results_page(request, mlist_fqdn, threads, search_type,
+ page=1, num_threads=25, limit=None):
+ search_form = SearchForm(auto_id=False)
+ t = loader.get_template('search.html')
+ list_name = mlist_fqdn.split('@')[0]
+ res_num = len(threads)
+
+ participants = set()
+ for msg in threads:
+ participants.add(msg.sender)
+
+ paginator = Paginator(threads, num_threads)
+
+ #If page request is out of range, deliver last page of results.
+ try:
+ threads = paginator.page(page)
+ except (EmptyPage, InvalidPage):
+ threads = paginator.page(paginator.num_pages)
+
+ cnt = 0
+ for msg in threads.object_list:
+ msg.email = msg.email.strip()
+ # Statistics on how many participants and threads this month
+ participants.add(msg.sender)
+ if msg.thread_id:
+ msg.participants = STORE.get_thread_participants(list_name,
+ msg.thread_id)
+ msg.answers = STORE.get_thread_length(list_name,
+ msg.thread_id)
+ else:
+ msg.participants = 0
+ msg.answers = 0
+ threads.object_list[cnt] = msg
+ cnt = cnt + 1
+
+ c = RequestContext(request, {
+ 'list_name' : list_name,
+ 'list_address': mlist_fqdn,
+ 'search_form': search_form,
+ 'month': search_type,
+ 'month_participants': len(participants),
+ 'month_discussions': res_num,
+ 'threads': threads,
+ 'full_path': request.get_full_path(),
+ })
+ return HttpResponse(t.render(c))
+
+
+def search(request, mlist_fqdn):
+ keyword = request.GET.get('keyword')
+ target = request.GET.get('target')
+ page = request.GET.get('page')
+ if keyword and target:
+ url = '/search/%s/%s/%s/' % (mlist_fqdn, target, keyword)
+ if page:
+ url += '%s/' % page
+ else:
+ url = '/search/%s' % (mlist_fqdn)
+ return HttpResponseRedirect(url)
+
+
+def search_keyword(request, mlist_fqdn, target, keyword, page=1):
+ ## Should we remove the code below?
+ ## If urls.py does it job we should never need it
+ if not keyword:
+ keyword = request.GET.get('keyword')
+ if not target:
+ target = request.GET.get('target')
+ if not target:
+ target = 'Subject'
+ regex = '%%%s%%' % keyword
+ list_name = mlist_fqdn.split('@')[0]
+ if target.lower() == 'subjectcontent':
+ threads = STORE.search_content_subject(list_name, keyword)
+ elif target.lower() == 'subject':
+ threads = STORE.search_subject(list_name, keyword)
+ elif target.lower() == 'content':
+ threads = STORE.search_content(list_name, keyword)
+ elif target.lower() == 'from':
+ threads = STORE.search_sender(list_name, keyword)
+
+ return _search_results_page(request, mlist_fqdn, threads, 'Search', page)
+
+
+def search_tag(request, mlist_fqdn, tag=None, page=1):
+ '''Searches both tag and topic'''
+ if tag:
+ query_string = {'Category': tag.capitalize()}
+ else:
+ query_string = None
+ return _search_results_page(request, mlist_fqdn, query_string,
+ 'Tag search', page, limit=50)
+
diff --git a/hyperkitty/views/message.py b/hyperkitty/views/message.py
new file mode 100644
index 0000000..0b70969
--- /dev/null
+++ b/hyperkitty/views/message.py
@@ -0,0 +1,82 @@
+import re
+import os
+import django.utils.simplejson as simplejson
+
+from django.http import HttpResponse, HttpResponseRedirect
+from django.template import RequestContext, loader
+from django.conf import settings
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger, InvalidPage
+from django.contrib.auth.decorators import (login_required,
+ permission_required,
+ user_passes_test)
+
+from kittystore.kittysastore import KittySAStore
+
+from gsoc.models import Rating
+from lib.mockup import *
+from forms import *
+from gsoc.utils import log
+
+STORE = KittySAStore(settings.KITTYSTORE_URL)
+
+
+def index (request, mlist_fqdn, messageid):
+ ''' Displays a single message identified by its messageid '''
+ list_name = mlist_fqdn.split('@')[0]
+
+ search_form = SearchForm(auto_id=False)
+ t = loader.get_template('message.html')
+ message = STORE.get_email(list_name, messageid)
+ message.email = message.email.strip()
+ # Extract all the votes for this message
+ try:
+ votes = Rating.objects.filter(messageid = messageid)
+ except Rating.DoesNotExist:
+ votes = {}
+
+ likes = 0
+ dislikes = 0
+
+ for vote in votes:
+ if vote.vote == 1:
+ likes = likes + 1
+ elif vote.vote == -1:
+ dislikes = dislikes + 1
+ else:
+ pass
+
+ message.votes = votes
+ message.likes = likes
+ message.dislikes = dislikes
+
+ c = RequestContext(request, {
+ 'list_name' : list_name,
+ 'list_address': mlist_fqdn,
+ 'message': message,
+ 'messageid' : messageid,
+ })
+ return HttpResponse(t.render(c))
+
+
+
+@login_required
+def vote (request, mlist_fqdn):
+ """ Add a rating to a given message identified by messageid. """
+ if not request.user.is_authenticated():
+ return redirect('user_login')
+
+ value = request.POST['vote']
+ messageid = request.POST['messageid']
+
+ # Checks if the user has already voted for a this message. If yes modify db entry else create a new one.
+ try:
+ v = Rating.objects.get(user = request.user, messageid = messageid, list_address = mlist_fqdn)
+ except Rating.DoesNotExist:
+ v = Rating(list_address=mlist_fqdn, messageid = messageid, vote = value)
+
+ v.user = request.user
+ v.vote = value
+ v.save()
+ response_dict = { }
+
+ return HttpResponse(simplejson.dumps(response_dict), mimetype='application/javascript')
diff --git a/hyperkitty/views/pages.py b/hyperkitty/views/pages.py
new file mode 100644
index 0000000..189d574
--- /dev/null
+++ b/hyperkitty/views/pages.py
@@ -0,0 +1,38 @@
+#-*- coding: utf-8 -*-
+
+import re
+import os
+import json
+import urllib
+import django.utils.simplejson as simplejson
+
+from calendar import timegm
+from datetime import datetime, timedelta
+
+from urlparse import urljoin
+from django.http import HttpResponse, HttpResponseRedirect
+from django.template import RequestContext, loader
+from django.conf import settings
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger, InvalidPage
+from django.contrib.auth.decorators import (login_required,
+ permission_required,
+ user_passes_test)
+from gsoc.models import Rating
+from lib.mockup import *
+from forms import *
+from gsoc.utils import log
+
+def index(request):
+ t = loader.get_template('index.html')
+ search_form = SearchForm(auto_id=False)
+
+ base_url = settings.MAILMAN_API_URL % {
+ 'username': settings.MAILMAN_USER, 'password': settings.MAILMAN_PASS}
+
+ list_data = ['devel@fp.o', 'packaging@fp.o', 'fr-users@fp.o']
+
+ c = RequestContext(request, {
+ 'lists': list_data,
+ 'search_form': search_form,
+ })
+ return HttpResponse(t.render(c))
diff --git a/hyperkitty/views/thread.py b/hyperkitty/views/thread.py
new file mode 100644
index 0000000..06a1bda
--- /dev/null
+++ b/hyperkitty/views/thread.py
@@ -0,0 +1,113 @@
+import django.utils.simplejson as simplejson
+
+from django.http import HttpResponse, HttpResponseRedirect
+from django.template import RequestContext, loader
+from django.conf import settings
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger, InvalidPage
+from django.contrib.auth.decorators import (login_required,
+ permission_required,
+ user_passes_test)
+from kittystore.kittysastore import KittySAStore
+
+from gsoc.models import Rating
+from lib.mockup import *
+from forms import *
+from gsoc.utils import log
+
+STORE = KittySAStore(settings.KITTYSTORE_URL)
+
+
+
+def thread_index (request, mlist_fqdn, threadid):
+ ''' Displays all the email for a given thread identifier '''
+ list_name = mlist_fqdn.split('@')[0]
+
+ search_form = SearchForm(auto_id=False)
+ t = loader.get_template('thread.html')
+ threads = STORE.get_thread(list_name, threadid)
+ #prev_thread = mongo.get_thread_name(list_name, int(threadid) - 1)
+ prev_thread = []
+ if len(prev_thread) > 30:
+ prev_thread = '%s...' % prev_thread[:31]
+ #next_thread = mongo.get_thread_name(list_name, int(threadid) + 1)
+ next_thread = []
+ if len(next_thread) > 30:
+ next_thread = '%s...' % next_thread[:31]
+
+ participants = {}
+ cnt = 0
+
+ for message in threads:
+ # @TODO: Move this logic inside KittyStore?
+ message.email = message.email.strip()
+
+ # Extract all the votes for this message
+ try:
+ votes = Rating.objects.filter(messageid = message.message_id)
+ except Rating.DoesNotExist:
+ votes = {}
+
+ likes = 0
+ dislikes = 0
+
+ for vote in votes:
+ if vote.vote == 1:
+ likes = likes + 1
+ elif vote.vote == -1:
+ dislikes = dislikes + 1
+ else:
+ pass
+
+ message.votes = votes
+ message.likes = likes
+ message.dislikes = dislikes
+
+ # Statistics on how many participants and threads this month
+ participants[message.sender] = {'email': message.email}
+ cnt = cnt + 1
+
+ archives_length = STORE.get_archives_length(list_name)
+ from_url = '/thread/%s/%s/' %(mlist_fqdn, threadid)
+ tag_form = AddTagForm(initial={'from_url' : from_url})
+
+ c = RequestContext(request, {
+ 'list_name' : list_name,
+ 'list_address': mlist_fqdn,
+ 'search_form': search_form,
+ 'addtag_form': tag_form,
+ 'month': 'Thread',
+ 'participants': participants,
+ 'answers': cnt,
+ 'first_mail': threads[0],
+ 'threads': threads[1:],
+ 'next_thread': next_thread,
+ 'next_thread_id': 0,
+ 'prev_thread': prev_thread,
+ 'prev_thread_id': 0,
+ 'archives_length': archives_length,
+ })
+ return HttpResponse(t.render(c))
+
+
+@login_required
+def add_tag(request, mlist_fqdn, email_id):
+ """ Add a tag to a given thread. """
+ t = loader.get_template('threads/add_tag_form.html')
+ if request.method == 'POST':
+ form = AddTagForm(request.POST)
+ if form.is_valid():
+ print "THERE WE ARE"
+ # TODO: Add the logic to add the tag
+ if form.data['from_url']:
+ return HttpResponseRedirect(form.data['from_url'])
+ else:
+ return HttpResponseRedirect('/')
+ else:
+ form = AddTagForm()
+ c = RequestContext(request, {
+ 'list_address': mlist_fqdn,
+ 'email_id': email_id,
+ 'addtag_form': form,
+ })
+ return HttpResponse(t.render(c))
+