Merge lp:~zematynnad/ubuntu-webcatalog/banners_965560 into lp:ubuntu-webcatalog

Proposed by Danny Tamez
Status: Merged
Approved by: Danny Tamez
Approved revision: 104
Merged at revision: 101
Proposed branch: lp:~zematynnad/ubuntu-webcatalog/banners_965560
Merge into: lp:ubuntu-webcatalog
Diff against target: 291 lines (+186/-6)
7 files modified
src/webcatalog/management/commands/import_exhibits.py (+2/-0)
src/webcatalog/migrations/0020_weight_to_exhibit.py (+164/-0)
src/webcatalog/models/applications.py (+1/-0)
src/webcatalog/tests/factory.py (+2/-2)
src/webcatalog/tests/test_commands.py (+3/-1)
src/webcatalog/tests/test_views.py (+13/-0)
src/webcatalog/views.py (+1/-3)
To merge this branch: bzr merge lp:~zematynnad/ubuntu-webcatalog/banners_965560
Reviewer Review Type Date Requested Status
Michael Nelson (community) Approve
Review via email: mp+101977@code.launchpad.net

Commit message

Adds ordering of the exhibits in the exhibits banner

Description of the change

Overview
========
This branch fixes the ordering of the banners displayed in the exhibits widget.

Details
========
The weight field which is used for ordering the exhibits in sca is now being brought over in the import_exhibits command. The exhibits are now ordered by that field and their order is no longer randomized in the view.

To Test
=======
$fab bootstrap test

To post a comment you must log in.
Revision history for this message
Michael Nelson (michael.nelson) wrote :

Nice and straight-forward - thanks Danny!

No need to change, but just if it's helpful information - you can actually grab things out of the response context for you test... in this case you could grab response.context['exhibits'] (or whatever it is in the context) and check the ordering directly, rather than having to search and compare indexes in the response html. That said, your current test is more end-to-end, as a template tag could always be used to reverse the order or whatever. Just food for thought:)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/webcatalog/management/commands/import_exhibits.py'
--- src/webcatalog/management/commands/import_exhibits.py 2012-03-01 21:38:31 +0000
+++ src/webcatalog/management/commands/import_exhibits.py 2012-04-13 21:23:18 +0000
@@ -56,6 +56,8 @@
56 for field in ['package_names', 'html', 'banner_url']:56 for field in ['package_names', 'html', 'banner_url']:
57 args[field] = exhibit.get(field, '')57 args[field] = exhibit.get(field, '')
5858
59 args['weight'] = exhibit.get('weight', 0)
60
59 # Munge banner_url into html61 # Munge banner_url into html
60 banner_url = args['banner_url']62 banner_url = args['banner_url']
61 if banner_url:63 if banner_url:
6264
=== added file 'src/webcatalog/migrations/0020_weight_to_exhibit.py'
--- src/webcatalog/migrations/0020_weight_to_exhibit.py 1970-01-01 00:00:00 +0000
+++ src/webcatalog/migrations/0020_weight_to_exhibit.py 2012-04-13 21:23:18 +0000
@@ -0,0 +1,164 @@
1# -*- coding: utf-8 -*-
2import datetime
3from south.db import db
4from south.v2 import SchemaMigration
5from django.db import models
6
7
8class Migration(SchemaMigration):
9
10 def forwards(self, orm):
11 # Adding field 'Exhibit.weight'
12 db.add_column('webcatalog_exhibit', 'weight',
13 self.gf('django.db.models.fields.IntegerField')(default=0),
14 keep_default=False)
15
16 def backwards(self, orm):
17 # Deleting field 'Exhibit.weight'
18 db.delete_column('webcatalog_exhibit', 'weight')
19
20 models = {
21 'auth.group': {
22 'Meta': {'object_name': 'Group'},
23 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
24 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
25 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
26 },
27 'auth.permission': {
28 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
29 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
30 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
31 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
32 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
33 },
34 'auth.user': {
35 'Meta': {'object_name': 'User'},
36 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
37 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
38 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
39 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
40 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
41 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
42 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
43 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
44 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
45 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
46 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
47 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
48 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
49 },
50 'contenttypes.contenttype': {
51 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
52 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
53 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
54 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
55 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
56 },
57 'webcatalog.application': {
58 'Meta': {'unique_together': "(('distroseries', 'archive_id'),)", 'object_name': 'Application'},
59 'app_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
60 'architectures': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
61 'archive_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'null': 'True', 'blank': 'True'}),
62 'categories': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
63 'channel': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
64 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
65 'debtags': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
66 'departments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Department']", 'symmetrical': 'False', 'blank': 'True'}),
67 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
68 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']"}),
69 'for_purchase': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
70 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
71 'icon_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
72 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
73 'is_latest': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
74 'keywords': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
75 'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}),
76 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
77 'package_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
78 'popcon': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
79 'price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2', 'blank': 'True'}),
80 'ratings_average': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '3', 'decimal_places': '2', 'blank': 'True'}),
81 'ratings_histogram': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
82 'ratings_total': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
83 'section': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
84 'version': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
85 'wilson_score': ('django.db.models.fields.FloatField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
86 },
87 'webcatalog.applicationmedia': {
88 'Meta': {'unique_together': "(('application', 'url'),)", 'object_name': 'ApplicationMedia'},
89 'application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Application']"}),
90 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
91 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
92 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
93 },
94 'webcatalog.consumer': {
95 'Meta': {'object_name': 'Consumer'},
96 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
97 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
98 'key': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
99 'secret': ('django.db.models.fields.CharField', [], {'default': "'nDcywpUpPYwdIckXOsrVjMBKQwMuSk'", 'max_length': '255', 'blank': 'True'}),
100 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
101 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'oauth_consumer'", 'unique': 'True', 'to': "orm['auth.User']"})
102 },
103 'webcatalog.department': {
104 'Meta': {'object_name': 'Department'},
105 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
106 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
107 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Department']", 'null': 'True', 'blank': 'True'}),
108 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
109 },
110 'webcatalog.distroseries': {
111 'Meta': {'object_name': 'DistroSeries'},
112 'code_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20', 'db_index': 'True'}),
113 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
114 'version': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'})
115 },
116 'webcatalog.exhibit': {
117 'Meta': {'object_name': 'Exhibit'},
118 'banner_url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
119 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
120 'display': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
121 'distroseries': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.DistroSeries']", 'symmetrical': 'False'}),
122 'html': ('django.db.models.fields.TextField', [], {}),
123 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
124 'package_names': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
125 'published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
126 'sca_id': ('django.db.models.fields.IntegerField', [], {}),
127 'weight': ('django.db.models.fields.IntegerField', [], {'default': '0'})
128 },
129 'webcatalog.machine': {
130 'Meta': {'unique_together': "(('owner', 'uuid'),)", 'object_name': 'Machine'},
131 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
132 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
133 'logo_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56', 'blank': 'True'}),
134 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
135 'package_list': ('django.db.models.fields.TextField', [], {}),
136 'packages_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56'}),
137 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'})
138 },
139 'webcatalog.nonce': {
140 'Meta': {'object_name': 'Nonce'},
141 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}),
142 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
143 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
144 'nonce': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
145 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Token']"})
146 },
147 'webcatalog.reviewstatsimport': {
148 'Meta': {'object_name': 'ReviewStatsImport'},
149 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']", 'unique': 'True'}),
150 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
151 'last_import': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'})
152 },
153 'webcatalog.token': {
154 'Meta': {'object_name': 'Token'},
155 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}),
156 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
157 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
158 'token': ('django.db.models.fields.CharField', [], {'default': "'uKqOdpKariCfWFVhuVQbAYOknPhTELPfpvfZVNdKeapBClaiiU'", 'max_length': '50', 'primary_key': 'True'}),
159 'token_secret': ('django.db.models.fields.CharField', [], {'default': "'QkGeNWgqkohZyvBVCcMGtHDiNoSmSoxUxjlblBvjJbEZTmyAof'", 'max_length': '50'}),
160 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
161 }
162 }
163
164 complete_apps = ['webcatalog']
0\ No newline at end of file165\ No newline at end of file
1166
=== modified file 'src/webcatalog/models/applications.py'
--- src/webcatalog/models/applications.py 2012-04-05 01:09:37 +0000
+++ src/webcatalog/models/applications.py 2012-04-13 21:23:18 +0000
@@ -255,6 +255,7 @@
255 display = models.NullBooleanField(255 display = models.NullBooleanField(
256 help_text="Yes: Always display. No: Never display. "256 help_text="Yes: Always display. No: Never display. "
257 "Unknown: Display if published")257 "Unknown: Display if published")
258 weight = models.IntegerField(default=0)
258259
259 class Meta:260 class Meta:
260 app_label = 'webcatalog'261 app_label = 'webcatalog'
261262
=== modified file 'src/webcatalog/tests/factory.py'
--- src/webcatalog/tests/factory.py 2012-03-23 22:41:16 +0000
+++ src/webcatalog/tests/factory.py 2012-04-13 21:23:18 +0000
@@ -130,7 +130,7 @@
130 return Department.objects.create(name=name, parent=parent, slug=slug)130 return Department.objects.create(name=name, parent=parent, slug=slug)
131131
132 def make_exhibit(self, package_names=None, published=True, display=None,132 def make_exhibit(self, package_names=None, published=True, display=None,
133 distroseries=None):133 distroseries=None, weight=0):
134 sca_id = self.get_unique_integer()134 sca_id = self.get_unique_integer()
135 if package_names is None:135 if package_names is None:
136 package_names = self.get_unique_string(prefix='package-')136 package_names = self.get_unique_string(prefix='package-')
@@ -140,7 +140,7 @@
140 distroseries = self.make_distroseries()140 distroseries = self.make_distroseries()
141 xibit = Exhibit.objects.create(sca_id=sca_id,141 xibit = Exhibit.objects.create(sca_id=sca_id,
142 package_names=package_names, banner_url=banner_url, html=html,142 package_names=package_names, banner_url=banner_url, html=html,
143 published=published, display=display)143 published=published, display=display, weight=weight)
144 xibit.distroseries.add(distroseries)144 xibit.distroseries.add(distroseries)
145 return xibit145 return xibit
146146
147147
=== modified file 'src/webcatalog/tests/test_commands.py'
--- src/webcatalog/tests/test_commands.py 2012-04-03 17:45:07 +0000
+++ src/webcatalog/tests/test_commands.py 2012-04-13 21:23:18 +0000
@@ -684,6 +684,7 @@
684 'code_name': ds.code_name,684 'code_name': ds.code_name,
685 'html': exhibit.html,685 'html': exhibit.html,
686 'date_created': str(exhibit.date_created),686 'date_created': str(exhibit.date_created),
687 'weight': str(exhibit.weight),
687 'id': exhibit.sca_id})688 'id': exhibit.sca_id})
688 if changes:689 if changes:
689 for atts, change in zip(data, changes):690 for atts, change in zip(data, changes):
@@ -713,7 +714,7 @@
713 new_html = self.factory.get_unique_string(prefix='new-')714 new_html = self.factory.get_unique_string(prefix='new-')
714 mock_urlopen.return_value = self.mock_response([xibit], changes=[715 mock_urlopen.return_value = self.mock_response([xibit], changes=[
715 {'package_names': new_package_names, 'banner_url': new_banner_url,716 {'package_names': new_package_names, 'banner_url': new_banner_url,
716 'html': new_html}])717 'html': new_html, 'weight': 3}])
717718
718 call_command('import_exhibits')719 call_command('import_exhibits')
719720
@@ -722,6 +723,7 @@
722 self.assertEqual(new_package_names, retrieved.package_names)723 self.assertEqual(new_package_names, retrieved.package_names)
723 self.assertEqual(new_banner_url, retrieved.banner_url)724 self.assertEqual(new_banner_url, retrieved.banner_url)
724 self.assertEqual(new_html, retrieved.html)725 self.assertEqual(new_html, retrieved.html)
726 self.assertEqual(3, retrieved.weight)
725727
726 @patch('urllib.urlopen')728 @patch('urllib.urlopen')
727 def test_creates_exhibit_if_scaid_does_not_match(self, mock_urlopen):729 def test_creates_exhibit_if_scaid_does_not_match(self, mock_urlopen):
728730
=== modified file 'src/webcatalog/tests/test_views.py'
--- src/webcatalog/tests/test_views.py 2012-03-30 13:42:37 +0000
+++ src/webcatalog/tests/test_views.py 2012-04-13 21:23:18 +0000
@@ -569,6 +569,19 @@
569569
570 self.assertContains(response, '<li class="slide', count=1)570 self.assertContains(response, '<li class="slide', count=1)
571571
572 def test_exhibits_orders_banners_by_weight(self):
573 third = self.factory.make_exhibit(display=True, weight=3)
574 second = self.factory.make_exhibit(display=True, weight=2)
575 first = self.factory.make_exhibit(display=True, weight=1)
576
577 response = self.client.get(reverse('wc-index'))
578
579 first_pos = response.content.index(first.destination_url())
580 second_pos = response.content.index(second.destination_url())
581 third_pos = response.content.index(third.destination_url())
582
583 self.assertTrue(third_pos > second_pos > first_pos)
584
572 def test_featured_apps(self):585 def test_featured_apps(self):
573 app = self.factory.make_application(package_name='foobar')586 app = self.factory.make_application(package_name='foobar')
574587
575588
=== modified file 'src/webcatalog/views.py'
--- src/webcatalog/views.py 2012-04-05 01:09:37 +0000
+++ src/webcatalog/views.py 2012-04-13 21:23:18 +0000
@@ -25,7 +25,6 @@
25import json25import json
26import operator26import operator
27import os27import os
28from random import shuffle
2928
30from convoy.combo import combine_files, parse_qs29from convoy.combo import combine_files, parse_qs
31from django.conf import settings30from django.conf import settings
@@ -112,8 +111,7 @@
112 depts = Department.objects.filter(parent=None).order_by('name')111 depts = Department.objects.filter(parent=None).order_by('name')
113 depts = depts.order_by('name')112 depts = depts.order_by('name')
114 exhibits = list(Exhibit.objects.filter(Q(display=True) |113 exhibits = list(Exhibit.objects.filter(Q(display=True) |
115 Q(display=None, published=True,)))114 Q(display=None, published=True,)).order_by('weight'))
116 shuffle(exhibits)
117 featured_apps = [Application.objects.find_best(package_name=app)115 featured_apps = [Application.objects.find_best(package_name=app)
118 for app in settings.FEATURED_APPS]116 for app in settings.FEATURED_APPS]
119 featured_apps = [x for x in featured_apps if x]117 featured_apps = [x for x in featured_apps if x]

Subscribers

People subscribed via source and target branches