...
 
Commits (79)
...@@ -9,63 +9,63 @@ from operator import itemgetter ...@@ -9,63 +9,63 @@ from operator import itemgetter
from captcha.fields import CaptchaField from captcha.fields import CaptchaField
class AdvancedEditor(forms.Textarea): class AdvancedEditor(forms.Textarea):
class Media: 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): def __init__(self, language=None, attrs=None):
self.language = language or settings.LANGUAGE_CODE[:2] self.language = language or settings.LANGUAGE_CODE[:2]
self.attrs = {'class': 'advancededitor'} self.attrs = {'class': 'advancededitor'}
if attrs: self.attrs.update(attrs) if attrs: self.attrs.update(attrs)
super(AdvancedEditor, self).__init__(attrs) super(AdvancedEditor, self).__init__(attrs)
class AddViolation(forms.Form): 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.")) 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.')) 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.')) 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)')) 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?')) 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.')) 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)")) 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!")) 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.")) 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.")) 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)')) 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)')) 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)')) 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)')) 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)')) 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)')) 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)")) 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): 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.')) 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=True, max_length=256, label=_("Operator"), help_text=_('The ISP or operator providing the Internet service.')) operator = forms.CharField(required=False, 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)')) 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=True, choices=(('',''),)+tuple(sorted(MEDIA,key=itemgetter(1))), label=_('Is the Internet connection over mobile or fixed line?')) 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): def search(self):
# By default, teh search field is q. So let's check if it's empty # By default, the search field is q. So let's check if it's empty
if not self.cleaned_data['q']: if not self.cleaned_data['q']:
sqs = SearchQuerySet().all() sqs = SearchQuerySet().all().exclude(old=True)
else: else:
sqs = super(SearchViolation, self).search() sqs = super(SearchViolation, self).search().exclude(old=True)
if not self.is_valid(): if not self.is_valid():
return self.no_query_found() return self.no_query_found()
if self.cleaned_data['operator']: if self.cleaned_data['operator']:
sqs = sqs.filter(operator=self.cleaned_data['operator']) sqs = sqs.filter(operator__icontains=self.cleaned_data['operator'])
if self.cleaned_data['contract']: if self.cleaned_data['contract']:
sqs = sqs.filter(contract=self.cleaned_data['contract']) sqs = sqs.filter(contract__icontains=self.cleaned_data['contract'])
if self.cleaned_data['media']: if self.cleaned_data['media']:
sqs = sqs.filter(media=self.cleaned_data['media']) sqs = sqs.filter(media=self.cleaned_data['media'])
if self.cleaned_data['country']: if self.cleaned_data['country']:
sqs = sqs.filter(country=self.cleaned_data['country']) sqs = sqs.filter(country=self.cleaned_data['country'])
return sqs return sqs
class QuickSearchViolation(forms.Form): class QuickSearchViolation(forms.Form):
query = forms.CharField(required='True', max_length=256, label=_("Search"), help_text=_('Search for an existing violation')) 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): ...@@ -64,11 +64,11 @@ class Migration(migrations.Migration):
('media', models.CharField(blank=True, max_length=20, choices=[(b'fixed', 'Fixed'), (b'mobile', 'Mobile')])), ('media', models.CharField(blank=True, max_length=20, choices=[(b'fixed', 'Fixed'), (b'mobile', 'Mobile')])),
('temporary', models.BooleanField()), ('temporary', models.BooleanField()),
('contractual', models.BooleanField()), ('contractual', models.BooleanField()),
('contract_excerpt', models.TextField(blank=True)), ('contract_excerpt', models.TextField(null=True, blank=True)),
('loophole', models.BooleanField()), ('loophole', models.BooleanField()),
('activationid', models.CharField(max_length=128, blank=True)), ('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')])), ('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')), ('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 ...@@ -5,6 +5,7 @@ from django_comments.moderation import CommentModerator, moderator
COUNTRIES = ( COUNTRIES = (
('BE', _('Belgium')), ('BE', _('Belgium')),
('BG', _('Bulgaria')), ('BG', _('Bulgaria')),
('CH', _('Switzerland')),
('CZ', _('Czech Republic')), ('CZ', _('Czech Republic')),
('DK', _('Denmark')), ('DK', _('Denmark')),
('DE', _('Germany')), ('DE', _('Germany')),
...@@ -13,9 +14,11 @@ COUNTRIES = ( ...@@ -13,9 +14,11 @@ COUNTRIES = (
('EL', _('Greece')), ('EL', _('Greece')),
('ES', _('Spain')), ('ES', _('Spain')),
('FR', _('France')), ('FR', _('France')),
('IC', _('Iceland')),
('IS', _('Iceland')), ('IS', _('Iceland')),
('IT', _('Italy')), ('IT', _('Italy')),
('CY', _('Cyprus')), ('CY', _('Cyprus')),
('LI', _('Liechtenstein')),
('LV', _('Latvia')), ('LV', _('Latvia')),
('LT', _('Lithuania')), ('LT', _('Lithuania')),
('LU', _('Luxembourg')), ('LU', _('Luxembourg')),
...@@ -38,13 +41,21 @@ RESOURCES = ( ...@@ -38,13 +41,21 @@ RESOURCES = (
('port', _('port')), ('port', _('port')),
('protocol', _('protocol')), ('protocol', _('protocol')),
('service', _('service')), ('service', _('service')),
('site', _('site')), ('site', _('website')),
('user', _('user')), ('user', _('user')),
('ip', _('ip')), ('ip', _('ip')),
('video', _('video streaming')),
('audio', _('audio streaming')),
('class', _('class of application or contraint')),
('other', _('other'))
) )
TYPES = ( TYPES = (
('zerorating', _('Zero Rating')),
('blocking', _('Blocking')), ('blocking', _('Blocking')),
('throttling', _('Throttling')), ('throttling', _('Throttling')),
('prioritisation', _('Prioritisation')),
('specialised', _('Specialised Service')),
('other', _('Other'))
) )
MEDIA = ( MEDIA = (
('fixed', _('Fixed')), ('fixed', _('Fixed')),
...@@ -73,7 +84,6 @@ class Operator(models.Model): ...@@ -73,7 +84,6 @@ class Operator(models.Model):
def __unicode__(self): def __unicode__(self):
return self.name return self.name
class Violation(models.Model): class Violation(models.Model):
country = models.CharField(max_length=2, choices=COUNTRIES) country = models.CharField(max_length=2, choices=COUNTRIES)
operator_ref = models.ForeignKey(Operator, related_name="violations") operator_ref = models.ForeignKey(Operator, related_name="violations")
...@@ -84,11 +94,13 @@ class Violation(models.Model): ...@@ -84,11 +94,13 @@ class Violation(models.Model):
media = models.CharField( max_length=20, choices=MEDIA, blank=True) media = models.CharField( max_length=20, choices=MEDIA, blank=True)
temporary = models.BooleanField( ) temporary = models.BooleanField( )
contractual = models.BooleanField() contractual = models.BooleanField()
contract_excerpt = models.TextField(blank=True) contract_excerpt = models.TextField(null=True, blank=True)
loophole = models.BooleanField() 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) 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): def confirmations(self):
return self.confirmation_set.filter(key='').count() return self.confirmation_set.filter(key='').count()
...@@ -108,7 +120,6 @@ class Violation(models.Model): ...@@ -108,7 +120,6 @@ class Violation(models.Model):
def __unicode__(self): def __unicode__(self):
return "#%s %s/%s" % (self.pk, self.country, self.operator) return "#%s %s/%s" % (self.pk, self.country, self.operator)
class Comment(models.Model): class Comment(models.Model):
submitter_email = models.EmailField() submitter_email = models.EmailField()
submitter_name = models.CharField(max_length=20) submitter_name = models.CharField(max_length=20)
......
...@@ -5,9 +5,12 @@ class ViolationIndexes(indexes.SearchIndex, indexes.Indexable): ...@@ -5,9 +5,12 @@ class ViolationIndexes(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True) text = indexes.CharField(document=True, use_template=True)
operator = indexes.CharField(model_attr="operator_ref") operator = indexes.CharField(model_attr="operator_ref")
country = indexes.CharField(model_attr="country") country = indexes.CharField(model_attr="country")
contract = indexes.CharField(model_attr="contract_excerpt") contract = indexes.CharField(model_attr="contract")
type = indexes.BooleanField(model_attr="contractual") type = indexes.CharField(model_attr="contractual")
media = indexes.CharField(model_attr="media")
operator_name = indexes.CharField() operator_name = indexes.CharField()
state = indexes.NgramField(model_attr="state")
old = indexes.BooleanField(model_attr="old")
def get_model(self): def get_model(self):
return Violation 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 ...@@ -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.template import RequestContext, loader, Context
from django.core.files import File from django.core.files import File
from django.core.servers.basehttp import FileWrapper from django.core.servers.basehttp import FileWrapper
from django.core import serializers
from django.conf import settings from django.conf import settings
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
...@@ -15,7 +16,8 @@ from django.contrib.auth.models import User ...@@ -15,7 +16,8 @@ from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.db.models import Count from django.db.models import Count
from haystack.generic_views import SearchView 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 tempfile import mkstemp
from datetime import datetime from datetime import datetime
import hashlib, os, re, json import hashlib, os, re, json
...@@ -142,20 +144,10 @@ def sendverifymail(service,to,body): ...@@ -142,20 +144,10 @@ def sendverifymail(service,to,body):
return actid 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): class AddForm(FormView):
model = Violation
template_name = 'index.html' template_name = 'index.html'
form_class = AddViolation form_class = AddViolation
success_url = '/' success_url = '/'
context_object_name = 'violations'
def form_valid(self, form): 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.") 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): ...@@ -173,7 +165,8 @@ class AddForm(FormView):
contractual = form.cleaned_data['contractual'], contractual = form.cleaned_data['contractual'],
contract_excerpt = sanitizeHtml(form.cleaned_data['contract_excerpt']), contract_excerpt = sanitizeHtml(form.cleaned_data['contract_excerpt']),
loophole = form.cleaned_data['loophole'], loophole = form.cleaned_data['loophole'],
activationid = actid activationid = actid,
old = False
) )
v.save() v.save()
#c=Confirmation(key='', email=form.cleaned_data['email'], violation=v) #c=Confirmation(key='', email=form.cleaned_data['email'], violation=v)
...@@ -187,7 +180,7 @@ class AddForm(FormView): ...@@ -187,7 +180,7 @@ class AddForm(FormView):
violation=v, violation=v,
) )
c.save() 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) a=Attachment(comment=c, name=f.name, type=f.content_type)
m = hashlib.sha256() m = hashlib.sha256()
for chunk in f.chunks(): for chunk in f.chunks():
...@@ -195,27 +188,25 @@ class AddForm(FormView): ...@@ -195,27 +188,25 @@ class AddForm(FormView):
sname=m.hexdigest() sname=m.hexdigest()
a.storage.save(sname,f) a.storage.save(sname,f)
a.save() 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) 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): def get_context_data(self, **kwargs):
context = super(AddForm, self).get_context_data(**kwargs) context = super(AddForm, self).get_context_data(**kwargs)
reports = sorted([(i['total'],i['id']) 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) reverse=True)
confirms = sorted([(i['total'],i['country']) 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) reverse=True)
operators = sorted([(i['total'],i['operator_ref__name']) 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) reverse=True)
context['stats'] = [ context['stats'] = [
(_('Total confirmed reports'), len([i for i,z in reports 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])), (_('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]))] (_('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 return context
class ViolationsList(ListView): class ViolationsList(ListView):
...@@ -223,17 +214,17 @@ class ViolationsList(ListView): ...@@ -223,17 +214,17 @@ class ViolationsList(ListView):
context_object_name = 'violations' context_object_name = 'violations'
def get_queryset(self): def get_queryset(self):
queryset = Violation.objects.filter(activationid='') queryset = Violation.objects.filter(activationid='').exclude(old=True)
if 'operator' in self.kwargs: if 'operator' in self.kwargs:
# If i Have operator I have a country # If i Have operator I have a country
queryset = Violation.objects.filter(activationid='', queryset = Violation.objects.filter(activationid='',
country=self.kwargs['country'], country=self.kwargs['country'],
operator_ref__name=self.kwargs['operator']) operator_ref__name=self.kwargs['operator']).exclude(old=True)
if 'country' in self.kwargs: if 'country' in self.kwargs:
queryset = Violation.objects.filter(activationid='', queryset = Violation.objects.filter(activationid='',
country=self.kwargs['country']) country=self.kwargs['country']).exclude(old=True)
if 'all' not in self.request.GET: 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 return queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
...@@ -243,7 +234,7 @@ class ViolationsList(ListView): ...@@ -243,7 +234,7 @@ class ViolationsList(ListView):
context['country'] = self.kwargs['country'] context['country'] = self.kwargs['country']
else: else:
countries = sorted([(i['total'], i['country']) 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) reverse=True)
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 context['countries'] = countries
...@@ -262,11 +253,26 @@ class ViolationView(DetailView): ...@@ -262,11 +253,26 @@ class ViolationView(DetailView):
raise Http404 raise Http404
return object return object
class LookupView(JSONMixin, SearchView): class LookupView(SearchView):
queryset = Violation.objects.filter(activationid='') searchqueryset = SearchQuerySet().exclude(old=True)
form_class = SearchViolation 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): 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): def get_context_data(self, *args, **kwargs):
context = super(ViolationSearchView, self).get_context_data(*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')]))]) 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 "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
...@@ -18,119 +18,127 @@ msgstr "" ...@@ -18,119 +18,127 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: bt/forms.py:20 #: bt/forms.py:22
msgid "Please specify the affected resource" msgid "Please specify the affected resource"
msgstr "" msgstr ""
#: bt/forms.py:20 #: bt/forms.py:22
msgid "" msgid ""
"What service or site, or person is unavailable or seems artificially slowed " "What service or site, or person is unavailable or seems artificially slowed "
"down. e.g. VoIP, p2p, filesharing, specific websites, etc." "down. e.g. VoIP, p2p, filesharing, specific websites, etc."
msgstr "" msgstr ""
#: bt/forms.py:21 bt/forms.py:39 #: bt/forms.py:23 bt/forms.py:41
msgid "Country" msgid "Country"
msgstr "" 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." msgid "EU member state where the restriction is reported."
msgstr "" msgstr ""
#: bt/forms.py:22 bt/forms.py:40 #: bt/forms.py:24 bt/forms.py:42
msgid "Operator" msgid "Operator"
msgstr "" 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." msgid "The ISP or operator providing the Internet service."
msgstr "" msgstr ""
#: bt/forms.py:23 bt/forms.py:41 #: bt/forms.py:25 bt/forms.py:43
msgid "Contract" msgid "Contract"
msgstr "" msgstr ""
#: bt/forms.py:23 bt/forms.py:41 #: bt/forms.py:25 bt/forms.py:43
msgid "" msgid ""
"The specific contract at the ISP provider. (please be as specific as " "The specific contract at the ISP provider. (please be as specific as "
"possible)" "possible)"
msgstr "" 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?" msgid "Is the Internet connection over mobile or fixed line?"
msgstr "" msgstr ""
#: bt/forms.py:25 #: bt/forms.py:27
msgid "Please describe the symptoms you are experiencing." msgid "Please describe the symptoms you are experiencing."
msgstr "" msgstr ""
#: bt/forms.py:26 #: bt/forms.py:28
msgid "Email (set this to enable saving)" msgid "Email (set this to enable saving)"
msgstr "" msgstr ""
#: bt/forms.py:26 #: bt/forms.py:28
msgid "" msgid ""
"We need your email to validate your report. Your email address is " "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 " "obligatory, but we will never use your personal data for anything else than "
"checking the submission. (see next for an optional exception)" "checking the submission. (see next for an optional exception)"
msgstr "" msgstr ""
#: bt/forms.py:27 #: bt/forms.py:29
msgid "I want to help further" msgid "I want to help further"
msgstr "" msgstr ""
#: bt/forms.py:27 #: bt/forms.py:29
msgid "" msgid ""
"We need your consent to contact you for clarifications regarding your " "We need your consent to contact you for clarifications regarding your "
"report. This is optional, but helps us improve the quality of the reports. " "report. This is optional, but helps us improve the quality of the reports. "
"Thanks!" "Thanks!"
msgstr "" msgstr ""
#: bt/forms.py:28 #: bt/forms.py:30
msgid "Name or nickname" msgid "Name or nickname"
msgstr "" msgstr ""
#: bt/forms.py:28 #: bt/forms.py:30
msgid "We need some name to display that instead of an email address." msgid "We need some name to display that instead of an email address."
msgstr "" msgstr ""
#: bt/forms.py:29 #: bt/forms.py:31
msgid "Attach screenshot, document or any other relevant information." msgid "Attach screenshot, document or any other relevant information."
msgstr "" msgstr ""
#: bt/forms.py:30 #: bt/forms.py:32
msgid "What is the affected resource type. (optional)" msgid "What is the affected resource type. (optional)"
msgstr "" msgstr ""
#: bt/forms.py:31 #: bt/forms.py:33
msgid "Is the Resource Blocked or otherwise discrimated? (optional)" msgid "What types of resctriction happens in this case?"
msgstr "" msgstr ""
#: bt/forms.py:32 #: bt/forms.py:34
msgid "" msgid ""
"Is the restriction only temporary, e.g. due to network overload? (optional)" "Is the restriction only temporary, e.g. due to network overload? (optional)"
msgstr "" msgstr ""
#: bt/forms.py:33 #: bt/forms.py:35
msgid "" msgid ""
"Is there another offer provided by this Operator which removes this " "Is there another offer provided by this Operator which removes this "
"restriction? (optional)" "restriction? (optional)"
msgstr "" msgstr ""
#: bt/forms.py:34 #: bt/forms.py:36
msgid "Is the restriction described in the subscribers contract? (optional)" msgid "The restriction is described in the subscribers contract."
msgstr "" msgstr ""
#: bt/forms.py:35 #: bt/forms.py:37
msgid "" msgid ""
"Please copy the relevant section describing the restriction from the user " "Please copy the relevant section describing the restriction from the user "
"contract. (optional)" "contract. (optional)"
msgstr "" msgstr ""
#: bt/forms.py:36 #: bt/forms.py:38
msgid "" msgid ""
"In order to protect against spam, please fill in the result of the following " "In order to protect against spam, please fill in the result of the following "
"calculation. (note the + and the * are somewhat confusing)" "calculation. (note the + and the * are somewhat confusing)"
msgstr "" 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 #: bt/models.py:6
msgid "Belgium" msgid "Belgium"
msgstr "" msgstr ""
...@@ -140,179 +148,220 @@ msgid "Bulgaria" ...@@ -140,179 +148,220 @@ msgid "Bulgaria"
msgstr "" msgstr ""
#: bt/models.py:8 #: bt/models.py:8
msgid "Czech Republic" msgid "Switzerland"
msgstr "" msgstr ""
#: bt/models.py:9 #: bt/models.py:9
msgid "Denmark" msgid "Czech Republic"
msgstr "" msgstr ""
#: bt/models.py:10 #: bt/models.py:10
msgid "Germany" msgid "Denmark"
msgstr "" msgstr ""
#: bt/models.py:11 #: bt/models.py:11
msgid "Estonia" msgid "Germany"
msgstr "" msgstr ""
#: bt/models.py:12 #: bt/models.py:12
msgid "Ireland" msgid "Estonia"
msgstr "" msgstr ""
#: bt/models.py:13 #: bt/models.py:13
msgid "Greece" msgid "Ireland"
msgstr "" msgstr ""
#: bt/models.py:14 #: bt/models.py:14
msgid "Greece"
msgstr ""
#: bt/models.py:15
msgid "Spain" msgid "Spain"
msgstr "" msgstr ""
#: bt/models.py:15 nnmon/templates/about.html:12 #: bt/models.py:16
msgid "France" msgid "France"
msgstr "" msgstr ""
#: bt/models.py:16 #: bt/models.py:17 bt/models.py:18
msgid "Iceland" msgid "Iceland"
msgstr "" msgstr ""
#: bt/models.py:17 #: bt/models.py:19
msgid "Italy" msgid "Italy"
msgstr "" msgstr ""
#: bt/models.py:18 #: bt/models.py:20
msgid "Cyprus" msgid "Cyprus"
msgstr "" msgstr ""
#: bt/models.py:19 #: bt/models.py:21
msgid "Liechtenstein"
msgstr ""
#: bt/models.py:22
msgid "Latvia" msgid "Latvia"
msgstr "" msgstr ""
#: bt/models.py:20 #: bt/models.py:23
msgid "Lithuania" msgid "Lithuania"
msgstr "" msgstr ""
#: bt/models.py:21 #: bt/models.py:24
msgid "Luxembourg" msgid "Luxembourg"
msgstr "" msgstr ""
#: bt/models.py:22 #: bt/models.py:25
msgid "Hungary" msgid "Hungary"
msgstr "" msgstr ""
#: bt/models.py:23 #: bt/models.py:26
msgid "Malta" msgid "Malta"
msgstr "" msgstr ""
#: bt/models.py:24 nnmon/templates/about.html:13 #: bt/models.py:27
msgid "Netherlands" msgid "Netherlands"
msgstr "" msgstr ""
#: bt/models.py:25 #: bt/models.py:28
msgid "Norway" msgid "Norway"
msgstr "" msgstr ""
#: bt/models.py:26 #: bt/models.py:29
msgid "Austria" msgid "Austria"
msgstr "" msgstr ""
#: bt/models.py:27 #: bt/models.py:30
msgid "Poland" msgid "Poland"
msgstr "" msgstr ""
#: bt/models.py:28 #: bt/models.py:31
msgid "Portugal" msgid "Portugal"
msgstr "" msgstr ""
#: bt/models.py:29 #: bt/models.py:32
msgid "Romania" msgid "Romania"
msgstr "" msgstr ""
#: bt/models.py:30 #: bt/models.py:33
msgid "Slovenia" msgid "Slovenia"
msgstr "" msgstr ""
#: bt/models.py:31 #: bt/models.py:34
msgid "Slovakia" msgid "Slovakia"
msgstr "" msgstr ""
#: bt/models.py:32 #: bt/models.py:35
msgid "Finland" msgid "Finland"
msgstr "" msgstr ""
#: bt/models.py:33 #: bt/models.py:36
msgid "Sweden" msgid "Sweden"
msgstr "" msgstr ""
#: bt/models.py:34 #: bt/models.py:37
msgid "United Kingdom" msgid "United Kingdom"
msgstr "" msgstr ""
#: bt/models.py:38 #: bt/models.py:41
msgid "port" msgid "port"
msgstr "" msgstr ""
#: bt/models.py:39 #: bt/models.py:42
msgid "protocol" msgid "protocol"
msgstr "" msgstr ""
#: bt/models.py:40 #: bt/models.py:43
msgid "service" msgid "service"
msgstr "" msgstr ""
#: bt/models.py:41 #: bt/models.py:44
msgid "site" msgid "website"
msgstr "" 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 #: env/lib/python2.7/site-packages/django_comments/models.py:189
msgid "user" msgid "user"
msgstr "" msgstr ""
#: bt/models.py:43 #: bt/models.py:46
msgid "ip" msgid "ip"
msgstr "" 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" msgid "Blocking"
msgstr "" msgstr ""
#: bt/models.py:47 #: bt/models.py:55
msgid "Throttling" msgid "Throttling"
msgstr "" 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" msgid "Fixed"
msgstr "" msgstr ""
#: bt/models.py:51 #: bt/models.py:62
msgid "Mobile" msgid "Mobile"
msgstr "" msgstr ""
#: bt/models.py:54 #: bt/models.py:65
msgid "Need more info" msgid "Need more info"
msgstr "" 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" msgid "New"
msgstr "" msgstr ""
#: bt/models.py:56 #: bt/models.py:67
msgid "Verified" msgid "Verified"
msgstr "" msgstr ""
#: bt/models.py:57 #: bt/models.py:68
msgid "Duplicate" msgid "Duplicate"
msgstr "" msgstr ""
#: bt/models.py:58 #: bt/models.py:69
msgid "Out of scope" msgid "Out of scope"
msgstr "" msgstr ""
#: bt/models.py:59 #: bt/models.py:70
msgid "Closed" msgid "Closed"
msgstr "" msgstr ""
#: bt/models.py:124 #: bt/models.py:135
#, python-format #, python-format
msgid "Comment #%s" msgid "Comment #%s"
msgstr "" msgstr ""
...@@ -336,41 +385,41 @@ msgstr "" ...@@ -336,41 +385,41 @@ msgstr ""
msgid "An incorrect number of files were uploaded." msgid "An incorrect number of files were uploaded."
msgstr "" 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" msgid "Thank you, this key has been already activated"
msgstr "" msgstr ""
#: bt/views.py:72 #: bt/views.py:78
msgid "" msgid ""
"Thank you for verifying your submission. It will be listed shortly, after " "Thank you for verifying your submission. It will be listed shortly, after "
"we've checked that the report is valid." "we've checked that the report is valid."
msgstr "" msgstr ""
#: bt/views.py:82 #: bt/views.py:88
msgid "No such key" msgid "No such key"
msgstr "" msgstr ""
#: bt/views.py:85 #: bt/views.py:91
#, python-format #, python-format
msgid "Thank you for approving the <a href=\"%s\">submission</a>." msgid "Thank you for approving the <a href=\"%s\">submission</a>."
msgstr "" msgstr ""
#: bt/views.py:89 #: bt/views.py:95
msgid "NNMon submission approved" msgid "NNMon submission approved"
msgstr "" msgstr ""
#: bt/views.py:90 #: bt/views.py:96
#, python-format #, python-format
msgid "" msgid ""
"Your report has been approved.\n" "Your report has been approved.\n"
"To see it, please visit: %s/%s" "To see it, please visit: %s/%s"
msgstr "" msgstr ""
#: bt/views.py:105 #: bt/views.py:111
msgid "Thank you for deleting the submission." msgid "Thank you for deleting the submission."
msgstr "" msgstr ""
#: bt/views.py:112 #: bt/views.py:118
#, python-format #, python-format
msgid "" msgid ""
"Thank you for confirming a case. To finalize your confirmation please " "Thank you for confirming a case. To finalize your confirmation please "
...@@ -378,23 +427,23 @@ msgid "" ...@@ -378,23 +427,23 @@ msgid ""
"Your confirmation key is %s/%s%s" "Your confirmation key is %s/%s%s"
msgstr "" 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" msgid "Thank you, this has been already confirmed"
msgstr "" msgstr ""
#: bt/views.py:119 #: bt/views.py:125
msgid "Thank you for your confirmation" msgid "Thank you for your confirmation"
msgstr "" msgstr ""
#: bt/views.py:127 #: bt/views.py:133
msgid "Thank you for verifying your confirmation" msgid "Thank you for verifying your confirmation"
msgstr "" msgstr ""
#: bt/views.py:134 #: bt/views.py:140
msgid "NNMon submission verification" msgid "NNMon submission verification"
msgstr "" msgstr ""
#: bt/views.py:145 #: bt/views.py:153
#, python-format #, python-format
msgid "" msgid ""
"Thank you for submitting a new report. To finalize your submission please " "Thank you for submitting a new report. To finalize your submission please "
...@@ -404,170 +453,26 @@ msgid "" ...@@ -404,170 +453,26 @@ msgid ""
"report appears online. Thank you for your patience." "report appears online. Thank you for your patience."
msgstr "" msgstr ""
#: bt/views.py:183 #: bt/views.py:191
msgid "" msgid ""
"Thank you for submitting this report, you will receive a verification email " "Thank you for submitting this report, you will receive a verification email "
"immediately, if not check your spam folder." "immediately, if not check your spam folder."
msgstr "" msgstr ""
#: bt/views.py:221 #: bt/views.py:206
msgid "Total confirmed reports" msgid "Total confirmed reports"
msgstr "" msgstr ""
#: bt/views.py:222 #: bt/views.py:207 bt/views.py:286
msgid "Countries with some confirmed reports" msgid "Countries with some confirmed reports"
msgstr "" msgstr ""
#: bt/views.py:223 #: bt/views.py:208 bt/views.py:287
msgid "Operators with some confirmed reports" msgid "Operators with some confirmed reports"
msgstr "" msgstr ""
#: env/lib/python2.7/site-packages/argparse.py:313 #: bt/views.py:285
msgid "usage: " msgid "Number of reports in this search"
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 ""