# Path: topics/models.py
# class Topic(TimeStampedModel):
#     """
#     Stores a topic, basically a string like a tag and manages it.
#     """
# 
#     # Topic fields
#     title     = models.CharField(max_length=128)
#     slug      = AutoSlugField(populate_from='title', unique=True)
#     link      = models.URLField(null=True, blank=True, default=None)
#     refers_to = models.ForeignKey('self', related_name='references', null=True, blank=True, default=None)
#     is_canonical = models.BooleanField(default=True)
# 
#     # Custom topic manager
#     objects = TopicManager()
# 
#     # Topic meta class
#     class Meta:
#         db_table = 'topics'
#         ordering = ('title', )
# 
#     def __unicode__(self):
#         return self.title
# 
#     def vote_total(self):
#         """
#         Accumulates the votes via aggregation
#         """
#         votes = self.votes.aggregate(
#             total=models.Sum('vote')
#         )['total']
# 
#         if self.is_canonical:
#             for ref in self.references.all():
#                 votes += ref.vote_total()
# 
#         return votes
# 
# class Vote(TimeStampedModel):
#     """
#     Simple voting model that stores an up or down vote for a particular topic
#     associated with a particular IP address (and time of day).
#     """
# 
#     DATEFMT  = "%a %b %d, %Y at %H:%M"
#     BALLOT   = Choices((-1, 'downvote', 'downvote'), (1, 'upvote', 'upvote'), (0, 'novote', 'novote'))
# 
#     # Vote fields
#     vote    = models.SmallIntegerField(choices=BALLOT, default=BALLOT.upvote)
#     topic   = models.ForeignKey(Topic, related_name='votes')
#     ipaddr  = models.GenericIPAddressField()
# 
#     # Custom voting manager
#     objects = VotingManager()
# 
#     # Vote meta class
#     class Meta:
#         db_table = 'voting'
#         ordering = ('-created',)
# 
#     def __unicode__(self):
#         action = {
#             -1: "-1",
#              0: "--",
#              1: "+1",
#         }[self.vote]
# 
#         return "{} for \"{}\" ({} on {})".format(
#             action, self.topic, self.ipaddr, self.modified.strftime(self.DATEFMT)
#         )
# 
# Path: topics/forms.py
# class MultiTopicForm(forms.Form):
#     """
#     Post multiple topics separated by newlines.
#     """
# 
#     topics = forms.CharField(
#         widget=forms.Textarea, required=True,
#         help_text="Enter multiple topics each on their own line."
#     )
# 
#     def __init__(self, *args, **kwargs):
#         self.request = kwargs.pop('request', None)
#         super(MultiTopicForm, self).__init__(*args, **kwargs)
# 
#     @property
#     def ipaddr(self):
#         """
#         Get the IP Address of the form submitter via the request.
#         """
#         if not hasattr(self, '_ipaddr'):
#             self._ipaddr = get_real_ip(self.request) or get_ip(self.request)
#         return self._ipaddr
# 
#     def clean_topics(self):
#         """
#         Run validation for topics form.
#         """
# 
#         data   = self.cleaned_data['topics']
#         topics = filter(lambda x: x, [slugify(t) for t in data.splitlines()])
# 
#         # Check if there are commas or semicolons in the field.
#         if "," in data or ";" in data or "|" in data:
#             raise forms.ValidationError(
#                 _("This form is not comma, semicolon, or pipe delimited!"),
#                 code="bad_delimiter"
#             )
# 
#         # Ensure at least two topics are submitted.
#         if len(topics) < 2:
#             raise forms.ValidationError(
#                 _("Please provide at least 2 topics, techniques, or technologies!"),
#                 code="single_topic_error"
#             )
# 
#         # 50 topics is too many.
#         if len(topics) > 50:
#             raise forms.ValidationError(
#                 _("Thanks for thinking of so many topics! To prevent spam, however, "
#                   "we have to limit you to 50 topics per form submission."),
#                 code="topic_spam_error"
#             )
# 
#         # Ensure topic uniqueness in submission.
#         if len(frozenset(topics)) < len(topics):
#             raise forms.ValidationError(
#                 _("Duplicate topics detected! Please check your list and try again."),
#                 code="duplicate_topics"
#             )
# 
#         return data
# 
#     def save_topics(self):
#         """
#         Write the topics and their votes to disk.
#         """
#         for topic in Topic.objects.from_string(self.cleaned_data['topics']):
#             Vote.objects.create(topic=topic, ipaddr=self.ipaddr)


import csv
import random
from topics.serializers import *
from topics.models import Topic, Vote
from topics.forms import MultiTopicForm
from django.http import HttpResponse
from django.views.generic import View, TemplateView
from django.views.generic.edit import FormView
from django.core.urlresolvers import reverse
from braces.views import LoginRequiredMixin
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework.exceptions import APIException
        writer.writerow(('user', 'term', 'time'))
        for vote in self.queryset:
            # Set unique id tag for ip address if not exists
            if vote.ipaddr not in ipmap:
                idtag += 1
                ipmap[vote.ipaddr] = idtag

            # write the row to the CSV file
            writer.writerow([
                ipmap[vote.ipaddr], vote.topic, vote.created.strftime(dtfmt)
            ])

        return response

##########################################################################
## API/DRF Views
##########################################################################

class BadParameter(APIException):

    status_code    = 400
    default_detail = 'Bad parameter passed into GET request.'


class TopicViewSet(viewsets.ViewSet):

    queryset = Topic.objects.with_votes()
    serializer_class = TopicSerializer

    def random_topics(self, limit=10):

# Path: topics/models.py
# class Topic(TimeStampedModel):
#     """
#     Stores a topic, basically a string like a tag and manages it.
#     """
# 
#     # Topic fields
#     title     = models.CharField(max_length=128)
#     slug      = AutoSlugField(populate_from='title', unique=True)
#     link      = models.URLField(null=True, blank=True, default=None)
#     refers_to = models.ForeignKey('self', related_name='references', null=True, blank=True, default=None)
#     is_canonical = models.BooleanField(default=True)
# 
#     # Custom topic manager
#     objects = TopicManager()
# 
#     # Topic meta class
#     class Meta:
#         db_table = 'topics'
#         ordering = ('title', )
# 
#     def __unicode__(self):
#         return self.title
# 
#     def vote_total(self):
#         """
#         Accumulates the votes via aggregation
#         """
#         votes = self.votes.aggregate(
#             total=models.Sum('vote')
#         )['total']
# 
#         if self.is_canonical:
#             for ref in self.references.all():
#                 votes += ref.vote_total()
# 
#         return votes
# 
# class Vote(TimeStampedModel):
#     """
#     Simple voting model that stores an up or down vote for a particular topic
#     associated with a particular IP address (and time of day).
#     """
# 
#     DATEFMT  = "%a %b %d, %Y at %H:%M"
#     BALLOT   = Choices((-1, 'downvote', 'downvote'), (1, 'upvote', 'upvote'), (0, 'novote', 'novote'))
# 
#     # Vote fields
#     vote    = models.SmallIntegerField(choices=BALLOT, default=BALLOT.upvote)
#     topic   = models.ForeignKey(Topic, related_name='votes')
#     ipaddr  = models.GenericIPAddressField()
# 
#     # Custom voting manager
#     objects = VotingManager()
# 
#     # Vote meta class
#     class Meta:
#         db_table = 'voting'
#         ordering = ('-created',)
# 
#     def __unicode__(self):
#         action = {
#             -1: "-1",
#              0: "--",
#              1: "+1",
#         }[self.vote]
# 
#         return "{} for \"{}\" ({} on {})".format(
#             action, self.topic, self.ipaddr, self.modified.strftime(self.DATEFMT)
#         )
# 
# Path: topics/forms.py
# class MultiTopicForm(forms.Form):
#     """
#     Post multiple topics separated by newlines.
#     """
# 
#     topics = forms.CharField(
#         widget=forms.Textarea, required=True,
#         help_text="Enter multiple topics each on their own line."
#     )
# 
#     def __init__(self, *args, **kwargs):
#         self.request = kwargs.pop('request', None)
#         super(MultiTopicForm, self).__init__(*args, **kwargs)
# 
#     @property
#     def ipaddr(self):
#         """
#         Get the IP Address of the form submitter via the request.
#         """
#         if not hasattr(self, '_ipaddr'):
#             self._ipaddr = get_real_ip(self.request) or get_ip(self.request)
#         return self._ipaddr
# 
#     def clean_topics(self):
#         """
#         Run validation for topics form.
#         """
# 
#         data   = self.cleaned_data['topics']
#         topics = filter(lambda x: x, [slugify(t) for t in data.splitlines()])
# 
#         # Check if there are commas or semicolons in the field.
#         if "," in data or ";" in data or "|" in data:
#             raise forms.ValidationError(
#                 _("This form is not comma, semicolon, or pipe delimited!"),
#                 code="bad_delimiter"
#             )
# 
#         # Ensure at least two topics are submitted.
#         if len(topics) < 2:
#             raise forms.ValidationError(
#                 _("Please provide at least 2 topics, techniques, or technologies!"),
#                 code="single_topic_error"
#             )
# 
#         # 50 topics is too many.
#         if len(topics) > 50:
#             raise forms.ValidationError(
#                 _("Thanks for thinking of so many topics! To prevent spam, however, "
#                   "we have to limit you to 50 topics per form submission."),
#                 code="topic_spam_error"
#             )
# 
#         # Ensure topic uniqueness in submission.
#         if len(frozenset(topics)) < len(topics):
#             raise forms.ValidationError(
#                 _("Duplicate topics detected! Please check your list and try again."),
#                 code="duplicate_topics"
#             )
# 
#         return data
# 
#     def save_topics(self):
#         """
#         Write the topics and their votes to disk.
#         """
#         for topic in Topic.objects.from_string(self.cleaned_data['topics']):
#             Vote.objects.create(topic=topic, ipaddr=self.ipaddr)


# Path: topics/views.py
import csv
import random
from topics.serializers import *
from topics.models import Topic, Vote
from topics.forms import MultiTopicForm
from django.http import HttpResponse
from django.views.generic import View, TemplateView
from django.views.generic.edit import FormView
from django.core.urlresolvers import reverse
from braces.views import LoginRequiredMixin
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework.exceptions import APIException

        writer.writerow(('user', 'term', 'time'))
        for vote in self.queryset:
            # Set unique id tag for ip address if not exists
            if vote.ipaddr not in ipmap:
                idtag += 1
                ipmap[vote.ipaddr] = idtag

            # write the row to the CSV file
            writer.writerow([
                ipmap[vote.ipaddr], vote.topic, vote.created.strftime(dtfmt)
            ])

        return response

##########################################################################
## API/DRF Views
##########################################################################

class BadParameter(APIException):

    status_code    = 400
    default_detail = 'Bad parameter passed into GET request.'


class TopicViewSet(viewsets.ViewSet):

    queryset = Topic.objects.with_votes()
    serializer_class = TopicSerializer

    def random_topics(self, limit=10):

        last = Topic.objects.filter(is_canonical=True).count() - 1