コード例 #1
0
ファイル: activity.py プロジェクト: UPCnet/max
    def addComment(self, comment):
        """
            Adds a comment to an existing activity and updates refering activity keywords and hashtags
        """

        # Clean innecessary fields
        non_needed_actor_fields = [
            "talkingIn",
            "subscribedTo",
            "following",
            "last_login",
            "_id",
            "published",
            "twitterUsername",
        ]
        for fieldname in non_needed_actor_fields:
            if fieldname in comment["actor"]:
                del comment["actor"][fieldname]

        self.add_to_list("replies", comment, allow_duplicates=True)
        self.setKeywords()

        activity_hashtags = self["object"].setdefault("_hashtags", [])
        activity_hashtags.extend(comment.get("_hashtags", []))
        self["object"]["_hashtags"] = list(set(activity_hashtags))
        self["lastComment"] = ObjectId(comment["id"])

        self.save()

        notify = self.get("contexts", [{}])[0].get("notifications", False)
        if notify in ["comments"]:
            notifier = RabbitNotifications(self.request)
            notifier.notify_context_activity_comment(self, comment)
コード例 #2
0
ファイル: conversation.py プロジェクト: UPCnet/max
    def _after_subscription_remove(self, username):
        """
            Removes rabbitmq bindings after new subscription
        """
        save_context = False

        # Remove leaving participant from participants list ONLY for group conversations of >=2 participants
        if len(self['participants']) >= 2 and 'group' in self.get('tags', []):
            self['participants'] = [user for user in self['participants'] if user['username'] != self.request.actor['username']]
            save_context = True

        # Tag no-group conversations that will be left as 1 participant only as single
        if len(self['participants']) == 2:
            self.setdefault('tags', [])
            if 'group' not in self['tags']:
                if 'single' not in self['tags']:
                    self['tags'].append('single')
                    save_context = True

        # Tag group conversations that will be left as 1 participant only as archived
        if len(self['participants']) == 1:
            self.setdefault('tags', [])
            if 'group' in self['tags']:
                if 'archive' not in self['tags']:
                    self['tags'].append('archive')
                    save_context = True

        if save_context:
            self.save()

        notifier = RabbitNotifications(self.request)
        notifier.unbind_user_from_conversation(self, username)
コード例 #3
0
ファイル: context.py プロジェクト: UPCnet/max
 def _after_subscription_add(self, username):
     """
         Creates rabbitmq bindings after new subscription
     """
     if self.get("notifications", False):
         notifier = RabbitNotifications(self.request)
         notifier.bind_user_to_context(self, username)
コード例 #4
0
ファイル: context.py プロジェクト: UPCnet/max
    def modifyContext(self, properties):
        """Update the user object with the given properties"""
        # If updating the twitterUsername, get its Twitter ID
        if properties.get("twitterUsername", None):
            api = get_twitter_api(self.request.registry)
            properties["twitterUsernameId"] = get_userid_from_twitter(api, properties["twitterUsername"])

        self.updateFields(properties)

        if self.get("twitterUsername", None) is None and self.get("twitterUsernameId", None) is not None:
            del self["twitterUsernameId"]

        # someone changed notifications settings for this context
        if "notifications" in properties:
            notifier = RabbitNotifications(self.request)
            if self.get("notifications", False):
                for user in self.subscribedUsers():
                    notifier.bind_user_to_context(self, user["username"])
            else:
                for user in self.subscribedUsers():
                    notifier.unbind_user_from_context(self, user["username"])

        if "url" in properties:
            self["hash"] = sha1(self["url"]).hexdigest()

        self.save()
コード例 #5
0
ファイル: activity.py プロジェクト: UPCnet/max
    def _after_insert_object(self, oid):
        # notify activity if the activity is from a context
        # with enabled notifications
        self["lastComment"] = oid
        self.save()

        notify = self.get("contexts", [{}])[0].get("notifications", False)
        if notify in ["posts", "comments", True]:
            notifier = RabbitNotifications(self.request)
            notifier.notify_context_activity(self)
コード例 #6
0
ファイル: messages.py プロジェクト: UPCnet/max
def add_message(conversation, request):
    """
        Adds a message to a conversation

        The request.actor is the one "talking", either if it was the authenticated user,
        the rest username or the post body actor, in this order.
    """

    try:
        mobile = request.decoded_payload['object']['mobile']
    except:
        mobile = False

    message_params = {'actor': request.actor,
                      'verb': 'post',
                      'contexts': [conversation]
                      }

    if 'single' in message_params['contexts'][0]['tags']:
        users = MADMaxCollection(request, 'users', query_key='username')
        for participant in message_params['contexts'][0]['participants']:
            user = users[participant['username']]
            if user.getSubscription(conversation) is None:
                user.addSubscription(conversation)
                conversation['tags'].remove('single')
                conversation.save()
                notifier = RabbitNotifications(request)
                notifier.add_conversation(conversation)


    # Initialize a Message (Activity) object from the request
    newmessage = Message.from_request(request, rest_params=message_params)

    if newmessage['object']['objectType'] == u'image' or \
       newmessage['object']['objectType'] == u'file':
        # Extract the file before saving object
        message_file = newmessage.extract_file_from_activity()
        message_oid = newmessage.insert()
        newmessage['_id'] = ObjectId(message_oid)
        newmessage.process_file(request, message_file)
        newmessage.save()
        if mobile:
            notifier = RabbitNotifications(request)
            notifier.add_conversation_message(conversation, newmessage)
    else:
        message_oid = newmessage.insert()
        newmessage['_id'] = message_oid
        if mobile:
            notifier = RabbitNotifications(request)
            notifier.add_conversation_message(conversation, newmessage)

    handler = JSONResourceEntity(request, newmessage.flatten(), status_code=201)
    return handler.buildResponse()
コード例 #7
0
    def _after_insert_object(self, oid, notifications=True):
        """
            Create user exchanges just after user creation on the database
        """
        query = {
            'objectType': 'conversation',
            'participants.username': self['username']
        }

        conversations_search = self.request.db.conversations.search(query)
        for conversation in conversations_search:
            if len(conversation['participants']) == 2:
                if 'group' not in conversation['tags']:
                    if 'archive' in conversation['tags']:
                        conversation['tags'].remove('archive')
                        conversation['tags'].append('single')
                        conversation.save()

        if notifications:
            notifier = RabbitNotifications(self.request)
            notifier.add_user(self['username'])
コード例 #8
0
 def _after_delete(self):
     """
         Deletes user exchanges just after user is deleted.
     """
     notifier = RabbitNotifications(self.request)
     notifier.delete_user(self['username'])
コード例 #9
0
ファイル: conversations.py プロジェクト: UPCnet/max
def postMessage2Conversation(conversations, request):
    """
        Add a new conversation
    """
    # We are forced the check and extract the context of the conversation here,
    # We can't initialize the activity first, because it would fail (chiken-egg stuff)
    data = request.decoded_payload
    ctxts = data.get('contexts', [])
    if len(ctxts) == 0:
        raise ValidationError('Empty contexts parameter')

    request_participants = ctxts[0].get('participants', [])
    if len(request_participants) == 0:
        raise ValidationError('Empty participants parameter')
    if len(request_participants) != len(list(set(request_participants))):
        raise ValidationError('One or more users duplicated in participants list')
    if len(request_participants) == 1 and request_participants[0] == request.actor['username']:
        raise ValidationError('Cannot start a conversation with oneself')

    if request.actor['username'] not in request_participants and not request.has_permission(add_conversation_for_others):
        raise ValidationError('Actor must be part of the participants list.')

    # Loop trough all participants, if there's one that doesn't exists, an exception will raise
    # This check is to avoid any conversation creation if there's any invalid participant
    # Also store the definitive list that will be saved in participants field

    participants = {}
    users = MADMaxCollection(request, 'users', query_key='username')
    for participant in request_participants:
        user = users[participant]
        if request.actor['username'] != user['username'] and not request.actor.is_allowed_to_see(user):
            raise Forbidden('User {} is not allowed to have a conversation with {}'.format(request.actor['username'], user['username']))
        participants[participant] = user

    # If there are only two participants in the conversation, try to get an existing conversation
    # Otherwise, assume is a group conversation and create a new one
    current_conversation = None
    if len(request_participants) == 2:
        current_conversation = conversations.first({
            'objectType': 'conversation',
            'participants': {
                '$size': 2},
            'tags': {'$not': {'$in': ['group']}},
            'participants.username': {
                '$all': request_participants}
        })

        if current_conversation and 'single' in current_conversation['tags']:
                for participant in participants:
                    if participants[participant].getSubscription(current_conversation) is None:
                        participants[participant].addSubscription(current_conversation)
                        current_conversation['tags'].remove('single')
                        current_conversation.save()

    if current_conversation is None:
        # Initialize a conversation (context) object from the request, overriding the object using the context
        conversation_params = dict(actor=request.actor,
                                   tags=['group'] if len(participants) > 2 else [],
                                   participants=[participant.flatten(preserve=['displayName', 'objectType', 'username']) for participant in participants.values()],
                                   permissions={'read': 'subscribed',
                                                'write': 'subscribed',
                                                'subscribe': 'restricted',
                                                'unsubscribe': 'subscribed'})
        if ctxts[0].get('displayName', False):
            conversation_params['displayName'] = ctxts[0]['displayName']

        newconversation = Conversation.from_request(request, rest_params=conversation_params)

        # New conversation
        contextid = newconversation.insert()
        newconversation['_id'] = contextid

        # Subscribe everyone,
        for user in newconversation['participants']:
            db_user = participants[user['username']]
            db_user.addSubscription(newconversation)
            # Initialize a Subscription Activity
            rest_params = {'actor': db_user,
                           'verb': 'subscribe',
                           'object': {'objectType': 'conversation',
                                      'id': newconversation['_id'],
                                      'participants': newconversation['participants']},
                           'contexts': []  # Override contexts from request

                           }
            newactivity = Activity.from_request(request, rest_params=rest_params)
            newactivity_oid = newactivity.insert()  # Insert a subscribe activity
            newactivity['_id'] = newactivity_oid

        current_conversation = newconversation

    # We need to reload the actor, in order to have the subscription updated
    # We need to reload reified acl's, so then new actor subscription will be visible by __acl__
    request.actor.reload()
    current_conversation.reload__acl__()

    message_params = {'actor': request.actor,
                      'contexts': [current_conversation],
                      'verb': 'post'}

    try:
        # Initialize a Message (Activity) object from the request
        newmessage = Message.from_request(request, rest_params=message_params)
    except Exception as catched:
        # In case we coulnd't post the message, rollback conversation creation
        current_conversation.delete()
        raise catched

    # Grant subscribe permission to the user creating the conversation, only if the conversation
    # is bigger than 2 people. Conversations that are created with only 2 people from the beggining
    # Will not be able to grow

    if len(current_conversation['participants']) > 2:
        subscription = request.actor.getSubscription(current_conversation)
        request.actor.grantPermission(subscription, 'invite', permanent=False)
        request.actor.grantPermission(subscription, 'kick', permanent=False)
        request.actor.revokePermission(subscription, 'unsubscribe', permanent=False)

    message_oid = newmessage.insert()
    newmessage['_id'] = message_oid

    output_message = newmessage.flatten()
    output_message['contexts'][0]['displayName'] = current_conversation.realDisplayName(request.actor)
    output_message['contexts'][0]['tags'] = current_conversation.get('tags', [])

    # Notification is done here because we don't want to do it right after insertion
    # as a possible rollback would cause a  notification of a inexistent conversation
    notifier = RabbitNotifications(request)
    notifier.add_conversation(current_conversation)

    handler = JSONResourceEntity(request, output_message, status_code=201)
    return handler.buildResponse()
コード例 #10
0
ファイル: conversation.py プロジェクト: UPCnet/max
 def _after_delete(self):
     notifier = RabbitNotifications(self.request)
     notifier.unbind_conversation(self)
コード例 #11
0
ファイル: conversation.py プロジェクト: UPCnet/max
 def _after_subscription_add(self, username):
     """
         Creates rabbitmq bindings after new subscription
     """
     notifier = RabbitNotifications(self.request)
     notifier.bind_user_to_conversation(self, username)
コード例 #12
0
ファイル: people.py プロジェクト: UPCnet/max
def addUser(users, request):
    """
        Add a user

        Creates a new user in the system, with all the attributes provided
        in the posted user object.

        - `username` - Used to identify and login the user. This is the only required parameter and cannot be modified.
        - `displayname` - The full name of the user.
        - `twitterUsername` - A valid Twitter® username (without @ prefix), used on the twitter integration service.


        This operation is idempotent, which means that a request to create a user that already exists,
        will not recreate or overwrite that user. Instead, the existing user object will be returned. You can
        tell when this happens by looking at the HTTP response status code. A new user insertion will return
        a **201 CREATED** code, and a **200 OK** for an existing user.

        + Request

            {
                "username": "******",
                "displayName": "user2",
                "twitterUsername": "******"
            }

    """
    payload = request.decoded_payload
    if not isinstance(payload, dict):
        raise ValidationError('Unexpected data type in request')

    username = payload.get('username', None)
    if username is None:
        raise ValidationError('Missing username in request')

    rest_params = {'username': username.lower()}

    # Initialize a User object from the request
    newuser = User.from_request(request, rest_params=rest_params)

    # If we have the _id setted, then the object already existed in the DB,
    # otherwise, proceed to insert it into the DB
    # In both cases, respond with the JSON of the object and the appropiate
    # HTTP Status Code

    if newuser.get('_id'):
        # Already Exists
        code = 200

        # Determine if we have to recreate exchanges for an existing user
        # Defaults NOT to recreate them if not specified
        create_exchanges = asbool(request.params.get('notifications', False))
        if create_exchanges:
            notifier = RabbitNotifications(request)
            notifier.add_user(username)
    else:
        # New User
        code = 201

        # Determine if we have to recreate exchanges for a new user
        # Defaults to Create them if not specified
        create_exchanges = asbool(request.params.get('notifications', True))
        userid = newuser.insert(notifications=create_exchanges)

        newuser['_id'] = userid
    handler = JSONResourceEntity(request, newuser.getInfo(), status_code=code)
    return handler.buildResponse()
コード例 #13
0
ファイル: context.py プロジェクト: UPCnet/max
 def _after_subscription_remove(self, username):
     """
         Removes rabbitmq bindings after new subscription
     """
     notifier = RabbitNotifications(self.request)
     notifier.unbind_user_from_context(self, username)
コード例 #14
0
ファイル: context.py プロジェクト: UPCnet/max
 def _after_saving_object(self, oid):
     if self.field_changed("twitterUsername"):
         notifier = RabbitNotifications(self.request)
         notifier.restart_tweety()