Пример #1
0
def fb_change_object_visibility(channel, object_id, object_type, visibility):
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException, FacebookConfigurationException
    from solariat_bottle.db.post.facebook import FacebookPost
    try:
        graph = get_facebook_api(channel)
        try:
            post = FacebookPost.get_by_native_id(str(object_id))
            graph = get_page_based_api(post, graph)
        except FacebookPost.DoesNotExist:
            pass

        if object_type == TYPE_POST:
            allowed_values = ("starred", "hidden", "normal")
            if visibility not in allowed_values:
                raise FacebookCommunicationException(
                    "Only allowed visibility values for statuses are %s" %
                    allowed_values)
            result = graph.request(
                object_id, post_args={"timeline_visibility": visibility})
            success = result.get('success', False)
            return dict(ok=success, id=object_id)
        elif object_type == TYPE_COMMENT:
            allowed_values = ("private", "hidden", "normal")
            if visibility not in allowed_values:
                raise FacebookCommunicationException(
                    "Only allowed visibility values for comments are %s" %
                    allowed_values)
            if visibility == "private":
                post_data = {"is_private": True}
            elif visibility == "hidden":
                post_data = {"is_hidden": True}
            else:
                post_data = {"is_private": False}
            result = graph.request(object_id, post_args=post_data)
            success = result.get('success', False)
            return dict(ok=success, id=object_id)
        else:
            raise FacebookCommunicationException(
                "Unknown object type %s. Only <Post, Comment> allowed." %
                object_type)
        # Facebook being annoying as usual.
        # if result in (True, False):
        #     return dict(ok=result)
        # else:
        #     return result
        return dict(id=object_id)
    except FacebookConfigurationException, ex:
        er = "Failure in change object visibility. Exc: %s, Channel: %s, Object_id: %s, Object_type: %s, Visibility: %s"
        logger.error(er % (ex, channel, object_id, object_type, visibility))
        raise
Пример #2
0
def fb_get_comments_for_post(channel,
                             post_id,
                             limit=None,
                             offset=None,
                             since=None,
                             until=None,
                             order='ASC'):
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException, FacebookConfigurationException

    params = {}
    if since:
        params['since'] = since
    if until:
        params['until'] = until
    if limit:
        params['limit'] = limit
    if offset:
        params['offset'] = offset

    comments_fields = "attachment,can_comment,can_remove," \
                      "comment_count,created_time,from,id," \
                      "like_count,message,message_tags,parent,user_likes,likes"
    params['fields'] = comments_fields + ",comments{" + comments_fields + "}"

    try:
        graph = get_facebook_api(channel)
        comments_data = graph.request(post_id + '/comments', params)
        return comments_data.get("data", [])
    except FacebookConfigurationException:
        raise
    except Exception as exc:
        log_channel_error(channel, logger)
        logger.error(exc)
        raise FacebookCommunicationException(exc.message)
Пример #3
0
def fb_edit_publication(channel, object_id, message):
    """ Edit a comment with a new message """
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException, FacebookConfigurationException
    from solariat_bottle.db.post.facebook import FacebookPost
    try:
        graph = get_facebook_api(channel)
        try:
            post = FacebookPost.objects.get(_native_id=str(object_id))
            graph = get_page_based_api(post, graph)
        except FacebookPost.DoesNotExist:
            pass
        data = {'message': message}
        result = graph.request(object_id, post_args=data)
        # Another quirk from facebook, where this returns a boolean instead of a json (might be problem with
        # facebook sdk wrapper) For now just hack around it
        if result in (True, False):
            return dict(ok=result, id=object_id)
        else:
            return dict(ok=result.get("success", False), id=object_id)
    except FacebookConfigurationException:
        raise
    except Exception as exc:
        log_channel_error(channel, logger)
        logger.error(exc)
        raise FacebookCommunicationException(exc.message)
Пример #4
0
def fb_put_post(channel,
                target_id,
                message,
                picture_name=None,
                media=None,
                link=None,
                link_description=None):
    """ Send post to a user feed or a page feed """
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException
    from solariat_bottle.tasks.twitter import get_file_from_media
    from solariat_bottle.utils.post import get_service_channel

    api = get_facebook_api(channel)
    service_channel = get_service_channel(channel)
    if service_channel:
        possible_targets = service_channel.all_fb_events + service_channel.facebook_pages
        matched_targets = [
            target for target in possible_targets if target['id'] == target_id
        ]
        if matched_targets:
            token = matched_targets[0]['access_token']
            api = get_facebook_api(channel, token=token)

    if media:
        filename, f = get_file_from_media(media)

        kwargs = dict()
        if message:
            kwargs['caption'] = message
        # if target_id:
        #     kwargs['target_id'] = target_id
        photo = api.put_photo(f, album_path=target_id + "/photos", **kwargs)
        # attachment_data['link'] = picture_info['link']
        if f:
            try:
                f.close()
                os.unlink(f.name)
            except IOError:
                pass
        return photo
    else:
        attachment_data = {}
        if link:
            # attachment_data['link'] = link
            attachment_data["picture"] = link
            if link_description:
                attachment_data['description'] = link_description

        try:
            result = api.put_wall_post(force_bytes(message, 'utf-8',
                                                   'replace'),
                                       profile_id=target_id,
                                       attachment=attachment_data)
            return result
        except Exception, ex:
            er = "Failure on posting to facebook. Channel: %s, Target: %s, Message: %s, Pic_N: %s, Pic_B: %s, Link: %s"
            logger.error(
                er % (channel, target_id, message, picture_name, media, link))
            raise FacebookCommunicationException(ex.message)
Пример #5
0
def fb_get_object(channel, object_id, token):
    """ Delete object (post/comment) """
    try:
        graph = get_facebook_api(channel, token=token)
        graph.timeout = 100
        graph.get_object(object_id)
        return dict(id=object_id)
    except Exception, ex:
        err = "Failure on getting object. Channel: %s, Target: %s"
        logger.error(err % (channel, object_id))
        raise FacebookCommunicationException(ex.message)
Пример #6
0
def fb_channel_user(channel):
    """ Share a post url on own timeline """
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException, FacebookConfigurationException
    try:
        return channel.facebook_me()
    except FacebookConfigurationException:
        raise
    except Exception as exc:
        log_channel_error(channel, logger)
        logger.error(exc)
        raise FacebookCommunicationException(exc.message)
Пример #7
0
def fb_put_comment_by_channel(channel, object_id, message):

    from solariat_bottle.settings import LOGGER
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException

    try:
        return get_facebook_api(channel).put_comment(
            object_id, force_bytes(message, 'utf-8', 'replace'))
    except Exception, ex:
        LOGGER.error(
            "Failure posting comment to facebook. Exc: %s,  Channel: %s, Object_id: %s, Message: %s"
            % (ex, channel, object_id, message))
        raise FacebookCommunicationException(ex.message)
Пример #8
0
def fb_like_post(channel, object_id, delete=False):
    """ Like / unlike a post given the post id """
    import facebook
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException, FacebookConfigurationException
    from solariat_bottle.db.post.facebook import FacebookPost

    try:
        graph = get_facebook_api(channel)
        try:
            post = FacebookPost.objects.get(_native_id=str(object_id))
            post.user_liked = False if delete in (True, 'true', 'True',
                                                  1) else True
            post.save()
            graph = get_page_based_api(post, graph)
        except FacebookPost.DoesNotExist:
            pass

        facebook_post_id = object_id

        logger.warning(
            "Got like/unlike request to object_id=%s with delete=%s" %
            (object_id, delete))
        if delete in (True, 'true', 'True', 1):
            result = graph.put_object(facebook_post_id,
                                      "likes",
                                      method="delete")
        else:
            result = graph.put_object(facebook_post_id, "likes")

        return dict(id=facebook_post_id, ok=result.get("success", False))

    except facebook.GraphAPIError, exc:

        def _get_error_code(exc):
            try:
                return exc.code
            except AttributeError:
                try:
                    ex_data = json.loads(exc.message)
                except ValueError:
                    return -1
                else:
                    return ex_data.get('code', -1)

        if _get_error_code(exc) == 100:
            # This is raised if we try to unlike a post that was already unliked.
            # Since we don't keep these things in sync on our side, we need to make sure we
            # just gracefully handle this since we don't care about it
            pass
        else:
            raise FacebookCommunicationException(exc.message)
Пример #9
0
def fb_share_post(channel, post_url):
    """ Share a post url on own timeline """
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException, FacebookConfigurationException
    try:
        graph = get_facebook_api(channel)
        data = {'link': post_url}
        result = graph.request('/me/feed', post_args=data)
        return dict(id=result['id'])
    except FacebookConfigurationException:
        raise
    except Exception as exc:
        log_channel_error(channel, logger)
        logger.error(exc)
        raise FacebookCommunicationException(exc.message)
Пример #10
0
def fb_delete_object(channel, target_id):
    """ Delete object (post/comment) """
    # func = lambda: get_facebook_api(channel).delete_object(target_id)
    # return __try_execute_safely(func, 5, 3600)
    #try:
    import facebook
    try:
        token = __get_token_for_item(channel, target_id)
        graph = get_facebook_api(channel, token=token)
        graph.timeout = 100
        graph.delete_object(target_id)
        return dict(id=target_id)
    except Exception, ex:
        err = "Failure on deleting object. Channel: %s, Target: %s"
        logger.error(err % (channel, target_id))
        raise FacebookCommunicationException(ex.message)
Пример #11
0
    def find_token_for_source_id(channels, source_ids):
        source_ids = set(map(str, source_ids))
        from solariat_bottle.db.channel.facebook import FacebookServiceChannel

        for channel in channels:
            assert isinstance(
                channel,
                FacebookServiceChannel), "%s is not instance of %s" % (
                    channel, FacebookServiceChannel)

            for fb_object in channel.all_facebook_pages + channel.all_fb_events:
                if isinstance(fb_object, dict) and 'access_token' in fb_object and 'id' in fb_object \
                        and str(fb_object['id']) in source_ids:
                    return channel, fb_object['access_token']
        raise FacebookCommunicationException(
            "No token found in channels %s for source ids %s" %
            (channels, source_ids))
Пример #12
0
def fb_put_comment(channel, object_id, message):
    """put comment to some object"""
    # func = lambda: get_facebook_api(channel).put_comment(object_id, message.encode('utf-8', 'replace'))
    # return __try_execute_safely(func, 5, 3600)

    from solariat_bottle.settings import LOGGER
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException
    from solariat_bottle.db.post.facebook import FacebookPost
    try:
        fb_post = FacebookPost.objects.get(_native_id=str(object_id))
    except FacebookPost.DoesNotExist:
        LOGGER.warning(
            "No mapping post for native_id=%s was found. Defaulting to posting comment as user."
            % object_id)
    else:
        try:
            return fb_comment_by_page(fb_post, object_id, message)
        except (FacebookCommunicationException,
                facebook_driver.facebook.GraphAPIError) as exc:
            if '#1705' in str(
                    exc
            ):  # GraphAPIError: (#1705) There was an error posting to this wall
                LOGGER.info("Failed sending comment to post %s with error %s" %
                            (object_id, str(exc)))
                if fb_post.is_second_level_reply:
                    try:
                        object_id = fb_post.wrapped_data['parent_id']
                    except KeyError:
                        LOGGER.error("Can't find parent for comment %s" %
                                     fb_post)
                        raise exc
                    LOGGER.info(
                        "Sending comment to parent %s of initial post %s %s" %
                        (object_id, fb_post, fb_post.native_id))
                    return fb_comment_by_page(fb_post, object_id, message)
            raise exc

    try:
        return get_facebook_api(channel).put_comment(
            object_id, force_bytes(message, 'utf-8', 'replace'))
    except Exception, ex:
        LOGGER.error(
            "Failure posting comment to facebook. Exc: %s,  Channel: %s, Object_id: %s, Message: %s"
            % (ex, channel, object_id, message))
        raise FacebookCommunicationException(ex.message)
Пример #13
0
def fb_get_channel_description(channel):
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException, FacebookConfigurationException
    from solariat_bottle.utils.post import get_service_channel
    channel_info = {'user': [], 'pages': [], 'events': []}

    def pick_user_for_channel(ch):
        from solariat_bottle.db.user import User

        user = None
        for user in User.objects.find(accounts__in=[ch.account.id],
                                      is_superuser=False):
            if user.is_admin:
                return user
        return user

    service_channel = get_service_channel(channel)
    if not service_channel:
        raise FacebookConfigurationException(
            "No service channel was found for channel: " + str(channel))

    try:
        cached_info = service_channel.channel_description
        if cached_info:
            return cached_info

        graph = get_facebook_api(service_channel)
        user_info = graph.get_object('me')

        picture = graph.get_object('me/picture')
        if picture:
            user_info['pic_url'] = picture.get('url')
        #friends = graph.get_object('me/friends')
        #user_info['friend_count'] = str(friends.get('summary', {}).get('total_count', 0))
        channel_info['user'] = user_info

        for page_id in service_channel.facebook_page_ids:
            try:
                page_info = graph.get_object(page_id)
            except (facebook_driver.facebook.GraphAPIError,
                    FacebookCommunicationException) as exc:
                if 'does not exist' in exc.message:
                    logger.info(
                        "%s facebook page %s does not exist. Removing from channel"
                        % (channel, page_id))
                    service_channel.remove_facebook_page(
                        {
                            'id': page_id,
                            'name': page_id
                        }, pick_user_for_channel(service_channel))
                else:
                    raise exc
            else:
                picture = graph.get_object(page_id + '/picture')
                if picture:
                    url = picture.get('url')
                    page_info['pic_url'] = url
                channel_info['pages'].append(page_info)

        for event_id in service_channel.tracked_fb_event_ids:
            try:
                event_info = graph.get_object(event_id)
            except (facebook_driver.facebook.GraphAPIError,
                    FacebookCommunicationException) as exc:
                if 'does not exist' in exc.message:
                    logger.info(
                        "%s facebook event %s does not exist. Removing from channel"
                        % (channel, event_id))
                    service_channel.untrack_fb_event(
                        {
                            'id': event_id,
                            'name': event_id
                        }, pick_user_for_channel(service_channel))
                else:
                    raise exc
            else:
                picture = graph.get_object(event_id + '/picture')
                if picture:
                    url = picture.get('url')
                    event_info['pic_url'] = url
                channel_info['events'].append(event_info)
        service_channel.channel_description = channel_info

        return channel_info
    except FacebookConfigurationException:
        raise
    except Exception as exc:
        log_channel_error(service_channel, logger)
        logger.error(traceback.format_exc())
        raise FacebookCommunicationException(exc.message)
Пример #14
0
                else:
                    return ex_data.get('code', -1)

        if _get_error_code(exc) == 100:
            # This is raised if we try to unlike a post that was already unliked.
            # Since we don't keep these things in sync on our side, we need to make sure we
            # just gracefully handle this since we don't care about it
            pass
        else:
            raise FacebookCommunicationException(exc.message)
    except FacebookConfigurationException:
        raise
    except Exception as exc:
        logger.error("Exception: %s, Channel: %s, Object_id: %s" %
                     (exc, channel, object_id))
        raise FacebookCommunicationException(exc.message)


@io_pool.task
def fb_get_comments_for_post(channel,
                             post_id,
                             limit=None,
                             offset=None,
                             since=None,
                             until=None,
                             order='ASC'):
    from solariat_bottle.tasks.exceptions import FacebookCommunicationException, FacebookConfigurationException

    params = {}
    if since:
        params['since'] = since