Merge lp:~canonical-ca-hackers/ubuntu-webcatalog/938226-multiple-screenshots into lp:ubuntu-webcatalog
- 938226-multiple-screenshots
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Anthony Lenton |
Approved revision: | 93 |
Merged at revision: | 84 |
Proposed branch: | lp:~canonical-ca-hackers/ubuntu-webcatalog/938226-multiple-screenshots |
Merge into: | lp:ubuntu-webcatalog |
Diff against target: |
1207 lines (+873/-28) 16 files modified
src/webcatalog/forms.py (+47/-2) src/webcatalog/management/commands/import_for_purchase_apps.py (+1/-0) src/webcatalog/migrations/0015_add_applicationmedia.py (+169/-0) src/webcatalog/migrations/0016_populate_application_media.py (+168/-0) src/webcatalog/migrations/0017_delete_screenshot_url.py (+158/-0) src/webcatalog/migrations/0018_add_unique_together_to_application_media.py (+157/-0) src/webcatalog/models/__init__.py (+2/-0) src/webcatalog/models/applications.py (+30/-2) src/webcatalog/static/css/carousel.css (+37/-0) src/webcatalog/templates/webcatalog/application_detail.html (+4/-3) src/webcatalog/templates/webcatalog/screenshot_widget.html (+28/-0) src/webcatalog/tests/factory.py (+10/-2) src/webcatalog/tests/test_commands.py (+9/-1) src/webcatalog/tests/test_data/sca_apps.txt (+4/-0) src/webcatalog/tests/test_forms.py (+21/-1) src/webcatalog/tests/test_views.py (+28/-17) |
To merge this branch: | bzr merge lp:~canonical-ca-hackers/ubuntu-webcatalog/938226-multiple-screenshots |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Anthony Lenton (community) | Approve | ||
Review via email: mp+98389@code.launchpad.net |
Commit message
Add multiple screenthots support.
Description of the change
Overview
========
This branch adds ability to display multiple screenshots for an application. End result looks this: http://
Details
=======
- added new model, ApplicationMedia, which allows tracking unlimited number of screenshots, videos and other media for each application, this will be useful when implementing video support,
- with the new model there are appropriate migrations for moving data from application attribute to the new model (most of the code are from migrations),
- added code to the template, which uses carousel to display screenthots, but only in case when there's more than one
- 92. By Łukasz Czyżykowski
-
Added unique_together index to the ApplicationMedia to restrict possibility of multiple same urls for the same application.
- 93. By Łukasz Czyżykowski
-
Merged from trunk.
Preview Diff
1 | === modified file 'src/webcatalog/forms.py' |
2 | --- src/webcatalog/forms.py 2012-03-16 00:37:44 +0000 |
3 | +++ src/webcatalog/forms.py 2012-03-20 14:12:21 +0000 |
4 | @@ -29,6 +29,7 @@ |
5 | from django import forms |
6 | from django.conf import settings |
7 | from django.core.mail import EmailMultiAlternatives |
8 | +from django.core.validators import URLValidator |
9 | from django.template.loader import render_to_string |
10 | |
11 | from webcatalog.models import Application |
12 | @@ -55,6 +56,8 @@ |
13 | |
14 | class ApplicationForm(forms.ModelForm): |
15 | |
16 | + screenshot_url = forms.URLField(required=False) |
17 | + |
18 | class Meta: |
19 | model = Application |
20 | exclude = ('distroseries', 'for_purchase', 'archive_id', 'price') |
21 | @@ -68,13 +71,11 @@ |
22 | if desktop_key in data: |
23 | data[app_key] = data[desktop_key] |
24 | del(data[desktop_key]) |
25 | - |
26 | try: |
27 | instance = Application.objects.get( |
28 | package_name=data['package_name'], distroseries=distroseries) |
29 | except Application.DoesNotExist: |
30 | instance = None |
31 | - |
32 | return cls(data=data, instance=instance) |
33 | |
34 | def clean(self): |
35 | @@ -86,12 +87,43 @@ |
36 | for key, value in cleaned_data.items(): |
37 | if not value: |
38 | instance_value = getattr(self.instance, key, False) |
39 | + if hasattr(instance_value, 'all'): |
40 | + instance_value = instance_value.all() |
41 | cleaned_data[key] = instance_value or value |
42 | |
43 | return cleaned_data |
44 | |
45 | + def save(self, commit=True): |
46 | + app = super(ApplicationForm, self).save(commit) |
47 | + screenshot_url = self.cleaned_data['screenshot_url'] |
48 | + if screenshot_url: |
49 | + if screenshot_url not in app.screenshots: |
50 | + app.applicationmedia_set.create( |
51 | + media_type='screenshot', url=screenshot_url) |
52 | + return app |
53 | + |
54 | + |
55 | +class MultiURLField(forms.Field): |
56 | + def to_python(self, value): |
57 | + "Normalize data to a list of strings." |
58 | + # Return an empty list if no input was given. |
59 | + if not value: |
60 | + return [] |
61 | + return value.split(',') |
62 | + |
63 | + def validate(self, value): |
64 | + "Check if value consists only of valid urls." |
65 | + # Use the parent's handling of required fields, etc. |
66 | + super(MultiURLField, self).validate(value) |
67 | + |
68 | + for email in value: |
69 | + validator = URLValidator() |
70 | + validator(email) |
71 | + |
72 | |
73 | class ForPurchaseApplicationForm(forms.ModelForm): |
74 | + screenshot_urls = MultiURLField(required=False) |
75 | + |
76 | class Meta: |
77 | model = Application |
78 | exclude = ('distroseries', 'section', 'popcon') |
79 | @@ -103,6 +135,8 @@ |
80 | tagline, _, description = app_data['description'].partition('\n') |
81 | app_data['comment'] = tagline |
82 | app_data['description'] = description |
83 | + if 'screenshot_urls' in app_data: |
84 | + app_data['screenshot_urls'] = ",".join(app_data['screenshot_urls']) |
85 | try: |
86 | instance = Application.objects.get( |
87 | archive_id=app_data.get('archive_id'), |
88 | @@ -116,6 +150,17 @@ |
89 | value = self.cleaned_data['version'] |
90 | return apt.apt_pkg.upstream_version(value) |
91 | |
92 | + def save(self, commit=True): |
93 | + app = super(ForPurchaseApplicationForm, self).save(commit) |
94 | + if commit: |
95 | + self.save_screenshot_urls() |
96 | + return app |
97 | + |
98 | + def save_screenshot_urls(self): |
99 | + for screenshot_url in self.cleaned_data['screenshot_urls']: |
100 | + self.instance.applicationmedia_set.get_or_create( |
101 | + url=screenshot_url, media_type='screenshot') |
102 | + |
103 | |
104 | class EmailDownloadLinkForm(forms.Form): |
105 | email = forms.EmailField() |
106 | |
107 | === modified file 'src/webcatalog/management/commands/import_for_purchase_apps.py' |
108 | --- src/webcatalog/management/commands/import_for_purchase_apps.py 2012-03-16 01:42:36 +0000 |
109 | +++ src/webcatalog/management/commands/import_for_purchase_apps.py 2012-03-20 14:12:21 +0000 |
110 | @@ -76,6 +76,7 @@ |
111 | app.distroseries = distroseries |
112 | app.for_purchase = True |
113 | app.save() |
114 | + form.save_screenshot_urls() |
115 | app.update_departments() |
116 | self.add_icon_to_app(app, data=icon_data) |
117 | self.output(u"{0} created.\n".format(app.name).encode('utf-8'), 1) |
118 | |
119 | === added file 'src/webcatalog/migrations/0015_add_applicationmedia.py' |
120 | --- src/webcatalog/migrations/0015_add_applicationmedia.py 1970-01-01 00:00:00 +0000 |
121 | +++ src/webcatalog/migrations/0015_add_applicationmedia.py 2012-03-20 14:12:21 +0000 |
122 | @@ -0,0 +1,169 @@ |
123 | +# encoding: utf-8 |
124 | +from south.db import db |
125 | +from south.v2 import SchemaMigration |
126 | + |
127 | + |
128 | +class Migration(SchemaMigration): |
129 | + |
130 | + def forwards(self, orm): |
131 | + db.create_table('webcatalog_applicationmedia', ( |
132 | + ('id', |
133 | + self.gf('django.db.models.fields.AutoField')(primary_key=True)), |
134 | + ('application', |
135 | + self.gf('django.db.models.fields.related.ForeignKey')( |
136 | + to=orm['webcatalog.Application'])), |
137 | + ('media_type', |
138 | + self.gf('django.db.models.fields.CharField')(max_length=16)), |
139 | + ('url', |
140 | + self.gf('django.db.models.fields.URLField')( |
141 | + max_length=200, verify_exists=False)), |
142 | + )) |
143 | + db.send_create_signal('webcatalog', ['ApplicationMedia']) |
144 | + |
145 | + def backwards(self, orm): |
146 | + db.delete_table('webcatalog_applicationmedia') |
147 | + |
148 | + models = { |
149 | + 'auth.group': { |
150 | + 'Meta': {'object_name': 'Group'}, |
151 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
152 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
153 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
154 | + }, |
155 | + 'auth.permission': { |
156 | + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, |
157 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
158 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), |
159 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
160 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
161 | + }, |
162 | + 'auth.user': { |
163 | + 'Meta': {'object_name': 'User'}, |
164 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
165 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
166 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
167 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
168 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
169 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
170 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
171 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
172 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
173 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
174 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
175 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
176 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
177 | + }, |
178 | + 'contenttypes.contenttype': { |
179 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
180 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
181 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
182 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
183 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
184 | + }, |
185 | + 'webcatalog.applicationmedia': { |
186 | + 'Meta': {'object_name': 'ApplicationMedia'}, |
187 | + 'application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Application']"}), |
188 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
189 | + 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}), |
190 | + 'url': ('django.db.models.fields.URLField', [], |
191 | + {'max_length': '200', 'verify_exists': 'False'}) |
192 | + }, |
193 | + 'webcatalog.application': { |
194 | + 'Meta': {'unique_together': "(('distroseries', 'archive_id'),)", 'object_name': 'Application'}, |
195 | + 'app_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), |
196 | + 'architectures': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
197 | + 'archive_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'null': 'True', 'blank': 'True'}), |
198 | + 'categories': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
199 | + 'channel': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
200 | + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
201 | + 'departments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Department']", 'symmetrical': 'False', 'blank': 'True'}), |
202 | + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), |
203 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']"}), |
204 | + 'for_purchase': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
205 | + 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), |
206 | + 'icon_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
207 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
208 | + 'is_latest': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
209 | + 'keywords': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
210 | + 'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}), |
211 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
212 | + 'package_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
213 | + 'popcon': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
214 | + 'price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2', 'blank': 'True'}), |
215 | + 'ratings_average': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '3', 'decimal_places': '2', 'blank': 'True'}), |
216 | + 'ratings_histogram': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), |
217 | + 'ratings_total': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
218 | + 'screenshot_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), |
219 | + 'section': ('django.db.models.fields.CharField', [], {'max_length': '32'}), |
220 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}) |
221 | + }, |
222 | + 'webcatalog.consumer': { |
223 | + 'Meta': {'object_name': 'Consumer'}, |
224 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
225 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
226 | + 'key': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
227 | + 'secret': ('django.db.models.fields.CharField', [], {'default': "'TqnEDawbCrtYpntzTHKnAyIYkQxStI'", 'max_length': '255', 'blank': 'True'}), |
228 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
229 | + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'oauth_consumer'", 'unique': 'True', 'to': "orm['auth.User']"}) |
230 | + }, |
231 | + 'webcatalog.department': { |
232 | + 'Meta': {'object_name': 'Department'}, |
233 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
234 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
235 | + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Department']", 'null': 'True', 'blank': 'True'}), |
236 | + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'}) |
237 | + }, |
238 | + 'webcatalog.distroseries': { |
239 | + 'Meta': {'object_name': 'DistroSeries'}, |
240 | + 'code_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20', 'db_index': 'True'}), |
241 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
242 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}) |
243 | + }, |
244 | + 'webcatalog.exhibit': { |
245 | + 'Meta': {'object_name': 'Exhibit'}, |
246 | + 'banner_url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
247 | + 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
248 | + 'display': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), |
249 | + 'distroseries': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.DistroSeries']", 'symmetrical': 'False'}), |
250 | + 'html': ('django.db.models.fields.TextField', [], {}), |
251 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
252 | + 'package_names': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
253 | + 'published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
254 | + 'sca_id': ('django.db.models.fields.IntegerField', [], {}) |
255 | + }, |
256 | + 'webcatalog.machine': { |
257 | + 'Meta': {'unique_together': "(('owner', 'uuid'),)", 'object_name': 'Machine'}, |
258 | + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
259 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
260 | + 'logo_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56', 'blank': 'True'}), |
261 | + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), |
262 | + 'package_list': ('django.db.models.fields.TextField', [], {}), |
263 | + 'packages_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56'}), |
264 | + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}) |
265 | + }, |
266 | + 'webcatalog.nonce': { |
267 | + 'Meta': {'object_name': 'Nonce'}, |
268 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
269 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
270 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
271 | + 'nonce': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), |
272 | + 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Token']"}) |
273 | + }, |
274 | + 'webcatalog.reviewstatsimport': { |
275 | + 'Meta': {'object_name': 'ReviewStatsImport'}, |
276 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']", 'unique': 'True'}), |
277 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
278 | + 'last_import': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'}) |
279 | + }, |
280 | + 'webcatalog.token': { |
281 | + 'Meta': {'object_name': 'Token'}, |
282 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
283 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
284 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
285 | + 'token': ('django.db.models.fields.CharField', [], {'default': "'QwZbSFwQynUCbUyICBRGQlveynoyGnkAXPBQnTkHXomzhKkxAe'", 'max_length': '50', 'primary_key': 'True'}), |
286 | + 'token_secret': ('django.db.models.fields.CharField', [], {'default': "'wTyHCVgrQHxgbdUzoeanRdVaDvtGAojXsYoPjZaoarXzyieOmh'", 'max_length': '50'}), |
287 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) |
288 | + } |
289 | + } |
290 | + |
291 | + complete_apps = ['webcatalog'] |
292 | |
293 | === added file 'src/webcatalog/migrations/0016_populate_application_media.py' |
294 | --- src/webcatalog/migrations/0016_populate_application_media.py 1970-01-01 00:00:00 +0000 |
295 | +++ src/webcatalog/migrations/0016_populate_application_media.py 2012-03-20 14:12:21 +0000 |
296 | @@ -0,0 +1,168 @@ |
297 | +# encoding: utf-8 |
298 | +from south.v2 import DataMigration |
299 | + |
300 | + |
301 | +class Migration(DataMigration): |
302 | + |
303 | + def forwards(self, orm): |
304 | + for app in orm.Application.objects.all(): |
305 | + if app.screenshot_url: |
306 | + orm.ApplicationMedia.objects.create( |
307 | + application=app, |
308 | + media_type='screenshot', |
309 | + url=app.screenshot_url, |
310 | + ) |
311 | + |
312 | + def backwards(self, orm): |
313 | + for app in orm.Application.objects.all(): |
314 | + # Set first found screenshot url to the screenshot_url attribute |
315 | + screenshots = app.applicationmedia_set.filter( |
316 | + media_type='screenshot') |
317 | + if screenshots.count(): |
318 | + app.screenshot_url = screenshots[0].url |
319 | + app.save() |
320 | + |
321 | + models = { |
322 | + 'auth.group': { |
323 | + 'Meta': {'object_name': 'Group'}, |
324 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
325 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
326 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
327 | + }, |
328 | + 'auth.permission': { |
329 | + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, |
330 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
331 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), |
332 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
333 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
334 | + }, |
335 | + 'auth.user': { |
336 | + 'Meta': {'object_name': 'User'}, |
337 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
338 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
339 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
340 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
341 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
342 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
343 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
344 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
345 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
346 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
347 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
348 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
349 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
350 | + }, |
351 | + 'contenttypes.contenttype': { |
352 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
353 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
354 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
355 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
356 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
357 | + }, |
358 | + 'webcatalog.application': { |
359 | + 'Meta': {'unique_together': "(('distroseries', 'archive_id'),)", 'object_name': 'Application'}, |
360 | + 'app_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), |
361 | + 'architectures': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
362 | + 'archive_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'null': 'True', 'blank': 'True'}), |
363 | + 'categories': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
364 | + 'channel': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
365 | + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
366 | + 'departments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Department']", 'symmetrical': 'False', 'blank': 'True'}), |
367 | + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), |
368 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']"}), |
369 | + 'for_purchase': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
370 | + 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), |
371 | + 'icon_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
372 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
373 | + 'is_latest': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
374 | + 'keywords': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
375 | + 'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}), |
376 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
377 | + 'package_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
378 | + 'popcon': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
379 | + 'price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2', 'blank': 'True'}), |
380 | + 'ratings_average': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '3', 'decimal_places': '2', 'blank': 'True'}), |
381 | + 'ratings_histogram': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), |
382 | + 'ratings_total': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
383 | + 'screenshot_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), |
384 | + 'section': ('django.db.models.fields.CharField', [], {'max_length': '32'}), |
385 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}) |
386 | + }, |
387 | + 'webcatalog.applicationmedia': { |
388 | + 'Meta': {'object_name': 'ApplicationMedia'}, |
389 | + 'application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Application']"}), |
390 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
391 | + 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}), |
392 | + 'url': ('django.db.models.fields.URLField', [], |
393 | + {'max_length': '200', 'verify_exists': 'False'}) |
394 | + }, |
395 | + 'webcatalog.consumer': { |
396 | + 'Meta': {'object_name': 'Consumer'}, |
397 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
398 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
399 | + 'key': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
400 | + 'secret': ('django.db.models.fields.CharField', [], {'default': "'WpxqoTmAenfQszGjGvfbFISHJhThgo'", 'max_length': '255', 'blank': 'True'}), |
401 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
402 | + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'oauth_consumer'", 'unique': 'True', 'to': "orm['auth.User']"}) |
403 | + }, |
404 | + 'webcatalog.department': { |
405 | + 'Meta': {'object_name': 'Department'}, |
406 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
407 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
408 | + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Department']", 'null': 'True', 'blank': 'True'}), |
409 | + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'}) |
410 | + }, |
411 | + 'webcatalog.distroseries': { |
412 | + 'Meta': {'object_name': 'DistroSeries'}, |
413 | + 'code_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20', 'db_index': 'True'}), |
414 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
415 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}) |
416 | + }, |
417 | + 'webcatalog.exhibit': { |
418 | + 'Meta': {'object_name': 'Exhibit'}, |
419 | + 'banner_url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
420 | + 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
421 | + 'display': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), |
422 | + 'distroseries': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.DistroSeries']", 'symmetrical': 'False'}), |
423 | + 'html': ('django.db.models.fields.TextField', [], {}), |
424 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
425 | + 'package_names': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
426 | + 'published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
427 | + 'sca_id': ('django.db.models.fields.IntegerField', [], {}) |
428 | + }, |
429 | + 'webcatalog.machine': { |
430 | + 'Meta': {'unique_together': "(('owner', 'uuid'),)", 'object_name': 'Machine'}, |
431 | + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
432 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
433 | + 'logo_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56', 'blank': 'True'}), |
434 | + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), |
435 | + 'package_list': ('django.db.models.fields.TextField', [], {}), |
436 | + 'packages_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56'}), |
437 | + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}) |
438 | + }, |
439 | + 'webcatalog.nonce': { |
440 | + 'Meta': {'object_name': 'Nonce'}, |
441 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
442 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
443 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
444 | + 'nonce': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), |
445 | + 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Token']"}) |
446 | + }, |
447 | + 'webcatalog.reviewstatsimport': { |
448 | + 'Meta': {'object_name': 'ReviewStatsImport'}, |
449 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']", 'unique': 'True'}), |
450 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
451 | + 'last_import': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'}) |
452 | + }, |
453 | + 'webcatalog.token': { |
454 | + 'Meta': {'object_name': 'Token'}, |
455 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
456 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
457 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
458 | + 'token': ('django.db.models.fields.CharField', [], {'default': "'HVhkYAvgwlonjshHUvoeilzKvaqwvoowjADVxoonRifHvlnktE'", 'max_length': '50', 'primary_key': 'True'}), |
459 | + 'token_secret': ('django.db.models.fields.CharField', [], {'default': "'xKXYwfpMJLvPvmayvjqlPqWvKrviDopKCXcnyUEkNTtWJoTXCE'", 'max_length': '50'}), |
460 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) |
461 | + } |
462 | + } |
463 | + |
464 | + complete_apps = ['webcatalog'] |
465 | |
466 | === added file 'src/webcatalog/migrations/0017_delete_screenshot_url.py' |
467 | --- src/webcatalog/migrations/0017_delete_screenshot_url.py 1970-01-01 00:00:00 +0000 |
468 | +++ src/webcatalog/migrations/0017_delete_screenshot_url.py 2012-03-20 14:12:21 +0000 |
469 | @@ -0,0 +1,158 @@ |
470 | +# encoding: utf-8 |
471 | +from south.db import db |
472 | +from south.v2 import SchemaMigration |
473 | + |
474 | + |
475 | +class Migration(SchemaMigration): |
476 | + |
477 | + def forwards(self, orm): |
478 | + db.delete_column('webcatalog_application', 'screenshot_url') |
479 | + |
480 | + def backwards(self, orm): |
481 | + db.add_column('webcatalog_application', 'screenshot_url', |
482 | + self.gf('django.db.models.fields.URLField')( |
483 | + default='', max_length=200, blank=True), |
484 | + keep_default=False) |
485 | + |
486 | + models = { |
487 | + 'auth.group': { |
488 | + 'Meta': {'object_name': 'Group'}, |
489 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
490 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
491 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
492 | + }, |
493 | + 'auth.permission': { |
494 | + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, |
495 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
496 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), |
497 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
498 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
499 | + }, |
500 | + 'auth.user': { |
501 | + 'Meta': {'object_name': 'User'}, |
502 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
503 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
504 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
505 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
506 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
507 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
508 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
509 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
510 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
511 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
512 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
513 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
514 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
515 | + }, |
516 | + 'contenttypes.contenttype': { |
517 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
518 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
519 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
520 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
521 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
522 | + }, |
523 | + 'webcatalog.application': { |
524 | + 'Meta': {'unique_together': "(('distroseries', 'archive_id'),)", 'object_name': 'Application'}, |
525 | + 'app_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), |
526 | + 'architectures': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
527 | + 'archive_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'null': 'True', 'blank': 'True'}), |
528 | + 'categories': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
529 | + 'channel': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
530 | + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
531 | + 'departments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Department']", 'symmetrical': 'False', 'blank': 'True'}), |
532 | + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), |
533 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']"}), |
534 | + 'for_purchase': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
535 | + 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), |
536 | + 'icon_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
537 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
538 | + 'is_latest': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
539 | + 'keywords': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
540 | + 'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}), |
541 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
542 | + 'package_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
543 | + 'popcon': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
544 | + 'price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2', 'blank': 'True'}), |
545 | + 'ratings_average': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '3', 'decimal_places': '2', 'blank': 'True'}), |
546 | + 'ratings_histogram': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), |
547 | + 'ratings_total': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
548 | + 'section': ('django.db.models.fields.CharField', [], {'max_length': '32'}), |
549 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}) |
550 | + }, |
551 | + 'webcatalog.applicationmedia': { |
552 | + 'Meta': {'object_name': 'ApplicationMedia'}, |
553 | + 'application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Application']"}), |
554 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
555 | + 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}), |
556 | + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) |
557 | + }, |
558 | + 'webcatalog.consumer': { |
559 | + 'Meta': {'object_name': 'Consumer'}, |
560 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
561 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
562 | + 'key': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
563 | + 'secret': ('django.db.models.fields.CharField', [], {'default': "'DuVUqQPfeNRHRxrsetXaaCgCAsqCpl'", 'max_length': '255', 'blank': 'True'}), |
564 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
565 | + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'oauth_consumer'", 'unique': 'True', 'to': "orm['auth.User']"}) |
566 | + }, |
567 | + 'webcatalog.department': { |
568 | + 'Meta': {'object_name': 'Department'}, |
569 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
570 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
571 | + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Department']", 'null': 'True', 'blank': 'True'}), |
572 | + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'}) |
573 | + }, |
574 | + 'webcatalog.distroseries': { |
575 | + 'Meta': {'object_name': 'DistroSeries'}, |
576 | + 'code_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20', 'db_index': 'True'}), |
577 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
578 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}) |
579 | + }, |
580 | + 'webcatalog.exhibit': { |
581 | + 'Meta': {'object_name': 'Exhibit'}, |
582 | + 'banner_url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
583 | + 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
584 | + 'display': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), |
585 | + 'distroseries': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.DistroSeries']", 'symmetrical': 'False'}), |
586 | + 'html': ('django.db.models.fields.TextField', [], {}), |
587 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
588 | + 'package_names': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
589 | + 'published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
590 | + 'sca_id': ('django.db.models.fields.IntegerField', [], {}) |
591 | + }, |
592 | + 'webcatalog.machine': { |
593 | + 'Meta': {'unique_together': "(('owner', 'uuid'),)", 'object_name': 'Machine'}, |
594 | + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
595 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
596 | + 'logo_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56', 'blank': 'True'}), |
597 | + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), |
598 | + 'package_list': ('django.db.models.fields.TextField', [], {}), |
599 | + 'packages_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56'}), |
600 | + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}) |
601 | + }, |
602 | + 'webcatalog.nonce': { |
603 | + 'Meta': {'object_name': 'Nonce'}, |
604 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
605 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
606 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
607 | + 'nonce': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), |
608 | + 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Token']"}) |
609 | + }, |
610 | + 'webcatalog.reviewstatsimport': { |
611 | + 'Meta': {'object_name': 'ReviewStatsImport'}, |
612 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']", 'unique': 'True'}), |
613 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
614 | + 'last_import': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'}) |
615 | + }, |
616 | + 'webcatalog.token': { |
617 | + 'Meta': {'object_name': 'Token'}, |
618 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
619 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
620 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
621 | + 'token': ('django.db.models.fields.CharField', [], {'default': "'tKSJuAZIguDcEzJQNGqCebjlZUEosUkZtKYJcEHqtCHgipXtOs'", 'max_length': '50', 'primary_key': 'True'}), |
622 | + 'token_secret': ('django.db.models.fields.CharField', [], {'default': "'gUFMuThoNMYOuRbIqLcmEiITrEcHWLibbLFOdDdaaICoVoZHyo'", 'max_length': '50'}), |
623 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) |
624 | + } |
625 | + } |
626 | + |
627 | + complete_apps = ['webcatalog'] |
628 | |
629 | === added file 'src/webcatalog/migrations/0018_add_unique_together_to_application_media.py' |
630 | --- src/webcatalog/migrations/0018_add_unique_together_to_application_media.py 1970-01-01 00:00:00 +0000 |
631 | +++ src/webcatalog/migrations/0018_add_unique_together_to_application_media.py 2012-03-20 14:12:21 +0000 |
632 | @@ -0,0 +1,157 @@ |
633 | +# encoding: utf-8 |
634 | +from south.db import db |
635 | +from south.v2 import SchemaMigration |
636 | + |
637 | + |
638 | +class Migration(SchemaMigration): |
639 | + |
640 | + def forwards(self, orm): |
641 | + db.create_unique('webcatalog_applicationmedia', |
642 | + ['url', 'application_id']) |
643 | + |
644 | + def backwards(self, orm): |
645 | + db.delete_unique('webcatalog_applicationmedia', |
646 | + ['url', 'application_id']) |
647 | + |
648 | + models = { |
649 | + 'auth.group': { |
650 | + 'Meta': {'object_name': 'Group'}, |
651 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
652 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
653 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
654 | + }, |
655 | + 'auth.permission': { |
656 | + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, |
657 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
658 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), |
659 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
660 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
661 | + }, |
662 | + 'auth.user': { |
663 | + 'Meta': {'object_name': 'User'}, |
664 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
665 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
666 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
667 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
668 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
669 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
670 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
671 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
672 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
673 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
674 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
675 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
676 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
677 | + }, |
678 | + 'contenttypes.contenttype': { |
679 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
680 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
681 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
682 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
683 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
684 | + }, |
685 | + 'webcatalog.application': { |
686 | + 'Meta': {'unique_together': "(('distroseries', 'archive_id'),)", 'object_name': 'Application'}, |
687 | + 'app_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), |
688 | + 'architectures': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
689 | + 'archive_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'null': 'True', 'blank': 'True'}), |
690 | + 'categories': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
691 | + 'channel': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
692 | + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
693 | + 'departments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Department']", 'symmetrical': 'False', 'blank': 'True'}), |
694 | + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), |
695 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']"}), |
696 | + 'for_purchase': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
697 | + 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), |
698 | + 'icon_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
699 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
700 | + 'is_latest': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
701 | + 'keywords': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
702 | + 'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}), |
703 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
704 | + 'package_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
705 | + 'popcon': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
706 | + 'price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2', 'blank': 'True'}), |
707 | + 'ratings_average': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '3', 'decimal_places': '2', 'blank': 'True'}), |
708 | + 'ratings_histogram': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), |
709 | + 'ratings_total': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
710 | + 'section': ('django.db.models.fields.CharField', [], {'max_length': '32'}), |
711 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}) |
712 | + }, |
713 | + 'webcatalog.applicationmedia': { |
714 | + 'Meta': {'unique_together': "(('application', 'url'),)", 'object_name': 'ApplicationMedia'}, |
715 | + 'application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Application']"}), |
716 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
717 | + 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}), |
718 | + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) |
719 | + }, |
720 | + 'webcatalog.consumer': { |
721 | + 'Meta': {'object_name': 'Consumer'}, |
722 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
723 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
724 | + 'key': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
725 | + 'secret': ('django.db.models.fields.CharField', [], {'default': "'RVPuZojYHnlWbiYQtZFBDrLEQFVKjR'", 'max_length': '255', 'blank': 'True'}), |
726 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
727 | + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'oauth_consumer'", 'unique': 'True', 'to': "orm['auth.User']"}) |
728 | + }, |
729 | + 'webcatalog.department': { |
730 | + 'Meta': {'object_name': 'Department'}, |
731 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
732 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
733 | + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Department']", 'null': 'True', 'blank': 'True'}), |
734 | + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'}) |
735 | + }, |
736 | + 'webcatalog.distroseries': { |
737 | + 'Meta': {'object_name': 'DistroSeries'}, |
738 | + 'code_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20', 'db_index': 'True'}), |
739 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
740 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}) |
741 | + }, |
742 | + 'webcatalog.exhibit': { |
743 | + 'Meta': {'object_name': 'Exhibit'}, |
744 | + 'banner_url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
745 | + 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
746 | + 'display': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), |
747 | + 'distroseries': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.DistroSeries']", 'symmetrical': 'False'}), |
748 | + 'html': ('django.db.models.fields.TextField', [], {}), |
749 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
750 | + 'package_names': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
751 | + 'published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
752 | + 'sca_id': ('django.db.models.fields.IntegerField', [], {}) |
753 | + }, |
754 | + 'webcatalog.machine': { |
755 | + 'Meta': {'unique_together': "(('owner', 'uuid'),)", 'object_name': 'Machine'}, |
756 | + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
757 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
758 | + 'logo_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56', 'blank': 'True'}), |
759 | + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), |
760 | + 'package_list': ('django.db.models.fields.TextField', [], {}), |
761 | + 'packages_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56'}), |
762 | + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}) |
763 | + }, |
764 | + 'webcatalog.nonce': { |
765 | + 'Meta': {'object_name': 'Nonce'}, |
766 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
767 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
768 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
769 | + 'nonce': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), |
770 | + 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Token']"}) |
771 | + }, |
772 | + 'webcatalog.reviewstatsimport': { |
773 | + 'Meta': {'object_name': 'ReviewStatsImport'}, |
774 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']", 'unique': 'True'}), |
775 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
776 | + 'last_import': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'}) |
777 | + }, |
778 | + 'webcatalog.token': { |
779 | + 'Meta': {'object_name': 'Token'}, |
780 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
781 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
782 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
783 | + 'token': ('django.db.models.fields.CharField', [], {'default': "'hxEWMjHsidgiAoDiyBOmdzzAynmFtUySRnVTtAQxLjXgNmkMgw'", 'max_length': '50', 'primary_key': 'True'}), |
784 | + 'token_secret': ('django.db.models.fields.CharField', [], {'default': "'yNkBVzMQcOPQKuzNuVWHNTjQPQAdSXGYJToNQqpsuXyioPfmMw'", 'max_length': '50'}), |
785 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) |
786 | + } |
787 | + } |
788 | + |
789 | + complete_apps = ['webcatalog'] |
790 | |
791 | === modified file 'src/webcatalog/models/__init__.py' |
792 | --- src/webcatalog/models/__init__.py 2012-03-01 21:38:31 +0000 |
793 | +++ src/webcatalog/models/__init__.py 2012-03-20 14:12:21 +0000 |
794 | @@ -25,6 +25,7 @@ |
795 | # applications |
796 | 'DistroSeries', |
797 | 'Application', |
798 | + 'ApplicationMedia', |
799 | 'Department', |
800 | 'Exhibit', |
801 | 'ReviewStatsImport', |
802 | @@ -34,6 +35,7 @@ |
803 | from .oauthtoken import Token, Consumer, Nonce, DataStore |
804 | from .applications import ( |
805 | Application, |
806 | + ApplicationMedia, |
807 | Department, |
808 | DistroSeries, |
809 | Exhibit, |
810 | |
811 | === modified file 'src/webcatalog/models/applications.py' |
812 | --- src/webcatalog/models/applications.py 2012-03-19 20:43:17 +0000 |
813 | +++ src/webcatalog/models/applications.py 2012-03-20 14:12:21 +0000 |
814 | @@ -37,6 +37,7 @@ |
815 | __metaclass__ = type |
816 | __all__ = [ |
817 | 'Application', |
818 | + 'ApplicationMedia', |
819 | 'Department', |
820 | 'DistroSeries', |
821 | 'Exhibit', |
822 | @@ -73,8 +74,6 @@ |
823 | comment = models.CharField(max_length=255, blank=True) |
824 | popcon = models.IntegerField(null=True, blank=True) |
825 | channel = models.CharField(max_length=255, blank=True) |
826 | - screenshot_url = models.URLField(blank=True, verify_exists=False, |
827 | - help_text="Only use this if it is other than the normal screenshot url.") |
828 | mimetype = models.CharField(max_length=2048, blank=True) |
829 | architectures = models.CharField(max_length=255, blank=True) |
830 | keywords = models.CharField(max_length=255, blank=True) |
831 | @@ -114,6 +113,13 @@ |
832 | return u"{0} ({1})".format(self.name, self.package_name) |
833 | |
834 | @property |
835 | + def screenshots(self): |
836 | + if not hasattr(self, '_screenshots'): |
837 | + qs = self.applicationmedia_set.filter(media_type='screenshot') |
838 | + self._screenshots = [am.url for am in qs] |
839 | + return self._screenshots |
840 | + |
841 | + @property |
842 | def categories_set(self): |
843 | """Return the set of categories for this app""" |
844 | stripped = [x.strip() for x in self.categories.split(';')] |
845 | @@ -170,6 +176,28 @@ |
846 | unique_together = ('distroseries', 'archive_id') |
847 | |
848 | |
849 | +class ApplicationMedia(models.Model): |
850 | + MEDIA_CHOICES = ( |
851 | + ('icon_16', 'Icon 16x16'), |
852 | + ('icon_32', 'Icon 32x32'), |
853 | + ('icon_64', 'Icon 64x64'), |
854 | + ('icon_128', 'Icon 128x128'), |
855 | + ('screenshot', 'Screenshot'), |
856 | + ('video', 'Video'), |
857 | + ) |
858 | + |
859 | + application = models.ForeignKey(Application) |
860 | + media_type = models.CharField(max_length=16, choices=MEDIA_CHOICES) |
861 | + url = models.URLField(verify_exists=False) |
862 | + |
863 | + def __unicode__(self): |
864 | + return "{0} for {1}".format(self.media_type, self.application) |
865 | + |
866 | + class Meta: |
867 | + app_label = 'webcatalog' |
868 | + unique_together = (('application', 'url'),) |
869 | + |
870 | + |
871 | class Department(models.Model): |
872 | parent = models.ForeignKey('self', blank=True, null=True) |
873 | name = models.CharField(max_length=64) |
874 | |
875 | === modified file 'src/webcatalog/static/css/carousel.css' |
876 | --- src/webcatalog/static/css/carousel.css 2012-03-19 20:43:17 +0000 |
877 | +++ src/webcatalog/static/css/carousel.css 2012-03-20 14:12:21 +0000 |
878 | @@ -187,6 +187,43 @@ |
879 | .featured-widget h4 { |
880 | font-weight: bold; |
881 | } |
882 | + |
883 | +/* Screenshots carousel */ |
884 | +.screenshot .carousel-wrapper { |
885 | + height: 190px; |
886 | + width: 233px; |
887 | +} |
888 | +.screenshot .carousel .pagination li a.active { |
889 | + background-color: #DD4814; |
890 | +} |
891 | +#screenshots-controls { |
892 | + width: 70px; |
893 | + height: 32px; |
894 | + margin-left: 94px; |
895 | +} |
896 | +#screenshots-controls .next, #screenshots-controls .prev { |
897 | + background: url(/assets/images/arrow-sliders.png) no-repeat 0 0; |
898 | + float: left; |
899 | + z-index: 20; |
900 | + width: 32px; |
901 | + height: 29px; |
902 | +} |
903 | +#screenshots-controls .next span, #screenshots-controls .prev span { |
904 | + position:absolute; |
905 | + left: -9999em; |
906 | + height: 0; |
907 | + width: 0; |
908 | +} |
909 | +#screenshots-controls .prev { |
910 | + background-position:0 0; |
911 | +} |
912 | +#screenshots-controls .next { |
913 | + background-position: -32px 0; |
914 | +} |
915 | +#screenshots-controls .prev:hover, #screenshots-controls .prev:focus, |
916 | +#screenshots-controls .next:hover, #screenshots-controls .next:focus { |
917 | + outline: none; |
918 | + |
919 | .top-rated-stars { |
920 | position: relative; |
921 | left: -50px; |
922 | |
923 | === modified file 'src/webcatalog/templates/webcatalog/application_detail.html' |
924 | --- src/webcatalog/templates/webcatalog/application_detail.html 2012-03-16 17:18:41 +0000 |
925 | +++ src/webcatalog/templates/webcatalog/application_detail.html 2012-03-20 14:12:21 +0000 |
926 | @@ -6,7 +6,8 @@ |
927 | {% block header %}Details for {{ application.name }}{% endblock %} |
928 | {% block head_extra %} |
929 | {{ block.super }} |
930 | -<script src="{{ STATIC_URL }}yui/3.4.0/build/yui/yui-min.js"></script> |
931 | +<link rel="stylesheet" type="text/css" href="{% url wc-combo %}?light/css/reset.css&light/css/styles.css&css/webcatalog.css&light/css/forms.css&css/carousel.css"/> |
932 | +<script src="{% url wc-combo %}?yui/3.4.0/build/yui/yui-min.js&js/carousel.js"></script> |
933 | <script> |
934 | YUI({combine: true, comboBase: '{% url wc-combo %}?', root: 'yui/3.4.0/build/'}).use('io-base', 'node-base', function (Y) { |
935 | function complete(id, obj){ |
936 | @@ -71,8 +72,8 @@ |
937 | </div> |
938 | <div class="description"> |
939 | <div class="screenshot"> |
940 | - {% if application.screenshot_url %} |
941 | - <img src="{{ application.screenshot_url }}" /> |
942 | + {% if application.screenshots %} |
943 | + {% include "webcatalog/screenshot_widget.html" %} |
944 | {% else %} |
945 | <img src="http://screenshots.ubuntu.com/thumbnail-with-version/{{ application.package_name }}/ignored" /> |
946 | {% endif %} |
947 | |
948 | === added file 'src/webcatalog/templates/webcatalog/screenshot_widget.html' |
949 | --- src/webcatalog/templates/webcatalog/screenshot_widget.html 1970-01-01 00:00:00 +0000 |
950 | +++ src/webcatalog/templates/webcatalog/screenshot_widget.html 2012-03-20 14:12:21 +0000 |
951 | @@ -0,0 +1,28 @@ |
952 | +{% if application.screenshots|length_is:1 %} |
953 | + <img src="{{ application.screenshots.0 }}" /> |
954 | +{% else %} |
955 | + <div class="carousel-wrapper"> |
956 | + <div id="screenshots-carousel" class="carousel"> |
957 | + <ol class="carouselol"> |
958 | + {% for screenshot in application.screenshots %} |
959 | + <li class="slide{% if forloop.counter > 1 %} disabled{% endif %}"> |
960 | + <img src="{{ screenshot }}" /> |
961 | + </li> |
962 | + {% endfor %} |
963 | + </ol> |
964 | + </div> |
965 | + </div> |
966 | + <div id="screenshots-controls"></div> |
967 | + <script type="text/javascript"> |
968 | + YUI({combine: true, comboBase: '{% url wc-combo %}?', root: 'yui/3.4.0/build/'}).use('uwc-carousel', function(Y) { |
969 | + var caro = new Y.uwc.Carousel({ |
970 | + nodeContainer: "#screenshots-carousel", |
971 | + controlsContainer: "#screenshots-controls", |
972 | + containerHeight: 170, |
973 | + containerWidth: 225, |
974 | + autoPlay: true |
975 | + }); |
976 | + Y.all('.slide').removeClass('disabled'); |
977 | + }); |
978 | + </script> |
979 | +{% endif %} |
980 | |
981 | === modified file 'src/webcatalog/tests/factory.py' |
982 | --- src/webcatalog/tests/factory.py 2012-03-16 19:27:47 +0000 |
983 | +++ src/webcatalog/tests/factory.py 2012-03-20 14:12:21 +0000 |
984 | @@ -30,6 +30,7 @@ |
985 | |
986 | from webcatalog.models import ( |
987 | Application, |
988 | + ApplicationMedia, |
989 | Consumer, |
990 | Department, |
991 | DistroSeries, |
992 | @@ -106,15 +107,22 @@ |
993 | if distroseries is None: |
994 | distroseries = self.make_distroseries() |
995 | |
996 | - return Application.objects.create( |
997 | + application = Application.objects.create( |
998 | package_name=package_name, name=name, comment=comment, |
999 | description=description, popcon=999, icon=icon, |
1000 | icon_name=icon_name, distroseries=distroseries, architectures=arch, |
1001 | ratings_average=ratings_average, ratings_total=ratings_total, |
1002 | - ratings_histogram=ratings_histogram, screenshot_url=screenshot_url, |
1003 | + ratings_histogram=ratings_histogram, |
1004 | archive_id=archive_id, version=version, is_latest=is_latest, |
1005 | wilson_score=wilson_score) |
1006 | |
1007 | + if screenshot_url: |
1008 | + ApplicationMedia.objects.create( |
1009 | + application=application, |
1010 | + url=screenshot_url, |
1011 | + media_type='screenshot') |
1012 | + return application |
1013 | + |
1014 | def make_department(self, name, parent=None, slug=None): |
1015 | if slug is None: |
1016 | slug = self.get_unique_string(prefix='slug-') |
1017 | |
1018 | === modified file 'src/webcatalog/tests/test_commands.py' |
1019 | --- src/webcatalog/tests/test_commands.py 2012-03-16 19:27:47 +0000 |
1020 | +++ src/webcatalog/tests/test_commands.py 2012-03-20 14:12:21 +0000 |
1021 | @@ -483,6 +483,14 @@ |
1022 | distroseries=self.natty) |
1023 | self.assertTrue(app.is_latest) |
1024 | |
1025 | + def test_app_gets_screenshots(self): |
1026 | + call_command('import_for_purchase_apps') |
1027 | + |
1028 | + app = Application.objects.get(package_name='hello', |
1029 | + distroseries=self.natty) |
1030 | + qs = app.applicationmedia_set.filter(media_type='screenshot') |
1031 | + self.assertEqual(2, qs.count()) |
1032 | + |
1033 | |
1034 | class ImportRatingsTestCase(TestCaseWithFactory): |
1035 | |
1036 | @@ -561,7 +569,7 @@ |
1037 | self.assertEqual(Decimal('4.00'), scribus.ratings_average) |
1038 | self.assertEqual(4, scribus.ratings_total) |
1039 | self.assertEqual('[0, 1, 0, 1, 2]', scribus.ratings_histogram) |
1040 | - self.assertEqual(3.36480032198111, scribus.wilson_score) |
1041 | + self.assertAlmostEqual(3.36480032198111, scribus.wilson_score) |
1042 | otherapp = Application.objects.get(id=otherapp.id) |
1043 | self.assertEqual(None, otherapp.ratings_total) |
1044 | |
1045 | |
1046 | === modified file 'src/webcatalog/tests/test_data/sca_apps.txt' |
1047 | --- src/webcatalog/tests/test_data/sca_apps.txt 2012-03-13 14:09:29 +0000 |
1048 | +++ src/webcatalog/tests/test_data/sca_apps.txt 2012-03-20 14:12:21 +0000 |
1049 | @@ -10,6 +10,10 @@ |
1050 | "archive_id": "launchpad_zematynnad2/myppa", |
1051 | "icon_data": "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", |
1052 | "screenshot_url": "", |
1053 | + "screenshot_urls": [ |
1054 | + "http://localhost:8000/screenshot_1.png", |
1055 | + "http://localhost:8000/screenshot_2.png" |
1056 | + ], |
1057 | "archive_root": "", |
1058 | "tos_url": "", |
1059 | "icon_url": "http://localhost:8000/site_media/icons/2011/06/eg_64x64.png", |
1060 | |
1061 | === modified file 'src/webcatalog/tests/test_forms.py' |
1062 | --- src/webcatalog/tests/test_forms.py 2011-09-12 13:37:24 +0000 |
1063 | +++ src/webcatalog/tests/test_forms.py 2012-03-20 14:12:21 +0000 |
1064 | @@ -28,7 +28,7 @@ |
1065 | ApplicationForm, |
1066 | desktop_field_mappings, |
1067 | ) |
1068 | -from webcatalog.models import Application |
1069 | +from webcatalog.models import Application, ApplicationMedia |
1070 | from webcatalog.tests.factory import TestCaseWithFactory |
1071 | |
1072 | __metaclass__ = type |
1073 | @@ -132,6 +132,26 @@ |
1074 | self.assertEqual( |
1075 | extra_desktop_info[key], form.cleaned_data[form_key]) |
1076 | |
1077 | + def test_screenshot_url_is_properly_saved_as_application_media(self): |
1078 | + app = self.factory.make_application() |
1079 | + extra_desktop_info = { |
1080 | + 'X-AppInstall-Screenshot-Url': 'http://example.com/screenshot', |
1081 | + 'X-AppInstall-Package': app.package_name, |
1082 | + } |
1083 | + desktop_entry = self.get_desktop_entry(self.get_desktop_data( |
1084 | + extra_desktop_info)) |
1085 | + |
1086 | + form = ApplicationForm.get_form_from_desktop_data(desktop_entry, |
1087 | + distroseries=app.distroseries) |
1088 | + form.save() |
1089 | + |
1090 | + app = Application.objects.get(pk=app.pk) |
1091 | + |
1092 | + self.assertTrue('http://example.com/screenshot' in app.screenshots) |
1093 | + self.assertTrue(ApplicationMedia.objects.filter( |
1094 | + application=app, media_type='screenshot', |
1095 | + url='http://example.com/screenshot').exists()) |
1096 | + |
1097 | def test_screenshot_url_isnt_verified(self): |
1098 | # Verifying if this URLField actually exists is a bad idea: |
1099 | # - It expects us to allow arbitrary outgoing connections from the DC |
1100 | |
1101 | === modified file 'src/webcatalog/tests/test_views.py' |
1102 | --- src/webcatalog/tests/test_views.py 2012-03-20 11:12:02 +0000 |
1103 | +++ src/webcatalog/tests/test_views.py 2012-03-20 14:12:21 +0000 |
1104 | @@ -60,6 +60,10 @@ |
1105 | |
1106 | class ApplicationDetailTestCase(TestCaseWithFactory): |
1107 | |
1108 | + def get_app_details_url(self, app): |
1109 | + return reverse('wc-package-detail', |
1110 | + args=[app.distroseries.code_name, app.package_name]) |
1111 | + |
1112 | def get_app_and_response(self, code_name='natty', version='11.04', |
1113 | arch='x86_64', name=None, comment=None, |
1114 | description=None, detail_distro=None, |
1115 | @@ -216,9 +220,7 @@ |
1116 | |
1117 | app.for_purchase = True |
1118 | app.save() |
1119 | - url = reverse('wc-package-detail', args=[app.distroseries.code_name, |
1120 | - app.package_name]) |
1121 | - response = self.client.get(url) |
1122 | + response = self.client.get(self.get_app_details_url(app)) |
1123 | self.assertContains(response, '<td>Proprietary</td>') |
1124 | self.assertNotContains(response, '<td>Open Source</td>') |
1125 | |
1126 | @@ -241,8 +243,7 @@ |
1127 | def test_email_for_download_contents(self): |
1128 | response, app = self.get_app_and_response(name="salamander") |
1129 | data = {'email': 'joe@intestinal-flora.net'} |
1130 | - args = [app.distroseries.code_name, app.package_name] |
1131 | - url = reverse('wc-package-detail', args=args) |
1132 | + url = self.get_app_details_url(app) |
1133 | |
1134 | self.client.post(url, data=data, follow=True) |
1135 | |
1136 | @@ -254,8 +255,7 @@ |
1137 | def test_email_for_download_success_message(self): |
1138 | response, app = self.get_app_and_response(name="salamander") |
1139 | data = {'email': 'joe@intestinal-flora.net'} |
1140 | - args = [app.distroseries.code_name, app.package_name] |
1141 | - url = reverse('wc-package-detail', args=args) |
1142 | + url = self.get_app_details_url(app) |
1143 | |
1144 | response = self.client.post(url, data=data, follow=True) |
1145 | |
1146 | @@ -265,8 +265,7 @@ |
1147 | def test_email_error_blank(self): |
1148 | response, app = self.get_app_and_response(name="salamander") |
1149 | data = {'email': ''} |
1150 | - args = [app.distroseries.code_name, app.package_name] |
1151 | - url = reverse('wc-package-detail', args=args) |
1152 | + url = self.get_app_details_url(app) |
1153 | |
1154 | response = self.client.post(url, data=data, follow=True) |
1155 | |
1156 | @@ -277,8 +276,7 @@ |
1157 | def test_email_error_bogus(self): |
1158 | response, app = self.get_app_and_response(name="salamander") |
1159 | data = {'email': 'bogus'} |
1160 | - args = [app.distroseries.code_name, app.package_name] |
1161 | - url = reverse('wc-package-detail', args=args) |
1162 | + url = self.get_app_details_url(app) |
1163 | |
1164 | response = self.client.post(url, data=data, follow=True) |
1165 | |
1166 | @@ -290,9 +288,7 @@ |
1167 | app = self.factory.make_application(version='1.2.3', |
1168 | distroseries=self.factory.make_distroseries()) |
1169 | |
1170 | - url = reverse('wc-package-detail', kwargs=dict( |
1171 | - distro=app.distroseries.code_name, package_name=app.package_name)) |
1172 | - response = self.client.get(url) |
1173 | + response = self.client.get(self.get_app_details_url(app)) |
1174 | |
1175 | self.assertContains(response, '<th>Version:</th>') |
1176 | self.assertContains(response, '<td>1.2.3</td>') |
1177 | @@ -301,12 +297,27 @@ |
1178 | app = self.factory.make_application(version='', |
1179 | distroseries=self.factory.make_distroseries()) |
1180 | |
1181 | - url = reverse('wc-package-detail', kwargs=dict( |
1182 | - distro=app.distroseries.code_name, package_name=app.package_name)) |
1183 | - response = self.client.get(url) |
1184 | + response = self.client.get(self.get_app_details_url(app)) |
1185 | |
1186 | self.assertNotContains(response, '<th>Version</th>') |
1187 | |
1188 | + def test_with_only_one_screenshot_there_is_no_carousel(self): |
1189 | + response, _ = self.get_app_and_response( |
1190 | + screenshot_url='http://example.com/screenshot.png') |
1191 | + |
1192 | + self.assertNotContains(response, 'Y.uwc.Carousel') |
1193 | + |
1194 | + def test_with_multiple_screenshots_there_is_js_carousel(self): |
1195 | + app = self.factory.make_application() |
1196 | + for i in range(3): |
1197 | + app.applicationmedia_set.create( |
1198 | + url='http://example.com/{}.png'.format(i), |
1199 | + media_type='screenshot') |
1200 | + |
1201 | + response = self.client.get(self.get_app_details_url(app)) |
1202 | + |
1203 | + self.assertContains(response, 'id="screenshots-carousel"') |
1204 | + |
1205 | |
1206 | class ApplicationDetailNoSeriesTestCase(TestCaseWithFactory): |
1207 | def test_renders_latest(self): |
Nice!