Merge lp:~michael.nelson/ubuntu-webcatalog/1267731-import-sca-apps-error into lp:ubuntu-webcatalog
- 1267731-import-sca-apps-error
- Merge into trunk
Proposed by
Michael Nelson
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Nelson | ||||
Approved revision: | 199 | ||||
Merged at revision: | 196 | ||||
Proposed branch: | lp:~michael.nelson/ubuntu-webcatalog/1267731-import-sca-apps-error | ||||
Merge into: | lp:ubuntu-webcatalog | ||||
Diff against target: |
254 lines (+191/-3) 5 files modified
src/webcatalog/forms.py (+1/-1) src/webcatalog/management/commands/import_sca_apps.py (+6/-1) src/webcatalog/migrations/0030_application_debtags_to_textfield.py (+174/-0) src/webcatalog/models/applications.py (+1/-1) src/webcatalog/tests/test_commands.py (+9/-0) |
||||
To merge this branch: | bzr merge lp:~michael.nelson/ubuntu-webcatalog/1267731-import-sca-apps-error | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Albisetti (community) | Approve | ||
Review via email: mp+201146@code.launchpad.net |
Commit message
Don't error on bad/unexpected import data.
Enable debtags field to be > 255.
Description of the change
Fixes bug 1267731 by:
1) Ensuring we don't error if one sca app happens to have unexpected data, instead logging the error
2) Enabling the debtags field to be > 255
To post a comment you must log in.
Revision history for this message
Martin Albisetti (beuno) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/webcatalog/forms.py' |
2 | --- src/webcatalog/forms.py 2013-05-21 12:24:28 +0000 |
3 | +++ src/webcatalog/forms.py 2014-01-10 09:19:06 +0000 |
4 | @@ -161,7 +161,7 @@ |
5 | |
6 | try: |
7 | instance = Application.objects.get( |
8 | - package_name=app_data['package_name'], |
9 | + package_name=app_data.get('package_name'), |
10 | distroseries=distroseries) |
11 | except Application.DoesNotExist: |
12 | instance = None |
13 | |
14 | === modified file 'src/webcatalog/management/commands/import_sca_apps.py' |
15 | --- src/webcatalog/management/commands/import_sca_apps.py 2013-09-03 08:45:45 +0000 |
16 | +++ src/webcatalog/management/commands/import_sca_apps.py 2014-01-10 09:19:06 +0000 |
17 | @@ -123,12 +123,17 @@ |
18 | def import_app_from_data(self, app_data, icon_data, distroseries): |
19 | form = SCAApplicationForm.from_api_data( |
20 | app_data, distroseries) |
21 | + package_name = None |
22 | if form.is_valid(): |
23 | app = form.save() |
24 | department_names = app_data.get('department', []) |
25 | app.update_departments(department_names) |
26 | + package_name = app.package_name |
27 | self.add_icon_to_app(app, data=icon_data) |
28 | - return app.package_name |
29 | + else: |
30 | + logger.error("An SCA app failed to import. Errors: %s", |
31 | + form.errors) |
32 | + return package_name |
33 | |
34 | def get_icon_data(self, app_data): |
35 | icon_data = app_data.get('icon_data', '') |
36 | |
37 | === added file 'src/webcatalog/migrations/0030_application_debtags_to_textfield.py' |
38 | --- src/webcatalog/migrations/0030_application_debtags_to_textfield.py 1970-01-01 00:00:00 +0000 |
39 | +++ src/webcatalog/migrations/0030_application_debtags_to_textfield.py 2014-01-10 09:19:06 +0000 |
40 | @@ -0,0 +1,174 @@ |
41 | +# -*- coding: utf-8 -*- |
42 | +import datetime |
43 | +from south.db import db |
44 | +from south.v2 import SchemaMigration |
45 | +from django.db import models |
46 | + |
47 | + |
48 | +class Migration(SchemaMigration): |
49 | + |
50 | + def forwards(self, orm): |
51 | + |
52 | + # Changing field 'Application.debtags' |
53 | + db.alter_column(u'webcatalog_application', 'debtags', self.gf('django.db.models.fields.TextField')()) |
54 | + |
55 | + def backwards(self, orm): |
56 | + |
57 | + # Changing field 'Application.debtags' |
58 | + db.alter_column(u'webcatalog_application', 'debtags', self.gf('django.db.models.fields.CharField')(max_length=255)) |
59 | + |
60 | + models = { |
61 | + u'auth.group': { |
62 | + 'Meta': {'object_name': 'Group'}, |
63 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
64 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
65 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
66 | + }, |
67 | + u'auth.permission': { |
68 | + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, |
69 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
70 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), |
71 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
72 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
73 | + }, |
74 | + u'auth.user': { |
75 | + 'Meta': {'object_name': 'User'}, |
76 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
77 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
78 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
79 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
80 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
81 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
82 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
83 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
84 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
85 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
86 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
87 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
88 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
89 | + }, |
90 | + u'contenttypes.contenttype': { |
91 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
92 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
93 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
94 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
95 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
96 | + }, |
97 | + 'webcatalog.application': { |
98 | + 'Meta': {'ordering': "('-wilson_score', 'name')", 'unique_together': "(('distroseries', 'package_name'),)", 'object_name': 'Application'}, |
99 | + 'app_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), |
100 | + 'architectures': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
101 | + 'archive_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'null': 'True', 'blank': 'True'}), |
102 | + 'categories': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
103 | + 'channel': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
104 | + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
105 | + 'debtags': ('django.db.models.fields.TextField', [], {'blank': 'True'}), |
106 | + 'departments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Department']", 'symmetrical': 'False', 'blank': 'True'}), |
107 | + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), |
108 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']"}), |
109 | + 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), |
110 | + 'icon_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
111 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
112 | + 'imported_from_sca': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
113 | + 'is_latest': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
114 | + 'keywords': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
115 | + 'license': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), |
116 | + 'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}), |
117 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
118 | + 'package_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
119 | + 'popcon': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
120 | + 'price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2', 'blank': 'True'}), |
121 | + 'ratings_average': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '3', 'decimal_places': '2', 'blank': 'True'}), |
122 | + 'ratings_histogram': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), |
123 | + 'ratings_total': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
124 | + 'section': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), |
125 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), |
126 | + 'wilson_score': ('django.db.models.fields.FloatField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}) |
127 | + }, |
128 | + 'webcatalog.applicationmedia': { |
129 | + 'Meta': {'ordering': "('url',)", 'unique_together': "(('application', 'url'),)", 'object_name': 'ApplicationMedia'}, |
130 | + 'application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Application']"}), |
131 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
132 | + 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}), |
133 | + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) |
134 | + }, |
135 | + 'webcatalog.applicationwidget': { |
136 | + 'Meta': {'object_name': 'ApplicationWidget'}, |
137 | + 'applications': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Application']", 'symmetrical': 'False'}), |
138 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
139 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}), |
140 | + 'template_snippet': ('django.db.models.fields.TextField', [], {}) |
141 | + }, |
142 | + 'webcatalog.consumer': { |
143 | + 'Meta': {'object_name': 'Consumer'}, |
144 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
145 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
146 | + 'key': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
147 | + 'secret': ('django.db.models.fields.CharField', [], {'default': "'eOaKTZKZvdBXcmqOogpjVgwahoZiCG'", 'max_length': '255', 'blank': 'True'}), |
148 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
149 | + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'oauth_consumer'", 'unique': 'True', 'to': u"orm['auth.User']"}) |
150 | + }, |
151 | + 'webcatalog.department': { |
152 | + 'Meta': {'object_name': 'Department'}, |
153 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
154 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
155 | + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Department']", 'null': 'True', 'blank': 'True'}), |
156 | + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}) |
157 | + }, |
158 | + 'webcatalog.distroseries': { |
159 | + 'Meta': {'object_name': 'DistroSeries'}, |
160 | + 'code_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20', 'db_index': 'True'}), |
161 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
162 | + 'prerelease': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
163 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}) |
164 | + }, |
165 | + 'webcatalog.exhibit': { |
166 | + 'Meta': {'object_name': 'Exhibit'}, |
167 | + 'banner_url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
168 | + 'click_url': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '200'}), |
169 | + 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
170 | + 'display': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), |
171 | + 'distroseries': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.DistroSeries']", 'symmetrical': 'False'}), |
172 | + 'html': ('django.db.models.fields.TextField', [], {}), |
173 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
174 | + 'package_names': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), |
175 | + 'published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
176 | + 'sca_id': ('django.db.models.fields.IntegerField', [], {}), |
177 | + 'weight': ('django.db.models.fields.IntegerField', [], {'default': '0'}) |
178 | + }, |
179 | + 'webcatalog.machine': { |
180 | + 'Meta': {'unique_together': "(('owner', 'uuid'),)", 'object_name': 'Machine'}, |
181 | + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '64'}), |
182 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
183 | + 'logo_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56', 'blank': 'True'}), |
184 | + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), |
185 | + 'package_list': ('django.db.models.fields.TextField', [], {}), |
186 | + 'packages_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56'}), |
187 | + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}) |
188 | + }, |
189 | + 'webcatalog.nonce': { |
190 | + 'Meta': {'unique_together': "(('nonce', 'token', 'consumer'),)", 'object_name': 'Nonce'}, |
191 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
192 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
193 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
194 | + 'nonce': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
195 | + 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Token']"}) |
196 | + }, |
197 | + 'webcatalog.reviewstatsimport': { |
198 | + 'Meta': {'object_name': 'ReviewStatsImport'}, |
199 | + 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']", 'unique': 'True'}), |
200 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
201 | + 'last_import': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'}) |
202 | + }, |
203 | + 'webcatalog.token': { |
204 | + 'Meta': {'object_name': 'Token'}, |
205 | + 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}), |
206 | + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
207 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
208 | + 'token': ('django.db.models.fields.CharField', [], {'default': "'KuCuRllKERFEWvVDGwtGZVBScLCUayQJucTDuMnjJopJEmcPie'", 'max_length': '50', 'primary_key': 'True'}), |
209 | + 'token_secret': ('django.db.models.fields.CharField', [], {'default': "'odbGcySxXFGCRbSnhOIoicNWCkMTUGPUcyVbRDkDPptJrNRHba'", 'max_length': '50'}), |
210 | + 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) |
211 | + } |
212 | + } |
213 | + |
214 | + complete_apps = ['webcatalog'] |
215 | \ No newline at end of file |
216 | |
217 | === modified file 'src/webcatalog/models/applications.py' |
218 | --- src/webcatalog/models/applications.py 2013-04-23 10:18:41 +0000 |
219 | +++ src/webcatalog/models/applications.py 2014-01-10 09:19:06 +0000 |
220 | @@ -104,7 +104,7 @@ |
221 | ratings_histogram = models.CharField(max_length=128, blank=True) |
222 | is_latest = models.BooleanField() |
223 | wilson_score = models.FloatField(null=True, blank=True, db_index=True) |
224 | - debtags = models.CharField(max_length=255, blank=True) |
225 | + debtags = models.TextField(blank=True) |
226 | license = models.CharField( |
227 | max_length=64, blank=True, |
228 | help_text=u"The name of the license used for the app.") |
229 | |
230 | === modified file 'src/webcatalog/tests/test_commands.py' |
231 | --- src/webcatalog/tests/test_commands.py 2013-04-10 07:57:06 +0000 |
232 | +++ src/webcatalog/tests/test_commands.py 2014-01-10 09:19:06 +0000 |
233 | @@ -57,6 +57,7 @@ |
234 | from webcatalog.management.commands import ( |
235 | import_app_install_data, |
236 | import_ratings_stats, |
237 | + import_sca_apps, |
238 | ) |
239 | from webcatalog.tests.factory import ( |
240 | TestCaseWithFactory, |
241 | @@ -731,6 +732,14 @@ |
242 | self.assertEqual('natty', |
243 | remaining_hello_apps[0].distroseries.code_name) |
244 | |
245 | + def test_import_app_from_data_returns_none(self): |
246 | + command = import_sca_apps.Command() |
247 | + precise = self.factory.make_distroseries(code_name='precise') |
248 | + |
249 | + result = command.import_app_from_data({}, {}, precise) |
250 | + |
251 | + self.assertIsNone(result) |
252 | + |
253 | |
254 | class ImportRatingsTestCase(TestCaseWithFactory): |
255 |