Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/extensions/web/facebook_online_account.py
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/web/facebook_online_account.py')
-rw-r--r--extensions/web/facebook_online_account.py235
1 files changed, 235 insertions, 0 deletions
diff --git a/extensions/web/facebook_online_account.py b/extensions/web/facebook_online_account.py
new file mode 100644
index 0000000..f07209d
--- /dev/null
+++ b/extensions/web/facebook_online_account.py
@@ -0,0 +1,235 @@
+#!/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
+
+from facebook import facebook
+
+from gi.repository import Gtk
+from gi.repository import GdkPixbuf
+from gi.repository import GConf
+
+from sugar3.datastore import datastore
+from sugar3.graphics.alert import Alert, 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
+
+
+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())
+
+ 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):
+ # TODO:
+ # this logic belongs inside FacebookShareMenu
+ # we should set this menu to insensitive if !is_active()
+ if self.is_active():
+ icon_name = 'facebook-share'
+ else:
+ icon_name = 'facebook-share-insensitive'
+ fb_share_menu = FacebookShareMenu(journal_entry_metadata)
+ fb_share_menu.set_image(Icon(icon_name=icon_name,
+ icon_size=Gtk.IconSize.MENU))
+ fb_share_menu.show()
+ return fb_share_menu
+
+ def get_refresh_button(self):
+ return FacebookRefreshButton(self.is_active())
+
+ def _access_token(self):
+ return self._client.get_string(self.ACCESS_TOKEN_KEY)
+
+
+class FacebookShareMenu(online_account.OnlineShareMenu):
+ __gtype_name__ = 'JournalFacebookMenu'
+
+ def __init__(self, metadata):
+ online_account.OnlineShareMenu.__init__(self, _('Facebook'))
+
+ 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')
+
+ 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)
+ result = 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)
+
+ self._fb_notify(failed_reason)
+
+ def _comment_added_cb(self, fb_photo, fb_comment_id):
+ logging.debug("_comment_added_cb")
+ self._fb_notify(_('Upload successful'))
+
+ def _comment_add_failed_cb(self, fb_photo, failed_reason):
+ logging.debug("_comment_add_failed_cb")
+ self._fb_notify(failed_reason)
+
+ def _fb_notify(self, message):
+ alert = NotifyAlert()
+ title_string = _('Facebook')
+ alert.props.title = title_string
+ alert.props.msg = message
+ alert.connect('response', self._facebook_alert_response_cb)
+ journalwindow.get_journal_window().add_alert(alert)
+ alert.show()
+
+ def _facebook_alert_response_cb(self, alert, response_id):
+ journalwindow.get_journal_window().remove_alert(alert)
+
+ 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 FacebookRefreshButton(online_account.OnlineRefreshButton):
+ def __init__(self, is_active):
+ online_account.OnlineRefreshButton.__init__(self, 'facebook-refresh-insensitive')
+
+ self._metadata = None
+ self._is_active = is_active
+ self.set_tooltip(_('Facebook refresh'))
+ self.set_sensitive(False)
+ self.connect('clicked', self._fb_refresh_button_clicked_cb)
+ self.show()
+
+ def set_metadata(self, metadata):
+ self._metadata = metadata
+ if self._is_active:
+ if self._metadata and 'fb_object_id' in self._metadata:
+ self.set_sensitive(True)
+ self.set_icon_name('facebook-refresh')
+
+ def _fb_refresh_button_clicked_cb(self, button):
+ logging.debug('_fb_refresh_button_clicked_cb')
+
+ if self._metadata is None:
+ logging.debug('_fb_refresh_button_clicked_cb called without metadata')
+ return
+
+ 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.refresh_comments()
+
+ def _fb_comments_downloaded_cb(self, fb_photo, comments):
+ logging.debug('_fb_comments_downloaded_cb')
+
+ ds_object = datastore.get(self._metadata['uid'])
+ for comment in comments:
+ c_str = "%s: %s" % (comment['from'], comment['message'])
+ ds_object.metadata['description'] += c_str
+
+ 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))
+ alert = NotifyAlert()
+ alert.props.title = _('Comments download')
+ alert.props.msg = failed_reason
+ alert.connect('response', self.__fb_refresh_offline_response_cb)
+ journalwindow.get_journal_window().add_alert(alert)
+ alert.show()
+
+ def __fb_refresh_offline_response_cb(self, alert, alert_id):
+ pass
+
+def get_account():
+ return FacebookOnlineAccount()