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()
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()