views.py 13.9 KB
Newer Older
stef's avatar
stef committed
1
from forms import AddViolation, SearchViolation
2
3
from django.views.generic import ListView, FormView, DetailView
from django.views.generic.list import MultipleObjectMixin
stef's avatar
stef committed
4
from django.http import HttpResponse, HttpResponseRedirect, Http404
5
from django.shortcuts import render_to_response, get_object_or_404, redirect
6
from django.template import RequestContext, loader, Context
stef's avatar
stef committed
7
from django.core.files import File
8
from django.core.servers.basehttp import FileWrapper
9
10
from django.conf import settings
from django.core import serializers
stef's avatar
stef committed
11
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
12
from django.core.exceptions import ObjectDoesNotExist
13
from django.core.mail import send_mail
14
from django.contrib import messages
15
from django.contrib.auth.models import User
stef's avatar
stef committed
16
from django.utils.translation import ugettext_lazy as _
stef's avatar
stef committed
17
from django.db.models import Count
18
from haystack.generic_views import SearchView
stef's avatar
stef committed
19
from models import Violation, Attachment, Comment, Confirmation, COUNTRIES, STATUS, Operator
stef's avatar
stef committed
20
21
from tempfile import mkstemp
from datetime import datetime
22
import hashlib, os, re, json
23
24
from random import randint
from email.mime.text import MIMEText
stef's avatar
stef committed
25
from email.header import Header
26
27
from urlparse import urljoin
from BeautifulSoup import BeautifulSoup, Comment as BComment
stef's avatar
stef committed
28
from operator import itemgetter
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

def sanitizeHtml(value, base_url=None):
    rjs = r'[\s]*(&#x.{1,7})?'.join(list('javascript:'))
    rvb = r'[\s]*(&#x.{1,7})?'.join(list('vbscript:'))
    re_scripts = re.compile('(%s)|(%s)' % (rjs, rvb), re.IGNORECASE)
    validTags = 'p i strong b u a h1 h2 h3 pre br img'.split()
    validAttrs = 'href src width height'.split()
    urlAttrs = 'href src'.split() # Attributes which should have a URL
    soup = BeautifulSoup(value)
    for comment in soup.findAll(text=lambda text: isinstance(text, BComment)):
        # Get rid of comments
        comment.extract()
    for tag in soup.findAll(True):
        if tag.name not in validTags:
            tag.hidden = True
        attrs = tag.attrs
        tag.attrs = []
        for attr, val in attrs:
            if attr in validAttrs:
                val = re_scripts.sub('', val) # Remove scripts (vbs & js)
                if attr in urlAttrs:
                    val = urljoin(base_url, val) # Calculate the absolute url
                tag.attrs.append((attr, val))

    return soup.renderContents().decode('utf8')
stef's avatar
stef committed
54

55
def activate(request):
56
57
58
    try:
        v=Violation.objects.get(activationid=request.GET.get('key','asdf'))
    except:
59
60
        messages.add_message(request, messages.INFO, unicode(_('Thank you, this key has been already activated')))
        return HttpResponseRedirect('/') # Redirect after POST
61
62
63
    if v:
        actid = hashlib.sha1(''.join([chr(randint(32, 122)) for x in range(12)])).hexdigest()
        to=[x.email for x in User.objects.filter(groups__name='moderator')]
stef's avatar
stef committed
64
        details='\n'.join(["%s: %s" % (k.capitalize(), val) for k,val in v.__dict__.items() if not k.startswith('_') and val])
65
66
67
68
69
70
71
72
73

        msg = {'from': 'nnmon@respectmynet.eu',
               'to': to,
               'subject': 'NNMon submission approval'.encode("Utf-8"),
               'body': "A new report was submitted. To approve click here: %s/moderate/?key=%s\n\nDetails follow:\n%s\n%s" %
                       (settings.ROOT_URL or 'http://localhost:8001/', actid, details, v.comment_set.get().comment)
               }
        send_mail(msg['subject'], msg['body'], msg['from'], msg['to'], fail_silently=False)

74
75
        v.activationid=actid
        v.save()
Benjamin Sonntag's avatar
Benjamin Sonntag committed
76
        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"))
77
78
    return HttpResponseRedirect('/') # Redirect after POST

79
def moderate(request):
80
81
82
    try:
        v=Violation.objects.get(activationid=request.GET.get('key','asdf'))
    except:
83
84
        messages.add_message(request, messages.INFO, unicode(_('Thank you, this key has been already activated')))
        return HttpResponseRedirect('/') # Redirect after POST
85
86
87
88
    if not v:
        messages.add_message(request, messages.INFO, _('No such key'))
        return HttpResponseRedirect('/') # Redirect after POST
    if request.GET.get('action','')=='approve':
stef's avatar
stef committed
89
        messages.add_message(request, messages.INFO, _('Thank you for approving the <a href="%s">submission</a>.' % v.get_absolute_url()))
stef's avatar
stef committed
90

91
92
93
        msg = {'from': 'nnmon@respectmynet.eu',
               'to': [v.comment_set.get().submitter_email],
               'subject': _('NNMon submission approved').encode("Utf-8"),
stef's avatar
stef committed
94
               'body': _("Your report has been approved.\nTo see it, please visit: %s/%s") %
stef's avatar
stef committed
95
                      (settings.ROOT_URL or 'http://localhost:8001/', v.get_absolute_url())
96
97
98
               }
        send_mail(msg['subject'], msg['body'], msg['from'], msg['to'], fail_silently=False)

99
        if settings.TWITTER_API:
stef's avatar
stef committed
100
            try:
stef's avatar
stef committed
101
                settings.TWITTER_API.PostUpdate("New #NetNeutrality violation reported for %s (%s) %s %s/%s" % (v.operator, v.country, v.contract, settings.ROOT_URL or 'http://localhost:8001/', v.id))
stef's avatar
stef committed
102
103
            except:
                pass
104
105
        v.activationid=''
        v.save()
106
        return redirect(v) # Redirect after POST to violation url
107
108
109
110
111
112
    if request.GET.get('action','')=='delete':
        v.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))

stef's avatar
stef committed
113
114
115
def confirm(request, id, name=None):
    if name:
        if Confirmation.objects.filter(email=name, violation=id).count()==0:
stef's avatar
stef committed
116
117
            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)
118
119
120
            try:
                c=Confirmation(key=actid, email=name, violation=Violation.objects.get(pk=id))
            except:
stef's avatar
stef committed
121
                return HttpResponse(unicode(_('Thank you, this has been already confirmed')))
stef's avatar
stef committed
122
            c.save()
stef's avatar
stef committed
123
        return HttpResponse(unicode(_('Thank you for your confirmation')))
stef's avatar
stef committed
124
125
126
    try:
        c = get_object_or_404(Confirmation, key=id)
    except:
127
128
        messages.add_message(request, messages.INFO, unicode(_("Thank you, this has been already confirmed")))
        return HttpResponseRedirect('/') # Redirect after POST
stef's avatar
stef committed
129
130
    c.key=''
    c.save()
stef's avatar
stef committed
131
    messages.add_message(request, messages.INFO, unicode(_('Thank you for verifying your confirmation')))
132
    return HttpResponseRedirect('/') # Redirect after POST
stef's avatar
stef committed
133

stef's avatar
stef committed
134
def sendverifymail(service,to,body):
stef's avatar
stef committed
135
    actid = hashlib.sha1(''.join([chr(randint(32, 122)) for x in range(12)])).hexdigest()
136
137
138
    msg = {'from': 'nnmon@respectmynet.eu',
           'to': [to.encode("Utf-8")],
           'subject': _('NNMon submission verification').encode("Utf-8"),
stef's avatar
stef committed
139
           'body': body % (settings.ROOT_URL or 'http://localhost:8001/', service, actid),
140
141
142
           }
    send_mail(msg['subject'], msg['body'], msg['from'], msg['to'], fail_silently=False)

stef's avatar
stef committed
143
144
    return actid

145
146
class JSONMixin(object):
    def get(self, request, *args, **kwargs):
147
        return HttpResponse(serializers.serialize('json', self.get_queryset()))
148

Okhin's avatar
Okhin committed
149
150
151
class AddForm(FormView):
    model = Violation
    template_name = 'index.html'
152
153
154
155
156
157
158
159
160
    form_class = AddViolation
    success_url = '/'
    context_object_name = 'violations'

    def form_valid(self, form):
        msg=_("Thank you for submitting a new report. To finalize your submission please confirm using your validation key.\nYour verification key is %s/%s%s\nPlease note that reports are moderated, it might take some time before your report appears online. Thank you for your patience.")
        actid=sendverifymail('activate?key=',form.cleaned_data['email'], msg)
        operator, created = Operator.objects.get_or_create(name=form.cleaned_data['operator'])
        v=Violation(
stef's avatar
stef committed
161
                country = form.cleaned_data['country'],
162
                operator_ref = operator,
stef's avatar
stef committed
163
164
                contract = form.cleaned_data['contract'],
                resource = form.cleaned_data['resource'],
stef's avatar
stef committed
165
                resource_name = form.cleaned_data['resource_name'],
stef's avatar
stef committed
166
167
168
169
                type = form.cleaned_data['type'],
                media = form.cleaned_data['media'],
                temporary = form.cleaned_data['temporary'],
                contractual = form.cleaned_data['contractual'],
170
                contract_excerpt = sanitizeHtml(form.cleaned_data['contract_excerpt']),
171
172
                loophole = form.cleaned_data['loophole'],
                activationid = actid
stef's avatar
stef committed
173
                )
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
        v.save()
        #c=Confirmation(key='', email=form.cleaned_data['email'], violation=v)
        #c.save()
        c = Comment(
            comment=form.cleaned_data['comment'],
            submitter_email=form.cleaned_data['email'],
            submitter_name=form.cleaned_data['nick'],
            consent=form.cleaned_data['consent'],
            timestamp=datetime.now(),
            violation=v,
            )
        c.save()
        for f in request.FILES.getlist('attachments[]'):
            a=Attachment(comment=c, name=f.name, type=f.content_type)
            m = hashlib.sha256()
            for chunk in f.chunks():
                m.update(chunk)
            sname=m.hexdigest()
            a.storage.save(sname,f)
            a.save()
        messages.add_message(request, messages.INFO, _('Thank you for submitting this report, you will receive a verification email immediately, if not check your spam folder.'))
        return super(AddForm, self).form_valid(form)
stef's avatar
stef committed
196

197
198
    def get_queryset(self):
        return Violation.objects.filter(activationid='',featuredcase__isnull=False).order_by('id').reverse()[:3]
stef's avatar
stef committed
199

200
201
202
203
    def get_context_data(self, **kwargs):
        context = super(AddForm, self).get_context_data(**kwargs)
        reports = sorted([(i['total'],i['id'])
                         for i in Violation.objects.values('id').filter(activationid='').exclude(state__in=['closed', 'ooscope', 'duplicate']).annotate(total=Count('confirmation'))],
stef's avatar
stef committed
204
                    reverse=True)
205
206
        confirms = sorted([(i['total'],i['country'])
                         for i in Violation.objects.values('country').filter(activationid='').exclude(state__in=['closed', 'ooscope', 'duplicate']).annotate(total=Count('confirmation'))],
stef's avatar
stef committed
207
                    reverse=True)
208
209
        operators = sorted([(i['total'],i['operator_ref__name'])
                         for i in Violation.objects.values('operator_ref__name').filter(activationid='').exclude(state__in=['closed', 'ooscope', 'duplicate']).annotate(total=Count('confirmation'))],
stef's avatar
stef committed
210
                     reverse=True)
211
212
        context['stats'] = [reports, confirms, operators]
        return context
stef's avatar
stef committed
213

214
215
216
217
class ViolationsList(ListView):
    queryset = Violation.objects.filter(activationid='')
    template_name = 'list.html'
    context_object_name = 'violations'
218

219
220
221
222
223
224
225
226
227
    def get_queryset(self):
        queryset = Violation.objects.filter(activationid='')
        if 'all' not in self.request.GET:
            queryset = queryset.exclude(state__in=['duplicate', 'closed'])
        if 'country' in self.kwargs:
            queryset = queryset.filter(country=self.kwargs['country'])
        if 'operator' in self.kwargs:
            queryset = queryset.filter(operator_ref__name=self.kwargs['operator'])
        return queryset
stef's avatar
stef committed
228

229
230
231
232
233
    def get_context_data(self, **kwargs):
        context = super(ViolationsList, self).get_context_data(**kwargs)

        if 'country' in self.kwargs:
            context['country'] = self.kwargs['country']
234

235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
        countries = sorted([(i['total'], i['country'])
            for i in Violation.objects.values('country').filter(activationid='').exclude(state__in=['duplicate', 'closed']).annotate(total=Count('country'))],
            reverse=True)
        countryweights=json.dumps([{'iso2': y, 'w': x} for x, y in countries])
        context['countries'] = countries
        context['countryweights'] = countryweights
        return context

class ViolationView(DetailView):
    model = Violation
    template_name = 'view.html'
    pk_url_kwarg = 'id'
    context_object_name = 'v'

    def get_object(self):
        object = super(ViolationView, self).get_object()
        if object.activationid:
            raise Http404
        return object
stef's avatar
stef committed
254

255
256
257
258
def get_attach(request,id):
    f = get_object_or_404(Attachment, pk=id)
    wrapper = FileWrapper(f.storage)
    response=HttpResponse(wrapper, mimetype=f.type)
259
    response['Content-Disposition'] = 'attachment; filename="%s"' % f.name
260
261
262
    response['Content-Length'] = f.storage.size
    return response

263
class LookupView(JSONMixin, SearchView):
264
    model = Violation
265
    form_class = SearchViolation
266
267
268
269
270
271
272
273
274

#def lookup(request):
#    if request.method == 'GET':
#        form = SearchViolation(request.GET)
#        if form.is_valid():
#            v=form.search()
#            res=json.dumps(sorted([(x.object.id,x.object.resource_name) for x in v],reverse=True))
#            return HttpResponse(res)
#    return HttpResponse('')
275
276
277
278
279
280
281
282
283
284
285
286
287
288

def ascsv(request):
    response = HttpResponse(mimetype='text/csv')
    response['Content-Disposition'] = 'attachment; filename=respectmynet.csv'

    res=[]
    for v in Violation.objects.filter(activationid=''):
        res.append((v.state, v.country, v.operator, v.contract, v.resource, v.resource_name, v.type, v.media, v.temporary, v.contractual, v.contract_excerpt, v.loophole, v.editorial,v.comment_set.get().comment))
    t = loader.get_template('csv.tmpl')
    c = Context({
        'data': res,
    })
    response.write(t.render(c))
    return response
289
290
291
292
293
294
295
296
297
298

from sheet import save_ods
def asods(request):
    response = HttpResponse(mimetype='application/vnd.oasis.opendocument.spreadsheet')
    response['Content-Disposition'] = 'attachment; filename=respectmynet-ec_berec_tm_questionnaire.ods'
    save_ods()
    f=open('/tmp/ec_berec_tm_questionnaire.ods','r')
    response.write(f.read())
    f.close()
    return response