From 30acd5c81689545ba02dfa392b118f262f3511b8 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 12 Feb 2012 21:54:05 -0600 Subject: Protect urlencode calls against Unicode data These would cause page errors if passed anything not in the ASCII character set. This change allows for packages to have names composed of any Unicode characters, not just those in the ASCII set. Signed-off-by: Dan McGee --- packages/templatetags/package_extras.py | 7 +++++-- packages/urls.py | 2 +- packages/views/__init__.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index 25e943ff..5cc826ed 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -9,8 +9,11 @@ from django.utils.html import escape register = template.Library() -def link_encode(url, query, doseq=False): - data = urlencode(query, doseq).replace('&', '&') +def link_encode(url, query): + # massage the data into all utf-8 encoded strings first, so urlencode + # doesn't barf at the data we pass it + query = dict((k, unicode(v).encode('utf-8')) for k, v in query.items()) + data = urlencode(query).replace('&', '&') return "%s?%s" % (url, data) @register.filter diff --git a/packages/urls.py b/packages/urls.py index 6c616297..52b09d2c 100644 --- a/packages/urls.py +++ b/packages/urls.py @@ -28,7 +28,7 @@ urlpatterns = patterns('packages.views', (r'^stale_relations/$', 'stale_relations'), (r'^stale_relations/update/$','stale_relations_update'), - (r'^(?P[A-z0-9\-+.]+)/$', + (r'^(?P[^ /]+)/$', 'details'), (r'^(?P[A-z0-9\-]+)/(?P[^ /]+)/$', 'details'), diff --git a/packages/views/__init__.py b/packages/views/__init__.py index 63942474..8f22a8a1 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -142,7 +142,7 @@ def details(request, name='', repo='', arch=''): ('q', name), ] # only include non-blank values in the query we generate - pkg_data = [(x, y) for x, y in pkg_data if y] + pkg_data = [(x, y.encode('utf-8')) for x, y in pkg_data if y] return redirect("/packages/?%s" % urlencode(pkg_data)) def groups(request, arch=None): -- cgit v1.2.3-2-g168b From fa6f85f127f5f100f98c0ce130cea2277cd02a0e Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 12 Feb 2012 22:47:25 -0600 Subject: Reduce false positives returned by uncompressed manpages report Explicitly exclude '.html' files from the report. This fixes the issue noted in FS#28372. We also add `is_directory=False` to both the manpage and info page queries; this could help the database come up with a better plan. Signed-off-by: Dan McGee --- devel/views.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/devel/views.py b/devel/views.py index 35918d66..5f1aed54 100644 --- a/devel/views.py +++ b/devel/views.py @@ -209,8 +209,10 @@ def report(request, report_name, username=None): elif report_name == 'uncompressed-man': title = 'Packages with uncompressed manpages' # checking for all '.0'...'.9' + '.n' extensions - bad_files = PackageFile.objects.filter(directory__contains='/man/', - filename__regex=r'\.[0-9n]').exclude(filename__endswith='.gz') + bad_files = PackageFile.objects.filter(is_directory=False, + directory__contains='/man/', + filename__regex=r'\.[0-9n]').exclude( + filename__endswith='.gz').exclude(filename__endswith='.html') if username: pkg_ids = set(packages.values_list('id', flat=True)) bad_files = bad_files.filter(pkg__in=pkg_ids) @@ -220,8 +222,8 @@ def report(request, report_name, username=None): title = 'Packages with uncompressed infopages' # we don't worry about looking for '*.info-1', etc., given that an # uncompressed root page probably exists in the package anyway - bad_files = PackageFile.objects.filter(directory__endswith='/info/', - filename__endswith='.info') + bad_files = PackageFile.objects.filter(is_directory=False, + directory__endswith='/info/', filename__endswith='.info') if username: pkg_ids = set(packages.values_list('id', flat=True)) bad_files = bad_files.filter(pkg__in=pkg_ids) -- cgit v1.2.3-2-g168b From 3a1101db1d18be2f95342ad8943722eb94ae577e Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 13 Feb 2012 12:34:35 -0600 Subject: Don't select FTP by default in mirrorlists More generally, add a new 'default' column to the mirror protocol model so we can determine what is selected and shown by default. Signed-off-by: Dan McGee --- mirrors/admin.py | 8 ++- mirrors/fixtures/mirrorprotocols.json | 5 +- .../0010_auto__add_field_mirrorprotocol_default.py | 66 +++++++++++++++++++++ .../migrations/0011_adjust_protocol_defaults.py | 67 ++++++++++++++++++++++ mirrors/models.py | 2 + mirrors/views.py | 6 +- 6 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 mirrors/migrations/0010_auto__add_field_mirrorprotocol_default.py create mode 100644 mirrors/migrations/0011_adjust_protocol_defaults.py diff --git a/mirrors/admin.py b/mirrors/admin.py index 3786d8d2..a2b59b41 100644 --- a/mirrors/admin.py +++ b/mirrors/admin.py @@ -56,7 +56,9 @@ class MirrorRsyncInlineAdmin(admin.TabularInline): class MirrorAdminForm(forms.ModelForm): class Meta: model = Mirror - upstream = forms.ModelChoiceField(queryset=Mirror.objects.filter(tier__gte=0, tier__lte=1), required=False) + upstream = forms.ModelChoiceField( + queryset=Mirror.objects.filter(tier__gte=0, tier__lte=1), + required=False) class MirrorAdmin(admin.ModelAdmin): form = MirrorAdminForm @@ -70,8 +72,8 @@ class MirrorAdmin(admin.ModelAdmin): ] class MirrorProtocolAdmin(admin.ModelAdmin): - list_display = ('protocol', 'is_download',) - list_filter = ('is_download',) + list_display = ('protocol', 'is_download', 'default') + list_filter = ('is_download', 'default') admin.site.register(Mirror, MirrorAdmin) admin.site.register(MirrorProtocol, MirrorProtocolAdmin) diff --git a/mirrors/fixtures/mirrorprotocols.json b/mirrors/fixtures/mirrorprotocols.json index 35614b3a..72ed1a7f 100644 --- a/mirrors/fixtures/mirrorprotocols.json +++ b/mirrors/fixtures/mirrorprotocols.json @@ -4,6 +4,7 @@ "model": "mirrors.mirrorprotocol", "fields": { "is_download": true, + "default": true, "protocol": "http" } }, @@ -12,6 +13,7 @@ "model": "mirrors.mirrorprotocol", "fields": { "is_download": true, + "default": false, "protocol": "ftp" } }, @@ -20,7 +22,8 @@ "model": "mirrors.mirrorprotocol", "fields": { "is_download": false, + "default": false, "protocol": "rsync" } } -] \ No newline at end of file +] diff --git a/mirrors/migrations/0010_auto__add_field_mirrorprotocol_default.py b/mirrors/migrations/0010_auto__add_field_mirrorprotocol_default.py new file mode 100644 index 00000000..6868cb25 --- /dev/null +++ b/mirrors/migrations/0010_auto__add_field_mirrorprotocol_default.py @@ -0,0 +1,66 @@ +# encoding: utf-8 +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + db.add_column('mirrors_mirrorprotocol', 'default', self.gf('django.db.models.fields.BooleanField')(default=True), keep_default=False) + + def backwards(self, orm): + db.delete_column('mirrors_mirrorprotocol', 'default') + + + models = { + 'mirrors.mirror': { + 'Meta': {'ordering': "('country', 'name')", 'object_name': 'Mirror'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), + 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), + 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), + 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['mirrors.Mirror']", 'null': 'True'}) + }, + 'mirrors.mirrorlog': { + 'Meta': {'object_name': 'MirrorLog'}, + 'check_time': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'error': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_success': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_sync': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'url': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'logs'", 'to': "orm['mirrors.MirrorUrl']"}) + }, + 'mirrors.mirrorprotocol': { + 'Meta': {'ordering': "('protocol',)", 'object_name': 'MirrorProtocol'}, + 'default': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_download': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) + }, + 'mirrors.mirrorrsync': { + 'Meta': {'object_name': 'MirrorRsync'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), + 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['mirrors.Mirror']"}) + }, + 'mirrors.mirrorurl': { + 'Meta': {'object_name': 'MirrorUrl'}, + 'country': ('mirrors.models.NullCharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'has_ipv4': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'has_ipv6': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.Mirror']"}), + 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.MirrorProtocol']"}), + 'url': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) + } + } + + complete_apps = ['mirrors'] diff --git a/mirrors/migrations/0011_adjust_protocol_defaults.py b/mirrors/migrations/0011_adjust_protocol_defaults.py new file mode 100644 index 00000000..0118de67 --- /dev/null +++ b/mirrors/migrations/0011_adjust_protocol_defaults.py @@ -0,0 +1,67 @@ +# encoding: utf-8 +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + orm.MirrorProtocol.objects.all().update(default=False) + orm.MirrorProtocol.objects.filter(protocol='http').update(default=True) + + def backwards(self, orm): + pass + + + models = { + 'mirrors.mirror': { + 'Meta': {'ordering': "('country', 'name')", 'object_name': 'Mirror'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), + 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), + 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), + 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['mirrors.Mirror']", 'null': 'True'}) + }, + 'mirrors.mirrorlog': { + 'Meta': {'object_name': 'MirrorLog'}, + 'check_time': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'error': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_success': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_sync': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'url': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'logs'", 'to': "orm['mirrors.MirrorUrl']"}) + }, + 'mirrors.mirrorprotocol': { + 'Meta': {'ordering': "('protocol',)", 'object_name': 'MirrorProtocol'}, + 'default': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_download': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) + }, + 'mirrors.mirrorrsync': { + 'Meta': {'object_name': 'MirrorRsync'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), + 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['mirrors.Mirror']"}) + }, + 'mirrors.mirrorurl': { + 'Meta': {'object_name': 'MirrorUrl'}, + 'country': ('mirrors.models.NullCharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'has_ipv4': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'has_ipv6': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.Mirror']"}), + 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.MirrorProtocol']"}), + 'url': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) + } + } + + complete_apps = ['mirrors'] diff --git a/mirrors/models.py b/mirrors/models.py index 111654fd..86905eea 100644 --- a/mirrors/models.py +++ b/mirrors/models.py @@ -54,6 +54,8 @@ class MirrorProtocol(models.Model): protocol = models.CharField(max_length=10, unique=True) is_download = models.BooleanField(default=True, help_text="Is protocol useful for end-users, e.g. FTP/HTTP") + default = models.BooleanField(default=True, + help_text="Included by default when building mirror list?") def __unicode__(self): return self.protocol diff --git a/mirrors/views.py b/mirrors/views.py index 417e26ee..2ef8654d 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -29,8 +29,9 @@ class MirrorlistForm(forms.Form): self.fields['country'].initial = ['all'] protos = make_choice( MirrorProtocol.objects.filter(is_download=True)) + initial = MirrorProtocol.objects.filter(is_download=True, default=True) self.fields['protocol'].choices = protos - self.fields['protocol'].initial = [t[0] for t in protos] + self.fields['protocol'].initial = [p.protocol for p in initial] self.fields['ip_version'].initial = ['4'] @csrf_exempt @@ -48,7 +49,8 @@ def generate_mirrorlist(request): else: form = MirrorlistForm() - return direct_to_template(request, 'mirrors/index.html', {'mirrorlist_form': form}) + return direct_to_template(request, 'mirrors/index.html', + {'mirrorlist_form': form}) def find_mirrors(request, countries=None, protocols=None, use_status=False, ipv4_supported=True, ipv6_supported=True): -- cgit v1.2.3-2-g168b From ef9d1c1ea2dce131ffd63730a5cd2df1744ff018 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 14 Feb 2012 10:32:01 -0600 Subject: Require message when flagging package out of date This is not a very high bar to meet, and should cut down on at least a few bogus or spam requests. Signed-off-by: Dan McGee --- packages/views/flag.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/views/flag.py b/packages/views/flag.py index 8879695c..c0990e8e 100644 --- a/packages/views/flag.py +++ b/packages/views/flag.py @@ -18,9 +18,9 @@ def flaghelp(request): return direct_to_template(request, 'packages/flaghelp.html') class FlagForm(forms.Form): - email = forms.EmailField(label='* E-mail Address') - message = forms.CharField(label='Message To Dev', - widget=forms.Textarea, required=False) + email = forms.EmailField(label='E-mail Address') + message = forms.CharField(label='Message To Developer', + widget=forms.Textarea) # The field below is used to filter out bots that blindly fill out all # input elements website = forms.CharField(label='', -- cgit v1.2.3-2-g168b From 03a0d27971898592698dbb0c5948b93c6a3a4741 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 16 Feb 2012 14:07:25 -0600 Subject: Update sidebar links Signed-off-by: Dan McGee --- templates/public/index.html | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/templates/public/index.html b/templates/public/index.html index a4b03141..038fd8d6 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -134,12 +134,8 @@ title="Official and regional IRC communities">IRC Channels
  • Planet Arch
  • -
  • Rolling Release Ezine
  • International Communities
  • -
  • Related Projects
  • Support

    @@ -169,34 +165,29 @@

    Development

    -

    About

    +

    More Resources