Merge lp:~michael.nelson/ubuntu-webcatalog/1019326-missing-ratings-summary into lp:ubuntu-webcatalog

Proposed by Michael Nelson
Status: Merged
Approved by: Michael Nelson
Approved revision: 182
Merged at revision: 174
Proposed branch: lp:~michael.nelson/ubuntu-webcatalog/1019326-missing-ratings-summary
Merge into: lp:ubuntu-webcatalog
Diff against target: 256 lines (+100/-25)
6 files modified
src/webcatalog/admin.py (+6/-0)
src/webcatalog/management/commands/import_all_ratings_stats.py (+13/-1)
src/webcatalog/management/commands/import_ratings_stats.py (+25/-13)
src/webcatalog/tasks.py (+7/-1)
src/webcatalog/tests/test_commands.py (+44/-9)
src/webcatalog/tests/test_views.py (+5/-1)
To merge this branch: bzr merge lp:~michael.nelson/ubuntu-webcatalog/1019326-missing-ratings-summary
Reviewer Review Type Date Requested Status
Łukasz Czyżykowski (community) Approve
Review via email: mp+137619@code.launchpad.net

Commit message

Add admin class for ReviewStatsImport and optional --download-all flag for import_ratings_stats.

Description of the change

After some investigation on bug 1015604, this branch adds:

1) An admin class for ReviewStatsImport, so we can view/update when the last import occurred,
2) An --download-all flag for the import_ratings_stats command which forces all stats for the series to be downloaded, rather than requesting the optimised last X days,
3) An extra task so that we can request all ratings stats to be downloaded without needing a webop.

`fab test`

To post a comment you must log in.
Revision history for this message
Łukasz Czyżykowski (lukasz-czyzykowski) wrote :

All great

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/webcatalog/admin.py'
2--- src/webcatalog/admin.py 2012-09-06 14:07:55 +0000
3+++ src/webcatalog/admin.py 2012-12-03 17:04:22 +0000
4@@ -28,6 +28,7 @@
5 DistroSeries,
6 Exhibit,
7 Machine,
8+ ReviewStatsImport,
9 )
10
11 __metaclass__ = type
12@@ -80,6 +81,10 @@
13 raw_id_fields = ('applications',)
14
15
16+class ReviewStatsImportAdmin(admin.ModelAdmin):
17+ list_display = ('distroseries', 'last_import')
18+
19+
20 admin.site.register(Application, ApplicationAdmin)
21 admin.site.register(ApplicationMedia, ApplicationMediaAdmin)
22 admin.site.register(ApplicationWidget, ApplicationWidgetAdmin)
23@@ -87,3 +92,4 @@
24 admin.site.register(DistroSeries)
25 admin.site.register(Exhibit, ExhibitAdmin)
26 admin.site.register(Machine, MachineAdmin)
27+admin.site.register(ReviewStatsImport, ReviewStatsImportAdmin)
28
29=== modified file 'src/webcatalog/management/commands/import_all_ratings_stats.py'
30--- src/webcatalog/management/commands/import_all_ratings_stats.py 2012-07-02 21:25:30 +0000
31+++ src/webcatalog/management/commands/import_all_ratings_stats.py 2012-12-03 17:04:22 +0000
32@@ -22,12 +22,23 @@
33 __metaclass__ = type
34 __all__ = []
35
36+from optparse import make_option
37+
38 from django.conf import settings
39 from django.core.management import call_command
40 from django.core.management.base import NoArgsCommand
41
42
43 class Command(NoArgsCommand):
44+ option_list = NoArgsCommand.option_list + (
45+ make_option(
46+ '--download-all',
47+ action='store_true',
48+ dest='download_all',
49+ default=False,
50+ help='Download all ratings stats instead of stats since last '
51+ 'import.'),
52+ )
53
54 def handle_noargs(self, **options):
55 self.verbosity = int(options['verbosity'])
56@@ -35,7 +46,8 @@
57 self.output("Importing ratings stats for {0}\n".format(
58 distroseries), 1)
59 call_command('import_ratings_stats', distroseries,
60- verbosity=self.verbosity)
61+ verbosity=self.verbosity,
62+ download_all=options['download_all'])
63
64 def output(self, message, level=None, flush=False):
65 if hasattr(self, 'stdout'):
66
67=== modified file 'src/webcatalog/management/commands/import_ratings_stats.py'
68--- src/webcatalog/management/commands/import_ratings_stats.py 2012-06-19 13:10:25 +0000
69+++ src/webcatalog/management/commands/import_ratings_stats.py 2012-12-03 17:04:22 +0000
70@@ -17,11 +17,12 @@
71
72 """Management command to import review statistics for a distroseries."""
73
74+import json
75 from datetime import (
76 datetime,
77 timedelta,
78 )
79-import json
80+from optparse import make_option
81
82 from django.core.management.base import LabelCommand
83
84@@ -37,12 +38,22 @@
85
86
87 class Command(LabelCommand):
88+ option_list = LabelCommand.option_list + (
89+ make_option(
90+ '--download-all',
91+ action='store_true',
92+ dest='download_all',
93+ default=False,
94+ help='Download all ratings stats instead of stats since last '
95+ 'import.'),
96+ )
97
98 help = "Update application review statistics."
99 verbosity = 1
100
101 def handle_label(self, distroseries_name, **options):
102 self.verbosity = int(options['verbosity'])
103+ self.download_all = options['download_all']
104 # Check when we most recently imported review stats for this
105 # distroseries.
106 distroseries, created = DistroSeries.objects.get_or_create(
107@@ -81,19 +92,20 @@
108
109 def download_review_stats(self, distroseries):
110 # Download the appropriate stats based on above.
111- other_imports = ReviewStatsImport.objects.filter(
112- distroseries=distroseries).order_by('-last_import')
113 num_days = None
114- if other_imports:
115- stats_import = other_imports[0]
116- time_since_last_import = (
117- datetime.utcnow() - stats_import.last_import)
118- if time_since_last_import < timedelta(days=1):
119- num_days = 1
120- elif time_since_last_import < timedelta(days=3):
121- num_days = 3
122- elif time_since_last_import < timedelta(days=7):
123- num_days = 7
124+ if not self.download_all:
125+ other_imports = ReviewStatsImport.objects.filter(
126+ distroseries=distroseries).order_by('-last_import')
127+ if other_imports:
128+ stats_import = other_imports[0]
129+ time_since_last_import = (
130+ datetime.utcnow() - stats_import.last_import)
131+ if time_since_last_import < timedelta(days=1):
132+ num_days = 1
133+ elif time_since_last_import < timedelta(days=3):
134+ num_days = 3
135+ elif time_since_last_import < timedelta(days=7):
136+ num_days = 7
137
138 # Currently we have ratings in rnr for ubuntu and for-purchase
139 # PPAs only, so we set origin to any. If we later support reviews
140
141=== modified file 'src/webcatalog/tasks.py'
142--- src/webcatalog/tasks.py 2012-06-29 19:51:06 +0000
143+++ src/webcatalog/tasks.py 2012-12-03 17:04:22 +0000
144@@ -25,10 +25,16 @@
145
146 @task(name="webcatalog.tasks.import_ratings_stats")
147 def import_ratings_stats():
148- """Import all ratings and reviews data"""
149+ """Import ratings data since the last import"""
150 call_command('import_all_ratings_stats', verbosity=0)
151
152
153+@task(name="webcatalog.tasks.import_ratings_stats_all")
154+def import_ratings_stats_all():
155+ """Import all ratings data"""
156+ call_command('import_all_ratings_stats', verbosity=0, download_all=True)
157+
158+
159 @task(name="webcatalog.tasks.check_all_latest")
160 def check_all_latest():
161 """Update the 'is_latest' bit on all Applications"""
162
163=== modified file 'src/webcatalog/tests/test_commands.py'
164--- src/webcatalog/tests/test_commands.py 2012-08-29 21:46:54 +0000
165+++ src/webcatalog/tests/test_commands.py 2012-12-03 17:04:22 +0000
166@@ -38,6 +38,7 @@
167 from django.test.testcases import TransactionTestCase
168
169 from mock import (
170+ call,
171 patch,
172 MagicMock,
173 Mock,
174@@ -773,6 +774,19 @@
175 self.mock_review_stats.assert_called_with(
176 origin='any', distroseries='onion', days=3)
177
178+ def test_force_download_all_stats(self):
179+ # If the download_all option is used, all stats are
180+ # downloaded, rather than the optimised last X days.
181+ onion = self.factory.make_distroseries(code_name='onion')
182+ orig_timestamp = datetime.utcnow() - timedelta(2)
183+ import_record = ReviewStatsImport.objects.create(
184+ distroseries=onion, last_import=orig_timestamp)
185+
186+ call_command('import_ratings_stats', 'onion', download_all=True)
187+
188+ self.mock_review_stats.assert_called_with(origin='any',
189+ distroseries='onion')
190+
191 def test_update_app_stats(self):
192 # Any stats provided in the api call will be used to update our
193 # apps in the db.
194@@ -1106,12 +1120,33 @@
195
196
197 class ImportAllRatingsStatsTestCase(TestCaseWithFactory):
198- @patch('sys.stdout')
199- def test_handle(self, mock_stdout):
200- patch_attr = ('webcatalog.management.commands.'
201- 'import_all_ratings_stats.call_command')
202- with patch_settings(UBUNTU_SERIES_FOR_VERSIONS=TEST_VERSIONS):
203- with patch(patch_attr) as mock_call_command:
204- call_command('import_all_ratings_stats')
205-
206- self.assertEqual(mock_call_command.call_count, len(TEST_VERSIONS))
207+
208+ def setUp(self):
209+ patcher = patch('webcatalog.management.commands.'
210+ 'import_all_ratings_stats.call_command')
211+ self.mock_call_command = patcher.start()
212+ self.addCleanup(patcher.stop)
213+
214+ patcher = patch('sys.stdout')
215+ patcher.start()
216+ self.addCleanup(patcher.stop)
217+
218+ def test_handle_download(self):
219+ with patch_settings(UBUNTU_SERIES_FOR_VERSIONS=TEST_VERSIONS):
220+ call_command('import_all_ratings_stats')
221+
222+ expected_calls = [
223+ call('import_ratings_stats', series, verbosity=1,
224+ download_all=False) for series in TEST_VERSIONS.values()]
225+ self.mock_call_command.assert_has_calls(expected_calls,
226+ any_order=True)
227+
228+ def test_handle_download_all(self):
229+ with patch_settings(UBUNTU_SERIES_FOR_VERSIONS=TEST_VERSIONS):
230+ call_command('import_all_ratings_stats', download_all=True)
231+
232+ expected_calls = [
233+ call('import_ratings_stats', series, verbosity=1,
234+ download_all=True) for series in TEST_VERSIONS.values()]
235+ self.mock_call_command.assert_has_calls(expected_calls,
236+ any_order=True)
237
238=== modified file 'src/webcatalog/tests/test_views.py'
239--- src/webcatalog/tests/test_views.py 2012-09-06 14:07:55 +0000
240+++ src/webcatalog/tests/test_views.py 2012-12-03 17:04:22 +0000
241@@ -1394,10 +1394,14 @@
242 'name': 'import_sca',
243 },
244 {
245- 'doc': 'Import all ratings and reviews data',
246+ 'doc': 'Import ratings data since the last import',
247 'name': 'import_ratings_stats',
248 },
249 {
250+ 'doc': 'Import all ratings data',
251+ 'name': 'import_ratings_stats_all',
252+ },
253+ {
254 'doc': "Update the 'is_latest' bit on all Applications",
255 'name': 'check_all_latest',
256 },

Subscribers

People subscribed via source and target branches