diff options
author | Walter Bender <walter@sugarlabs.org> | 2013-05-12 23:45:32 (GMT) |
---|---|---|
committer | Walter Bender <walter@sugarlabs.org> | 2013-05-12 23:45:32 (GMT) |
commit | 2db9dee01ab0e12a6b53c0da844b285a9312cab1 (patch) | |
tree | 04a804fd38ea0597a824709f7b29b706e3a5ccd5 | |
parent | d0110fcdeb9c0c5d83e3730215410ba720e21702 (diff) |
resync to latest version of patches submitted to sugar upstream on github
-rw-r--r-- | extensions/cpsection/webservices/services/facebook/service.py | 2 | ||||
-rw-r--r-- | extensions/cpsection/webservices/services/twitter/service.py | 2 | ||||
-rw-r--r-- | extensions/web/facebook/Makefile.am | 2 | ||||
-rw-r--r-- | extensions/web/facebook/account.py (renamed from extensions/web/facebook/facebookaccount.py) | 0 | ||||
-rw-r--r-- | extensions/web/facebook/facebook_online_account.py | 283 | ||||
-rw-r--r-- | extensions/web/twitter/Makefile.am | 2 | ||||
-rw-r--r-- | extensions/web/twitter/account.py (renamed from extensions/web/twitter/twitteraccount.py) | 0 | ||||
-rw-r--r-- | extensions/web/twitter/twitter_online_account.py | 284 | ||||
-rw-r--r-- | src/jarabe/journal/palettes.py | 4 | ||||
-rw-r--r-- | src/jarabe/web/__init__.py | 15 | ||||
-rw-r--r-- | src/jarabe/web/account.py | 115 | ||||
-rw-r--r-- | src/jarabe/web/accountsmanager.py | 62 | ||||
-rw-r--r-- | src/jarabe/web/online_account.py | 60 | ||||
-rw-r--r-- | src/jarabe/web/online_accounts_manager.py | 77 |
14 files changed, 148 insertions, 760 deletions
diff --git a/extensions/cpsection/webservices/services/facebook/service.py b/extensions/cpsection/webservices/services/facebook/service.py index f4c7b2e..5f5a183 100644 --- a/extensions/cpsection/webservices/services/facebook/service.py +++ b/extensions/cpsection/webservices/services/facebook/service.py @@ -26,7 +26,7 @@ from gi.repository import GObject from gi.repository import WebKit from gettext import gettext as _ from jarabe import config -from web.facebook import facebook_online_account as fboa +from web.facebook import account as fboa from cpsection.webservices.web_service import WebService diff --git a/extensions/cpsection/webservices/services/twitter/service.py b/extensions/cpsection/webservices/services/twitter/service.py index f404553..c7884b9 100644 --- a/extensions/cpsection/webservices/services/twitter/service.py +++ b/extensions/cpsection/webservices/services/twitter/service.py @@ -23,7 +23,7 @@ from gettext import gettext as _ from web.twitter.twitter.twr_oauth import TwrOauth from web.twitter.twitter.twr_account import TwrAccount -from web.twitter.twitter_online_account import TwitterOnlineAccount as twr +from web.twitter.account import TwitterOnlineAccount as twr from cpsection.webservices.web_service import WebService diff --git a/extensions/web/facebook/Makefile.am b/extensions/web/facebook/Makefile.am index f9bac63..1a08cc0 100644 --- a/extensions/web/facebook/Makefile.am +++ b/extensions/web/facebook/Makefile.am @@ -3,4 +3,4 @@ SUBDIRS = facebook icons sugardir = $(pkgdatadir)/extensions/web/facebook sugar_PYTHON = \ __init__.py \ - facebookaccount.py + account.py diff --git a/extensions/web/facebook/facebookaccount.py b/extensions/web/facebook/account.py index f105fdb..f105fdb 100644 --- a/extensions/web/facebook/facebookaccount.py +++ b/extensions/web/facebook/account.py diff --git a/extensions/web/facebook/facebook_online_account.py b/extensions/web/facebook/facebook_online_account.py deleted file mode 100644 index e8d306b..0000000 --- a/extensions/web/facebook/facebook_online_account.py +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2013 Walter Bender, Raul Gutierrez Segales - -#Permission is hereby granted, free of charge, to any person obtaining a copy -#of this software and associated documentation files (the "Software"), to deal -#in the Software without restriction, including without limitation the rights -#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -#copies of the Software, and to permit persons to whom the Software is -#furnished to do so, subject to the following conditions: - -#The above copyright notice and this permission notice shall be included in -#all copies or substantial portions of the Software. - -#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -#THE SOFTWARE. - -from gettext import gettext as _ -import logging -import os -import tempfile -import time -import json - -from facebook import facebook - -from gi.repository import Gtk -from gi.repository import GdkPixbuf -from gi.repository import GConf -from gi.repository import GObject - -from sugar3.datastore import datastore -from sugar3.graphics.alert import NotifyAlert -from sugar3.graphics.icon import Icon - -from jarabe.journal import journalwindow - -from jarabe.web import online_account - -ACCOUNT_NEEDS_ATTENTION = 0 -ACCOUNT_ACTIVE = 1 -ONLINE_ACCOUNT_NAME = _('Facebook') -COMMENTS = 'comments' -COMMENT_IDS = 'fb_comment_ids' - -class FacebookOnlineAccount(online_account.OnlineAccount): - - ACCESS_TOKEN_KEY = "/desktop/sugar/collaboration/facebook_access_token" - ACCESS_TOKEN_KEY_EXPIRATION_DATE = \ - "/desktop/sugar/collaboration/facebook_access_token_expiration_date" - - def __init__(self): - online_account.OnlineAccount.__init__(self) - self._client = GConf.Client.get_default() - facebook.FbAccount.set_access_token(self._access_token()) - self._alert = None - - def get_description(self): - return ONLINE_ACCOUNT_NAME - - def is_configured(self): - return self._access_token() is not None - - def is_active(self): - expiration_date = \ - self._client.get_int(self.ACCESS_TOKEN_KEY_EXPIRATION_DATE) - return expiration_date != 0 and expiration_date > time.time() - - def get_share_menu(self, journal_entry_metadata): - fb_share_menu = _FacebookShareMenu(journal_entry_metadata, - self.is_active()) - self._connect_transfer_signals(fb_share_menu) - return fb_share_menu - - def get_refresh_menu(self): - fb_refresh_menu = _FacebookRefreshMenu(self.is_active()) - self._connect_transfer_signals(fb_refresh_menu) - return fb_refresh_menu - - def _connect_transfer_signals(self, transfer_widget): - transfer_widget.connect('transfer-state-changed', - self._transfer_state_changed_cb) - - def _transfer_state_changed_cb(self, widget, state_message): - logging.debug('_transfer_state_changed_cb') - - # First, remove any existing alert - if self._alert is None: - logging.debug('creating new alert') - self._alert = NotifyAlert() - self._alert.props.title = ONLINE_ACCOUNT_NAME - self._alert.connect('response', self._alert_response_cb) - journalwindow.get_journal_window().add_alert(self._alert) - self._alert.show() - - logging.debug(state_message) - self._alert.props.msg = state_message - - def _alert_response_cb(self, alert, response_id): - journalwindow.get_journal_window().remove_alert(alert) - self._alert = None - - def _access_token(self): - return self._client.get_string(self.ACCESS_TOKEN_KEY) - - -class _FacebookShareMenu(online_account.OnlineMenu): - __gtype_name__ = 'JournalFacebookMenu' - - def __init__(self, metadata, is_active): - online_account.OnlineMenu.__init__(self, ONLINE_ACCOUNT_NAME) - - if is_active: - icon_name = 'facebook-share' - else: - icon_name = 'facebook-share-insensitive' - self.set_image(Icon(icon_name=icon_name, - icon_size=Gtk.IconSize.MENU)) - self.show() - self._metadata = metadata - self._comment = '%s: %s' % (self._get_metadata_by_key('title'), - self._get_metadata_by_key('description')) - - self.connect('activate', self._facebook_share_menu_cb) - - def _get_metadata_by_key(self, key, default_value=''): - if key in self._metadata: - return self._metadata[key] - return default_value - - def _facebook_share_menu_cb(self, menu_item): - logging.debug('_facebook_share_menu_cb') - - self.emit('transfer-state-changed', _('Upload started')) - tmp_file = tempfile.mktemp() - self._image_file_from_metadata(tmp_file) - - photo = facebook.FbPhoto() - photo.connect('photo-created', self._photo_created_cb, tmp_file) - photo.connect('photo-create-failed', - self._photo_create_failed_cb, - tmp_file) - photo.connect('transfer-state-changed', - self._transfer_state_changed_cb) - - GObject.idle_add(photo.create, tmp_file) - - def _photo_created_cb(self, fb_photo, fb_object_id, tmp_file): - logging.debug("_photo_created_cb") - - if os.path.exists(tmp_file): - os.unlink(tmp_file) - - fb_photo.connect('comment-added', self._comment_added_cb) - fb_photo.connect('comment-add-failed', self._comment_add_failed_cb) - fb_photo.add_comment(self._comment) - - try: - ds_object = datastore.get(self._metadata['uid']) - ds_object.metadata['fb_object_id'] = fb_object_id - datastore.write(ds_object, update_mtime=False) - except Exception as ex: - logging.debug("_photo_created_cb failed to write to datastore: " % \ - str(ex)) - - def _photo_create_failed_cb(self, fb_photo, failed_reason, tmp_file): - logging.debug("_photo_create_failed_cb") - - if os.path.exists(tmp_file): - os.unlink(tmp_file) - - def _comment_added_cb(self, fb_photo, fb_comment_id): - logging.debug("_comment_added_cb") - - def _comment_add_failed_cb(self, fb_photo, failed_reason): - logging.debug("_comment_add_failed_cb") - - def _image_file_from_metadata(self, image_path): - """ Load a pixbuf from a Journal object. """ - pixbufloader = \ - GdkPixbuf.PixbufLoader.new_with_mime_type('image/png') - pixbufloader.set_size(300, 225) - try: - pixbufloader.write(self._metadata['preview']) - pixbuf = pixbufloader.get_pixbuf() - except Exception as ex: - logging.debug("_image_file_from_metadata: %s" % (str(ex))) - pixbuf = None - - pixbufloader.close() - if pixbuf: - pixbuf.savev(image_path, 'png', [], []) - - -class _FacebookRefreshMenu(online_account.OnlineMenu): - def __init__(self, is_active): - online_account.OnlineMenu.__init__(self, ONLINE_ACCOUNT_NAME) - - self._is_active = is_active - self._metadata = None - - if is_active: - icon_name = 'facebook-refresh' - else: - icon_name = 'facebook-refresh-insensitive' - self.set_image(Icon(icon_name=icon_name, - icon_size=Gtk.IconSize.MENU)) - self.show() - - self.connect('activate', self._fb_refresh_menu_clicked_cb) - - def set_metadata(self, metadata): - self._metadata = metadata - if self._is_active: - if self._metadata: - if 'fb_object_id' in self._metadata: - self.set_sensitive(True) - icon_name = 'facebook-refresh' - else: - self.set_sensitive(False) - icon_name = 'facebook-refresh-insensitive' - self.set_image(Icon(icon_name=icon_name, - icon_size=Gtk.IconSize.MENU)) - - def _fb_refresh_menu_clicked_cb(self, button): - logging.debug('_fb_refresh_menu_clicked_cb') - - if self._metadata is None: - logging.debug('_fb_refresh_menu_clicked_cb called without metadata') - return - - if 'fb_object_id' not in self._metadata: - logging.debug('_fb_refresh_menu_clicked_cb called without fb_object_id in metadata') - return - - self.emit('transfer-state-changed', _('Download started')) - fb_photo = facebook.FbPhoto(self._metadata['fb_object_id']) - fb_photo.connect('comments-downloaded', - self._fb_comments_downloaded_cb) - fb_photo.connect('comments-download-failed', - self._fb_comments_download_failed_cb) - fb_photo.connect('transfer-state-changed', - self._transfer_state_changed_cb) - GObject.idle_add(fb_photo.refresh_comments) - - def _fb_comments_downloaded_cb(self, fb_photo, comments): - logging.debug('_fb_comments_downloaded_cb') - - ds_object = datastore.get(self._metadata['uid']) - if not COMMENTS in ds_object.metadata: - ds_comments = [] - else: - ds_comments = json.loads(ds_object.metadata[COMMENTS]) - if not COMMENT_IDS in ds_object.metadata: - ds_comment_ids = [] - else: - ds_comment_ids = json.loads(ds_object.metadata[COMMENT_IDS]) - new_comment = False - for comment in comments: - if comment['id'] not in ds_comment_ids: - # TODO: get avatar icon and add it to icon_theme - ds_comments.append({'from': comment['from'], - 'message': comment['message'], - 'icon': 'facebook-share'}) - ds_comment_ids.append(comment['id']) - new_comment = True - if new_comment: - ds_object.metadata[COMMENTS] = json.dumps(ds_comments) - ds_object.metadata[COMMENT_IDS] = json.dumps(ds_comment_ids) - self.emit('comments-changed', ds_object.metadata[COMMENTS]) - - datastore.write(ds_object, update_mtime=False) - - def _fb_comments_download_failed_cb(self, fb_photo, failed_reason): - logging.debug('_fb_comments_download_failed_cb: %s' % (failed_reason)) - -def get_account(): - return FacebookOnlineAccount() diff --git a/extensions/web/twitter/Makefile.am b/extensions/web/twitter/Makefile.am index 438d3fa..2fb2c6b 100644 --- a/extensions/web/twitter/Makefile.am +++ b/extensions/web/twitter/Makefile.am @@ -3,4 +3,4 @@ SUBDIRS = twitter icons sugardir = $(pkgdatadir)/extensions/web/twitter sugar_PYTHON = \ __init__.py \ - twitteraccount.py + account.py diff --git a/extensions/web/twitter/twitteraccount.py b/extensions/web/twitter/account.py index a2e4bf0..a2e4bf0 100644 --- a/extensions/web/twitter/twitteraccount.py +++ b/extensions/web/twitter/account.py diff --git a/extensions/web/twitter/twitter_online_account.py b/extensions/web/twitter/twitter_online_account.py deleted file mode 100644 index 89f7d8f..0000000 --- a/extensions/web/twitter/twitter_online_account.py +++ /dev/null @@ -1,284 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2013 Walter Bender, Raul Gutierrez Segales, Martin Abente - -#Permission is hereby granted, free of charge, to any person obtaining a copy -#of this software and associated documentation files (the "Software"), to deal -#in the Software without restriction, including without limitation the rights -#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -#copies of the Software, and to permit persons to whom the Software is -#furnished to do so, subject to the following conditions: - -#The above copyright notice and this permission notice shall be included in -#all copies or substantial portions of the Software. - -#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -#THE SOFTWARE. - -from gettext import gettext as _ -import logging -import os -import tempfile -import time -import json - -from twitter.twr_account import TwrAccount -from twitter.twr_status import TwrStatus -from twitter.twr_timeline import TwrTimeline - -from gi.repository import Gtk -from gi.repository import GdkPixbuf -from gi.repository import GConf -from gi.repository import GObject - -from sugar3.datastore import datastore -from sugar3.graphics.alert import NotifyAlert -from sugar3.graphics.icon import Icon - -from jarabe.journal import journalwindow - -from jarabe.web import online_account - -ACCOUNT_NEEDS_ATTENTION = 0 -ACCOUNT_ACTIVE = 1 -ONLINE_ACCOUNT_NAME = _('Twitter') -COMMENTS = 'comments' -COMMENT_IDS = 'twr_comment_ids' -COMMENT_LAST_ID = 'last_comment_id' - -class TwitterOnlineAccount(online_account.OnlineAccount): - - CONSUMER_TOKEN_KEY = "/desktop/sugar/collaboration/twitter_consumer_token" - CONSUMER_SECRET_KEY = "/desktop/sugar/collaboration/twitter_consumer_secret" - ACCESS_TOKEN_KEY = "/desktop/sugar/collaboration/twitter_access_token" - ACCESS_SECRET_KEY = "/desktop/sugar/collaboration/twitter_access_secret" - - def __init__(self): - online_account.OnlineAccount.__init__(self) - self._client = GConf.Client.get_default() - ctoken, csecret, atoken, asecret = self._access_tokens() - TwrAccount.set_secrets(ctoken, csecret, atoken, asecret) - self._alert = None - - def get_description(self): - return ONLINE_ACCOUNT_NAME - - def is_configured(self): - return None not in self._access_tokens() - - def is_active(self): - # No expiration date - return None not in self._access_tokens() - - def get_share_menu(self, journal_entry_metadata): - twr_share_menu = _TwitterShareMenu(journal_entry_metadata, - self.is_active()) - self._connect_transfer_signals(twr_share_menu) - return twr_share_menu - - def get_refresh_menu(self): - twr_refresh_menu = _TwitterRefreshMenu(self.is_active()) - self._connect_transfer_signals(twr_refresh_menu) - return twr_refresh_menu - - def _connect_transfer_signals(self, transfer_widget): - transfer_widget.connect('transfer-state-changed', - self._transfer_state_changed_cb) - - def _transfer_state_changed_cb(self, widget, state_message): - logging.debug('_transfer_state_changed_cb') - - # First, remove any existing alert - if self._alert is None: - self._alert = NotifyAlert() - self._alert.props.title = ONLINE_ACCOUNT_NAME - self._alert.connect('response', self._alert_response_cb) - journalwindow.get_journal_window().add_alert(self._alert) - self._alert.show() - - logging.debug(state_message) - self._alert.props.msg = state_message - - def _alert_response_cb(self, alert, response_id): - journalwindow.get_journal_window().remove_alert(alert) - self._alert = None - - def _access_tokens(self): - return (self._client.get_string(self.CONSUMER_TOKEN_KEY), - self._client.get_string(self.CONSUMER_SECRET_KEY), - self._client.get_string(self.ACCESS_TOKEN_KEY), - self._client.get_string(self.ACCESS_SECRET_KEY)) - - -class _TwitterShareMenu(online_account.OnlineMenu): - __gtype_name__ = 'JournalTwitterMenu' - - def __init__(self, metadata, is_active): - online_account.OnlineMenu.__init__(self, ONLINE_ACCOUNT_NAME) - - if is_active: - icon_name = 'twitter-share' - else: - icon_name = 'twitter-share-insensitive' - self.set_image(Icon(icon_name=icon_name, - icon_size=Gtk.IconSize.MENU)) - self.show() - self._metadata = metadata - self._comment = '%s: %s' % (self._get_metadata_by_key('title'), - self._get_metadata_by_key('description')) - - self.connect('activate', self._twitter_share_menu_cb) - - def _get_metadata_by_key(self, key, default_value=''): - if key in self._metadata: - return self._metadata[key] - return default_value - - def _status_updated_cb(self, status, data, tmp_file): - if os.path.exists(tmp_file): - os.unlink(tmp_file) - try: - ds_object = datastore.get(self._metadata['uid']) - ds_object.metadata['twr_object_id'] = status._status_id - datastore.write(ds_object, update_mtime=False) - except Exception as e: - logging.debug('_status_updated_cb failed to write: %s', str(e)) - - def _status_updated_failed_cb(self, status, message, tmp_file): - if os.path.exists(tmp_file): - os.unlink(tmp_file) - logging.error('_status_updated_failed_cb %s', message) - - def _twitter_share_menu_cb(self, menu_item): - logging.debug('_twitter_share_menu_cb') - - self.emit('transfer-state-changed', _('Download started')) - tmp_file = tempfile.mktemp() - self._image_file_from_metadata(tmp_file) - - status = TwrStatus() - status.connect('status-updated', self._status_updated_cb, tmp_file) - status.connect('status-updated-failed', - self._status_updated_failed_cb, tmp_file) - status.update_with_media(self._comment, tmp_file) - - def _image_file_from_metadata(self, image_path): - """ Load a pixbuf from a Journal object. """ - pixbufloader = \ - GdkPixbuf.PixbufLoader.new_with_mime_type('image/png') - pixbufloader.set_size(300, 225) - try: - pixbufloader.write(self._metadata['preview']) - pixbuf = pixbufloader.get_pixbuf() - except Exception as ex: - logging.debug("_image_file_from_metadata: %s" % (str(ex))) - pixbuf = None - - pixbufloader.close() - if pixbuf: - pixbuf.savev(image_path, 'png', [], []) - - -class _TwitterRefreshMenu(online_account.OnlineMenu): - def __init__(self, is_active): - online_account.OnlineMenu.__init__(self, ONLINE_ACCOUNT_NAME) - - self._is_active = is_active - self._metadata = None - - if is_active: - icon_name = 'twitter-refresh' - else: - icon_name = 'twitter-refresh-insensitive' - self.set_image(Icon(icon_name=icon_name, - icon_size=Gtk.IconSize.MENU)) - self.show() - - self.connect('activate', self._twr_refresh_menu_clicked_cb) - - def set_metadata(self, metadata): - self._metadata = metadata - if self._is_active: - if self._metadata: - if 'fb_object_id' in self._metadata: - self.set_sensitive(True) - icon_name = 'twitter-refresh' - else: - self.set_sensitive(False) - icon_name = 'twitter-refresh-insensitive' - self.set_image(Icon(icon_name=icon_name, - icon_size=Gtk.IconSize.MENU)) - - def _twr_refresh_menu_clicked_cb(self, button): - logging.debug('_twr_refresh_menu_clicked_cb') - - if self._metadata is None: - logging.debug('_twr_refresh_menu_clicked_cb called without metadata') - return - - if 'twr_object_id' not in self._metadata: - logging.debug('_twr_refresh_menu_clicked_cb called without twr_object_id in metadata') - return - - self.emit('transfer-state-changed', _('Download started')) - - status_id = self._metadata['twr_object_id'] - - # XXX is there other way to update metadata? - ds_object = datastore.get(self._metadata['uid']) - if COMMENT_LAST_ID in ds_object.metadata: - status_id = ds_object.metadata[COMMENT_LAST_ID] - - timeline = TwrTimeline() - timeline.connect('mentions-downloaded', self._twr_mentions_downloaded_cb) - timeline.mentions_timeline(since_id=status_id) - - def _twr_mentions_downloaded_cb(self, timeline, comments): - logging.debug('_twr_mentions_downloaded_cb') - - ds_object = datastore.get(self._metadata['uid']) - if not COMMENTS in ds_object.metadata: - ds_comments = [] - else: - ds_comments = json.loads(ds_object.metadata[COMMENTS]) - if not COMMENT_IDS in ds_object.metadata: - ds_comment_ids = [] - else: - ds_comment_ids = json.loads(ds_object.metadata[COMMENT_IDS]) - - comment_id = None - new_comment = False - for comment in comments: - # XXX hope for a better API - if comment['in_reply_to_status_id_str'] != self._metadata['twr_object_id']: - continue - - if comment['id_str'] not in ds_comment_ids: - ds_comments.append({'from': comment['user']['name'], - 'message': comment['text'], - 'icon': 'twitter-share'}) - ds_comment_ids.append(comment['id_str']) - - # XXX keep the latest one - if comment['id_str'] > comment_id: - comment_id = comment['id_str'] - new_comment = True - - if new_comment: - ds_object.metadata[COMMENT_LAST_ID] = comment_id - ds_object.metadata[COMMENTS] = json.dumps(ds_comments) - ds_object.metadata[COMMENT_IDS] = json.dumps(ds_comment_ids) - self.emit('comments-changed', ds_object.metadata[COMMENTS]) - - datastore.write(ds_object, update_mtime=False) - - def _twr_comments_download_failed_cb(self, tweet, failed_reason): - logging.debug('_twr_comments_download_failed_cb: %s' % (failed_reason)) - -def get_account(): - return TwitterOnlineAccount() diff --git a/src/jarabe/journal/palettes.py b/src/jarabe/journal/palettes.py index 5ba959e..cc604dc 100644 --- a/src/jarabe/journal/palettes.py +++ b/src/jarabe/journal/palettes.py @@ -39,7 +39,7 @@ from jarabe.model import mimeregistry from jarabe.journal import misc from jarabe.journal import model from jarabe.journal import journalwindow -from jarabe.web import accountsmanager as oam +from jarabe.web import accountsmanager class ObjectPalette(Palette): @@ -252,7 +252,7 @@ class CopyMenu(Gtk.Menu): self.append(volume_menu) volume_menu.show() - for account in oam.get_configured_accounts(): + for account in accountsmanager.get_configured_accounts(): menu = account.get_share_menu(metadata) self.append(menu) diff --git a/src/jarabe/web/__init__.py b/src/jarabe/web/__init__.py index e69de29..85f6a24 100644 --- a/src/jarabe/web/__init__.py +++ b/src/jarabe/web/__init__.py @@ -0,0 +1,15 @@ +# Copyright (C) 2006-2007, Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/src/jarabe/web/account.py b/src/jarabe/web/account.py index f9be23e..2e55f25 100644 --- a/src/jarabe/web/account.py +++ b/src/jarabe/web/account.py @@ -25,54 +25,119 @@ from sugar3.graphics.toolbutton import ToolButton class Account(): ''' Account is a prototype class for online accounts. It provides - stubs for five public methods that are used by online services: - - get_description returns a brief description of the online service - used in palette menuitems and on the webservices control panel. - - is_configured returns True if the service has been configured for - use, e.g., an access token has been acquired. - - is_active returns True if the service is currently available, - e.g., the access token has not expired. - - get_share_menu returns a menu item used on the Copy To palette in - the Journal and on the Journal detail view toolbar. - - get_refresh_menu returns a menu item used on the Journal detail - view toolbar. + stubs for five public methods that are used by online services ''' def get_description(self): + ''' get_description returns a brief description of the online + service. The description is used in palette menuitems and on + the webservices control panel. + + :returns: online-account name + :rtype: string + ''' raise NotImplementedError def is_configured(self): + ''' is_configured returns True if the service has been + configured for use, e.g., an access token has been acquired. + + :returns: configuration status + :rtype: bool + ''' raise NotImplementedError def is_active(self): + ''' is_active returns True if the service is currently + available, e.g., the access token has not expired. + + :returns: active status + :rtype: bool + ''' raise NotImplementedError def get_share_menu(self): + ''' get_share_menu returns a menu item used on the Copy To + palette in the Journal and on the Journal detail-view toolbar. + + :param: journal_entry_metadata + :type: dict + :returns: MenuItem + :rtype: MenuItem + ''' raise NotImplementedError def get_refresh_menu(self): + ''' get_refresh_menu returns a menu item used on the Journal + detail-view toolbar. + + :param: journal_entry_metadata + :type: dict + :returns: MenuItem + :rtype: MenuItem + ''' raise NotImplementedError class MenuItem(MenuItem): + ''' This is a subclass of sugar3.graphics.menuitem.MenuItem + + The transfer signals are used to update progress of data transfer + between Sugar and the online service. Signal handlers in the + journaltoolbox manage a Notification Alert of this progress. + + 'transfer-started' is emitted at the beginning of a transfer. + + 'transfer-progress' is emitted periodically to indicate progress. + + :emits: total data to transfer + :type: float + :emits: quantity of data transfered + :type: float + :emits: message string + :type: string + + 'transfer-completed' is emitted at the successful completion of a + transfer. + + :emits: message string + :type: string + + 'transfer-failed' is emitted at if the transfer fails. + + :emits: message string + :type: string + + 'transfer-state-changed' is emitted when the account manager wants + to indicate a change in state. + + :emits: message string + :type: string + + The comments-changed signal is emitted by the online service if + changes to the 'comments' metadata have been made. The + expandedentry of the Journal detail view displays these comments. + + :emits: metadata['comments'] + :type: string + ''' __gsignals__ = { - 'transfer-started': (GObject.SignalFlags.RUN_FIRST, None, - ([int, int])), + 'transfer-started': (GObject.SignalFlags.RUN_FIRST, None, ([])), 'transfer-progress': (GObject.SignalFlags.RUN_FIRST, None, - ([int, int, float])), - 'transfer-completed': (GObject.SignalFlags.RUN_FIRST, None, - ([int, int])), - 'transfer-failed': (GObject.SignalFlags.RUN_FIRST, None, - ([int, int, str])), + ([int, int, str])), + 'transfer-completed': (GObject.SignalFlags.RUN_FIRST, None, ([str])), + 'transfer-failed': (GObject.SignalFlags.RUN_FIRST, None, ([str])), 'transfer-state-changed': (GObject.SignalFlags.RUN_FIRST, None, ([str])), - 'comments-changed': (GObject.SignalFlags.RUN_FIRST, None, ([str])), - } + 'comments-changed': (GObject.SignalFlags.RUN_FIRST, None, ([str])) + } def set_metadata(self, metadata): + ''' The online account uses this method to set metadata in the + Sugar journal and provide a means of updating menuitem status, + e.g., enabling the refresh menu after a successful transfer. + + :param: journal_entry_metadata + :type: dict + ''' raise NotImplementedError diff --git a/src/jarabe/web/accountsmanager.py b/src/jarabe/web/accountsmanager.py index be083c0..cd1da83 100644 --- a/src/jarabe/web/accountsmanager.py +++ b/src/jarabe/web/accountsmanager.py @@ -22,38 +22,45 @@ from gi.repository import Gtk from jarabe import config +_accounts = [] + def get_all_accounts(): - accounts = [] + ''' Returns a list of all installed online account managers ''' + global _accounts # No need to do this every time. + if len(_accounts) > 0: + return _accounts web_path = os.path.join(config.ext_path, 'web') - if os.path.exists(web_path): - for d in os.listdir(web_path): - dir_path = os.path.join(web_path, d) - module = _load_module(dir_path) - if module is not None: - accounts.append(module) - _load_icon_path(dir_path) + try: + web_path_dirs = os.listdir(web_path) + except OSError, e: + web_path_dirs = [] + logging.warning('listdir: %s: %s' % (web_path, e)) + + for d in web_path_dirs: + dir_path = os.path.join(web_path, d) + module = _load_module(dir_path) + if module is not None: + _accounts.append(module) + _extend_icon_theme_search_path(dir_path) - return accounts + return _accounts def _load_module(dir_path): module = None if os.path.isdir(dir_path): for f in os.listdir(dir_path): - if f.endswith('.py') and not f.startswith('__'): + if f == 'account.py': module_name = f[:-3] logging.debug('OnlineAccountsManager loading %s' % ( module_name)) - + module_path = 'web.%s.%s' % (os.path.basename(dir_path), + module_name) try: - mod = __import__( - 'web.' + os.path.basename(dir_path) + '.' + \ - module_name, - globals(), - locals(), - [module_name]) + mod = __import__(module_path, globals(), locals(), + [module_name]) if hasattr(mod, 'get_account'): module = mod.get_account() @@ -64,17 +71,22 @@ def _load_module(dir_path): return module -def _load_icon_path(dir_path): +def _extend_icon_theme_search_path(dir_path): icon_theme = Gtk.IconTheme.get_default() icon_search_path = icon_theme.get_search_path() - if os.path.isdir(dir_path): - for f in os.listdir(dir_path): - if f == 'icons': - icon_path = os.path.join(dir_path, f) - if os.path.isdir(icon_path) and \ - icon_path not in icon_search_path: - icon_theme.append_search_path(icon_path) + try: + icon_path_dirs = os.listdir(dir_path) + except OSError, e: + icon_path_dirs = [] + logging.warning('listdir: %s: %s' % (dir_path, e)) + + for f in icon_path_dirs: + if f == 'icons': + icon_path = os.path.join(dir_path, f) + if os.path.isdir(icon_path) and \ + icon_path not in icon_search_path: + icon_theme.append_search_path(icon_path) def get_configured_accounts(): diff --git a/src/jarabe/web/online_account.py b/src/jarabe/web/online_account.py deleted file mode 100644 index d0b7a67..0000000 --- a/src/jarabe/web/online_account.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2013 Walter Bender, Raul Gutierrez Segales -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. - -import logging - -from gi.repository import GObject - -from sugar3.graphics.menuitem import MenuItem -from sugar3.graphics.toolbutton import ToolButton - - -class OnlineAccount(GObject.GObject): - def get_description(self): - raise Exception("Not defined") - - def is_configured(self): - raise Exception("Not defined") - - def is_active(self): - raise Exception("Not defined") - - def get_share_menu(self): - raise Exception("Not defined") - - def get_refresh_button(self): - raise Exception("Not defined") - - -class OnlineMenu(MenuItem): - __gsignals__ = { - 'transfer-started': (GObject.SignalFlags.RUN_FIRST, None, ([int, int])), - 'transfer-progress': (GObject.SignalFlags.RUN_FIRST, None, ([int, int, float])), - 'transfer-completed': (GObject.SignalFlags.RUN_FIRST, None, ([int, int])), - 'transfer-failed': (GObject.SignalFlags.RUN_FIRST, None, ([int, int, str])), - 'transfer-state-changed': (GObject.SignalFlags.RUN_FIRST, None, ([str])), - 'comments-changed': (GObject.SignalFlags.RUN_FIRST, None, ([str])), - } - - def _transfer_state_changed_cb(self, transfer_object, state): - logging.debug('_transfer_state_changed_cb') - self.emit('transfer-state-changed', state) - - def set_metadata(self, metadata): - raise Exception("Not defined") diff --git a/src/jarabe/web/online_accounts_manager.py b/src/jarabe/web/online_accounts_manager.py deleted file mode 100644 index d2c26c9..0000000 --- a/src/jarabe/web/online_accounts_manager.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2013 Walter Bender -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. - -from gi.repository import Gtk -from gi.repository import GObject -import logging -import os - -from jarabe import config - - -class OnlineAccountsManager(GObject.GObject): - @classmethod - def all_accounts(cls): - accounts = [] - - icon_theme = Gtk.IconTheme.get_default() - icon_search_path = icon_theme.get_search_path() - - web_paths = [os.path.join(config.ext_path, 'web'), - os.path.join(os.path.expanduser('~'), - '.sugar', 'extensions', 'web')] - - for web_path in web_paths: - if os.path.exists(web_path): - for d in os.listdir(web_path): - dir_path = os.path.join(web_path, d) - if os.path.isdir(dir_path): - for f in os.listdir(dir_path): - if f.endswith('.py') and not f.startswith('__'): - module_name = f[:-3] - logging.debug( - 'OnlineAccountsManager loading %s' % \ - (module_name)) - try: - mod = __import__( - 'web.' + d + '.' + module_name, - globals(), - locals(), - [module_name]) - if hasattr(mod, 'get_account'): - accounts.append(mod.get_account()) - except Exception as e: - logging.exception( - 'Exception while loading %s: %s' % \ - (module_name, str(e))) - elif f == 'icons': - icon_path = os.path.join(dir_path, f) - if os.path.isdir(icon_path) and \ - icon_path not in icon_search_path: - icon_theme.append_search_path(icon_path) - - return accounts - - @classmethod - def configured_accounts(cls): - return [a for a in cls.all_accounts() if a.is_configured()] - - @classmethod - def active_accounts(cls): - return [a for a in cls.all_accounts() if a.is_active()] |