Merge lp:~mvo/software-center/replace-restfulclient-with-piston into lp:software-center
- replace-restfulclient-with-piston
- Merge into trunk
Proposed by
Michael Vogt
Status: | Merged |
---|---|
Merged at revision: | 2637 |
Proposed branch: | lp:~mvo/software-center/replace-restfulclient-with-piston |
Merge into: | lp:software-center |
Diff against target: |
1365 lines (+377/-662) 19 files modified
debian/control (+0/-1) softwarecenter/backend/login.py (+0/-7) softwarecenter/backend/oneconfhandler/core.py (+6/-13) softwarecenter/backend/piston/ubuntusso_pristine.py (+22/-0) softwarecenter/backend/reviews/__init__.py (+3/-5) softwarecenter/backend/reviews/rnr.py (+11/-13) softwarecenter/backend/scagent.py (+32/-27) softwarecenter/backend/spawn_helper.py (+24/-0) softwarecenter/backend/ubuntusso.py (+50/-255) softwarecenter/enums.py (+5/-0) softwarecenter/paths.py (+1/-3) test/gtk3/test_views.py (+2/-0) test/test_reviews.py (+3/-2) test/test_ubuntu_sso_api.py (+6/-11) utils/piston-helpers/piston_generic_helper.py (+209/-0) utils/piston-helpers/piston_get_review_stats_helper.py (+0/-65) utils/piston-helpers/piston_get_scagent_available_apps.py (+0/-197) utils/piston-helpers/piston_get_useful_votes_helper.py (+0/-46) utils/submit_review_gtk3.py (+3/-17) |
To merge this branch: | bzr merge lp:~mvo/software-center/replace-restfulclient-with-piston |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
software-store-developers | Pending | ||
Review via email: mp+87636@code.launchpad.net |
Commit message
Description of the change
This branch removes the need for lazr.restfulclient by replacing it with a piston-mini-client based helper.
It also cleansup the use of the piston-mini-client helpers and unifies most of them into the piston_
To post a comment you must log in.
Revision history for this message
Kiwinote (kiwinote) wrote : | # |
Revision history for this message
Gary Lasker (gary-lasker) wrote : | # |
Hi mvo! So I made the fix that kiwinote mentioned above, plus some small fixes that I *think* are needed to make Ubuntu SSO work, and finally some pyflakes cleanup. I pushed this to:
lp:~gary-lasker/software-center/replace-restfulclient-with-piston-tweaks
Please take a look at the SSO changes in particular as I want to be sure these are correct.
I think that if these small changes look rigfht to you, we are good to go for this branch. Let's talk tomorrow if you like, to make sure everything's just right.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added symlink 'data/piston_generic_helper.py' |
2 | === target is u'../utils/piston-helpers/piston_generic_helper.py' |
3 | === removed symlink 'data/piston_get_review_stats_helper.py' |
4 | === target was u'../utils/piston-helpers/piston_get_review_stats_helper.py' |
5 | === removed symlink 'data/piston_get_scagent_available_apps.py' |
6 | === target was u'../utils/piston-helpers/piston_get_scagent_available_apps.py' |
7 | === removed symlink 'data/piston_get_useful_votes_helper.py' |
8 | === target was u'../utils/piston-helpers/piston_get_useful_votes_helper.py' |
9 | === modified file 'debian/control' |
10 | --- debian/control 2011-12-06 14:22:20 +0000 |
11 | +++ debian/control 2012-01-05 15:32:23 +0000 |
12 | @@ -40,7 +40,6 @@ |
13 | policykit-1, |
14 | policykit-1-gnome | policykit-1-kde, |
15 | python-xdg, |
16 | - python-lazr.restfulclient, |
17 | ubuntu-sso-client (>= 0.99.6), |
18 | python-piston-mini-client (>= 0.1+bzr29), |
19 | oneconf (>= 0.2.6), |
20 | |
21 | === modified file 'softwarecenter/backend/login.py' |
22 | --- softwarecenter/backend/login.py 2011-09-15 14:24:14 +0000 |
23 | +++ softwarecenter/backend/login.py 2012-01-05 15:32:23 +0000 |
24 | @@ -49,10 +49,3 @@ |
25 | raise NotImplemented |
26 | def cancel_login(self): |
27 | self.emit("login-canceled") |
28 | - @property |
29 | - def new_account_url(self): |
30 | - return self.NEW_ACCOUNT_URL |
31 | - @property |
32 | - def forgoten_password_url(self): |
33 | - return self.FORGOT_PASSWORD_URL |
34 | - |
35 | |
36 | === modified file 'softwarecenter/backend/oneconfhandler/core.py' |
37 | --- softwarecenter/backend/oneconfhandler/core.py 2011-10-26 12:01:19 +0000 |
38 | +++ softwarecenter/backend/oneconfhandler/core.py 2012-01-05 15:32:23 +0000 |
39 | @@ -22,7 +22,7 @@ |
40 | from oneconf.enums import MIN_TIME_WITHOUT_ACTIVITY |
41 | |
42 | from softwarecenter.backend.login_sso import get_sso_backend |
43 | -from softwarecenter.backend.restfulclient import get_ubuntu_sso_backend |
44 | +from softwarecenter.backend.ubuntusso import get_ubuntu_sso_backend |
45 | from softwarecenter.utils import clear_token_from_ubuntu_sso |
46 | |
47 | import datetime |
48 | @@ -172,10 +172,11 @@ |
49 | def _maybe_login_successful(self, sso, oauth_result): |
50 | """ called after we have the token, then we go and figure out our name """ |
51 | logging.debug("_maybe_login_successful") |
52 | - token = oauth_result |
53 | - self.ssoapi = get_ubuntu_sso_backend(token) |
54 | + self.ssoapi = get_ubuntu_sso_backend() |
55 | self.ssoapi.connect("whoami", self._whoami_done) |
56 | self.ssoapi.connect("error", self._whoami_error) |
57 | + # this will automatically verify the keyring token and retrigger |
58 | + # login (once) if its expired |
59 | self.ssoapi.whoami() |
60 | |
61 | def _whoami_done(self, ssologin, result): |
62 | @@ -184,13 +185,5 @@ |
63 | |
64 | def _whoami_error(self, ssologin, e): |
65 | logging.error("whoami error '%s'" % e) |
66 | - # HACK: clear the token from the keyring assuming that it expired |
67 | - # or got deauthorized by the user on the website |
68 | - # this really should be done by ubuntu-sso-client itself |
69 | - import lazr.restfulclient.errors |
70 | - errortype = lazr.restfulclient.errors.HTTPError |
71 | - if (type(e) == errortype): |
72 | - LOG.warn("authentication error, resetting token and retrying") |
73 | - clear_token_from_ubuntu_sso(self.appname) |
74 | - self._share_inventory(False) |
75 | - return |
76 | + self._share_inventory(False) |
77 | + return |
78 | |
79 | === added file 'softwarecenter/backend/piston/ubuntusso_pristine.py' |
80 | --- softwarecenter/backend/piston/ubuntusso_pristine.py 1970-01-01 00:00:00 +0000 |
81 | +++ softwarecenter/backend/piston/ubuntusso_pristine.py 2012-01-05 15:32:23 +0000 |
82 | @@ -0,0 +1,22 @@ |
83 | +from piston_mini_client import PistonAPI, returns_json |
84 | +from piston_mini_client.validators import oauth_protected |
85 | + |
86 | +# These are factored out as constants for if you need to work against a |
87 | +# server that doesn't support both schemes (like http-only dev servers) |
88 | +PUBLIC_API_SCHEME = 'http' |
89 | +AUTHENTICATED_API_SCHEME = 'https' |
90 | + |
91 | + |
92 | +# this is only here because: |
93 | +# a) ubuntu-sso-client does not support verifying if the credentials |
94 | +# are still valid |
95 | +# b) the restful client interface is not really needed because we just |
96 | +# need this one single call |
97 | +class UbuntuSsoAPI(PistonAPI): |
98 | + default_service_root = 'http://localhost:8000/api/2.0' |
99 | + |
100 | + @oauth_protected |
101 | + @returns_json |
102 | + def whoami(self, id=None): |
103 | + return self._get('accounts?ws.op=me', |
104 | + scheme=AUTHENTICATED_API_SCHEME) |
105 | |
106 | === modified file 'softwarecenter/backend/reviews/__init__.py' |
107 | --- softwarecenter/backend/reviews/__init__.py 2011-11-07 10:04:33 +0000 |
108 | +++ softwarecenter/backend/reviews/__init__.py 2012-01-05 15:32:23 +0000 |
109 | @@ -19,6 +19,7 @@ |
110 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
111 | |
112 | import datetime |
113 | +import json |
114 | import logging |
115 | import operator |
116 | import os |
117 | @@ -107,13 +108,10 @@ |
118 | return False |
119 | |
120 | # run the command and add watcher |
121 | - cmd = [os.path.join( |
122 | - softwarecenter.paths.datadir, PistonHelpers.GET_USEFUL_VOTES), |
123 | - "--username", user, |
124 | - ] |
125 | spawn_helper = SpawnHelper() |
126 | spawn_helper.connect("data-available", self._on_usefulness_data) |
127 | - spawn_helper.run(cmd) |
128 | + spawn_helper.run_generic_piston_helper( |
129 | + "RatingsAndReviewsAPI", "get_usefulness", username=user) |
130 | |
131 | def _on_usefulness_data(self, spawn_helper, results): |
132 | '''called if usefulness retrieved from server''' |
133 | |
134 | === modified file 'softwarecenter/backend/reviews/rnr.py' |
135 | --- softwarecenter/backend/reviews/rnr.py 2011-11-07 08:26:13 +0000 |
136 | +++ softwarecenter/backend/reviews/rnr.py 2012-01-05 15:32:23 +0000 |
137 | @@ -128,22 +128,20 @@ |
138 | except OSError: |
139 | days_delta = 0 |
140 | LOG.debug("refresh with days_delta: %s" % days_delta) |
141 | + # FIXME: the server currently has bug (#757695) so we |
142 | + # can not turn this on just yet and need to use |
143 | + # the old "catch-all" review-stats for now |
144 | #origin = "any" |
145 | #distroseries = self.distro.get_codename() |
146 | - cmd = [os.path.join( |
147 | - softwarecenter.paths.datadir, PistonHelpers.GET_REVIEW_STATS), |
148 | - # FIXME: the server currently has bug (#757695) so we |
149 | - # can not turn this on just yet and need to use |
150 | - # the old "catch-all" review-stats for now |
151 | - #"--origin", origin, |
152 | - #"--distroseries", distroseries, |
153 | - ] |
154 | + spawn_helper = SpawnHelper() |
155 | + spawn_helper.connect("data-available", self._on_review_stats_data, callback) |
156 | if days_delta: |
157 | - cmd += ["--days-delta", str(days_delta)] |
158 | - spawn_helper = SpawnHelper() |
159 | - spawn_helper.connect("data-available", self._on_review_stats_data, callback) |
160 | - spawn_helper.run(cmd) |
161 | - |
162 | + spawn_helper.run_generic_piston_helper( |
163 | + "RatingsAndReviewsAPI", "review_stats", days=days_delta) |
164 | + else: |
165 | + spawn_helper.run_generic_piston_helper( |
166 | + "RatingsAndReviewsAPI", "review_stats") |
167 | + |
168 | def _on_review_stats_data(self, spawn_helper, piston_review_stats, callback): |
169 | """ process stdout from the helper """ |
170 | review_stats = self.REVIEW_STATS_CACHE |
171 | |
172 | === modified file 'softwarecenter/backend/scagent.py' |
173 | --- softwarecenter/backend/scagent.py 2012-01-03 15:20:56 +0000 |
174 | +++ softwarecenter/backend/scagent.py 2012-01-05 15:32:23 +0000 |
175 | @@ -20,6 +20,7 @@ |
176 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
177 | |
178 | from gi.repository import GObject |
179 | +import json |
180 | import logging |
181 | import os |
182 | |
183 | @@ -56,14 +57,7 @@ |
184 | GObject.GObject.__init__(self) |
185 | self.distro = get_distro() |
186 | self.ignore_cache = ignore_cache |
187 | - binary = os.path.join( |
188 | - softwarecenter.paths.datadir, PistonHelpers.SOFTWARE_CENTER_AGENT) |
189 | - self.HELPER_CMD = [binary] |
190 | - if self.ignore_cache: |
191 | - self.HELPER_CMD.append("--ignore-cache") |
192 | - if xid: |
193 | - self.HELPER_CMD.append("--parent-xid") |
194 | - self.HELPER_CMD.append(str(xid)) |
195 | + self.xid = xid |
196 | |
197 | def query_available(self, series_name=None, arch_tag=None): |
198 | self._query_available(series_name, arch_tag, for_qa=False) |
199 | @@ -78,41 +72,52 @@ |
200 | if not arch_tag: |
201 | arch_tag = get_current_arch() |
202 | # build the command |
203 | - cmd = self.HELPER_CMD[:] |
204 | + spawner = SpawnHelper() |
205 | + spawner.parent_xid = self.xid |
206 | + spawner.ignore_cache = self.ignore_cache |
207 | + spawner.connect("data-available", self._on_query_available_data) |
208 | + spawner.connect("error", lambda spawner, err: self.emit("error", err)) |
209 | if for_qa: |
210 | - cmd.append("available_apps_qa") |
211 | + spawner.needs_auth = True |
212 | + spawner.run_generic_piston_helper( |
213 | + "SoftwareCenterAgentAPI", |
214 | + "available_apps_qa", |
215 | + lang=get_langugage(), |
216 | + series=series_name, |
217 | + arch=arch_tag) |
218 | else: |
219 | - cmd.append("available_apps") |
220 | - cmd += [language, |
221 | - series_name, |
222 | - arch_tag, |
223 | - ] |
224 | - spawner = SpawnHelper() |
225 | - spawner.connect("data-available", self._on_query_available_data) |
226 | - spawner.connect("error", lambda spawner, err: self.emit("error", err)) |
227 | - spawner.run(cmd) |
228 | + spawner.run_generic_piston_helper( |
229 | + "SoftwareCenterAgentAPI", |
230 | + "available_apps", |
231 | + lang=get_language(), |
232 | + series=series_name, |
233 | + arch=arch_tag) |
234 | + |
235 | def _on_query_available_data(self, spawner, piston_available): |
236 | self.emit("available", piston_available) |
237 | |
238 | def query_available_for_me(self, oauth_token, openid_identifier): |
239 | - cmd = self.HELPER_CMD[:] |
240 | - cmd.append("subscriptions_for_me") |
241 | spawner = SpawnHelper() |
242 | + spawner.parent_xid = self.xid |
243 | + spawner.ignore_cache = self.ignore_cache |
244 | spawner.connect("data-available", self._on_query_available_for_me_data) |
245 | spawner.connect("error", lambda spawner, err: self.emit("error", err)) |
246 | - spawner.run(cmd) |
247 | + spawner.needs_auth = True |
248 | + spawner.run_generic_piston_helper( |
249 | + "SoftwareCenterAgentAPI", "subscriptions_for_me") |
250 | def _on_query_available_for_me_data(self, spawner, piston_available_for_me): |
251 | self.emit("available-for-me", piston_available_for_me) |
252 | |
253 | def query_exhibits(self): |
254 | - cmd = self.HELPER_CMD[:] |
255 | - cmd.append("exhibits") |
256 | - cmd.append(get_language()) |
257 | - cmd.append(self.distro.get_codename()) |
258 | spawner = SpawnHelper() |
259 | + spawner.parent_xid = self.xid |
260 | + spawner.ignore_cache = self.ignore_cache |
261 | spawner.connect("data-available", self._on_exhibits_data_available) |
262 | spawner.connect("error", lambda spawner, err: self.emit("error", err)) |
263 | - spawner.run(cmd) |
264 | + spawner.run_generic_piston_helper( |
265 | + "SoftwareCenterAgentAPI", "exhiits", |
266 | + lang=get_language(), series=self.distro.get_codename()) |
267 | + |
268 | def _on_exhibits_data_available(self, spawner, exhibits): |
269 | for exhibit in exhibits: |
270 | # special case, if there is no title provided by the server |
271 | |
272 | === modified file 'softwarecenter/backend/spawn_helper.py' |
273 | --- softwarecenter/backend/spawn_helper.py 2011-09-15 14:24:14 +0000 |
274 | +++ softwarecenter/backend/spawn_helper.py 2012-01-05 15:32:23 +0000 |
275 | @@ -30,6 +30,9 @@ |
276 | import os |
277 | import json |
278 | |
279 | +import softwarecenter.paths |
280 | +from softwarecenter.paths import PistonHelpers |
281 | + |
282 | from gi.repository import GObject |
283 | |
284 | LOG = logging.getLogger(__name__) |
285 | @@ -59,6 +62,27 @@ |
286 | self._io_watch = None |
287 | self._child_watch = None |
288 | self._cmd = None |
289 | + self.needs_auth = False |
290 | + self.ignore_cache = False |
291 | + self.parent_xid = None |
292 | + |
293 | + def run_generic_piston_helper(self, klass, func, **kwargs): |
294 | + binary = os.path.join( |
295 | + softwarecenter.paths.datadir, PistonHelpers.GENERIC_HELPER) |
296 | + cmd = [binary] |
297 | + cmd += ["--datadir", softwarecenter.paths.datadir] |
298 | + if self.needs_auth: |
299 | + cmd.append("--needs-auth") |
300 | + if self.ignore_cache: |
301 | + cmd.append("--ignore-cache") |
302 | + if self.parent_xid: |
303 | + cmd.append("--parent-xid") |
304 | + cmd.append(str(xid)) |
305 | + cmd += [klass, func] |
306 | + if kwargs: |
307 | + cmd.append(json.dumps(kwargs)) |
308 | + LOG.debug("run_generic_piston_helper()") |
309 | + self.run(cmd) |
310 | |
311 | def run(self, cmd): |
312 | self._cmd = cmd |
313 | |
314 | === renamed file 'softwarecenter/backend/restfulclient.py' => 'softwarecenter/backend/ubuntusso.py' |
315 | --- softwarecenter/backend/restfulclient.py 2012-01-05 09:53:52 +0000 |
316 | +++ softwarecenter/backend/ubuntusso.py 2012-01-05 15:32:23 +0000 |
317 | @@ -19,134 +19,29 @@ |
318 | # this program; if not, write to the Free Software Foundation, Inc., |
319 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
320 | |
321 | -import os |
322 | |
323 | from gi.repository import GObject |
324 | |
325 | import logging |
326 | -import threading |
327 | - |
328 | -from softwarecenter.enums import BUY_SOMETHING_HOST |
329 | - |
330 | -# possible workaround for bug #599332 is to try to import lazr.restful |
331 | -# import lazr.restful |
332 | -# import lazr.restfulclient |
333 | - |
334 | -from lazr.restfulclient.resource import ServiceRoot |
335 | -from lazr.restfulclient.authorize import BasicHttpAuthorizer |
336 | -from lazr.restfulclient.authorize.oauth import OAuthAuthorizer |
337 | -from oauth.oauth import OAuthToken |
338 | - |
339 | -from softwarecenter.paths import SOFTWARE_CENTER_CACHE_DIR |
340 | -from Queue import Queue |
341 | +import os |
342 | + |
343 | +import softwarecenter.paths |
344 | +from softwarecenter.paths import PistonHelpers |
345 | + |
346 | +import piston_mini_client.auth |
347 | |
348 | # mostly for testing |
349 | from fake_review_settings import FakeReviewSettings, network_delay |
350 | - |
351 | -from login import LoginBackend |
352 | +from spawn_helper import SpawnHelper |
353 | + |
354 | +from softwarecenter.utils import clear_token_from_ubuntu_sso |
355 | + |
356 | +from gettext import gettext as _ |
357 | |
358 | LOG = logging.getLogger(__name__) |
359 | |
360 | -UBUNTU_SSO_SERVICE = os.environ.get( |
361 | - "USSOC_SERVICE_URL", "https://login.ubuntu.com/api/1.0") |
362 | -UBUNTU_SOFTWARE_CENTER_AGENT_SERVICE = BUY_SOMETHING_HOST+"/api/1.0" |
363 | - |
364 | -class AttributesObject(object): |
365 | - """ convinient object to hold attributes """ |
366 | - MAX_REPR_STRING_SIZE = 30 |
367 | - |
368 | - def __repr__(self): |
369 | - s = "<'%s': " % self.__class__.__name__ |
370 | - for key in vars(self): |
371 | - value = str(getattr(self, key)) |
372 | - if len(value) > self.MAX_REPR_STRING_SIZE: |
373 | - value = "%s..." % value[:self.MAX_REPR_STRING_SIZE] |
374 | - s += "%s='%s';" % (key, value) |
375 | - s += ">" |
376 | - return s |
377 | - |
378 | - |
379 | -def restful_collection_to_real_python(restful_list): |
380 | - """ take a restful and convert it to a python list with real python |
381 | - objects |
382 | - """ |
383 | - l = [] |
384 | - for entry in restful_list: |
385 | - o = AttributesObject() |
386 | - for attr in entry.lp_attributes: |
387 | - setattr(o, attr, getattr(entry, attr)) |
388 | - l.append(o) |
389 | - return l |
390 | - |
391 | -class RestfulClientWorker(threading.Thread): |
392 | - """ a generic worker thread for a lazr.restfulclient """ |
393 | - |
394 | - def __init__(self, authorizer, service_root): |
395 | - """ init the thread """ |
396 | - threading.Thread.__init__(self) |
397 | - self._service_root_url = service_root |
398 | - self._authorizer = authorizer |
399 | - self._pending_requests = Queue() |
400 | - self._shutdown = False |
401 | - self.daemon = True |
402 | - self.error = None |
403 | - self._cachedir = os.path.join(SOFTWARE_CENTER_CACHE_DIR, |
404 | - "restfulclient") |
405 | - |
406 | - def run(self): |
407 | - """ |
408 | - Main thread run interface, logs into launchpad |
409 | - """ |
410 | - LOG.debug("lp worker thread run") |
411 | - try: |
412 | - self.service = ServiceRoot(self._authorizer, |
413 | - self._service_root_url, |
414 | - self._cachedir) |
415 | - except: |
416 | - logging.exception("worker thread can not connect to service root") |
417 | - self.error = "ERROR_SERVICE_ROOT" |
418 | - self._shutdown = True |
419 | - return |
420 | - # loop |
421 | - self._wait_for_commands() |
422 | - |
423 | - def shutdown(self): |
424 | - """Request shutdown""" |
425 | - self._shutdown = True |
426 | - |
427 | - def queue_request(self, func, args, kwargs, result_callback, error_callback): |
428 | - """ |
429 | - queue a (remote) command for execution, the result_callback will |
430 | - call with the result_list when done (that function will be |
431 | - called async) |
432 | - """ |
433 | - self._pending_requests.put((func, args, kwargs, result_callback, error_callback)) |
434 | - |
435 | - def _wait_for_commands(self): |
436 | - """internal helper that waits for commands""" |
437 | - while True: |
438 | - while not self._pending_requests.empty(): |
439 | - LOG.debug("found pending request") |
440 | - (func_str, args, kwargs, result_callback, error_callback) = self._pending_requests.get() |
441 | - # run func async |
442 | - try: |
443 | - func = self.service |
444 | - for part in func_str.split("."): |
445 | - func = getattr(func, part) |
446 | - res = func(*args, **kwargs) |
447 | - except Exception ,e: |
448 | - error_callback(e) |
449 | - else: |
450 | - result_callback(res) |
451 | - self._pending_requests.task_done() |
452 | - # wait a bit |
453 | - import time |
454 | - time.sleep(0.1) |
455 | - if (self._shutdown and |
456 | - self._pending_requests.empty()): |
457 | - return |
458 | - |
459 | class UbuntuSSOAPI(GObject.GObject): |
460 | + """ Ubuntu SSO interface using the oauth token from the keyring """ |
461 | |
462 | __gsignals__ = { |
463 | "whoami" : (GObject.SIGNAL_RUN_LAST, |
464 | @@ -160,52 +55,27 @@ |
465 | |
466 | } |
467 | |
468 | - def __init__(self, token): |
469 | + def __init__(self): |
470 | GObject.GObject.__init__(self) |
471 | - self._whoami = None |
472 | - self._error = None |
473 | - self.service = UBUNTU_SSO_SERVICE |
474 | - self.token = token |
475 | - token = OAuthToken(self.token["token"], self.token["token_secret"]) |
476 | - authorizer = OAuthAuthorizer(self.token["consumer_key"], |
477 | - self.token["consumer_secret"], |
478 | - access_token=token) |
479 | - # we need to init the GObject.init_threads() |
480 | - # - if we do it globally s-c will crash on exit (LP: #907568) |
481 | - # - if we don't do it, s-c will hang in worker_thread.start() |
482 | - # (even though threads_init is deprecated and according to the |
483 | - # docs is run automatically nowdays) |
484 | - # - if we do it here some apps will still crash |
485 | - self.worker_thread = RestfulClientWorker(authorizer, self.service) |
486 | - self.worker_thread.start() |
487 | - GObject.timeout_add(200, self._monitor_thread) |
488 | - |
489 | - def _monitor_thread(self): |
490 | - # glib bit of the threading, runs in the main thread |
491 | - if self._whoami is not None: |
492 | - self.emit("whoami", self._whoami) |
493 | - self._whoami = None |
494 | - if self._error is not None: |
495 | - self.emit("error", self._error) |
496 | - self._error = None |
497 | - return True |
498 | - |
499 | - def _thread_whoami_done(self, result): |
500 | - self._whoami = result |
501 | - |
502 | - def _thread_whoami_error(self, e): |
503 | - self._error = e |
504 | + |
505 | + def _on_whoami_data(self, spawner, piston_whoami): |
506 | + self.emit("whoami", piston_whoami) |
507 | |
508 | def whoami(self): |
509 | + """ trigger request for the getting account information, this |
510 | + will also verify if the current token is valid and if not |
511 | + trigger a cleanup/re-authenticate |
512 | + """ |
513 | LOG.debug("whoami called") |
514 | - self.worker_thread.queue_request("accounts.me", (), {}, |
515 | - self._thread_whoami_done, |
516 | - self._thread_whoami_error) |
517 | - |
518 | + spawner = SpawnHelper() |
519 | + spawner.connect("data-available", self._on_whoami_data) |
520 | + spawner.connect("error", lambda spawner, err: self.emit("error", err)) |
521 | + spawner.needs_auth = True |
522 | + spawner.run_generic_piston_helper("UbuntuSsoAPI", "whoami") |
523 | |
524 | class UbuntuSSOAPIFake(UbuntuSSOAPI): |
525 | |
526 | - def __init__(self, token): |
527 | + def __init__(self): |
528 | GObject.GObject.__init__(self) |
529 | self._fake_settings = FakeReviewSettings() |
530 | |
531 | @@ -231,83 +101,18 @@ |
532 | def _make_error(): |
533 | return 'HTTP Error 401: Unauthorized' |
534 | |
535 | -def get_ubuntu_sso_backend(token): |
536 | +def get_ubuntu_sso_backend(): |
537 | """ |
538 | factory that returns an ubuntu sso loader singelton |
539 | """ |
540 | if "SOFTWARE_CENTER_FAKE_REVIEW_API" in os.environ: |
541 | - ubuntu_sso_class = UbuntuSSOAPIFake(token) |
542 | + ubuntu_sso_class = UbuntuSSOAPIFake() |
543 | LOG.warn('Using fake Ubuntu SSO API. Only meant for testing purposes') |
544 | else: |
545 | - ubuntu_sso_class = UbuntuSSOAPI(token) |
546 | + ubuntu_sso_class = UbuntuSSOAPI() |
547 | return ubuntu_sso_class |
548 | |
549 | |
550 | -class UbuntuSSOlogin(LoginBackend): |
551 | - |
552 | - NEW_ACCOUNT_URL = "https://login.launchpad.net/+standalone-login" |
553 | - FORGOT_PASSWORD_URL = "https://login.ubuntu.com/+forgot_password" |
554 | - |
555 | - SSO_AUTHENTICATE_FUNC = "authentications.authenticate" |
556 | - |
557 | - def __init__(self): |
558 | - LoginBackend.__init__(self) |
559 | - self.service = UBUNTU_SSO_SERVICE |
560 | - # we get a dict here with the following keys: |
561 | - # token |
562 | - # consumer_key (also the openid identifier) |
563 | - # consumer_secret |
564 | - # token_secret |
565 | - # name (that is just 'software-center') |
566 | - self.oauth_credentials = None |
567 | - self._oauth_credentials = None |
568 | - self._login_failure = None |
569 | - self.worker_thread = None |
570 | - |
571 | - def shutdown(self): |
572 | - self.worker_thread.shutdown() |
573 | - |
574 | - def login(self, username=None, password=None): |
575 | - if not username or not password: |
576 | - self.emit("need-username-password") |
577 | - return |
578 | - authorizer = BasicHttpAuthorizer(username, password) |
579 | - self.worker_thread = RestfulClientWorker(authorizer, self.service) |
580 | - self.worker_thread.start() |
581 | - kwargs = { "token_name" : "software-center", |
582 | - } |
583 | - self.worker_thread.queue_request(self.SSO_AUTHENTICATE_FUNC, (), kwargs, |
584 | - self._thread_authentication_done, |
585 | - self._thread_authentication_error) |
586 | - GObject.timeout_add(200, self._monitor_thread) |
587 | - |
588 | - def _monitor_thread(self): |
589 | - # glib bit of the threading, runs in the main thread |
590 | - if self._oauth_credentials: |
591 | - self.emit("login-successful", self._oauth_credentials) |
592 | - self.oauth_credentials = self._oauth_credentials |
593 | - self._oauth_credentials = None |
594 | - if self._login_failure: |
595 | - self.emit("login-failed") |
596 | - self._login_failure = None |
597 | - return True |
598 | - |
599 | - def _thread_authentication_done(self, result): |
600 | - # runs in the thread context, can not touch gui or glib |
601 | - #print "_authentication_done", result |
602 | - self._oauth_credentials = result |
603 | - |
604 | - def _thread_authentication_error(self, e): |
605 | - # runs in the thread context, can not touch gui or glib |
606 | - #print "_authentication_error", type(e) |
607 | - self._login_failure = e |
608 | - |
609 | - def __del__(self): |
610 | - #print "del" |
611 | - if self.worker_thread: |
612 | - self.worker_thread.shutdown() |
613 | - |
614 | - |
615 | # test code |
616 | def _login_success(lp, token): |
617 | print "success", lp, token |
618 | @@ -323,40 +128,30 @@ |
619 | password = sys.stdin.readline().strip() |
620 | sso.login(user, password) |
621 | |
622 | -def _error(scaagent, errormsg): |
623 | - print "_error:", errormsg |
624 | -def _whoami(sso, whoami): |
625 | - print "whoami: ", whoami |
626 | - |
627 | # interactive test code |
628 | if __name__ == "__main__": |
629 | + def _whoami(sso, result): |
630 | + print "res: ", result |
631 | + Gtk.main_quit() |
632 | + def _error(sso, result): |
633 | + print "err: ", result |
634 | + Gtk.main_quit() |
635 | + def _dbus_maybe_login_successful(ssologin, oauth_result): |
636 | + print "got token, verify it now" |
637 | + sso = UbuntuSSOAPI() |
638 | + sso.connect("whoami", _whoami) |
639 | + sso.connect("error", _error) |
640 | + sso.whoami() |
641 | + |
642 | + from gi.repository import Gtk |
643 | import sys |
644 | logging.basicConfig(level=logging.DEBUG) |
645 | - |
646 | - if len(sys.argv) < 2: |
647 | - print "need an argument, one of: 'sso', 'ssologin'" |
648 | - sys.exit(1) |
649 | - |
650 | - elif sys.argv[1] == "sso": |
651 | - def _dbus_maybe_login_successful(ssologin, oauth_result): |
652 | - sso = UbuntuSSOAPI(oauth_result) |
653 | - sso.connect("whoami", _whoami) |
654 | - sso.connect("error", _error) |
655 | - sso.whoami() |
656 | - from login_sso import get_sso_backend |
657 | - backend = get_sso_backend("", "appname", "help_text") |
658 | - backend.connect("login-successful", _dbus_maybe_login_successful) |
659 | - backend.login_or_register() |
660 | - |
661 | - elif sys.argv[1] == "ssologin": |
662 | - ssologin = UbuntuSSOlogin() |
663 | - ssologin.connect("login-successful", _login_success) |
664 | - ssologin.connect("login-failed", _login_failed) |
665 | - ssologin.connect("need-username-password", _login_need_user_and_password) |
666 | - ssologin.login() |
667 | - |
668 | - else: |
669 | - print "unknown option" |
670 | - sys.exit(1) |
671 | + softwarecenter.paths.datadir = "./data" |
672 | + |
673 | + from login_sso import get_sso_backend |
674 | + backend = get_sso_backend("", "appname", "help_text") |
675 | + backend.connect("login-successful", _dbus_maybe_login_successful) |
676 | + backend.login_or_register() |
677 | + Gtk.main() |
678 | |
679 | |
680 | |
681 | === modified file 'softwarecenter/enums.py' |
682 | --- softwarecenter/enums.py 2011-12-16 12:50:18 +0000 |
683 | +++ softwarecenter/enums.py 2012-01-05 15:32:23 +0000 |
684 | @@ -34,6 +34,11 @@ |
685 | BUY_SOMETHING_HOST = os.environ.get("SOFTWARE_CENTER_BUY_HOST") or "https://software-center.ubuntu.com" |
686 | BUY_SOMETHING_HOST_ANONYMOUS = os.environ.get("SOFTWARE_CENTER_BUY_HOST") or "http://software-center.ubuntu.com" |
687 | |
688 | +# for the sso login |
689 | +UBUNTU_SSO_SERVICE = os.environ.get( |
690 | + "USSOC_SERVICE_URL", "https://login.ubuntu.com/") |
691 | +SSO_LOGIN_HOST = UBUNTU_SSO_SERVICE |
692 | + |
693 | # version of the database, every time something gets added (like |
694 | # terms for mime-type) increase this (but keep as a string!) |
695 | DB_SCHEMA_VERSION = "6" |
696 | |
697 | === modified file 'softwarecenter/paths.py' |
698 | --- softwarecenter/paths.py 2011-09-13 12:45:56 +0000 |
699 | +++ softwarecenter/paths.py 2012-01-05 15:32:23 +0000 |
700 | @@ -86,9 +86,7 @@ |
701 | # piston helpers |
702 | class PistonHelpers: |
703 | GET_REVIEWS = "piston_get_reviews_helper.py" |
704 | - GET_REVIEW_STATS = "piston_get_review_stats_helper.py" |
705 | - GET_USEFUL_VOTES = "piston_get_useful_votes_helper.py" |
706 | - SOFTWARE_CENTER_AGENT = "piston_get_scagent_available_apps.py" |
707 | + GENERIC_HELPER = "piston_generic_helper.py" |
708 | |
709 | X2GO_HELPER = "x2go_helper.py" |
710 | |
711 | |
712 | === modified file 'test/gtk3/test_views.py' |
713 | --- test/gtk3/test_views.py 2011-11-15 10:54:54 +0000 |
714 | +++ test/gtk3/test_views.py 2012-01-05 15:32:23 +0000 |
715 | @@ -13,6 +13,8 @@ |
716 | |
717 | import softwarecenter.paths |
718 | softwarecenter.paths.datadir = "../data" |
719 | +import os |
720 | +os.environ["PYTHONPATH"] = "../" |
721 | |
722 | class TestViews(unittest.TestCase): |
723 | |
724 | |
725 | === modified file 'test/test_reviews.py' |
726 | --- test/test_reviews.py 2011-11-04 14:52:52 +0000 |
727 | +++ test/test_reviews.py 2012-01-05 15:32:23 +0000 |
728 | @@ -11,6 +11,7 @@ |
729 | |
730 | import softwarecenter.paths |
731 | softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR = tempfile.mkdtemp() |
732 | +softwarecenter.paths.datadir = "../data" |
733 | |
734 | from softwarecenter.backend.reviews.rnr import ( |
735 | ReviewLoaderSpawningRNRClient as ReviewLoader) |
736 | @@ -51,6 +52,6 @@ |
737 | main_loop.iteration() |
738 | |
739 | if __name__ == "__main__": |
740 | - #import logging |
741 | - #logging.basicConfig(level=logging.DEBUG) |
742 | + import logging |
743 | + logging.basicConfig(level=logging.DEBUG) |
744 | unittest.main() |
745 | |
746 | === modified file 'test/test_ubuntu_sso_api.py' |
747 | --- test/test_ubuntu_sso_api.py 2011-06-11 07:59:59 +0000 |
748 | +++ test/test_ubuntu_sso_api.py 2012-01-05 15:32:23 +0000 |
749 | @@ -6,10 +6,10 @@ |
750 | |
751 | import os |
752 | import unittest |
753 | -from softwarecenter.backend.restfulclient import (UbuntuSSOAPIFake, |
754 | - UbuntuSSOAPI, |
755 | - get_ubuntu_sso_backend, |
756 | - ) |
757 | +from softwarecenter.backend.ubuntusso import (UbuntuSSOAPIFake, |
758 | + UbuntuSSOAPI, |
759 | + get_ubuntu_sso_backend, |
760 | + ) |
761 | |
762 | class TestSSOAPI(unittest.TestCase): |
763 | """ tests the ubuntu sso backend stuff """ |
764 | @@ -24,17 +24,12 @@ |
765 | set([x for x in dir(sso_fake) if not x.startswith("_")])) |
766 | |
767 | def test_get_ubuntu_backend(self): |
768 | - token = { 'token' : 'tokenvalue', |
769 | - 'token_secret' : 'tokensecretvalue', |
770 | - 'consumer_key' : 'consumerkeyvalue', |
771 | - 'consumer_secret' : 'consumersecretvalue', |
772 | - } |
773 | # test that we get the real one |
774 | - self.assertEqual(type(get_ubuntu_sso_backend(token)), |
775 | + self.assertEqual(type(get_ubuntu_sso_backend()), |
776 | UbuntuSSOAPI) |
777 | # test that we get the fake one |
778 | os.environ["SOFTWARE_CENTER_FAKE_REVIEW_API"] = "1" |
779 | - self.assertEqual(type(get_ubuntu_sso_backend(token)), |
780 | + self.assertEqual(type(get_ubuntu_sso_backend()), |
781 | UbuntuSSOAPIFake) |
782 | # clean the environment |
783 | del os.environ["SOFTWARE_CENTER_FAKE_REVIEW_API"] |
784 | |
785 | === added file 'utils/piston-helpers/piston_generic_helper.py' |
786 | --- utils/piston-helpers/piston_generic_helper.py 1970-01-01 00:00:00 +0000 |
787 | +++ utils/piston-helpers/piston_generic_helper.py 2012-01-05 15:32:23 +0000 |
788 | @@ -0,0 +1,209 @@ |
789 | +#!/usr/bin/python |
790 | +# Copyright (C) 2011 Canonical |
791 | +# |
792 | +# Authors: |
793 | +# Michael Vogt |
794 | +# |
795 | +# This program is free software; you can redistribute it and/or modify it under |
796 | +# the terms of the GNU General Public License as published by the Free Software |
797 | +# Foundation; version 3. |
798 | +# |
799 | +# This program is distributed in the hope that it will be useful, but WITHOUT |
800 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
801 | +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
802 | +# details. |
803 | +# |
804 | +# You should have received a copy of the GNU General Public License along with |
805 | +# this program; if not, write to the Free Software Foundation, Inc., |
806 | +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
807 | + |
808 | +import argparse |
809 | +import logging |
810 | +import os |
811 | +import json |
812 | +import pickle |
813 | +import sys |
814 | + |
815 | +from gi.repository import GObject |
816 | + |
817 | +# useful for debugging |
818 | +if "SOFTWARE_CENTER_DEBUG_HTTP" in os.environ: |
819 | + import httplib2 |
820 | + httplib2.debuglevel = 1 |
821 | + |
822 | +import piston_mini_client.auth |
823 | + |
824 | +try: |
825 | + import softwarecenter |
826 | +except ImportError: |
827 | + if os.path.exists("../softwarecenter"): |
828 | + sys.path.insert(0, "../") |
829 | + else: |
830 | + sys.path.insert(0, "/usr/share/software-center") |
831 | + |
832 | +import softwarecenter.paths |
833 | +from softwarecenter.paths import SOFTWARE_CENTER_CACHE_DIR |
834 | +from softwarecenter.backend.login_sso import get_sso_backend |
835 | + |
836 | +from softwarecenter.enums import (SOFTWARE_CENTER_NAME_KEYRING, |
837 | + SOFTWARE_CENTER_SSO_DESCRIPTION, |
838 | + ) |
839 | + |
840 | +# the piston import |
841 | +from softwarecenter.backend.piston.ubuntusso_pristine import UbuntuSsoAPI |
842 | +from softwarecenter.backend.piston.rnrclient import RatingsAndReviewsAPI |
843 | +from softwarecenter.backend.piston.scaclient import SoftwareCenterAgentAPI |
844 | + |
845 | +RatingsAndReviewsAPI # pyflakes |
846 | +UbuntuSsoAPI # pyflakes |
847 | +SoftwareCenterAgentAPI # pyflakes |
848 | + |
849 | +# patch default_service_root to the one we use |
850 | +from softwarecenter.enums import SSO_LOGIN_HOST |
851 | +UbuntuSsoAPI.default_service_root = SSO_LOGIN_HOST+"/api/1.0" |
852 | + |
853 | +from gettext import gettext as _ |
854 | + |
855 | +# helper that is only used to verify that the token is ok |
856 | +# and trigger cleanup if not |
857 | +class SSOLoginHelper(object): |
858 | + |
859 | + def __init__(self, xid=0): |
860 | + self.oauth = None |
861 | + self.xid = xid |
862 | + self.loop = GObject.MainLoop(GObject.main_context_default()) |
863 | + |
864 | + def _login_successful(self, sso_backend, oauth_result): |
865 | + LOG.debug("_login_successful") |
866 | + self.oauth = oauth_result |
867 | + # FIXME: actually verify the token against ubuntu SSO |
868 | + self.loop.quit() |
869 | + |
870 | + def verify_token_sync(self, token): |
871 | + LOG.debug("verify_token") |
872 | + auth = piston_mini_client.auth.OAuthAuthorizer(token["token"], |
873 | + token["token_secret"], |
874 | + token["consumer_key"], |
875 | + token["consumer_secret"]) |
876 | + api = UbuntuSsoAPI(auth=auth) |
877 | + try: |
878 | + res = api.whoami() |
879 | + except: |
880 | + LOG.exception("api.whoami failed") |
881 | + return None |
882 | + return res |
883 | + |
884 | + def clear_token(self): |
885 | + clear_token_from_ubuntu_sso(SOFTWARE_CENTER_NAME_KEYRING) |
886 | + |
887 | + def get_oauth_token_sync(self): |
888 | + self.oauth = None |
889 | + sso = get_sso_backend( |
890 | + self.xid, |
891 | + SOFTWARE_CENTER_NAME_KEYRING, |
892 | + _(SOFTWARE_CENTER_SSO_DESCRIPTION)) |
893 | + sso.connect("login-successful", self._login_successful) |
894 | + sso.connect("login-failed", lambda s: self.loop.quit()) |
895 | + sso.connect("login-canceled", lambda s: self.loop.quit()) |
896 | + sso.login_or_register() |
897 | + self.loop.run() |
898 | + return self.oauth |
899 | + |
900 | + def get_oauth_token_and_verify_sync(self): |
901 | + token = self.get_oauth_token_sync() |
902 | + # check if the token is valid and reset it if it is not |
903 | + if token and not self.verify_token_sync(token): |
904 | + self.clear_token() |
905 | + # re-trigger login |
906 | + token = self.get_oauth_token_sync() |
907 | + return token |
908 | + |
909 | + |
910 | + |
911 | +LOG = logging.getLogger(__name__) |
912 | + |
913 | +if __name__ == "__main__": |
914 | + logging.basicConfig() |
915 | + |
916 | + # command line parser |
917 | + parser = argparse.ArgumentParser( |
918 | + description="Backend helper for piston-mini-client based APIs") |
919 | + parser.add_argument("--debug", action="store_true", default=False, |
920 | + help="enable debug output") |
921 | + parser.add_argument("--datadir", default="/usr/share/software-center", |
922 | + help="setup alternative datadir") |
923 | + parser.add_argument("--ignore-cache", action="store_true", default=False, |
924 | + help="force ignore cache") |
925 | + parser.add_argument("--needs-auth", default=False, action="store_true", |
926 | + help="need oauth credentials") |
927 | + parser.add_argument("--output", default="pickle", |
928 | + help="output result as [pickle|json|text]") |
929 | + parser.add_argument("--parent-xid", default=0, |
930 | + help="xid of the parent window") |
931 | + parser.add_argument('klass', help='class to use') |
932 | + parser.add_argument('function', help='function to call') |
933 | + parser.add_argument('kwargs', nargs="?", |
934 | + help='kwargs for the function call as json') |
935 | + args = parser.parse_args() |
936 | + |
937 | + if args.debug: |
938 | + logging.basicConfig(level=logging.DEBUG) |
939 | + LOG.setLevel(logging.DEBUG) |
940 | + |
941 | + if args.ignore_cache: |
942 | + cachedir = None |
943 | + else: |
944 | + cachedir = os.path.join(SOFTWARE_CENTER_CACHE_DIR, "piston-helper") |
945 | + |
946 | + # check what we need to call |
947 | + klass = globals()[args.klass] |
948 | + func = args.function |
949 | + kwargs = json.loads(args.kwargs or '{}') |
950 | + |
951 | + softwarecenter.paths.datadir = args.datadir |
952 | + |
953 | + if args.needs_auth: |
954 | + helper = SSOLoginHelper(args.parent_xid) |
955 | + token = helper.get_oauth_token_and_verify_sync() |
956 | + # if we don't have a token, error here |
957 | + if not token: |
958 | + sys.stderr.write("ERROR: can not obtain a oauth token\n") |
959 | + sys.exit(1) |
960 | + |
961 | + auth = piston_mini_client.auth.OAuthAuthorizer(token["token"], |
962 | + token["token_secret"], |
963 | + token["consumer_key"], |
964 | + token["consumer_secret"]) |
965 | + api = klass(cachedir=cachedir, auth=auth) |
966 | + else: |
967 | + api = klass() |
968 | + |
969 | + piston_reply = None |
970 | + # handle the args |
971 | + f = getattr(api, func) |
972 | + try: |
973 | + piston_reply = f(**kwargs) |
974 | + except: |
975 | + LOG.exception("urclient_apps") |
976 | + sys.exit(1) |
977 | + |
978 | + # print to stdout where its consumed by the parent |
979 | + if piston_reply is None: |
980 | + LOG.warn("no data") |
981 | + sys.exit(0) |
982 | + |
983 | + # check what format to use |
984 | + if args.output == "pickle": |
985 | + res = pickle.dumps(piston_reply) |
986 | + elif args.output == "json": |
987 | + res = json.dumps(piston_reply) |
988 | + elif args.output == "text": |
989 | + res = piston_reply |
990 | + |
991 | + # and output it |
992 | + try: |
993 | + print res |
994 | + except IOError: |
995 | + # this can happen if the parent gets killed, no need to trigger |
996 | + # apport for this |
997 | + pass |
998 | |
999 | === removed file 'utils/piston-helpers/piston_get_review_stats_helper.py' |
1000 | --- utils/piston-helpers/piston_get_review_stats_helper.py 2011-07-13 14:25:55 +0000 |
1001 | +++ utils/piston-helpers/piston_get_review_stats_helper.py 1970-01-01 00:00:00 +0000 |
1002 | @@ -1,65 +0,0 @@ |
1003 | -#!/usr/bin/python |
1004 | - |
1005 | -import os |
1006 | -import pickle |
1007 | -import logging |
1008 | -import sys |
1009 | - |
1010 | -from optparse import OptionParser |
1011 | - |
1012 | -from softwarecenter.paths import SOFTWARE_CENTER_CACHE_DIR |
1013 | -from softwarecenter.backend.piston.rnrclient import RatingsAndReviewsAPI |
1014 | - |
1015 | -LOG = logging.getLogger(__name__) |
1016 | - |
1017 | -if __name__ == "__main__": |
1018 | - logging.basicConfig() |
1019 | - |
1020 | - # common options for optparse go here |
1021 | - parser = OptionParser() |
1022 | - |
1023 | - # check options |
1024 | - parser.add_option("--origin", default="any") |
1025 | - parser.add_option("--distroseries", default="any") |
1026 | - parser.add_option("--days-delta", default=None) |
1027 | - parser.add_option("--debug", |
1028 | - action="store_true", default=False) |
1029 | - parser.add_option("--no-pickle", |
1030 | - action="store_true", default=False) |
1031 | - (options, args) = parser.parse_args() |
1032 | - |
1033 | - if options.debug: |
1034 | - LOG.setLevel(logging.DEBUG) |
1035 | - |
1036 | - cachedir = os.path.join(SOFTWARE_CENTER_CACHE_DIR, "rnrclient") |
1037 | - rnrclient = RatingsAndReviewsAPI(cachedir=cachedir) |
1038 | - |
1039 | - kwargs = {"origin": options.origin, |
1040 | - "distroseries": options.distroseries, |
1041 | - } |
1042 | - if options.days_delta: |
1043 | - kwargs["days"] = int(options.days_delta) |
1044 | - |
1045 | - # depending on the time delta, use a different call |
1046 | - piston_review_stats = [] |
1047 | - try: |
1048 | - piston_review_stats = rnrclient.review_stats(**kwargs) |
1049 | - except: |
1050 | - LOG.exception("get_review_stats") |
1051 | - sys.exit(1) |
1052 | - |
1053 | - # useful for debugging |
1054 | - if options.no_pickle: |
1055 | - print "\n".join(["pkgname=%s total=%s avg=%s" % (s.package_name, |
1056 | - s.ratings_total, |
1057 | - s.ratings_average) |
1058 | - for s in piston_review_stats]) |
1059 | - else: |
1060 | - # print to stdout where its consumed by the parent |
1061 | - try: |
1062 | - print pickle.dumps(piston_review_stats) |
1063 | - except IOError: |
1064 | - # this can happen if the parent gets killed, no need to trigger |
1065 | - # apport for this |
1066 | - sys.exit(1) |
1067 | - |
1068 | |
1069 | === removed file 'utils/piston-helpers/piston_get_scagent_available_apps.py' |
1070 | --- utils/piston-helpers/piston_get_scagent_available_apps.py 2012-01-05 09:53:52 +0000 |
1071 | +++ utils/piston-helpers/piston_get_scagent_available_apps.py 1970-01-01 00:00:00 +0000 |
1072 | @@ -1,197 +0,0 @@ |
1073 | -#!/usr/bin/python |
1074 | - |
1075 | -from gi.repository import GObject |
1076 | - |
1077 | -import argparse |
1078 | -import logging |
1079 | -import os |
1080 | -import pickle |
1081 | -import sys |
1082 | - |
1083 | -import piston_mini_client.auth |
1084 | - |
1085 | -from softwarecenter.enums import (SOFTWARE_CENTER_NAME_KEYRING, |
1086 | - SOFTWARE_CENTER_SSO_DESCRIPTION, |
1087 | - ) |
1088 | -from softwarecenter.paths import SOFTWARE_CENTER_CACHE_DIR |
1089 | -from softwarecenter.backend.piston.scaclient import SoftwareCenterAgentAPI |
1090 | -from softwarecenter.backend.login_sso import get_sso_backend |
1091 | -from softwarecenter.backend.restfulclient import UbuntuSSOAPI |
1092 | -from softwarecenter.utils import clear_token_from_ubuntu_sso |
1093 | - |
1094 | -from gettext import gettext as _ |
1095 | - |
1096 | -LOG = logging.getLogger(__name__) |
1097 | - |
1098 | -class SSOLoginHelper(object): |
1099 | - def __init__(self, xid=0): |
1100 | - self.oauth = None |
1101 | - self.xid = xid |
1102 | - self.loop = GObject.MainLoop(GObject.main_context_default()) |
1103 | - |
1104 | - def _login_successful(self, sso_backend, oauth_result): |
1105 | - LOG.debug("_login_successful") |
1106 | - self.oauth = oauth_result |
1107 | - # FIXME: actually verify the token against ubuntu SSO |
1108 | - self.loop.quit() |
1109 | - |
1110 | - def verify_token(self, token): |
1111 | - LOG.debug("verify_token") |
1112 | - def _whoami_done(sso, me): |
1113 | - self._whoami = me |
1114 | - self.loop.quit() |
1115 | - self._whoami = None |
1116 | - sso = UbuntuSSOAPI(token) |
1117 | - sso.connect("whoami", _whoami_done) |
1118 | - sso.connect("error", lambda sso, err: self.loop.quit()) |
1119 | - sso.whoami() |
1120 | - self.loop.run() |
1121 | - LOG.debug("verify_token finished") |
1122 | - # check if the token is valid |
1123 | - if self._whoami is None: |
1124 | - return False |
1125 | - else: |
1126 | - return True |
1127 | - |
1128 | - def clear_token(self): |
1129 | - clear_token_from_ubuntu_sso(SOFTWARE_CENTER_NAME_KEYRING) |
1130 | - |
1131 | - def get_oauth_token_sync(self): |
1132 | - self.oauth = None |
1133 | - sso = get_sso_backend( |
1134 | - self.xid, |
1135 | - SOFTWARE_CENTER_NAME_KEYRING, |
1136 | - _(SOFTWARE_CENTER_SSO_DESCRIPTION)) |
1137 | - sso.connect("login-successful", self._login_successful) |
1138 | - sso.connect("login-failed", lambda s: self.loop.quit()) |
1139 | - sso.connect("login-canceled", lambda s: self.loop.quit()) |
1140 | - sso.login_or_register() |
1141 | - self.loop.run() |
1142 | - return self.oauth |
1143 | - |
1144 | -if __name__ == "__main__": |
1145 | - logging.basicConfig() |
1146 | - |
1147 | - # command line parser |
1148 | - parser = argparse.ArgumentParser(description="Helper for software-center-agent") |
1149 | - parser.add_argument("--debug", action="store_true", default=False, |
1150 | - help="enable debug output") |
1151 | - parser.add_argument("--ignore-cache", action="store_true", default=False, |
1152 | - help="force ignore cache") |
1153 | - parser.add_argument("--parent-xid", default=0, |
1154 | - help="xid of the parent window") |
1155 | - |
1156 | - subparser = parser.add_subparsers(title="Commands") |
1157 | - # available_apps |
1158 | - command = subparser.add_parser("available_apps") |
1159 | - command.add_argument("lang") |
1160 | - command.add_argument("series") |
1161 | - command.add_argument("arch") |
1162 | - command.set_defaults(command="available_apps") |
1163 | - |
1164 | - # available_apps_qa |
1165 | - command = subparser.add_parser("available_apps_qa") |
1166 | - command.add_argument("lang") |
1167 | - command.add_argument("series") |
1168 | - command.add_argument("arch") |
1169 | - command.set_defaults(command="available_apps_qa") |
1170 | - # subscriptions |
1171 | - command = subparser.add_parser("subscriptions_for_me") |
1172 | - command.set_defaults(command="subscriptions_for_me") |
1173 | - # exhibits |
1174 | - command = subparser.add_parser("exhibits") |
1175 | - command.add_argument("lang") |
1176 | - command.add_argument("series") |
1177 | - command.set_defaults(command="exhibits") |
1178 | - |
1179 | - args = parser.parse_args() |
1180 | - |
1181 | - if args.debug: |
1182 | - LOG.setLevel(logging.DEBUG) |
1183 | - |
1184 | - if args.ignore_cache: |
1185 | - cachedir = None |
1186 | - else: |
1187 | - cachedir = os.path.join(SOFTWARE_CENTER_CACHE_DIR, "scaclient") |
1188 | - |
1189 | - |
1190 | - # check if auth is required |
1191 | - if args.command in ("available_apps_qa", "subscriptions_for_me"): |
1192 | - helper = SSOLoginHelper(args.parent_xid) |
1193 | - token = helper.get_oauth_token_sync() |
1194 | - # check if the token is valid and reset it if it is not |
1195 | - if token and not helper.verify_token(token): |
1196 | - helper.clear_token() |
1197 | - # re-trigger login |
1198 | - token = helper.get_oauth_token_sync() |
1199 | - # if we don't have a token, error here |
1200 | - if not token: |
1201 | - sys.stderr.write("ERROR: can not obtain a oauth token\n") |
1202 | - sys.exit(1) |
1203 | - |
1204 | - auth = piston_mini_client.auth.OAuthAuthorizer(token["token"], |
1205 | - token["token_secret"], |
1206 | - token["consumer_key"], |
1207 | - token["consumer_secret"]) |
1208 | - scaclient = SoftwareCenterAgentAPI(cachedir=cachedir, auth=auth) |
1209 | - else: |
1210 | - scaclient = SoftwareCenterAgentAPI(cachedir=cachedir) |
1211 | - |
1212 | - piston_reply = None |
1213 | - |
1214 | - # common kwargs |
1215 | - if args.command in ("available_apps", "available_apps_qa"): |
1216 | - kwargs = {"lang": args.lang, |
1217 | - "series": args.series, |
1218 | - "arch": args.arch |
1219 | - } |
1220 | - |
1221 | - # handle the args |
1222 | - if args.command == "available_apps": |
1223 | - try: |
1224 | - piston_reply = scaclient.available_apps(**kwargs) |
1225 | - except: |
1226 | - LOG.exception("available_apps") |
1227 | - sys.exit(1) |
1228 | - |
1229 | - elif args.command == "available_apps_qa": |
1230 | - try: |
1231 | - piston_reply = scaclient.available_apps_qa(**kwargs) |
1232 | - except: |
1233 | - LOG.exception("available_apps_qa") |
1234 | - sys.exit(1) |
1235 | - elif args.command == "subscriptions_for_me": |
1236 | - try: |
1237 | - piston_reply = scaclient.subscriptions_for_me(complete_only=True) |
1238 | - # the new piston API send the data in a nasty format, most |
1239 | - # interessting stuff is in the "application" dict, move it |
1240 | - # back int othe main object here so that the parser understands it |
1241 | - for item in piston_reply: |
1242 | - for k, v in item.application.iteritems(): |
1243 | - setattr(item, k, v) |
1244 | - except: |
1245 | - LOG.exception("subscriptions_for_me") |
1246 | - sys.exit(1) |
1247 | - if args.command == "exhibits": |
1248 | - try: |
1249 | - piston_reply = scaclient.exhibits(lang=args.lang, series=args.series) |
1250 | - except: |
1251 | - LOG.exception("exhibits") |
1252 | - sys.exit(1) |
1253 | - |
1254 | - if args.debug: |
1255 | - LOG.debug("reply: %s" % piston_reply) |
1256 | - for item in piston_reply: |
1257 | - for var in vars(item): |
1258 | - print "%s: %s" % (var, getattr(item, var)) |
1259 | - print "\n\n" |
1260 | - |
1261 | - |
1262 | - # print to stdout where its consumed by the parent |
1263 | - if piston_reply is not None: |
1264 | - try: |
1265 | - print pickle.dumps(piston_reply) |
1266 | - except IOError: |
1267 | - # this can happen if the parent gets killed, no need to trigger |
1268 | - # apport for this |
1269 | - pass |
1270 | |
1271 | === removed file 'utils/piston-helpers/piston_get_useful_votes_helper.py' |
1272 | --- utils/piston-helpers/piston_get_useful_votes_helper.py 2011-08-19 11:25:58 +0000 |
1273 | +++ utils/piston-helpers/piston_get_useful_votes_helper.py 1970-01-01 00:00:00 +0000 |
1274 | @@ -1,46 +0,0 @@ |
1275 | -#!/usr/bin/python |
1276 | - |
1277 | -import pickle |
1278 | -import logging |
1279 | -import sys |
1280 | - |
1281 | -from optparse import OptionParser |
1282 | -from softwarecenter.backend.piston.rnrclient import RatingsAndReviewsAPI |
1283 | -from piston_mini_client import APIError |
1284 | - |
1285 | -LOG = logging.getLogger(__name__) |
1286 | - |
1287 | -if __name__ == "__main__": |
1288 | - logging.basicConfig() |
1289 | - |
1290 | - # common options for optparse go here |
1291 | - parser = OptionParser() |
1292 | - |
1293 | - # check options |
1294 | - parser.add_option("--username", default=None) |
1295 | - (options, args) = parser.parse_args() |
1296 | - |
1297 | - rnrclient = RatingsAndReviewsAPI() |
1298 | - |
1299 | - useful_votes = [] |
1300 | - |
1301 | - if options.username: |
1302 | - try: |
1303 | - useful_votes = rnrclient.get_usefulness(username=options.username) |
1304 | - except ValueError as e: |
1305 | - LOG.error("failed to parse '%s'" % e.doc) |
1306 | - except APIError, e: |
1307 | - LOG.warn("_get_useful_votes_helper: no usefulness able to be retrieved for username: %s" % (options.username)) |
1308 | - LOG.debug("_get_reviews_threaded: no reviews able to be retrieved: %s" % e) |
1309 | - except: |
1310 | - LOG.exception("_get_useful_votes_helper") |
1311 | - sys.exit(1) |
1312 | - |
1313 | - # print to stdout where its consumed by the parent |
1314 | - try: |
1315 | - print pickle.dumps(useful_votes) |
1316 | - except IOError: |
1317 | - # this can happen if the parent gets killed, no need to trigger |
1318 | - # apport for this |
1319 | - pass |
1320 | - |
1321 | |
1322 | === modified file 'utils/submit_review_gtk3.py' |
1323 | --- utils/submit_review_gtk3.py 2011-10-24 07:49:37 +0000 |
1324 | +++ utils/submit_review_gtk3.py 2012-01-05 15:32:23 +0000 |
1325 | @@ -50,7 +50,7 @@ |
1326 | from gettext import gettext as _ |
1327 | from optparse import OptionParser |
1328 | |
1329 | -from softwarecenter.backend.restfulclient import get_ubuntu_sso_backend |
1330 | +from softwarecenter.backend.ubuntusso import get_ubuntu_sso_backend |
1331 | |
1332 | import piston_mini_client |
1333 | |
1334 | @@ -490,6 +490,8 @@ |
1335 | self.ssoapi = get_ubuntu_sso_backend(self.token) |
1336 | self.ssoapi.connect("whoami", self._whoami_done) |
1337 | self.ssoapi.connect("error", self._whoami_error) |
1338 | + # this will automatically verify the token and retrigger login |
1339 | + # if its expired |
1340 | self.ssoapi.whoami() |
1341 | |
1342 | def _whoami_done(self, ssologin, result): |
1343 | @@ -500,22 +502,6 @@ |
1344 | |
1345 | def _whoami_error(self, ssologin, e): |
1346 | logging.error("whoami error '%s'" % e) |
1347 | - # HACK: clear the token from the keyring assuming that it expired |
1348 | - # or got deauthorized by the user on the website |
1349 | - # this really should be done by ubuntu-sso-client itself |
1350 | - import lazr.restfulclient.errors |
1351 | - # compat with maverick, it does not have Unauthorized yet |
1352 | - if hasattr(lazr.restfulclient.errors, "Unauthorized"): |
1353 | - errortype = lazr.restfulclient.errors.Unauthorized |
1354 | - else: |
1355 | - errortype = lazr.restfulclient.errors.HTTPError |
1356 | - if (type(e) == errortype and |
1357 | - self._whoami_token_reset_nr == 0): |
1358 | - logging.warn("authentication error, reseting token and retrying") |
1359 | - clear_token_from_ubuntu_sso(self.appname) |
1360 | - self._whoami_token_reset_nr += 1 |
1361 | - self.login(show_register=False) |
1362 | - return |
1363 | # show error |
1364 | self.status_spinner.hide() |
1365 | self.login_status_label.set_markup('<b><big>%s</big></b>' % _("Failed to log in")) |
in line 118 of backend/scagent.py we want 'exhibits' rather than 'exhiits'