Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter Bender <walter@sugarlabs.org>2013-05-12 23:45:32 (GMT)
committer Walter Bender <walter@sugarlabs.org>2013-05-12 23:45:32 (GMT)
commit2db9dee01ab0e12a6b53c0da844b285a9312cab1 (patch)
tree04a804fd38ea0597a824709f7b29b706e3a5ccd5
parentd0110fcdeb9c0c5d83e3730215410ba720e21702 (diff)
resync to latest version of patches submitted to sugar upstream on github
-rw-r--r--extensions/cpsection/webservices/services/facebook/service.py2
-rw-r--r--extensions/cpsection/webservices/services/twitter/service.py2
-rw-r--r--extensions/web/facebook/Makefile.am2
-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.py283
-rw-r--r--extensions/web/twitter/Makefile.am2
-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.py284
-rw-r--r--src/jarabe/journal/palettes.py4
-rw-r--r--src/jarabe/web/__init__.py15
-rw-r--r--src/jarabe/web/account.py115
-rw-r--r--src/jarabe/web/accountsmanager.py62
-rw-r--r--src/jarabe/web/online_account.py60
-rw-r--r--src/jarabe/web/online_accounts_manager.py77
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()]