Merge lp:~michael.nelson/ubuntu-webcatalog/form-for-import-data into lp:ubuntu-webcatalog

Proposed by Michael Nelson
Status: Merged
Merged at revision: 6
Proposed branch: lp:~michael.nelson/ubuntu-webcatalog/form-for-import-data
Merge into: lp:ubuntu-webcatalog
Diff against target: 332 lines (+212/-32)
6 files modified
src/webcatalog/forms.py (+66/-0)
src/webcatalog/management/commands/import_app_install_data.py (+15/-17)
src/webcatalog/models.py (+14/-13)
src/webcatalog/tests/__init__.py (+2/-1)
src/webcatalog/tests/factory.py (+1/-1)
src/webcatalog/tests/test_forms.py (+114/-0)
To merge this branch: bzr merge lp:~michael.nelson/ubuntu-webcatalog/form-for-import-data
Reviewer Review Type Date Requested Status
Anthony Lenton (community) Approve
Review via email: mp+57342@code.launchpad.net

Description of the change

Overview
========

This branch adds the remaining fields which the USC client parses from the desktop files.

Most of these fields are parsed from the desktop files in app-install-data-ubuntu so that they can override the package values where appropriate.

I've also added simplified the importer by included a form for data validation, and ensured the form class can create instances based on the desktop file.

To post a comment you must log in.
10. By Michael Nelson

MimeType is not required, more helpful error when certain desktop files are ignored.

11. By Michael Nelson

Fixed the --local-app-install-deb option.

12. By Michael Nelson

Unicode strings when writing to stdout..

Revision history for this message
Anthony Lenton (elachuni) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'src/webcatalog/forms.py'
2--- src/webcatalog/forms.py 1970-01-01 00:00:00 +0000
3+++ src/webcatalog/forms.py 2011-04-12 15:56:34 +0000
4@@ -0,0 +1,66 @@
5+# -*- coding: utf-8 -*-
6+# This file is part of the Ubuntu Web Catalog
7+# Copyright (C) 2011 Canonical Ltd.
8+#
9+# This program is free software: you can redistribute it and/or modify
10+# it under the terms of the GNU Affero General Public License as
11+# published by the Free Software Foundation, either version 3 of the
12+# License, or (at your option) any later version.
13+#
14+# This program is distributed in the hope that it will be useful,
15+# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+# GNU Affero General Public License for more details.
18+#
19+# You should have received a copy of the GNU Affero General Public License
20+# along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+"""Forms used by the web catalog."""
23+
24+from __future__ import (
25+ absolute_import,
26+ with_statement,
27+ )
28+
29+from ConfigParser import ConfigParser
30+from StringIO import StringIO
31+
32+from django import forms
33+
34+from webcatalog.models import Application
35+
36+__metaclass__ = type
37+__all__ = [
38+ 'ApplicationForm',
39+ 'desktop_field_mappings',
40+ ]
41+
42+desktop_field_mappings = {
43+ 'x-appinstall-package': 'package_name',
44+ 'x-appinstall-popcon': 'popcon',
45+ 'x-appinstall-channel': 'channel',
46+ 'x-appinstall-screenshot-url': 'screenshot_url',
47+ 'x-appinstall-architectures': 'architectures',
48+ 'x-appinstall-keywords': 'keywords',
49+ 'x-appinstall-description': 'description',
50+ 'x-appinstall-section': 'section',
51+ 'type': 'app_type',
52+ }
53+
54+
55+class ApplicationForm(forms.ModelForm):
56+
57+ class Meta:
58+ model = Application
59+
60+ @classmethod
61+ def get_form_from_desktop_data(cls, str_data):
62+ parser = ConfigParser()
63+ parser.readfp(StringIO(str_data))
64+ data = dict(parser.items('Desktop Entry'))
65+ for desktop_key, app_key in desktop_field_mappings.items():
66+ if data.has_key(desktop_key):
67+ data[app_key] = data[desktop_key]
68+ del(data[desktop_key])
69+
70+ return cls(data=data)
71
72=== modified file 'src/webcatalog/management/commands/import_app_install_data.py'
73--- src/webcatalog/management/commands/import_app_install_data.py 2011-04-11 14:08:41 +0000
74+++ src/webcatalog/management/commands/import_app_install_data.py 2011-04-12 15:56:34 +0000
75@@ -25,13 +25,11 @@
76 import tempfile
77 import urllib
78 from apt_inst import DebFile
79-from ConfigParser import ConfigParser
80 from optparse import make_option
81-from StringIO import StringIO
82
83 from django.core.management.base import BaseCommand
84
85-from webcatalog.models import Application
86+from webcatalog.forms import ApplicationForm
87
88 __metaclass__ = type
89 __all__ = [
90@@ -43,7 +41,7 @@
91 help = "Update Application data from app-install-data package."
92 option_list = BaseCommand.option_list + (
93 make_option('--local-app-install-deb',
94- action='store_true',
95+ action='store',
96 dest='local_app_install_deb',
97 default='',
98 help=('Use a local app-install-data deb package rather than '
99@@ -52,7 +50,6 @@
100
101 def handle(self, *args, **options):
102 self.verbosity = int(options['verbosity'])
103-
104 # Download app install data when requested.
105 if options['local_app_install_deb'] == '':
106 install_data_url = ("http://archive.ubuntu.com/"
107@@ -60,7 +57,7 @@
108 "app-install-data_0.11.04.7.1_all.deb")
109 if self.verbosity > 0:
110 self.stdout.write(
111- "Downloading app-install-data-ubuntu from {0}...".format(
112+ u"Downloading app-install-data-ubuntu from {0}...".format(
113 install_data_url))
114 tmp_file = tempfile.NamedTemporaryFile()
115 urllib.urlretrieve(install_data_url, tmp_file.name)
116@@ -85,14 +82,15 @@
117
118 def process_archive_member(self, member, data):
119 if member.name.endswith('desktop'):
120- parser = ConfigParser()
121- parser.readfp(StringIO(data))
122- data = dict(parser.items('Desktop Entry'))
123- # TODO: Add a form and validate.
124- Application.objects.create(
125- package_name=data['x-appinstall-package'],
126- name=data['name'],
127- comment=data.get('comment', ''))
128- if self.verbosity > 0:
129- self.stdout.write(
130- "{0} created.\n".format(data['x-appinstall-package']))
131+ form = ApplicationForm.get_form_from_desktop_data(data)
132+
133+ if form.is_valid():
134+ app = form.save()
135+ if self.verbosity > 0:
136+ self.stdout.write(
137+ u"{0} created.\n".format(app.name))
138+ else:
139+ if self.verbosity > 0:
140+ self.stdout.write(
141+ u"Skipping {0} as input failed validation: {1}.\n".format(
142+ member.name, form.errors))
143
144=== modified file 'src/webcatalog/models.py'
145--- src/webcatalog/models.py 2011-04-08 12:25:25 +0000
146+++ src/webcatalog/models.py 2011-04-12 15:56:34 +0000
147@@ -39,27 +39,28 @@
148 # The following fields are extracted from app-install-data.
149 package_name = models.SlugField(max_length=100)
150 name = models.CharField(max_length=255)
151- comment = models.CharField(max_length=255)
152+ comment = models.CharField(max_length=255, blank=True)
153+ popcon = models.IntegerField()
154+ channel = models.CharField(max_length=255, blank=True)
155+ screenshot_url = models.URLField(blank=True,
156+ help_text="Only use this if it is other than the normal screenshot url.")
157+ mimetype = models.CharField(max_length=255, blank=True)
158+ architectures = models.CharField(max_length=255, blank=True)
159+ keywords = models.CharField(max_length=255, blank=True)
160+ app_type = models.CharField(max_length=32)
161+ section = models.CharField(max_length=32)
162+ categories = models.CharField(max_length=255)
163+
164 # Other desktop fields used by s-c
165+ gnome_full_name = models.CharField(max_length=255, blank=True)
166 # x-gnome-fullname
167 # X-AppInstall-Ignore
168- # X-AppInstall-Package
169- # X-AppInstall-Section
170- # X-AppInstall-Channel
171- # X-AppInstall-Screenshot-Url
172 # Icon
173- # Type
174- # X-AppInstall-Architectures
175- # X-AppInstall-Description
176- # X-AppInstall-Popcon
177- # Comment
178- # X-AppInstall-Keywords
179- # mime and categories too
180
181 # The following fields will need to be imported from the apt-cache
182 # (using python-apt - as above we'll need access to info from different
183 # series etc.)
184- description = models.TextField()
185+ description = models.TextField(blank=True)
186
187 def __unicode__(self):
188 return u"{0} ({1})".format(self.name, self.package_name)
189
190=== modified file 'src/webcatalog/tests/__init__.py'
191--- src/webcatalog/tests/__init__.py 2011-04-08 15:48:54 +0000
192+++ src/webcatalog/tests/__init__.py 2011-04-12 15:56:34 +0000
193@@ -16,5 +16,6 @@
194 # along with this program. If not, see <http://www.gnu.org/licenses/>.
195
196 """Import various view, model and other tests for django's default runner."""
197+from .test_forms import *
198+from .test_commands import *
199 from .test_views import *
200-from .test_commands import *
201
202=== modified file 'src/webcatalog/tests/factory.py'
203--- src/webcatalog/tests/factory.py 2011-04-11 13:51:17 +0000
204+++ src/webcatalog/tests/factory.py 2011-04-12 15:56:34 +0000
205@@ -82,7 +82,7 @@
206
207 return Application.objects.create(
208 package_name=package_name, name=name, comment=comment,
209- description=description)
210+ description=description, popcon=999)
211
212 def get_test_path(self, file_name):
213 return os.path.join(
214
215=== added file 'src/webcatalog/tests/test_forms.py'
216--- src/webcatalog/tests/test_forms.py 1970-01-01 00:00:00 +0000
217+++ src/webcatalog/tests/test_forms.py 2011-04-12 15:56:34 +0000
218@@ -0,0 +1,114 @@
219+# -*- coding: utf-8 -*-
220+# This file is part of the Ubuntu Web Catalog
221+# Copyright (C) 2011 Canonical Ltd.
222+#
223+# This program is free software: you can redistribute it and/or modify
224+# it under the terms of the GNU Affero General Public License as
225+# published by the Free Software Foundation, either version 3 of the
226+# License, or (at your option) any later version.
227+#
228+# This program is distributed in the hope that it will be useful,
229+# but WITHOUT ANY WARRANTY; without even the implied warranty of
230+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
231+# GNU Affero General Public License for more details.
232+#
233+# You should have received a copy of the GNU Affero General Public License
234+# along with this program. If not, see <http://www.gnu.org/licenses/>.
235+
236+"""Test cases for the web catalog forms."""
237+
238+from __future__ import (
239+ absolute_import,
240+ with_statement,
241+ )
242+
243+from textwrap import dedent
244+
245+from webcatalog.forms import (
246+ ApplicationForm,
247+ desktop_field_mappings,
248+ )
249+from webcatalog.models import Application
250+from webcatalog.tests.factory import TestCaseWithFactory
251+
252+__metaclass__ = type
253+__all__ = [
254+ 'ApplicationFormTestCase',
255+ ]
256+
257+
258+class ApplicationFormTestCase(TestCaseWithFactory):
259+
260+ def get_desktop_data(self, overrides):
261+ data = {
262+ 'Name': self.factory.get_unique_string(
263+ prefix='App Name'),
264+ 'X-AppInstall-Package': self.factory.get_unique_string(
265+ prefix='pkg_name'),
266+ 'X-AppInstall-Popcon': self.factory.get_unique_integer(),
267+ 'X-AppInstall-Section': self.factory.get_unique_string(
268+ prefix='section'),
269+ 'Type': 'Application',
270+ 'Categories': 'cat1;cat2',
271+ }
272+ data.update(overrides)
273+ return data
274+
275+ def get_desktop_entry(self, data):
276+ desktop_entry_template = dedent("""
277+ [Desktop Entry]
278+ GenericName=Page Layout (Stable)
279+ Terminal=false
280+ Icon=scribus
281+ X-StandardInstall=false
282+ StartupWMClass=scribus
283+ X-KDE-SubstituteUID=false
284+ X-KDE-Username=
285+
286+ X-Ubuntu-Gettext-Domain=app-install-data""")
287+ for key, value in data.items():
288+ desktop_entry_template += "\n{key}={value}".format(
289+ key=key, value=value)
290+
291+ desktop_data = desktop_entry_template.format(**data)
292+
293+ return desktop_data
294+
295+ def test_get_form_from_desktop_data(self):
296+ data = {
297+ 'Name': 'My Package',
298+ 'X-AppInstall-Package': 'mypkg',
299+ }
300+ desktop_entry = self.get_desktop_entry(self.get_desktop_data(data))
301+
302+ form = ApplicationForm.get_form_from_desktop_data(desktop_entry)
303+
304+ self.assertTrue(form.is_valid())
305+ self.assertEqual('My Package', form.cleaned_data['name'])
306+ self.assertEqual('mypkg', form.cleaned_data['package_name'])
307+
308+ def test_extra_fields(self):
309+ # There are a bunch of extra fields which are also supported by
310+ # the model form.
311+ extra_desktop_info = {
312+ 'X-AppInstall-Channel': 'channel-name',
313+ 'X-AppInstall-Section': 'section-name',
314+ 'X-AppInstall-Screenshot-Url': 'http://example.com/screenshot',
315+ 'Type': 'Application',
316+ 'X-AppInstall-Description': 'A description',
317+ 'X-AppInstall-Architectures': 'i386r;amd64',
318+ 'X-AppInstall-Popcon': 9876,
319+ 'X-AppInstall-Keywords': 'jazz,rock,country',
320+ 'Categories': 'Graphics;Jazz;Publishing',
321+ 'MimeType': 'application/vnd.scribus;text/javascript;'
322+ }
323+ desktop_entry = self.get_desktop_entry(self.get_desktop_data(
324+ extra_desktop_info))
325+
326+ form = ApplicationForm.get_form_from_desktop_data(desktop_entry)
327+
328+ self.assertTrue(form.is_valid())
329+ for key, value in extra_desktop_info.items():
330+ form_key = desktop_field_mappings.get(key.lower(), key.lower())
331+ self.assertEqual(
332+ extra_desktop_info[key], form.cleaned_data[form_key])

Subscribers

People subscribed via source and target branches