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
149
150
151
152
153
154
155
156
157
158
159

class AddForm(FormView, MultipleObjectMixin):
    template = 'index.html'
    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
160
                country = form.cleaned_data['country'],
161
                operator_ref = operator,
stef's avatar
stef committed
162
163
                contract = form.cleaned_data['contract'],
                resource = form.cleaned_data['resource'],
stef's avatar
stef committed
164
                resource_name = form.cleaned_data['resource_name'],
stef's avatar
stef committed
165
166
167
168
                type = form.cleaned_data['type'],
                media = form.cleaned_data['media'],
                temporary = form.cleaned_data['temporary'],
                contractual = form.cleaned_data['contractual'],
169
                contract_excerpt = sanitizeHtml(form.cleaned_data['contract_excerpt']),
170
171
                loophole = form.cleaned_data['loophole'],
                activationid = actid
stef's avatar
stef committed
172
                )
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
        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
195

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

199
200
201
202
    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
203
                    reverse=True)
204
205
        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
206
                    reverse=True)
207
208
        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
209
                     reverse=True)
210
211
        context['stats'] = [reports, confirms, operators]
        return context
stef's avatar
stef committed
212

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

218
219
220
221
222
223
224
225
226
    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
227

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

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

234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
        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
253

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

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

#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('')
274
275
276
277
278
279
280
281
282
283
284
285
286
287

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
288
289
290
291
292
293
294
295
296
297

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