...
 
Commits (79)
......@@ -9,63 +9,63 @@ from operator import itemgetter
from captcha.fields import CaptchaField
class AdvancedEditor(forms.Textarea):
class Media:
js = (settings.MEDIA_URL+'/js/tinymce/tiny_mce.js',)
class Media:
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)
super(AdvancedEditor, self).__init__(attrs)
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)
super(AdvancedEditor, self).__init__(attrs)
class AddViolation(forms.Form):
resource_name = forms.CharField(required=True, max_length=4096, label=_('Please specify the affected resource'), 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 restriction is reported.'))
operator = forms.CharField(required=True, max_length=256, label=_("Operator"), help_text=_('The ISP or operator providing the Internet service.'))
contract = forms.CharField(required=True, max_length=256, label=_("Contract"), help_text=_('The specific contract at the ISP provider. (please be as specific as possible)'))
media = forms.ChoiceField(required=True, choices=(('',''),)+tuple(sorted(MEDIA,key=itemgetter(1))), label=_('Is the Internet connection over mobile or fixed line?'))
comment = forms.CharField(required=True, widget=AdvancedEditor(), label=_('Please describe the symptoms you are experiencing.'))
email = forms.EmailField(required=True, label=_('Email (set this to enable saving)'), help_text=_("We need your email to validate your report. Your email address is obligatory, but we will never use your personal data for anything else than checking the submission. (see next for an optional exception)"))
consent = forms.BooleanField(required=False, label=_("I want to help further"), help_text=_("We need your consent to contact you for clarifications regarding your report. This is optional, but helps us improve the quality of the reports. Thanks!"))
nick = forms.CharField(required=False, label=_("Name or nickname"), help_text=_("We need some name to display that instead of an email address."))
attachments = MultiFileField(required=False, label=_("Attach screenshot, document or any other relevant information."))
resource = forms.ChoiceField(required=False, choices=(('',''),)+tuple(sorted(RESOURCES,key=itemgetter(1))), label=_('What is the affected resource type. (optional)'))
type = forms.ChoiceField(required=False, choices=(('',''),)+tuple(sorted(TYPES,key=itemgetter(1))), label=_('Is the Resource Blocked or otherwise discrimated? (optional)'))
temporary = forms.BooleanField(required=False, label=_('Is the restriction only temporary, e.g. due to network overload? (optional)'))
loophole = forms.BooleanField(required=False, label=_('Is there another offer provided by this Operator which removes this restriction? (optional)'))
contractual = forms.BooleanField(required=False, label=_('Is the restriction described in the subscribers contract? (optional)'))
contract_excerpt = forms.CharField(required=False, widget=AdvancedEditor(), label=_('Please copy the relevant section describing the restriction from the user contract. (optional)'))
captcha = CaptchaField(label=_("In order to protect against spam, please fill in the result of the following calculation. (note the + and the * are somewhat confusing)"))
resource_name = forms.CharField(required=True, max_length=4096, label=_('Please specify the affected resource'), 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 restriction is reported.'))
operator = forms.CharField(required=True, max_length=256, label=_("Operator"), help_text=_('The ISP or operator providing the Internet service.'))
contract = forms.CharField(required=True, max_length=256, label=_("Contract"), help_text=_('The specific contract at the ISP provider. (please be as specific as possible)'))
media = forms.ChoiceField(required=True, choices=tuple(sorted(MEDIA,key=itemgetter(1))), label=_('Is the Internet connection over mobile or fixed line?'))
comment = forms.CharField(required=True, widget=AdvancedEditor(), label=_('Please describe the symptoms you are experiencing.'))
email = forms.EmailField(required=True, label=_('Email (set this to enable saving)'), help_text=_("We need your email to validate your report. Your email address is obligatory, but we will never use your personal data for anything else than checking the submission. (see next for an optional exception)"))
consent = forms.BooleanField(required=False, label=_("I want to help further"), help_text=_("We need your consent to contact you for clarifications regarding your report. This is optional, but helps us improve the quality of the reports. Thanks!"))
nick = forms.CharField(required=False, label=_("Name or nickname"), help_text=_("We need some name to display that instead of an email address."))
attachments = MultiFileField(required=False, label=_("Attach screenshot, document or any other relevant information."))
resource = forms.ChoiceField(required=False, choices=tuple(sorted(RESOURCES,key=itemgetter(1))), label=_('What is the affected resource type. (optional)'))
type = forms.ChoiceField(required=True, choices=tuple(sorted(TYPES,key=itemgetter(1))), label=_('What types of resctriction happens in this case?'))
temporary = forms.BooleanField(required=False, label=_('Is the restriction only temporary, e.g. due to network overload? (optional)'))
loophole = forms.BooleanField(required=False, label=_('Is there another offer provided by this Operator which removes this restriction? (optional)'))
contractual = forms.BooleanField(required=False, label=_('The restriction is described in the subscribers contract.'))
contract_excerpt = forms.CharField(required=False, widget=AdvancedEditor(), label=_('Please copy the relevant section describing the restriction from the user contract. (optional)'))
captcha = CaptchaField(label=_("In order to protect against spam, please fill in the result of the following calculation. (note the + and the * are somewhat confusing)"))
class SearchViolation(SearchForm):
country = forms.ChoiceField(required=True, choices=(('',''),)+tuple(sorted(COUNTRIES,key=itemgetter(1))), label=_("Country"), help_text=_('EU member state where the restriction is reported.'))
operator = forms.CharField(required=True, max_length=256, label=_("Operator"), help_text=_('The ISP or operator providing the Internet service.'))
contract = forms.CharField(required=True, max_length=256, label=_("Contract"), help_text=_('The specific contract at the ISP provider. (please be as specific as possible)'))
media = forms.ChoiceField(required=True, choices=(('',''),)+tuple(sorted(MEDIA,key=itemgetter(1))), label=_('Is the Internet connection over mobile or fixed line?'))
country = forms.ChoiceField(required=False, choices=(('',''),)+tuple(sorted(COUNTRIES,key=itemgetter(1))), label=_("Country"), help_text=_('EU member state where the restriction is reported.'))
operator = forms.CharField(required=False, max_length=256, label=_("Operator"), help_text=_('The ISP or operator providing the Internet service.'))
contract = forms.CharField(required=False, max_length=256, label=_("Contract"), help_text=_('The specific contract at the ISP provider. (please be as specific as possible)'))
media = forms.ChoiceField(required=False, choices=(('',''),)+tuple(sorted(MEDIA,key=itemgetter(1))), label=_('Is the Internet connection over mobile or fixed line?'))
def search(self):
# By default, teh search field is q. So let's check if it's empty
if not self.cleaned_data['q']:
sqs = SearchQuerySet().all()
else:
sqs = super(SearchViolation, self).search()
def search(self):
# By default, the search field is q. So let's check if it's empty
if not self.cleaned_data['q']:
sqs = SearchQuerySet().all().exclude(old=True)
else:
sqs = super(SearchViolation, self).search().exclude(old=True)
if not self.is_valid():
return self.no_query_found()
if not self.is_valid():
return self.no_query_found()
if self.cleaned_data['operator']:
sqs = sqs.filter(operator=self.cleaned_data['operator'])
if self.cleaned_data['operator']:
sqs = sqs.filter(operator__icontains=self.cleaned_data['operator'])
if self.cleaned_data['contract']:
sqs = sqs.filter(contract=self.cleaned_data['contract'])
if self.cleaned_data['contract']:
sqs = sqs.filter(contract__icontains=self.cleaned_data['contract'])
if self.cleaned_data['media']:
sqs = sqs.filter(media=self.cleaned_data['media'])
if self.cleaned_data['media']:
sqs = sqs.filter(media=self.cleaned_data['media'])
if self.cleaned_data['country']:
sqs = sqs.filter(country=self.cleaned_data['country'])
if self.cleaned_data['country']:
sqs = sqs.filter(country=self.cleaned_data['country'])
return sqs
return sqs
class QuickSearchViolation(forms.Form):
query = forms.CharField(required='True', max_length=256, label=_("Search"), help_text=_('Search for an existing violation'))
......@@ -64,11 +64,11 @@ class Migration(migrations.Migration):
('media', models.CharField(blank=True, max_length=20, choices=[(b'fixed', 'Fixed'), (b'mobile', 'Mobile')])),
('temporary', models.BooleanField()),
('contractual', models.BooleanField()),
('contract_excerpt', models.TextField(blank=True)),
('contract_excerpt', models.TextField(null=True, blank=True)),
('loophole', models.BooleanField()),
('activationid', models.CharField(max_length=128, blank=True)),
('state', models.CharField(default=b'new', max_length=20, blank=True, choices=[(b'moreinfo', 'Need more info'), (b'new', 'New'), (b'verified', 'Verified'), (b'duplicate', 'Duplicate'), (b'ooscope', 'Out of scope'), (b'closed', 'Closed')])),
('editorial', models.TextField(blank=True)),
('editorial', models.TextField(null=True, blank=True)),
('operator_ref', models.ForeignKey(related_name='violations', to='bt.Operator')),
],
),
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bt', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='violation',
name='old',
field=models.BooleanField(default=b'False'),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
def archive_old(apps, schema_editor):
Violation = apps.get_model("bt", "Violation")
for violation in Violation.objects.all():
violation.old = True
violation.save()
class Migration(migrations.Migration):
dependencies = [
('bt', '0002_violation_old'),
]
operations = [
migrations.RunPython(archive_old),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bt', '0003_auto_20160301_2032'),
]
operations = [
migrations.AlterField(
model_name='violation',
name='activationid',
field=models.CharField(max_length=128, null=True, blank=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bt', '0004_auto_20160301_2103'),
]
operations = [
migrations.AlterField(
model_name='violation',
name='country',
field=models.CharField(max_length=2, choices=[(b'BE', 'Belgium'), (b'BG', 'Bulgaria'), (b'CH', 'Switzerland'), (b'CZ', 'Czech Republic'), (b'DK', 'Denmark'), (b'DE', 'Germany'), (b'EE', 'Estonia'), (b'IE', 'Ireland'), (b'EL', 'Greece'), (b'ES', 'Spain'), (b'FR', 'France'), (b'IC', 'Iceland'), (b'IS', 'Iceland'), (b'IT', 'Italy'), (b'CY', 'Cyprus'), (b'LI', 'Liechtenstein'), (b'LV', 'Latvia'), (b'LT', 'Lithuania'), (b'LU', 'Luxembourg'), (b'HU', 'Hungary'), (b'MT', 'Malta'), (b'NL', 'Netherlands'), (b'NO', 'Norway'), (b'AT', 'Austria'), (b'PL', 'Poland'), (b'PT', 'Portugal'), (b'RO', 'Romania'), (b'SI', 'Slovenia'), (b'SK', 'Slovakia'), (b'FI', 'Finland'), (b'SE', 'Sweden'), (b'UK', 'United Kingdom')]),
),
migrations.AlterField(
model_name='violation',
name='resource',
field=models.CharField(blank=True, max_length=20, choices=[(b'port', 'port'), (b'protocol', 'protocol'), (b'service', 'service'), (b'site', 'website'), (b'user', 'user'), (b'ip', 'ip'), (b'video', 'video streaming'), (b'audio', 'audio streaming'), (b'class', 'class of application or contraint'), (b'other', 'other')]),
),
migrations.AlterField(
model_name='violation',
name='type',
field=models.CharField(blank=True, max_length=20, choices=[(b'zerorating', 'Zero Rating'), (b'blocking', 'Blocking'), (b'throttling', 'Throttling'), (b'prioritisation', 'Prioritisation'), (b'specialised', 'Specialised Service'), (b'other', 'Other')]),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import datetime
class Migration(migrations.Migration):
dependencies = [
('bt', '0005_auto_20160302_1202'),
]
operations = [
migrations.AddField(
model_name='violation',
name='creation_date',
field=models.DateField(default=datetime.datetime(2016, 3, 2, 12, 14, 23, 907012), auto_now_add=True),
preserve_default=False,
),
]
......@@ -5,6 +5,7 @@ from django_comments.moderation import CommentModerator, moderator
COUNTRIES = (
('BE', _('Belgium')),
('BG', _('Bulgaria')),
('CH', _('Switzerland')),
('CZ', _('Czech Republic')),
('DK', _('Denmark')),
('DE', _('Germany')),
......@@ -13,9 +14,11 @@ COUNTRIES = (
('EL', _('Greece')),
('ES', _('Spain')),
('FR', _('France')),
('IC', _('Iceland')),
('IS', _('Iceland')),
('IT', _('Italy')),
('CY', _('Cyprus')),
('LI', _('Liechtenstein')),
('LV', _('Latvia')),
('LT', _('Lithuania')),
('LU', _('Luxembourg')),
......@@ -38,13 +41,21 @@ RESOURCES = (
('port', _('port')),
('protocol', _('protocol')),
('service', _('service')),
('site', _('site')),
('site', _('website')),
('user', _('user')),
('ip', _('ip')),
('video', _('video streaming')),
('audio', _('audio streaming')),
('class', _('class of application or contraint')),
('other', _('other'))
)
TYPES = (
('zerorating', _('Zero Rating')),
('blocking', _('Blocking')),
('throttling', _('Throttling')),
('prioritisation', _('Prioritisation')),
('specialised', _('Specialised Service')),
('other', _('Other'))
)
MEDIA = (
('fixed', _('Fixed')),
......@@ -73,7 +84,6 @@ class Operator(models.Model):
def __unicode__(self):
return self.name
class Violation(models.Model):
country = models.CharField(max_length=2, choices=COUNTRIES)
operator_ref = models.ForeignKey(Operator, related_name="violations")
......@@ -84,11 +94,13 @@ class Violation(models.Model):
media = models.CharField( max_length=20, choices=MEDIA, blank=True)
temporary = models.BooleanField( )
contractual = models.BooleanField()
contract_excerpt = models.TextField(blank=True)
contract_excerpt = models.TextField(null=True, blank=True)
loophole = models.BooleanField()
activationid= models.CharField(max_length=128, 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(blank=True)
editorial = models.TextField(null=True, blank=True)
old = models.BooleanField(default="False")
creation_date = models.DateField(auto_now_add=True)
def confirmations(self):
return self.confirmation_set.filter(key='').count()
......@@ -108,7 +120,6 @@ class Violation(models.Model):
def __unicode__(self):
return "#%s %s/%s" % (self.pk, self.country, self.operator)
class Comment(models.Model):
submitter_email = models.EmailField()
submitter_name = models.CharField(max_length=20)
......
......@@ -5,9 +5,12 @@ class ViolationIndexes(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
operator = indexes.CharField(model_attr="operator_ref")
country = indexes.CharField(model_attr="country")
contract = indexes.CharField(model_attr="contract_excerpt")
type = indexes.BooleanField(model_attr="contractual")
contract = indexes.CharField(model_attr="contract")
type = indexes.CharField(model_attr="contractual")
media = indexes.CharField(model_attr="media")
operator_name = indexes.CharField()
state = indexes.NgramField(model_attr="state")
old = indexes.BooleanField(model_attr="old")
def get_model(self):
return Violation
......
from django.core.serializers import serialize
from django.db.models.query import QuerySet
from django.template import Library
from haystack.models import SearchResult
import json
register = Library()
@register.filter(name='jsonify')
def jsonify(object):
if isinstance(object, QuerySet):
return serialize('json', object)
elif object == []:
return json.dumps(object)
elif isinstance(object[0], SearchResult):
return serialize('json', [x.object for x in object])
else:
return json.dumps(object)
......@@ -6,6 +6,7 @@ from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext, loader, Context
from django.core.files import File
from django.core.servers.basehttp import FileWrapper
from django.core import serializers
from django.conf import settings
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.exceptions import ObjectDoesNotExist
......@@ -15,7 +16,8 @@ from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from django.db.models import Count
from haystack.generic_views import SearchView
from models import Violation, Attachment, Comment, Confirmation, COUNTRIES, STATUS, Operator
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
......@@ -142,20 +144,10 @@ def sendverifymail(service,to,body):
return actid
class JSONMixin(object):
def get(self, request, *args, **kwargs):
qs = self.get_queryset()
if qs.count():
return HttpResponse(json.dumps(sorted([(x.id, x.resource_name) for x in qs])))
else:
return HttpResponse('')
class AddForm(FormView):
model = Violation
template_name = '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.")
......@@ -173,7 +165,8 @@ class AddForm(FormView):
contractual = form.cleaned_data['contractual'],
contract_excerpt = sanitizeHtml(form.cleaned_data['contract_excerpt']),
loophole = form.cleaned_data['loophole'],
activationid = actid
activationid = actid,
old = False
)
v.save()
#c=Confirmation(key='', email=form.cleaned_data['email'], violation=v)
......@@ -187,7 +180,7 @@ class AddForm(FormView):
violation=v,
)
c.save()
for f in request.FILES.getlist('attachments[]'):
for f in self.request.FILES.getlist('attachments[]'):
a=Attachment(comment=c, name=f.name, type=f.content_type)
m = hashlib.sha256()
for chunk in f.chunks():
......@@ -195,27 +188,25 @@ class AddForm(FormView):
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.'))
messages.add_message(self.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)
def get_queryset(self):
return Violation.objects.filter(activationid='',featuredcase__isnull=False).order_by('id').reverse()[:3]
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'))],
for i in Violation.objects.values('id').filter(activationid='').exclude(state__in=['closed', 'ooscope', 'duplicate']).exclude(old=True).annotate(total=Count('confirmation'))],
reverse=True)
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'))],
for i in Violation.objects.values('country').filter(activationid='').exclude(state__in=['closed', 'ooscope', 'duplicate']).exclude(old=True).annotate(total=Count('confirmation'))],
reverse=True)
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'))],
for i in Violation.objects.values('operator_ref__name').filter(activationid='').exclude(state__in=['closed', 'ooscope', 'duplicate']).exclude(old=True).annotate(total=Count('confirmation'))],
reverse=True)
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]))]
context['violations'] = [fc.case for fc in FeaturedCase.objects.all() if not fc.case.old][:3]
return context
class ViolationsList(ListView):
......@@ -223,17 +214,17 @@ class ViolationsList(ListView):
context_object_name = 'violations'
def get_queryset(self):
queryset = Violation.objects.filter(activationid='')
queryset = Violation.objects.filter(activationid='').exclude(old=True)
if 'operator' in self.kwargs:
# If i Have operator I have a country
queryset = Violation.objects.filter(activationid='',
country=self.kwargs['country'],
operator_ref__name=self.kwargs['operator'])
operator_ref__name=self.kwargs['operator']).exclude(old=True)
if 'country' in self.kwargs:
queryset = Violation.objects.filter(activationid='',
country=self.kwargs['country'])
country=self.kwargs['country']).exclude(old=True)
if 'all' not in self.request.GET:
queryset = queryset.filter(activationid='').exclude(state__in=['duplicate', 'closed'])
queryset = queryset.filter(activationid='').exclude(state__in=['duplicate', 'closed']).exclude(old=False)
return queryset
def get_context_data(self, **kwargs):
......@@ -243,7 +234,7 @@ class ViolationsList(ListView):
context['country'] = self.kwargs['country']
else:
countries = sorted([(i['total'], i['country'])
for i in Violation.objects.values('country').filter(activationid='').exclude(state__in=['duplicate', 'closed']).annotate(total=Count('country'))],
for i in Violation.objects.values('country').filter(activationid='').exclude(state__in=['duplicate', 'closed']).exclude(old=True).annotate(total=Count('country'))],
reverse=True)
countryweights=json.dumps([{'iso2': y, 'w': x} for x, y in countries])
context['countries'] = countries
......@@ -262,11 +253,26 @@ class ViolationView(DetailView):
raise Http404
return object
class LookupView(JSONMixin, SearchView):
queryset = Violation.objects.filter(activationid='')
class LookupView(SearchView):
searchqueryset = SearchQuerySet().exclude(old=True)
form_class = SearchViolation
def get_queryset(self):
return super(LookupView, self).get_queryset().exclude(old=True)
def get_context_data(self, *args, **kwargs):
context = super(LookupView, self).get_context_data(*args, **kwargs)
if 'object_list' in context:
context['object_list'] = [obj for obj in context['object_list'] if not obj.object.old]
return context
class ViolationSearchView(SearchView):
searchqueryset = SearchQuerySet().exclude(old=True)
form_class = SearchViolation
def get_queryset(self):
return super(ViolationSearchView, self).get_queryset().exclude(old=True)
def get_context_data(self, *args, **kwargs):
context = super(ViolationSearchView, self).get_context_data(*args, **kwargs)
countries = sorted([(k, len(list(g)),) for k, g in groupby(sorted([i['country'] for i in self.queryset.values('country')]))])
......
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-12-15 16:18+0100\n"
"POT-Creation-Date: 2016-03-02 13:30+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -18,119 +18,127 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: bt/forms.py:20
#: bt/forms.py:22
msgid "Please specify the affected resource"
msgstr ""
#: bt/forms.py:20
#: bt/forms.py:22
msgid ""
"What service or site, or person is unavailable or seems artificially slowed "
"down. e.g. VoIP, p2p, filesharing, specific websites, etc."
msgstr ""
#: bt/forms.py:21 bt/forms.py:39
#: bt/forms.py:23 bt/forms.py:41
msgid "Country"
msgstr ""
#: bt/forms.py:21 bt/forms.py:39
#: bt/forms.py:23 bt/forms.py:41
msgid "EU member state where the restriction is reported."
msgstr ""
#: bt/forms.py:22 bt/forms.py:40
#: bt/forms.py:24 bt/forms.py:42
msgid "Operator"
msgstr ""
#: bt/forms.py:22 bt/forms.py:40
#: bt/forms.py:24 bt/forms.py:42
msgid "The ISP or operator providing the Internet service."
msgstr ""
#: bt/forms.py:23 bt/forms.py:41
#: bt/forms.py:25 bt/forms.py:43
msgid "Contract"
msgstr ""
#: bt/forms.py:23 bt/forms.py:41
#: bt/forms.py:25 bt/forms.py:43
msgid ""
"The specific contract at the ISP provider. (please be as specific as "
"possible)"
msgstr ""
#: bt/forms.py:24 bt/forms.py:42
#: bt/forms.py:26 bt/forms.py:44
msgid "Is the Internet connection over mobile or fixed line?"
msgstr ""
#: bt/forms.py:25
#: bt/forms.py:27
msgid "Please describe the symptoms you are experiencing."
msgstr ""
#: bt/forms.py:26
#: bt/forms.py:28
msgid "Email (set this to enable saving)"
msgstr ""
#: bt/forms.py:26
#: bt/forms.py:28
msgid ""
"We need your email to validate your report. Your email address is "
"obligatory, but we will never use your personal data for anything else than "
"checking the submission. (see next for an optional exception)"
msgstr ""
#: bt/forms.py:27
#: bt/forms.py:29
msgid "I want to help further"
msgstr ""
#: bt/forms.py:27
#: bt/forms.py:29
msgid ""
"We need your consent to contact you for clarifications regarding your "
"report. This is optional, but helps us improve the quality of the reports. "
"Thanks!"
msgstr ""
#: bt/forms.py:28
#: bt/forms.py:30
msgid "Name or nickname"
msgstr ""
#: bt/forms.py:28
#: bt/forms.py:30
msgid "We need some name to display that instead of an email address."
msgstr ""
#: bt/forms.py:29
#: bt/forms.py:31
msgid "Attach screenshot, document or any other relevant information."
msgstr ""
#: bt/forms.py:30
#: bt/forms.py:32
msgid "What is the affected resource type. (optional)"
msgstr ""
#: bt/forms.py:31
msgid "Is the Resource Blocked or otherwise discrimated? (optional)"
#: bt/forms.py:33
msgid "What types of resctriction happens in this case?"
msgstr ""
#: bt/forms.py:32
#: bt/forms.py:34
msgid ""
"Is the restriction only temporary, e.g. due to network overload? (optional)"
msgstr ""
#: bt/forms.py:33
#: bt/forms.py:35
msgid ""
"Is there another offer provided by this Operator which removes this "
"restriction? (optional)"
msgstr ""
#: bt/forms.py:34
msgid "Is the restriction described in the subscribers contract? (optional)"
#: bt/forms.py:36
msgid "The restriction is described in the subscribers contract."
msgstr ""
#: bt/forms.py:35
#: bt/forms.py:37
msgid ""
"Please copy the relevant section describing the restriction from the user "
"contract. (optional)"
msgstr ""
#: bt/forms.py:36
#: bt/forms.py:38
msgid ""
"In order to protect against spam, please fill in the result of the following "
"calculation. (note the + and the * are somewhat confusing)"
msgstr ""
#: bt/forms.py:71 env/lib/python2.7/site-packages/haystack/forms.py:28
msgid "Search"
msgstr ""
#: bt/forms.py:71
msgid "Search for an existing violation"
msgstr ""
#: bt/models.py:6
msgid "Belgium"
msgstr ""
......@@ -140,179 +148,220 @@ msgid "Bulgaria"
msgstr ""
#: bt/models.py:8
msgid "Czech Republic"
msgid "Switzerland"
msgstr ""
#: bt/models.py:9
msgid "Denmark"
msgid "Czech Republic"
msgstr ""
#: bt/models.py:10
msgid "Germany"
msgid "Denmark"
msgstr ""
#: bt/models.py:11
msgid "Estonia"
msgid "Germany"
msgstr ""
#: bt/models.py:12
msgid "Ireland"
msgid "Estonia"
msgstr ""
#: bt/models.py:13
msgid "Greece"
msgid "Ireland"
msgstr ""
#: bt/models.py:14
msgid "Greece"
msgstr ""
#: bt/models.py:15
msgid "Spain"
msgstr ""
#: bt/models.py:15 nnmon/templates/about.html:12
#: bt/models.py:16
msgid "France"
msgstr ""
#: bt/models.py:16
#: bt/models.py:17 bt/models.py:18
msgid "Iceland"
msgstr ""
#: bt/models.py:17
#: bt/models.py:19
msgid "Italy"
msgstr ""
#: bt/models.py:18
#: bt/models.py:20
msgid "Cyprus"
msgstr ""
#: bt/models.py:19
#: bt/models.py:21
msgid "Liechtenstein"
msgstr ""
#: bt/models.py:22
msgid "Latvia"
msgstr ""
#: bt/models.py:20
#: bt/models.py:23
msgid "Lithuania"
msgstr ""
#: bt/models.py:21
#: bt/models.py:24
msgid "Luxembourg"
msgstr ""
#: bt/models.py:22
#: bt/models.py:25
msgid "Hungary"
msgstr ""
#: bt/models.py:23
#: bt/models.py:26
msgid "Malta"
msgstr ""
#: bt/models.py:24 nnmon/templates/about.html:13
#: bt/models.py:27
msgid "Netherlands"
msgstr ""
#: bt/models.py:25
#: bt/models.py:28
msgid "Norway"
msgstr ""
#: bt/models.py:26
#: bt/models.py:29
msgid "Austria"
msgstr ""
#: bt/models.py:27
#: bt/models.py:30
msgid "Poland"
msgstr ""
#: bt/models.py:28
#: bt/models.py:31
msgid "Portugal"
msgstr ""
#: bt/models.py:29
#: bt/models.py:32
msgid "Romania"
msgstr ""
#: bt/models.py:30
#: bt/models.py:33
msgid "Slovenia"
msgstr ""
#: bt/models.py:31
#: bt/models.py:34
msgid "Slovakia"
msgstr ""
#: bt/models.py:32
#: bt/models.py:35
msgid "Finland"
msgstr ""
#: bt/models.py:33
#: bt/models.py:36
msgid "Sweden"
msgstr ""
#: bt/models.py:34
#: bt/models.py:37
msgid "United Kingdom"
msgstr ""
#: bt/models.py:38
#: bt/models.py:41
msgid "port"
msgstr ""
#: bt/models.py:39
#: bt/models.py:42
msgid "protocol"
msgstr ""
#: bt/models.py:40
#: bt/models.py:43
msgid "service"
msgstr ""
#: bt/models.py:41
msgid "site"
#: bt/models.py:44
msgid "website"
msgstr ""
#: bt/models.py:42 env/lib/python2.7/site-packages/django_comments/models.py:59
#: bt/models.py:45 env/lib/python2.7/site-packages/django_comments/models.py:59
#: env/lib/python2.7/site-packages/django_comments/models.py:189
msgid "user"
msgstr ""
#: bt/models.py:43
#: bt/models.py:46
msgid "ip"
msgstr ""
#: bt/models.py:46
#: bt/models.py:47
msgid "video streaming"
msgstr ""
#: bt/models.py:48
msgid "audio streaming"
msgstr ""
#: bt/models.py:49
msgid "class of application or contraint"
msgstr ""
#: bt/models.py:50
msgid "other"
msgstr ""
#: bt/models.py:53
msgid "Zero Rating"
msgstr ""
#: bt/models.py:54
msgid "Blocking"
msgstr ""
#: bt/models.py:47
#: bt/models.py:55
msgid "Throttling"
msgstr ""
#: bt/models.py:50
#: bt/models.py:56
msgid "Prioritisation"
msgstr ""
#: bt/models.py:57
msgid "Specialised Service"
msgstr ""
#: bt/models.py:58
msgid "Other"
msgstr ""
#: bt/models.py:61
msgid "Fixed"
msgstr ""
#: bt/models.py:51
#: bt/models.py:62
msgid "Mobile"
msgstr ""
#: bt/models.py:54
#: bt/models.py:65
msgid "Need more info"
msgstr ""
#: bt/models.py:55 nnmon/templates/list.html:98
#: bt/models.py:66 nnmon/templates/list.html:48
#: nnmon/templates/search/search.html:67
msgid "New"
msgstr ""
#: bt/models.py:56
#: bt/models.py:67
msgid "Verified"
msgstr ""
#: bt/models.py:57
#: bt/models.py:68
msgid "Duplicate"
msgstr ""
#: bt/models.py:58
#: bt/models.py:69
msgid "Out of scope"
msgstr ""
#: bt/models.py:59
#: bt/models.py:70
msgid "Closed"
msgstr ""
#: bt/models.py:124
#: bt/models.py:135
#, python-format
msgid "Comment #%s"
msgstr ""
......@@ -336,41 +385,41 @@ msgstr ""
msgid "An incorrect number of files were uploaded."
msgstr ""
#: bt/views.py:55 bt/views.py:79
#: bt/views.py:61 bt/views.py:85
msgid "Thank you, this key has been already activated"
msgstr ""
#: bt/views.py:72
#: bt/views.py:78
msgid ""
"Thank you for verifying your submission. It will be listed shortly, after "
"we've checked that the report is valid."
msgstr ""
#: bt/views.py:82
#: bt/views.py:88
msgid "No such key"
msgstr ""
#: bt/views.py:85
#: bt/views.py:91
#, python-format
msgid "Thank you for approving the <a href=\"%s\">submission</a>."
msgstr ""
#: bt/views.py:89
#: bt/views.py:95
msgid "NNMon submission approved"
msgstr ""
#: bt/views.py:90
#: bt/views.py:96
#, python-format
msgid ""
"Your report has been approved.\n"
"To see it, please visit: %s/%s"
msgstr ""
#: bt/views.py:105
#: bt/views.py:111
msgid "Thank you for deleting the submission."
msgstr ""
#: bt/views.py:112
#: bt/views.py:118
#, python-format
msgid ""
"Thank you for confirming a case. To finalize your confirmation please "
......@@ -378,23 +427,23 @@ msgid ""
"Your confirmation key is %s/%s%s"
msgstr ""
#: bt/views.py:117 bt/views.py:123
#: bt/views.py:123 bt/views.py:129
msgid "Thank you, this has been already confirmed"
msgstr ""
#: bt/views.py:119
#: bt/views.py:125
msgid "Thank you for your confirmation"
msgstr ""
#: bt/views.py:127
#: bt/views.py:133
msgid "Thank you for verifying your confirmation"
msgstr ""
#: bt/views.py:134
#: bt/views.py:140
msgid "NNMon submission verification"
msgstr ""
#: bt/views.py:145
#: bt/views.py:153
#, python-format
msgid ""
"Thank you for submitting a new report. To finalize your submission please "
......@@ -404,170 +453,26 @@ msgid ""
"report appears online. Thank you for your patience."
msgstr ""
#: bt/views.py:183
#: bt/views.py:191
msgid ""
"Thank you for submitting this report, you will receive a verification email "
"immediately, if not check your spam folder."
msgstr ""
#: bt/views.py:221
#: bt/views.py:206
msgid "Total confirmed reports"
msgstr ""
#: bt/views.py:222
#: bt/views.py:207 bt/views.py:286
msgid "Countries with some confirmed reports"
msgstr ""
#: bt/views.py:223
#: bt/views.py:208 bt/views.py:287
msgid "Operators with some confirmed reports"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:313
msgid "usage: "
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:821
msgid ".__call__() not defined"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1105
#, python-format
msgid "unknown parser %r (choices: %s)"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1146
#, python-format
msgid "argument \"-\" with mode %r"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1349
#, python-format
msgid "cannot merge actions - two groups are named %r"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1387
msgid "'required' is an invalid argument for positionals"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1407
#, python-format
msgid "invalid option string %r: must start with a character %r"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1428
#, python-format
msgid "dest= is required for options like %r"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1445
#, python-format
msgid "invalid conflict_resolution value: %r"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1463
#, python-format
msgid "conflicting option string(s): %s"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1526
msgid "mutually exclusive arguments must be optional"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1596
msgid "positional arguments"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1597
msgid "optional arguments"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1615
msgid "show this help message and exit"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1621
msgid "show program's version number and exit"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1653
msgid "cannot have multiple subparser arguments"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1705
#, python-format
msgid "unrecognized arguments: %s"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1802
#, python-format
msgid "not allowed with argument %s"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1848
#: env/lib/python2.7/site-packages/argparse.py:1862
#, python-format
msgid "ignored explicit argument %r"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1952
msgid "too few arguments"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1959
#, python-format
msgid "argument %s is required"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:1973
#, python-format
msgid "one of the arguments %s is required"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2019
msgid "expected one argument"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2020
msgid "expected at most one argument"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2021
msgid "expected at least one argument"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2023
#, python-format
msgid "expected %s argument(s)"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2080
#, python-format
msgid "ambiguous option: %s could match %s"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2142
#, python-format
msgid "unexpected option string: %s"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2243
#, python-format
msgid "%r is not callable"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2259
#, python-format
msgid "invalid %s value: %r"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2269
#, python-format
msgid "invalid choice: %r (choose from %s)"
msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:2362
#, python-format
msgid "%s: error: %s\n"
#: bt/views.py:285
msgid "Number of reports in this search"
msgstr ""
#: env/lib/python2.7/site-packages/django/contrib/messages/apps.py:7
......@@ -874,6 +779,7 @@ msgid ""
msgstr ""
#: env/lib/python2.7/site-packages/django/db/models/fields/__init__.py:2180
#: env/lib/python2.7/site-packages/haystack/templates/panels/haystack.html:8
msgid "Time"
msgstr ""
......@@ -1794,7 +1700,7 @@ msgid ""
"\n"
"%(comment)s\n"
"\n"
"http:/%(domain)s%(url)s"
"http://%(domain)s%(url)s"
msgstr ""
#: env/lib/python2.7/site-packages/django_comments/models.py:191
......@@ -1907,6 +1813,48 @@ msgstr ""
msgid "or make changes"
msgstr ""
#: env/lib/python2.7/site-packages/haystack/admin.py:130
#, python-format
msgid "0 of %(count)d selected"
msgid_plural "of %(count)d selected"
msgstr[0] ""
msgstr[1] ""
#: env/lib/python2.7/site-packages/haystack/admin.py:132
#, python-format
msgid "%(total_count)s selected"
msgid_plural "All %(total_count)s selected"
msgstr[0] ""
msgstr[1] ""
#: env/lib/python2.7/site-packages/haystack/forms.py:102
msgid "Search In"
msgstr ""
#: env/lib/python2.7/site-packages/haystack/panels.py:31
msgid "Haystack"
msgstr ""
#: env/lib/python2.7/site-packages/haystack/panels.py:55
msgid "Search Queries"
msgstr ""
#: env/lib/python2.7/site-packages/haystack/templates/panels/haystack.html:5
msgid "Query"
msgstr ""
#: env/lib/python2.7/site-packages/haystack/templates/panels/haystack.html:6
msgid "Backend Alias"
msgstr ""
#: env/lib/python2.7/site-packages/haystack/templates/panels/haystack.html:7
msgid "Timeline"
msgstr ""
#: env/lib/python2.7/site-packages/haystack/templates/panels/haystack.html:9
msgid "Kwargs"
msgstr ""
#: env/lib/python2.7/site-packages/httplib2/__init__.py:410
#, python-format
msgid "Content purported to be compressed with %s but failed to decompress."
......@@ -1953,84 +1901,49 @@ msgstr ""
msgid "Error running spellchecker"
msgstr ""
#: nnmon/templates/about.html:7
msgid ""
"RespectMyNet.eu is an online platform enabling citizens to become the "
"watchmen of the Internet by reporting Net Neutrality violations. Everyone is "
"invited to report undue blocking or throttling of their Internet access, and "
"help name and shame operators' harmful practices."
msgstr ""
#: nnmon/templates/about.html:8
msgid ""
"This platform is a joint project by La Quadrature du Net, Bits of Freedom "
"and individual contributors. It was launched on September 22nd, 2011."
msgstr ""
#: nnmon/templates/about.html:9
msgid ""
"Organisations will submit reports to national and EU regulatory authorities "
"if appropriate."
msgstr ""
#: nnmon/templates/about.html:10
msgid "For enquiries about the project, please contact:"
msgstr ""
#: nnmon/templates/about.html:15
msgid "Initiators"
msgstr ""
#: nnmon/templates/about.html:20
msgid "Supporters"
msgstr ""
#: nnmon/templates/add.html:30
msgid "New Violation"
msgstr ""
#: nnmon/templates/add.html:33 nnmon/templates/index.html:107
msgid "Provide optional details"
msgstr ""
#: nnmon/templates/add.html:44 nnmon/templates/index.html:118
msgid "save"
msgstr ""
#: nnmon/templates/base.html:24
#: nnmon/templates/base.html:26
msgid "name and shame operators restricting access to the Internet"
msgstr ""
#: nnmon/templates/base.html:29
#: nnmon/templates/base.html:31
msgid "Logout"
msgstr ""
#: nnmon/templates/base.html:31
#: nnmon/templates/base.html:33
msgid "Admin"
msgstr ""
#: nnmon/templates/base.html:35
#: nnmon/templates/base.html:37
msgid "Login"
msgstr ""
#: nnmon/templates/base.html:40
msgid "Home"
#: nnmon/templates/base.html:47
msgid "Toggle navgation"
msgstr ""
#: nnmon/templates/base.html:41