Beispiel #1
0
def subscribe(context, request):
    """
        Subscribe user to context
    """
    actor = request.actor
    rest_params = {'object': context,
                   'verb': 'subscribe'}

    # Initialize a Activity object from the request
    newactivity = Activity.from_request(request, rest_params=rest_params)

    # Check if user is already subscribed
    subscribed_contexts_hashes = [a['hash'] for a in actor['subscribedTo']]
    if newactivity['object'].getHash() in subscribed_contexts_hashes:
        # If user already subscribed, send a 200 code and retrieve the original subscribe activity
        # post when user was subscribed. This way in th return data we'll have the date of subscription
        code = 200
        activities = MADMaxCollection(request, 'activity')
        query = {'verb': 'subscribe', 'object.url': newactivity['object']['url'], 'actor.username': actor['username']}
        newactivity = activities.last(query)  # Pick the last one, so we get the last time user subscribed (in cas a unsbuscription occured sometime...)

    else:
        actor.addSubscription(context)

        # If user wasn't created, 201 will show that the subscription has just been added
        code = 201
        newactivity_oid = newactivity.insert()  # Insert a subscribe activity
        newactivity['_id'] = newactivity_oid
    handler = JSONResourceEntity(request, newactivity.flatten(), status_code=code)
    return handler.buildResponse()
Beispiel #2
0
def like(activity, request):
    """
        Like activity
    """
    if activity.has_like_from(request.actor):
        code = 200

        activities = MADMaxCollection(request, 'activity')
        query = {'verb': 'like', 'object._id': activity['_id'], 'actor.username': request.actor['username']}
        newactivity = activities.last(query)  # Pick the last one, so we get the last time user liked this activity

    else:
        code = 201
        # Prepare rest parameters to be merged with post data
        rest_params = {
            'verb': 'like',
            'object': {
                '_id': ObjectId(activity['_id']),
                'objectType': activity['objectType'],
            }
        }

        # Initialize a Activity object from the request
        newactivity = Activity.from_request(request, rest_params=rest_params)

        newactivity_oid = newactivity.insert()
        newactivity['_id'] = newactivity_oid

        activity.add_like_from(request.actor)

    newactivity['object']['likes'] = activity['likes']  # Return the current likes of the activity
    newactivity['object']['likesCount'] = activity['likesCount']  # Return the current likes of the activity
    newactivity['object']['liked'] = activity.has_like_from(request.actor)
    handler = JSONResourceEntity(request, newactivity.flatten(), status_code=code)
    return handler.buildResponse()
Beispiel #3
0
 def removeActivities(self, logical=False):
     """
         Removes all activity posted to a context. If logical is set to True
         Activities are not actually deleted, only marked as not visible
     """
     activitydb = MADMaxCollection(self.request, self.activity_storage)
     which_to_delete = {"contexts.{}".format(self.unique.lstrip("_")): self.getIdentifier()}
     activitydb.remove(which_to_delete, logical=logical)
Beispiel #4
0
    def getInfo(self):
        actor = self.flatten()
        if self.has_field_permission('talkingIn', 'view'):
            actor.setdefault('talkingIn', [])

            if actor['talkingIn']:
                conversation_objectids = [ObjectId(conv['id']) for conv in actor['talkingIn']]
                conversations_collection = MADMaxCollection(self.request, 'conversations')
                conversations = conversations_collection.search({'_id': {'$in': conversation_objectids}})
                conversations_by_id = {str(conv['_id']): conv for conv in conversations}

                messages_collection = MADMaxCollection(self.request, 'messages').collection

                pipeline = [
                    {"$match": {"contexts.id": {"$in": conversations_by_id.keys()}}},
                    {"$sort": {"_id": 1}},
                    {"$group": {
                        "_id": "$contexts.id",
                        "object": {"$last": "$object"},
                        "published": {"$last": "$published"}
                    }}
                ]
                messages = messages_collection.aggregate(pipeline)['result']

                def format_message(db_message):
                    message_object = db_message.get('object', {})
                    message = dict(
                        objectType=message_object.get('objectType', 'note'),
                        content=message_object.get('content', ''),
                        published=db_message.get('published', '')
                    )

                    if isinstance(message['published'], datetime.datetime):
                        try:
                            message['published'] = message['published'].isoformat()
                        except:
                            message['published'] = message['published']

                    # Set object urls for media types
                    if message['objectType'] in ['file', 'image']:
                        message['fullURL'] = message_object.get('fullURL', '')
                        if message['objectType'] == 'image':
                            message['thumbURL'] = message_object.get('thumbURL', '')

                    return message
                messages_by_conversation = {message['_id'][0]: format_message(message) for message in messages}
                for subscription in actor['talkingIn']:
                    conversation_object = conversations_by_id[subscription['id']]
                    subscription['displayName'] = conversation_object.realDisplayName(self['username'])
                    subscription['lastMessage'] = messages_by_conversation[subscription['id']]
                    subscription['participants'] = conversation_object['participants']
                    subscription['tags'] = conversation_object['tags']
                    subscription['messages'] = 0

                actor['talkingIn'] = sorted(actor['talkingIn'], reverse=True, key=lambda conv: conv['lastMessage']['published'])

        return actor
Beispiel #5
0
    def removeUserSubscriptions(self, users_to_delete=[]):
        """
            Removes all users subscribed to the context, or only specifiyed
            user if userd_to_delete is provided
        """
        usersdb = MADMaxCollection(self.request, "users")
        criteria = {"{}.{}".format(self.user_subscription_storage, self.unique.lstrip("_")): self.getIdentifier()}
        users = usersdb.search(criteria)

        for user in users:
            if users_to_delete == [] or user["username"] in users_to_delete:
                user.removeSubscription(self)
Beispiel #6
0
    def delete_tokens(self, platform=None):
        """
            Deletes tokens from a user, filtered by platform if any
        """
        tokens = MADMaxCollection(self.request, 'tokens')
        query = {
            '_owner': self['_owner'],
        }

        if platform is not None:
            query['platform'] = platform

        tokens.remove(query)
Beispiel #7
0
def joinConversation(conversation, request):
    """
        Join conversation
    """
    actor = request.actor
    cid = request.matchdict['id']

    # Check if user is already subscribed
    if conversation.subscription:
        # If user already subscribed, send a 200 code and retrieve the original subscribe activity
        # post when user was subscribed. This way in th return data we'll have the date of subscription
        code = 200
        activities = MADMaxCollection(request, 'activity')
        query = {'verb': 'subscribe', 'object.id': cid, 'actor.username': actor['username']}
        newactivity = activities.last(query)  # Pick the last one, so we get the last time user subscribed (in cas a unsbuscription occured sometime...)

    else:
        if len(conversation['participants']) == CONVERSATION_PARTICIPANTS_LIMIT:
            raise Forbidden('This conversation is full, no more of {} participants allowed'.format(CONVERSATION_PARTICIPANTS_LIMIT))

        if 'group' not in conversation.get('tags', []):
            raise Forbidden('This is not a group conversation, so no one else is allowed'.format(CONVERSATION_PARTICIPANTS_LIMIT))

        if not request.creator.is_allowed_to_see(actor):
            raise Forbidden('User {} is not allowed to have a conversation with {}'.format(request.creator['username'], actor['username']))

        conversation['participants'].append(actor.flatten(preserve=['displayName', 'objectType', 'username']))
        actor.addSubscription(conversation)

        # If we add anyone to a conversation,  we remove the archive tag, no matter how many participants have
        if 'archive' in conversation.get('tags', []):
            conversation['tags'].remove('archive')

        conversation.save()

        # If user wasn't created, 201 will show that the subscription has just been added
        code = 201

        # Initialize a Activity object from the request
        rest_params = {'actor': actor,
                       'verb': 'subscribe',
                       'object': {'objectType': 'conversation',
                                  'id': cid,
                                  'participants': conversation['participants']}
                       }

        newactivity = Activity.from_request(request, rest_params=rest_params)
        newactivity_oid = newactivity.insert()  # Insert a subscribe activity
        newactivity['_id'] = newactivity_oid
    handler = JSONResourceEntity(request, newactivity.flatten(), status_code=code)
    return handler.buildResponse()
Beispiel #8
0
def ModifyContext(context, request):
    """
    """
    urlHash = request.matchdict['urlHash']
    contexts = MADMaxCollection(context.db.contexts)
    maxcontext = contexts.getItemsByurlHash(urlHash)
    if maxcontext:
        maxcontext = maxcontext[0]
    else:
        raise ObjectNotFound, 'Unknown context: %s' % urlHash

    properties = maxcontext.getMutablePropertiesFromRequest(request)
    maxcontext.modifyContext(properties)
    maxcontext.updateUsersSubscriptions()
    handler = JSONResourceEntity(maxcontext.flatten())
    return handler.buildResponse()
Beispiel #9
0
def ModifyContext(context, request):
    """
    """
    urlHash = request.matchdict['urlHash']
    contexts = MADMaxCollection(context.db.contexts)
    maxcontext = contexts.getItemsByurlHash(urlHash)
    if maxcontext:
        maxcontext = maxcontext[0]
    else:
        raise ObjectNotFound, 'Unknown context: %s' % urlHash

    properties = maxcontext.getMutablePropertiesFromRequest(request)
    maxcontext.modifyContext(properties)
    maxcontext.updateUsersSubscriptions()
    handler = JSONResourceEntity(maxcontext.flatten())
    return handler.buildResponse()
Beispiel #10
0
    def get_tokens(self, platform=None):
        """
            Returns all the tokens from a user, filtered by platform if any
        """

        tokens = MADMaxCollection(self.request, 'tokens')
        query = {
            '_owner': self['_owner'],
        }

        if platform is not None:
            query['platform'] = platform

        user_tokens = tokens.search(query)

        result = []
        for token in user_tokens:
            result.append(dict(token=token['token'], platform=token['platform'], username=token['_owner']))

        return result
Beispiel #11
0
def subscribe(context, request):
    """
        /people/{username}/subscriptions
    """
    # XXX For now only one context can be subscribed at a time
    actor = request.actor
    rest_params = {'actor': actor,
                   'verb': 'subscribe'}

    # Initialize a Activity object from the request
    newactivity = Activity()
    newactivity.fromRequest(request, rest_params=rest_params)

    #Check if user is already subscribed
    subscribed_contexts_hashes = [a['urlHash'] for a in actor.subscribedTo['items']]
    if sha1(newactivity.object['url']).hexdigest() in subscribed_contexts_hashes:
        # If user already subscribed, send a 200 code and retrieve the original subscribe activity
        # post when user was susbcribed. This way in th return data we'll have the date of subscription
        code = 200
        activities = MADMaxCollection(context.db.activity)
        query = {'verb': 'subscribe', 'object.url': newactivity.object['url'], 'actor.username': actor.username}
        newactivity = activities.search(query)[-1]  # Pick the last one, so we get the last time user subscribed (in case a unsbuscription occured sometime...)

    else:
        # If user wasn't created, 201 indicates that the subscription has just been added
        code = 201
        newactivity_oid = newactivity.insert()  # Insert a subscribe activity
        newactivity['_id'] = newactivity_oid

        #Register subscription to the actor
        contexts = MADMaxCollection(context.db.contexts, query_key='urlHash')
        scontext = contexts[sha1(newactivity['object']['url']).hexdigest()]
        actor.addSubscription(scontext)

    handler = JSONResourceEntity(newactivity.flatten(), status_code=code)
    return handler.buildResponse()
Beispiel #12
0
    def __getitem__(self, userid):
        """
            Overrides __getitem__ to avoid fetching the user twice , when
            user that we're going to request is the same actor on the request.

            Because the actor on the request won't be in the traversal chain,
            provide it a parent before returning.

            If the userid doesn't match the request actor fallback to query database.
            If the actor doesn't exists, raise a not found.
        """
        userid = userid.lower()
        if userid == self.request.actor_username:
            actor = self.request.actor
            if actor is None:
                raise UnknownUserError("Object with %s %s not found inside %s" % (self.query_key, userid, self.collection.name))
            actor.__parent__ = self
            return actor

        return MADMaxCollection.__getitem__(self, userid)
Beispiel #13
0
def processTweet(twitter_username, content, tweetID='---'):
    """ Process inbound tweet
    """
    logger.info("(INFO) Processing tweet %s from @%s with content: %s" % (str(tweetID), twitter_username, content))

    conn = pymongo.Connection(mongodb_url)
    db = conn[mongodb_db_name]
    users = MADMaxCollection(db.users)
    contexts = MADMaxCollection(db.contexts)

    contexts_with_twitter_username = contexts.search({"twitterUsernameId": {"$exists": True}})
    readable_follow_list = [users_to_follow.get('twitterUsername', '').lower() for users_to_follow in contexts_with_twitter_username]
    twitter_username = twitter_username.lower()
    # If we have a tweet from a followed user
    if twitter_username in readable_follow_list:
        # Find the context
        maxcontext = contexts.search({"twitterUsername": twitter_username})

        # Watch for the case when two or more context share twitterUsername
        for context in maxcontext:
            url_hash = context.get("urlHash")
            context_url = context.get("url")

            # Construct the payload with the activity information
            newactivity = {
                "object": {
                    "objectType": "note",
                    "content": content
                },
                "contexts": [
                    context_url,
                ],
                "generator": twitter_generator_name
            }

            re = requests.post('%s/admin/contexts/%s/activities' % (max_server_url, url_hash), json.dumps(newactivity), auth=('admin', 'admin'), verify=False)
            if re.status_code == 201:
                # 200: Successful tweet from context
                logger.info("(201) Successfully posted tweet %s from @%s as context %s" % (str(tweetID), twitter_username, context_url))
                return "(201) %s tweet from context %s" % (twitter_username, context_url)
            else:
                # 500: Error accessing the MAX API
                logger.info("(404) Discarding tweet %s from @%s : There's no MAX user with that twitter username." % (str(tweetID), twitter_username))
                return "(404) No Such Max User"

        return "Should not see me..."

    # If we have a tweet from a tracked hashtag
    # Parse text and determine the second or nth hashtag
    possible_hastags = findHashtags(content)
    # Prepare query with normalized possible_hastags

    query = [dict(twitterHashtag=hashtag.lower()) for hashtag in possible_hastags]

    if debug_hashtag in possible_hastags:
        logger.info("%s Debug hashtag detected!" % content)
        return "%s Debug hashtag detected! %s" % content

    # Check if twitter_username is a registered for a valid MAX username
    # if not, discard it
    maxuser = users.search({"twitterUsername": twitter_username})
    if maxuser:
        maxuser = maxuser[0]
    else:
        logger.info("(404) Discarding tweet %s from @%s : There's no MAX user with that twitter username." % (str(tweetID), twitter_username))
        return "(404) %s: No such MAX user." % twitter_username

    # Check if hashtag is registered for a valid MAX context
    # if not, discard it
    successful_tweets = 0
    maxcontext = contexts.search({"$or": query})
    if maxcontext:
        for context in maxcontext:
            # Check if MAX username has permission to post to the MAX context
            # if not, discard it
            try:
                can_write = canWriteInContexts(maxuser, [context.url])
            except:
                can_write = False
                logger.info("(401) Failure posting tweet %s: User %s can't write to %s" % (str(tweetID), maxuser.username, context['url']))

            if can_write:

                # Construct the payload with the activity information
                newactivity = {
                    "object": {
                        "objectType": "note",
                        "content": content
                    },
                    "contexts": [
                        context.url,
                    ],
                    "generator": twitter_generator_name
                }

                # Use the restricted REST endpoint for create a new activity in the specified
                # MAX context in name of the specified MAX username
                re = requests.post('%s/admin/people/%s/activities' % (max_server_url, maxuser.username), json.dumps(newactivity), auth=('admin', 'admin'), verify=False)
                if re.status_code == 201:
                    logger.info("(201) Successfully posted tweet %s from @%s as %s on context %s" % (str(tweetID), twitter_username, maxuser['username'], context.url))
                    successful_tweets += 1
                    #return "(201) Successful tweet from user %s in context %s" % (maxuser, context.url)
                else:
                    logger.info("(500) Error accessing the MAX API at %s" % max_server_url)
                    #return "(500) MAX API error"

        error_message = len(maxcontext) != successful_tweets and " We weren't able to send the tweet to all contexts. See above for more information." or ""
        logger.info("(INFO) Processed tweet %s to %d of %d possible contexts.%s" % (str(tweetID), successful_tweets, len(maxcontext), error_message))
        if error_message:
            return "(401) Some posts not sent"
        else:
            return "(200) All posts sent"
    else:
        logger.info("(404) Discarding tweet %s from @%s: There are no MAX context with any of those hashtags" % (str(tweetID), twitter_username))
        return "(404) %s: Not such MAX context %s" % (maxuser.username, maxcontext)

    return "Should not see mee"
Beispiel #14
0
def processTweet(twitter_username, content, tweetID='---'):
    """ Process inbound tweet
    """
    logger.info("(INFO) Processing tweet %s from @%s with content: %s" %
                (str(tweetID), twitter_username, content))

    conn = pymongo.Connection(mongodb_url)
    db = conn[mongodb_db_name]
    users = MADMaxCollection(db.users)
    contexts = MADMaxCollection(db.contexts)

    contexts_with_twitter_username = contexts.search(
        {"twitterUsernameId": {
            "$exists": True
        }})
    readable_follow_list = [
        users_to_follow.get('twitterUsername', '').lower()
        for users_to_follow in contexts_with_twitter_username
    ]
    twitter_username = twitter_username.lower()
    # If we have a tweet from a followed user
    if twitter_username in readable_follow_list:
        # Find the context
        maxcontext = contexts.search({"twitterUsername": twitter_username})

        # Watch for the case when two or more context share twitterUsername
        for context in maxcontext:
            url_hash = context.get("urlHash")
            context_url = context.get("url")

            # Construct the payload with the activity information
            newactivity = {
                "object": {
                    "objectType": "note",
                    "content": content
                },
                "contexts": [
                    context_url,
                ],
                "generator": twitter_generator_name
            }

            re = requests.post('%s/admin/contexts/%s/activities' %
                               (max_server_url, url_hash),
                               json.dumps(newactivity),
                               auth=('admin', 'admin'),
                               verify=False)
            if re.status_code == 201:
                # 200: Successful tweet from context
                logger.info(
                    "(201) Successfully posted tweet %s from @%s as context %s"
                    % (str(tweetID), twitter_username, context_url))
                return "(201) %s tweet from context %s" % (twitter_username,
                                                           context_url)
            else:
                # 500: Error accessing the MAX API
                logger.info(
                    "(404) Discarding tweet %s from @%s : There's no MAX user with that twitter username."
                    % (str(tweetID), twitter_username))
                return "(404) No Such Max User"

        return "Should not see me..."

    # If we have a tweet from a tracked hashtag
    # Parse text and determine the second or nth hashtag
    possible_hastags = findHashtags(content)
    # Prepare query with normalized possible_hastags

    query = [
        dict(twitterHashtag=hashtag.lower()) for hashtag in possible_hastags
    ]

    if debug_hashtag in possible_hastags:
        logger.info("%s Debug hashtag detected!" % content)
        return "%s Debug hashtag detected! %s" % content

    # Check if twitter_username is a registered for a valid MAX username
    # if not, discard it
    maxuser = users.search({"twitterUsername": twitter_username})
    if maxuser:
        maxuser = maxuser[0]
    else:
        logger.info(
            "(404) Discarding tweet %s from @%s : There's no MAX user with that twitter username."
            % (str(tweetID), twitter_username))
        return "(404) %s: No such MAX user." % twitter_username

    # Check if hashtag is registered for a valid MAX context
    # if not, discard it
    successful_tweets = 0
    maxcontext = contexts.search({"$or": query})
    if maxcontext:
        for context in maxcontext:
            # Check if MAX username has permission to post to the MAX context
            # if not, discard it
            try:
                can_write = canWriteInContexts(maxuser, [context.url])
            except:
                can_write = False
                logger.info(
                    "(401) Failure posting tweet %s: User %s can't write to %s"
                    % (str(tweetID), maxuser.username, context['url']))

            if can_write:

                # Construct the payload with the activity information
                newactivity = {
                    "object": {
                        "objectType": "note",
                        "content": content
                    },
                    "contexts": [
                        context.url,
                    ],
                    "generator": twitter_generator_name
                }

                # Use the restricted REST endpoint for create a new activity in the specified
                # MAX context in name of the specified MAX username
                re = requests.post('%s/admin/people/%s/activities' %
                                   (max_server_url, maxuser.username),
                                   json.dumps(newactivity),
                                   auth=('admin', 'admin'),
                                   verify=False)
                if re.status_code == 201:
                    logger.info(
                        "(201) Successfully posted tweet %s from @%s as %s on context %s"
                        % (str(tweetID), twitter_username, maxuser['username'],
                           context.url))
                    successful_tweets += 1
                    #return "(201) Successful tweet from user %s in context %s" % (maxuser, context.url)
                else:
                    logger.info("(500) Error accessing the MAX API at %s" %
                                max_server_url)
                    #return "(500) MAX API error"

        error_message = len(
            maxcontext
        ) != successful_tweets and " We weren't able to send the tweet to all contexts. See above for more information." or ""
        logger.info(
            "(INFO) Processed tweet %s to %d of %d possible contexts.%s" %
            (str(tweetID), successful_tweets, len(maxcontext), error_message))
        if error_message:
            return "(401) Some posts not sent"
        else:
            return "(200) All posts sent"
    else:
        logger.info(
            "(404) Discarding tweet %s from @%s: There are no MAX context with any of those hashtags"
            % (str(tweetID), twitter_username))
        return "(404) %s: Not such MAX context %s" % (maxuser.username,
                                                      maxcontext)

    return "Should not see mee"