Commit 44bbca8a authored by jc's avatar jc

fixes with autopep8

parent 0161a2d3
from django.contrib import admin
from bt import models
class CommentInline(admin.TabularInline):
model = models.Comment
max_num = 1
class ViolationAdmin(admin.ModelAdmin):
list_display = ('state', 'country', 'operator', 'contract', 'resource_name', 'media', 'activationid', 'old', 'creation_date')
list_filter = ('state', 'operator_ref', 'contract', 'resource_name', 'media', 'country', 'old')
inlines = [CommentInline, ], ViolationAdmin)
class CommentAdmin(admin.ModelAdmin):
list_display = ('violation', 'submitter_name', 'comment')
list_filter = ('violation', 'submitter_name'), CommentAdmin)
class AttachmentAdmin(admin.ModelAdmin):
list_display = ('name', 'comment'), AttachmentAdmin)
class ConfirmationAdmin(admin.ModelAdmin):
list_display = ('violation', 'key')
list_filter = ('violation__operator_ref', 'violation__contract', 'violation__resource_name', 'violation__media', 'violation__country'), ConfirmationAdmin)
class FeaturedCaseAdmin(admin.ModelAdmin):
pass, FeaturedCaseAdmin)
class OperatorAdmin(admin.ModelAdmin):
list_display = ("__unicode__", "reported_violations")
search_fields = ('name', )
pass, OperatorAdmin)
......@@ -5,7 +5,7 @@ from tastypie.resources import ModelResource, ALL, ALL_WITH_RELATIONS
from bt.models import Violation, Operator
#class UserResource(ModelResource):
# class UserResource(ModelResource):
# class Meta:
# queryset = User.objects.all()
# resource_name = 'auth/user'
......@@ -2,6 +2,7 @@ from django.contrib.syndication.views import Feed
from django.utils.feedgenerator import Atom1Feed
from bt.models import Violation
class RssSiteNewsFeed(Feed):
title = "NNMON - Latest NN Infringements"
link = "/"
......@@ -17,7 +18,7 @@ class RssSiteNewsFeed(Feed):
def item_title(self, item):
return "%s (%s) %s" % (item.operator,, item.contract)
class AtomSiteNewsFeed(RssSiteNewsFeed):
feed_type = Atom1Feed
subtitle = RssSiteNewsFeed.description
......@@ -8,16 +8,19 @@ from bt.multifile import MultiFileField
from operator import itemgetter
from captcha.fields import CaptchaField
class AdvancedEditor(forms.Textarea):
class Media:
js = (settings.MEDIA_URL+'/js/tinymce/tiny_mce.js',)
js = (settings.MEDIA_URL + '/js/tinymce/tiny_mce.js',)
def __init__(self, language=None, attrs=None):
self.language = language or settings.LANGUAGE_CODE[:2]
self.attrs = {'class': 'advancededitor'}
if attrs: self.attrs.update(attrs)
if attrs:
super(AdvancedEditor, self).__init__(attrs)
class AddViolation(forms.Form):
resource_name = forms.CharField(required=True, max_length=4096, label=_('Please describe the discrimination'), help_text=_("What service or site, or person is unavailable or seems artificially slowed down. e.g. VoIP, p2p, filesharing, specific websites, etc."))
country = forms.ChoiceField(required=True, choices=(('',''),)+tuple(sorted(COUNTRIES,key=itemgetter(1))), label=_("Country"), help_text=_('EU member state where the discrimination is reported.'))
......@@ -67,5 +70,6 @@ class SearchViolation(SearchForm):
return sqs
class QuickSearchViolation(forms.Form):
query = forms.CharField(required='True', max_length=256, label=_("Search"), help_text=_('Search for an existing violation'))
......@@ -36,7 +36,7 @@ COUNTRIES = (
('FI', _('Finland')),
('SE', _('Sweden')),
('UK', _('United Kingdom')),
('other', _('other')),
('port', _('port')),
......@@ -48,7 +48,7 @@ RESOURCES = (
('video', _('video streaming')),
('audio', _('audio streaming')),
('class', _('class of application or contraint')),
('zerorating', _('Zero Rating')),
('specialised', _('Specialised Service')),
......@@ -56,11 +56,11 @@ TYPES = (
('throttling', _('Throttling')),
('prioritisation', _('Prioritisation')),
('other', _('Other'))
('fixed', _('Fixed')),
('mobile', _('Mobile')),
('moreinfo', _('Need more info')),
('new', _('New')),
......@@ -69,7 +69,8 @@ STATUS = (
('ooscope', _('Out of scope')),
('resolved', _('Resolved')),
('closed', _('Closed')),
class Operator(models.Model):
......@@ -85,6 +86,7 @@ class Operator(models.Model):
def __unicode__(self):
class Violation(models.Model):
country = models.CharField(max_length=2, choices=COUNTRIES)
operator_ref = models.ForeignKey(Operator, related_name="violations")
......@@ -92,12 +94,12 @@ class Violation(models.Model):
resource = models.CharField(max_length=20, choices=RESOURCES, blank=True)
resource_name = models.CharField(max_length=4096, blank=True)
type = models.CharField(max_length=20, choices=TYPES, blank=True)
media = models.CharField( max_length=20, choices=MEDIA, blank=True)
temporary = models.BooleanField( )
media = models.CharField(max_length=20, choices=MEDIA, blank=True)
temporary = models.BooleanField()
contractual = models.BooleanField()
contract_excerpt = models.TextField(null=True, blank=True)
loophole = models.BooleanField()
activationid= models.CharField(max_length=128, null=True, blank=True)
activationid = models.CharField(max_length=128, null=True, blank=True)
state = models.CharField(max_length=20, choices=STATUS, default='new', blank=True)
editorial = models.TextField(null=True, blank=True)
old = models.BooleanField(default="False")
......@@ -131,7 +133,7 @@ class Violation(models.Model):
class Comment(models.Model):
submitter_email = models.EmailField()
submitter_name = models.CharField(max_length=20)
consent = models.BooleanField( )
consent = models.BooleanField()
comment = models.TextField()
timestamp = models.DateTimeField()
violation = models.ForeignKey(Violation)
......@@ -142,10 +144,11 @@ class Comment(models.Model):
def __unicode__(self):
return _("Comment #%s") % (
class Attachment(models.Model):
storage = models.FileField(upload_to='static')
name= models.CharField(max_length=512)
type= models.CharField(max_length=512)
name = models.CharField(max_length=512)
type = models.CharField(max_length=512)
comment = models.ForeignKey(Comment)
class Admin:
......@@ -154,23 +157,28 @@ class Attachment(models.Model):
def __unicode__(self):
class Confirmation(models.Model):
key=models.CharField(max_length=64, blank=True)
key = models.CharField(max_length=64, blank=True)
email = models.EmailField()
violation = models.ForeignKey(Violation)
class Admin:
class ViolationModerator(CommentModerator):
email_notification = True
moderate_after = 0
def moderate(self, comment, content_object, request):
return True
if Violation not in moderator._registry:
moderator.register(Violation, ViolationModerator)
class FeaturedCase(models.Model):
case = models.OneToOneField(Violation)
......@@ -16,6 +16,7 @@ from django.utils.safestring import mark_safe
class MultiFileInput(Input):
A widget to be used by the MultiFileField to allow the user to upload
......@@ -57,6 +58,7 @@ class MultiFileInput(Input):
return id_
id_for_label = classmethod(id_for_label)
class MultiFileField(Field):
A field allowing users to upload multiple files at once.
from haystack import indexes
from models import Operator, Violation
class ViolationIndexes(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
operator = indexes.CharField(model_attr="operator_ref")
......@@ -8,7 +8,8 @@ from bt.models import Violation
from django.db.models import Count
import odslib
from django.utils.html import strip_tags
import re, htmlentitydefs
import re
import htmlentitydefs
# Removes HTML or XML character references and entities from a text string.
......@@ -16,8 +17,10 @@ import re, htmlentitydefs
# @return The plain text, as a Unicode string, if necessary.
# source:
def unescape(text):
text = strip_tags(text)
def fixup(m):
text =
if text[:2] == "&#":
......@@ -38,44 +41,46 @@ def unescape(text):
return text # leave as is
return re.sub("&#?\w+;", fixup, text)
def save_ods():
# Create your document
doc = ooolib.Calc()
col = 1
row = 2
doc.set_cell_property('bold', True)
doc.set_row_property(row, 'height', '16.5pt')
for heading, width in [('Country', '73pt'),
('Operator', '77pt'),
('Type of measure*','355pt'),
('Type of measure*', '355pt'),
('', '355pt'),
('Description of the measure', '148pt'),
('Method of implementation (if applicable)',''),
('Number of subscribers having a subscription where this measure is implemented',''),
('How is the user informed?','148pt'),
('Objective', ''),
('Method of implementation (if applicable)', ''),
('Number of subscribers having a subscription where this measure is implemented', ''),
('How is the user informed?', '148pt'),
('Can the user activate/deactivate the measure? How?', '148pt'),
('Protection of business secret','239pt')]:
if width: doc.set_column_property(col, 'width', width)
('Protection of business secret', '239pt')]:
if width:
doc.set_column_property(col, 'width', width)
doc.set_cell_value(col, row, "string", heading)
col += 1
doc.set_cell_property('bold', False)
row = 3
for v in Violation.objects.filter(activationid='').exclude(state__in=['closed', 'ooscope', 'duplicate']).annotate(total=Count('confirmation')):
if>0 or v.state=='verified':
if > 0 or v.state == 'verified':
doc.set_row_property(row, 'height', '16.5pt')
doc.set_cell_property('wrap-option', 'wrap')
doc.set_cell_value(1, row, "string",
doc.set_cell_value(2, row, "string", v.operator)
doc.set_cell_value(3, row, "string", "%s %s" % (v.type, v.resource_name))
doc.set_cell_value(5, row, "string", "%s\n\n%s" % ( v.editorial, unescape(v.comment_set.get().comment)))
doc.set_cell_value(5, row, "string", "%s\n\n%s" % (v.editorial, unescape(v.comment_set.get().comment)))
doc.set_cell_value(9, row, "string", "%s %s" % ("Contractual" if v.contractual else "", unescape(v.contract_excerpt)))
doc.set_cell_value(10, row, "string", "can update to a different dataplan" if v.loophole else "")
doc.set_cell_value(12, row, "string",
row += 1
#(v.state,, v.operator, v.contract, v.resource, v.resource_name, v.type,, v.temporary, v.contractual, v.contract_excerpt, v.loophole, v.editorial,v.comment_set.get().comment)
# Save the document to the file you want to create
......@@ -6,20 +6,28 @@ from ..models import COUNTRIES, STATUS, TYPES, MEDIA
register = Library()
def root_url():
return settings.ROOT_URL
def media_url():
return settings.MEDIA_URL
country_map = dict(COUNTRIES)
def country(code):
return country_map[code]
status_map = dict(STATUS)
def status(code):
......@@ -27,7 +35,10 @@ def status(code):
return code
type_map = dict(TYPES)
def type(code):
......@@ -35,7 +46,10 @@ def type(code):
return code
media_map = dict(MEDIA)
def media(code):
......@@ -6,6 +6,7 @@ import json
register = Library()
def jsonify(object):
if isinstance(object, QuerySet):
......@@ -20,7 +20,10 @@ from haystack.query import SearchQuerySet
from models import Violation, Attachment, Comment, Confirmation, COUNTRIES, STATUS, Operator, FeaturedCase
from tempfile import mkstemp
from datetime import datetime
import hashlib, os, re, json
import hashlib
import os
import re
import json
from random import randint
from email.mime.text import MIMEText
from email.header import Header
......@@ -29,6 +32,7 @@ from BeautifulSoup import BeautifulSoup, Comment as BComment
from operator import itemgetter
from itertools import groupby
def sanitizeHtml(value, base_url=None):
rjs = r'[\s]*(&#x.{1,7})?'.join(list('javascript:'))
rvb = r'[\s]*(&#x.{1,7})?'.join(list('vbscript:'))
......@@ -54,16 +58,17 @@ def sanitizeHtml(value, base_url=None):
return soup.renderContents().decode('utf8')
def activate(request):
v = Violation.objects.get(activationid=request.GET.get('key', 'asdf'))
messages.add_message(request, messages.INFO, unicode(_('Thank you, this key has been already activated')))
return HttpResponseRedirect('/') # Redirect after POST
if v:
actid = hashlib.sha1(''.join([chr(randint(32, 122)) for x in range(12)])).hexdigest()
to=[ for x in User.objects.filter(groups__name='moderator')]
details='\n'.join(["%s: %s" % (k.capitalize(), val) for k,val in v.__dict__.items() if not k.startswith('_') and val])
to = [ for x in User.objects.filter(groups__name='moderator')]
details = '\n'.join(["%s: %s" % (k.capitalize(), val) for k, val in v.__dict__.items() if not k.startswith('_') and val])
msg = {'from': '',
'to': to,
......@@ -73,21 +78,21 @@ def activate(request):
send_mail(msg['subject'], msg['body'], msg['from'], msg['to'], fail_silently=False)
v.activationid = actid
messages.add_message(request, messages.INFO, _('Thank you for verifying your submission. It will be listed shortly, after we\'ve checked that the report is valid.').encode("Utf-8"))
return HttpResponseRedirect('/') # Redirect after POST
def moderate(request):
v = Violation.objects.get(activationid=request.GET.get('key', 'asdf'))
messages.add_message(request, messages.INFO, unicode(_('Thank you, this key has been already activated')))
return HttpResponseRedirect('/') # Redirect after POST
if not v:
messages.add_message(request, messages.INFO, _('No such key'))
return HttpResponseRedirect('/') # Redirect after POST
if request.GET.get('action','')=='approve':
if request.GET.get('action', '') == 'approve':
messages.add_message(request, messages.INFO, _('Thank you for approving the <a href="%s">submission</a>.' % v.get_absolute_url()))
msg = {'from': '',
......@@ -100,20 +105,23 @@ def moderate(request):
if settings.TWITTER_API:
settings.TWITTER_API.PostUpdate("New #NetNeutrality violation reported for %s (%s) %s %s/%s" % (v.operator,, v.contract, settings.ROOT_URL or 'http://localhost:8001/',
settings.TWITTER_API.PostUpdate("New #NetNeutrality violation reported for %s (%s) %s %s/%s" %
(v.operator,, v.contract, settings.ROOT_URL or 'http://localhost:8001/',
v.activationid = ''
return redirect(v) # Redirect after POST to violation url
if request.GET.get('action','')=='delete':
if request.GET.get('action', '') == 'delete':
messages.add_message(request, messages.INFO, _('Thank you for deleting the submission.'))
return HttpResponseRedirect('/') # Redirect after POST
return render_to_response('view.html', { 'v': v, 'key': request.GET.get('key') },context_instance=RequestContext(request))
return render_to_response('view.html', {'v': v, 'key': request.GET.get('key')}, context_instance=RequestContext(request))
from django.db import transaction
def confirm(request, id, name=None):
......@@ -123,11 +131,11 @@ def confirm(request, id, name=None):
if name:
if Confirmation.objects.filter(email=name, violation=id).count()==0:
msg=_("Thank you for confirming a case. To finalize your confirmation please validate using your confirmation key.\nYour confirmation key is %s/%s%s")
actid=sendverifymail('confirm/',name, msg)
if Confirmation.objects.filter(email=name, violation=id).count() == 0:
msg = _("Thank you for confirming a case. To finalize your confirmation please validate using your confirmation key.\nYour confirmation key is %s/%s%s")
actid = sendverifymail('confirm/', name, msg)
c=Confirmation(key=actid, email=name, violation=violation)
c = Confirmation(key=actid, email=name, violation=violation)
# should except IntegrityError properly
return HttpResponse(unicode(_('Thank you, this has been already confirmed')))
......@@ -138,12 +146,13 @@ def confirm(request, id, name=None):
messages.add_message(request, messages.INFO, unicode(_("Thank you, this has been already confirmed")))
return HttpResponseRedirect('/') # Redirect after POST
c.key = ''
messages.add_message(request, messages.INFO, unicode(_('Thank you for verifying your confirmation')))
return HttpResponseRedirect('/') # Redirect after POST
def sendverifymail(service,to,body):
def sendverifymail(service, to, body):
actid = hashlib.sha1(''.join([chr(randint(32, 122)) for x in range(12)])).hexdigest()
msg = {'from': '',
'to': [to.encode("Utf-8")],
......@@ -154,6 +163,7 @@ def sendverifymail(service,to,body):
return actid
class AddForm(FormView):
template_name = 'index.html'
form_class = AddViolation
......@@ -164,23 +174,23 @@ class AddForm(FormView):
#actid=sendverifymail('activate?key=',form.cleaned_data['email'], msg)
actid = hashlib.sha1(''.join([chr(randint(32, 122)) for x in range(12)])).hexdigest()
operator, created = Operator.objects.get_or_create(name=form.cleaned_data['operator'])
country = form.cleaned_data['country'],
operator_ref = operator,
contract = form.cleaned_data['contract'],
resource = form.cleaned_data['resource'],
resource_name = form.cleaned_data['resource_name'],
type = form.cleaned_data['type'],
media = form.cleaned_data['media'],
temporary = form.cleaned_data['temporary'],
contractual = form.cleaned_data['contractual'],
contract_excerpt = sanitizeHtml(form.cleaned_data['contract_excerpt']),
loophole = form.cleaned_data['loophole'],
activationid = actid,
old = False
v = Violation(
conf=Confirmation(key=actid, email=form.cleaned_data['email'], violation=v)
conf = Confirmation(key=actid, email=form.cleaned_data['email'], violation=v)
c = Comment(
......@@ -192,12 +202,12 @@ class AddForm(FormView):
for f in self.request.FILES.getlist('attachments[]'):
a=Attachment(comment=c,, type=f.content_type)
a = Attachment(comment=c,, type=f.content_type)
m = hashlib.sha256()
for chunk in f.chunks():
sname = m.hexdigest(), f)
messages.add_message(self.request, messages.INFO, _('Thank you for submitting this report.'))
return super(AddForm, self).form_valid(form)
......@@ -214,12 +224,13 @@ class AddForm(FormView):
for i in Violation.objects.values('operator_ref__name').exclude(state__in=['closed', 'ooscope', 'duplicate']).exclude(old=True).annotate(total=Count('confirmation'))],
context['stats'] = [
(_('Total confirmed reports'), len([i for i,z in reports if i>0])),
(_('Countries with some confirmed reports'), len([i for i,z in confirms if i>0])),
(_('Operators with some confirmed reports'), len([i for i,z in operators if i>0]))]
(_('Total confirmed reports'), len([i for i, z in reports if i > 0])),
(_('Countries with some confirmed reports'), len([i for i, z in confirms if i > 0])),
(_('Operators with some confirmed reports'), len([i for i, z in operators if i > 0]))]
context['violations'] = [ for fc in FeaturedCase.objects.all() if not][:3]
return context
class ViolationsList(ListView):
template_name = 'list.html'
context_object_name = 'violations'
......@@ -245,17 +256,19 @@ class ViolationsList(ListView):
countries = sorted([(i['total'], i['country'])
for i in Violation.objects.values('country').exclude(state__in=['ooscope', 'duplicate', 'closed']).exclude(old=True).annotate(total=Count('country'))],
countryweights=json.dumps([{'iso2': y, 'w': x} for x, y in countries])
countryweights = json.dumps([{'iso2': y, 'w': x} for x, y in countries])
context['countries'] = countries