Merge lp:~michael.nelson/ubuntu-webcatalog/1267731-import-sca-apps-error into lp:ubuntu-webcatalog

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
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
=== modified file 'src/webcatalog/forms.py'
--- src/webcatalog/forms.py 2013-05-21 12:24:28 +0000
+++ src/webcatalog/forms.py 2014-01-10 09:19:06 +0000
@@ -161,7 +161,7 @@
161161
162 try:162 try:
163 instance = Application.objects.get(163 instance = Application.objects.get(
164 package_name=app_data['package_name'],164 package_name=app_data.get('package_name'),
165 distroseries=distroseries)165 distroseries=distroseries)
166 except Application.DoesNotExist:166 except Application.DoesNotExist:
167 instance = None167 instance = None
168168
=== modified file 'src/webcatalog/management/commands/import_sca_apps.py'
--- src/webcatalog/management/commands/import_sca_apps.py 2013-09-03 08:45:45 +0000
+++ src/webcatalog/management/commands/import_sca_apps.py 2014-01-10 09:19:06 +0000
@@ -123,12 +123,17 @@
123 def import_app_from_data(self, app_data, icon_data, distroseries):123 def import_app_from_data(self, app_data, icon_data, distroseries):
124 form = SCAApplicationForm.from_api_data(124 form = SCAApplicationForm.from_api_data(
125 app_data, distroseries)125 app_data, distroseries)
126 package_name = None
126 if form.is_valid():127 if form.is_valid():
127 app = form.save()128 app = form.save()
128 department_names = app_data.get('department', [])129 department_names = app_data.get('department', [])
129 app.update_departments(department_names)130 app.update_departments(department_names)
131 package_name = app.package_name
130 self.add_icon_to_app(app, data=icon_data)132 self.add_icon_to_app(app, data=icon_data)
131 return app.package_name133 else:
134 logger.error("An SCA app failed to import. Errors: %s",
135 form.errors)
136 return package_name
132137
133 def get_icon_data(self, app_data):138 def get_icon_data(self, app_data):
134 icon_data = app_data.get('icon_data', '')139 icon_data = app_data.get('icon_data', '')
135140
=== added file 'src/webcatalog/migrations/0030_application_debtags_to_textfield.py'
--- src/webcatalog/migrations/0030_application_debtags_to_textfield.py 1970-01-01 00:00:00 +0000
+++ src/webcatalog/migrations/0030_application_debtags_to_textfield.py 2014-01-10 09:19:06 +0000
@@ -0,0 +1,174 @@
1# -*- coding: utf-8 -*-
2import datetime
3from south.db import db
4from south.v2 import SchemaMigration
5from django.db import models
6
7
8class Migration(SchemaMigration):
9
10 def forwards(self, orm):
11
12 # Changing field 'Application.debtags'
13 db.alter_column(u'webcatalog_application', 'debtags', self.gf('django.db.models.fields.TextField')())
14
15 def backwards(self, orm):
16
17 # Changing field 'Application.debtags'
18 db.alter_column(u'webcatalog_application', 'debtags', self.gf('django.db.models.fields.CharField')(max_length=255))
19
20 models = {
21 u'auth.group': {
22 'Meta': {'object_name': 'Group'},
23 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
24 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
25 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
26 },
27 u'auth.permission': {
28 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
29 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
30 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
31 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
32 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
33 },
34 u'auth.user': {
35 'Meta': {'object_name': 'User'},
36 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
37 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
38 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
39 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
40 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
41 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
42 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
43 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
44 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
45 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
46 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
47 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
48 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
49 },
50 u'contenttypes.contenttype': {
51 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
52 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
53 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
54 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
55 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
56 },
57 'webcatalog.application': {
58 'Meta': {'ordering': "('-wilson_score', 'name')", 'unique_together': "(('distroseries', 'package_name'),)", 'object_name': 'Application'},
59 'app_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
60 'architectures': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
61 'archive_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'null': 'True', 'blank': 'True'}),
62 'categories': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
63 'channel': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
64 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
65 'debtags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
66 'departments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Department']", 'symmetrical': 'False', 'blank': 'True'}),
67 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
68 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']"}),
69 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
70 'icon_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
71 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
72 'imported_from_sca': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
73 'is_latest': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
74 'keywords': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
75 'license': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
76 'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}),
77 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
78 'package_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
79 'popcon': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
80 'price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2', 'blank': 'True'}),
81 'ratings_average': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '3', 'decimal_places': '2', 'blank': 'True'}),
82 'ratings_histogram': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
83 'ratings_total': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
84 'section': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
85 'version': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
86 'wilson_score': ('django.db.models.fields.FloatField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
87 },
88 'webcatalog.applicationmedia': {
89 'Meta': {'ordering': "('url',)", 'unique_together': "(('application', 'url'),)", 'object_name': 'ApplicationMedia'},
90 'application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Application']"}),
91 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
92 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
93 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
94 },
95 'webcatalog.applicationwidget': {
96 'Meta': {'object_name': 'ApplicationWidget'},
97 'applications': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Application']", 'symmetrical': 'False'}),
98 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
99 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
100 'template_snippet': ('django.db.models.fields.TextField', [], {})
101 },
102 'webcatalog.consumer': {
103 'Meta': {'object_name': 'Consumer'},
104 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
105 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
106 'key': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
107 'secret': ('django.db.models.fields.CharField', [], {'default': "'eOaKTZKZvdBXcmqOogpjVgwahoZiCG'", 'max_length': '255', 'blank': 'True'}),
108 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
109 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'oauth_consumer'", 'unique': 'True', 'to': u"orm['auth.User']"})
110 },
111 'webcatalog.department': {
112 'Meta': {'object_name': 'Department'},
113 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
114 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
115 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Department']", 'null': 'True', 'blank': 'True'}),
116 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
117 },
118 'webcatalog.distroseries': {
119 'Meta': {'object_name': 'DistroSeries'},
120 'code_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20', 'db_index': 'True'}),
121 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
122 'prerelease': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
123 'version': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'})
124 },
125 'webcatalog.exhibit': {
126 'Meta': {'object_name': 'Exhibit'},
127 'banner_url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
128 'click_url': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '200'}),
129 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
130 'display': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
131 'distroseries': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.DistroSeries']", 'symmetrical': 'False'}),
132 'html': ('django.db.models.fields.TextField', [], {}),
133 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
134 'package_names': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
135 'published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
136 'sca_id': ('django.db.models.fields.IntegerField', [], {}),
137 'weight': ('django.db.models.fields.IntegerField', [], {'default': '0'})
138 },
139 'webcatalog.machine': {
140 'Meta': {'unique_together': "(('owner', 'uuid'),)", 'object_name': 'Machine'},
141 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
142 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
143 'logo_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56', 'blank': 'True'}),
144 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
145 'package_list': ('django.db.models.fields.TextField', [], {}),
146 'packages_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56'}),
147 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'})
148 },
149 'webcatalog.nonce': {
150 'Meta': {'unique_together': "(('nonce', 'token', 'consumer'),)", 'object_name': 'Nonce'},
151 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}),
152 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
153 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
154 'nonce': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
155 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Token']"})
156 },
157 'webcatalog.reviewstatsimport': {
158 'Meta': {'object_name': 'ReviewStatsImport'},
159 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']", 'unique': 'True'}),
160 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
161 'last_import': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'})
162 },
163 'webcatalog.token': {
164 'Meta': {'object_name': 'Token'},
165 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}),
166 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
167 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
168 'token': ('django.db.models.fields.CharField', [], {'default': "'KuCuRllKERFEWvVDGwtGZVBScLCUayQJucTDuMnjJopJEmcPie'", 'max_length': '50', 'primary_key': 'True'}),
169 'token_secret': ('django.db.models.fields.CharField', [], {'default': "'odbGcySxXFGCRbSnhOIoicNWCkMTUGPUcyVbRDkDPptJrNRHba'", 'max_length': '50'}),
170 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
171 }
172 }
173
174 complete_apps = ['webcatalog']
0\ No newline at end of file175\ No newline at end of file
1176
=== modified file 'src/webcatalog/models/applications.py'
--- src/webcatalog/models/applications.py 2013-04-23 10:18:41 +0000
+++ src/webcatalog/models/applications.py 2014-01-10 09:19:06 +0000
@@ -104,7 +104,7 @@
104 ratings_histogram = models.CharField(max_length=128, blank=True)104 ratings_histogram = models.CharField(max_length=128, blank=True)
105 is_latest = models.BooleanField()105 is_latest = models.BooleanField()
106 wilson_score = models.FloatField(null=True, blank=True, db_index=True)106 wilson_score = models.FloatField(null=True, blank=True, db_index=True)
107 debtags = models.CharField(max_length=255, blank=True)107 debtags = models.TextField(blank=True)
108 license = models.CharField(108 license = models.CharField(
109 max_length=64, blank=True,109 max_length=64, blank=True,
110 help_text=u"The name of the license used for the app.")110 help_text=u"The name of the license used for the app.")
111111
=== modified file 'src/webcatalog/tests/test_commands.py'
--- src/webcatalog/tests/test_commands.py 2013-04-10 07:57:06 +0000
+++ src/webcatalog/tests/test_commands.py 2014-01-10 09:19:06 +0000
@@ -57,6 +57,7 @@
57from webcatalog.management.commands import (57from webcatalog.management.commands import (
58 import_app_install_data,58 import_app_install_data,
59 import_ratings_stats,59 import_ratings_stats,
60 import_sca_apps,
60)61)
61from webcatalog.tests.factory import (62from webcatalog.tests.factory import (
62 TestCaseWithFactory,63 TestCaseWithFactory,
@@ -731,6 +732,14 @@
731 self.assertEqual('natty',732 self.assertEqual('natty',
732 remaining_hello_apps[0].distroseries.code_name)733 remaining_hello_apps[0].distroseries.code_name)
733734
735 def test_import_app_from_data_returns_none(self):
736 command = import_sca_apps.Command()
737 precise = self.factory.make_distroseries(code_name='precise')
738
739 result = command.import_app_from_data({}, {}, precise)
740
741 self.assertIsNone(result)
742
734743
735class ImportRatingsTestCase(TestCaseWithFactory):744class ImportRatingsTestCase(TestCaseWithFactory):
736745

Subscribers

People subscribed via source and target branches