def invite_user(self, message): room_id = message[VarNames.ROOM_ID] if room_id not in self.channels: raise ValidationError("Access denied, only allowed for channels {}".format(self.channels)) room = Room.objects.get(id=room_id) if room.is_private: raise ValidationError("You can't add users to direct room, create a new room instead") users = message.get(VarNames.ROOM_USERS) users_in_room = list(RoomUsers.objects.filter(room_id=room_id).values_list('user_id', flat=True)) intersect = set(users_in_room) & set(users) if bool(intersect): raise ValidationError("Users %s are already in the room", intersect) users_in_room.extend(users) max_id = Message.objects.filter(room_id=room_id).aggregate(Max('id'))['id__max'] if not max_id: max_id = Message.objects.all().aggregate(Max('id'))['id__max'] ru = [RoomUsers( user_id=user_id, room_id=room_id, last_read_message_id=max_id, volume=1, notifications=False ) for user_id in users] RoomUsers.objects.bulk_create(ru) add_invitee = { VarNames.EVENT: Actions.ADD_INVITE, VarNames.ROOM_ID: room_id, VarNames.ROOM_USERS: users_in_room, VarNames.ROOM_NAME: room.name, VarNames.INVITEE_USER_ID: users, VarNames.INVITER_USER_ID: self.user_id, VarNames.HANDLER_NAME: HandlerNames.ROOM, VarNames.TIME: get_milliseconds(), VarNames.VOLUME: 1, VarNames.NOTIFICATIONS: False, } add_invitee_dumped = encode_message(add_invitee, True) for user in users: self.raw_publish(add_invitee_dumped, RedisPrefix.generate_user(user)) invite = { VarNames.EVENT: Actions.INVITE_USER, VarNames.ROOM_ID: room_id, VarNames.INVITEE_USER_ID: users, VarNames.INVITER_USER_ID: self.user_id, VarNames.HANDLER_NAME: HandlerNames.ROOM, VarNames.ROOM_USERS: users_in_room, VarNames.TIME: get_milliseconds(), VarNames.CB_BY_SENDER: self.id, VarNames.JS_MESSAGE_ID: message[VarNames.JS_MESSAGE_ID] } self.publish(invite, room_id, True)
def save_channels_settings(self, message): channel_id = message[VarNames.CHANNEL_ID] channel_name = message[VarNames.CHANNEL_NAME] new_creator = message[VarNames.CHANNEL_CREATOR_ID] if not channel_name or len(channel_name) > 16: raise ValidationError('Incorrect channel name name "{}"'.format(channel_name)) channel = Channel.objects.get(id=channel_id) users_id = list(RoomUsers.objects.filter(room__channel_id=channel_id).values_list('user_id', flat=True)) if channel.creator_id != self.user_id and self.user_id not in users_id: raise ValidationError("You are not allowed to edit this channel") if new_creator != channel.creator_id: if self.user_id != channel.creator_id: raise ValidationError("Only admin can change the admin of this channel") if new_creator not in users_id: raise ValidationError("You can only change admin to one of the users in this channels room") channel.creator_id = new_creator if self.user_id not in users_id: # if channel has no rooms users_id.append(self.user_id) channel.name = channel_name channel.save() m = { VarNames.EVENT: Actions.SAVE_CHANNEL_SETTINGS, VarNames.CHANNEL_ID: channel_id, VarNames.CB_BY_SENDER: self.id, VarNames.HANDLER_NAME: HandlerNames.ROOM, VarNames.CHANNEL_NAME: channel_name, VarNames.CHANNEL_CREATOR_ID: channel.creator_id, VarNames.TIME: get_milliseconds(), VarNames.JS_MESSAGE_ID: message[VarNames.JS_MESSAGE_ID], } for user_id in users_id: self.publish(m, RedisPrefix.generate_user(user_id))
def delete_channel(self, message): channel_id = message[VarNames.CHANNEL_ID] channel = Channel.objects.get(id=channel_id) if channel.creator_id != self.user_id: raise ValidationError( f"Only admin can delete this channel. Please ask ${User.objects.get(id=channel.creator_id).username}" ) # if Room.objects.filter(channel_id=channel_id).count() > 0: users_id = list( RoomUsers.objects.filter(room__channel_id=channel_id).values_list( 'user_id', flat=True)) if len(users_id) > 0: raise ValidationError( f"Some users are still in the rooms on this channel Please ask them to leave" ) Room.objects.filter(channel_id=channel_id).update(disabled=True) channel.disabled = True channel.save() message = { VarNames.EVENT: Actions.DELETE_CHANNEL, VarNames.CHANNEL_ID: channel_id, VarNames.HANDLER_NAME: HandlerNames.CHANNELS, VarNames.TIME: get_milliseconds(), VarNames.CB_BY_SENDER: self.id, VarNames.JS_MESSAGE_ID: message[VarNames.JS_MESSAGE_ID] } self.publish(message, self.channel)
def set_connection_id(js_message_id, connection_id): return { VarNames.EVENT: Actions.SET_WEBRTC_ID, VarNames.HANDLER_NAME: HandlerNames.NULL, VarNames.CONNECTION_ID: connection_id, VarNames.JS_MESSAGE_ID: js_message_id, VarNames.TIME: get_milliseconds(), }
def validate_edit_message(self_id, message): if message.sender_id != self_id: raise ValidationError("You can only edit your messages") if message.time + ONE_DAY < get_milliseconds(): raise ValidationError( "You can only edit messages that were send not more than 1 day") if message.deleted: raise ValidationError("Already deleted")
def unsubscribe_direct_message(self, room_id): return { VarNames.EVENT: Actions.DELETE_ROOM, VarNames.ROOM_ID: room_id, VarNames.USER_ID: self.user_id, HandlerNames.NAME: HandlerNames.CHANNELS, VarNames.TIME: get_milliseconds() }
def edit_glyphy(message, giphy): Message.objects.filter(id=message.id).update( content=message.content, symbol=message.symbol, giphy=giphy, edited_times=get_milliseconds() ) message.giphy = giphy self.publish(self.message_creator.create_send_message(message, Actions.EDIT_MESSAGE, None, {}), message.room_id)
def default(self, content, event, handler): """ :return: {"action": event, "content": content, "time": "20:48:57"} """ return { VarNames.EVENT: event, VarNames.CONTENT: content, VarNames.USER_ID: self.user_id, VarNames.TIME: get_milliseconds(), HandlerNames.NAME: handler }
def set_room(self, rooms, users, online, up): return { VarNames.ROOM_USERS: users, VarNames.ONLINE: online, VarNames.ROOMS: rooms, VarNames.HANDLER_NAME: HandlerNames.WS, VarNames.EVENT: Actions.SET_WS_ID, VarNames.WEBRTC_OPPONENT_ID: self.id, VarNames.TIME: get_milliseconds(), VarNames.USER_IMAGE: up.photo.url if up.photo else None, VarNames.CURRENT_USER_SETTINGS: self.get_user_settings(up), VarNames.CURRENT_USER_INFO: self.get_user_profile(up), }
def offer_webrtc(self, content, connection_id, room_id, action): """ :return: {"action": "call", "content": content, "time": "20:48:57"} """ return { VarNames.EVENT: action, VarNames.CONTENT: content, VarNames.USER_ID: self.user_id, VarNames.HANDLER_NAME: HandlerNames.WEBRTC, VarNames.CONNECTION_ID: connection_id, VarNames.WEBRTC_OPPONENT_ID: self.id, VarNames.ROOM_ID: room_id, VarNames.TIME: get_milliseconds() }
def sync_history(self, in_message): room_ids = in_message[VarNames.ROOM_IDS] message_ids = in_message[VarNames.MESSAGE_IDS] if not set(room_ids).issubset(self.channels): raise ValidationError("This is not a messages in the room you are in") messages = Message.objects.filter( Q(room_id__in=room_ids) & ~Q(id__in=message_ids) & Q(edited_times__gt=get_milliseconds() - in_message[VarNames.LAST_SYNCED]) ) content = MessagesCreator.message_models_to_dtos(messages) self.ws_write({ VarNames.CONTENT: content, VarNames.JS_MESSAGE_ID: in_message[VarNames.JS_MESSAGE_ID], VarNames.HANDLER_NAME: HandlerNames.NULL })
def edit_message(self, data): message_id = data[VarNames.MESSAGE_ID] message = Message.objects.get(id=message_id) if message.sender_id != self.user_id: raise ValidationError("You can only edit your messages") if message.time + 60000 < get_milliseconds(): raise ValidationError("You can only edit messages that were send not more than 1 min ago") if message.deleted: raise ValidationError("Already deleted") message.content = data[VarNames.CONTENT] selector = Message.objects.filter(id=message_id) if message.content is None: selector.update(deleted=True) action = Actions.DELETE_MESSAGE else: action = Actions.EDIT_MESSAGE selector.update(content=message.content) self.publish(self.create_send_message(message, action), message.room_id)
def edit_message(self, data): message = Message.objects.get(id=data[VarNames.MESSAGE_ID]) validate_edit_message(self.user_id, message) message.content = data[VarNames.CONTENT] MessageHistory(message=message, content=message.content, giphy=message.giphy).save() message.edited_times += 1 giphy_match = self.isGiphy(data[VarNames.CONTENT]) if message.content is None: Message.objects.filter(id=data[VarNames.MESSAGE_ID]).update( deleted=True, edited_times=get_milliseconds(), content=None ) self.publish(self.message_creator.create_send_message(message, Actions.DELETE_MESSAGE, None, {}), message.room_id) elif giphy_match is not None: self.edit_message_giphy(giphy_match, message) else: self.edit_message_edit(data, message)
def on_close(self): if self.async_redis.subscribed: self.logger.info("Close event, unsubscribing from %s", self.channels) self.async_redis.unsubscribe(self.channels) else: self.logger.info("Close event, not subscribed, channels: %s", self.channels) self.async_redis_publisher.srem(RedisPrefix.ONLINE_VAR, self.id) online = self.get_dict_users_from_redis() my_online = online.setdefault(self.user_id, []) if self.id in my_online: my_online.remove(self.id) if self.connected: message = self.message_creator.room_online_logout(online) self.publish(message, settings.ALL_ROOM_ID) UserProfile.objects.filter(id=self.user_id).update( last_time_online=get_milliseconds()) self.disconnect()
def create_new_channel(self, message): channel_name = message.get(VarNames.CHANNEL_NAME) if not channel_name or len(channel_name) > 16: raise ValidationError('Incorrect channel name name "{}"'.format(channel_name)) channel = Channel(name=channel_name, creator_id=self.user_id) channel.save() channel_id = channel.id m = { VarNames.EVENT: Actions.CREATE_CHANNEL, VarNames.CHANNEL_ID: channel_id, VarNames.CHANNEL_CREATOR_ID: channel.creator_id, VarNames.CB_BY_SENDER: self.id, VarNames.HANDLER_NAME: HandlerNames.ROOM, VarNames.CHANNEL_NAME: channel_name, VarNames.TIME: get_milliseconds(), VarNames.JS_MESSAGE_ID: message[VarNames.JS_MESSAGE_ID], } self.publish(m, self.channel)
def no_history_q(q_objects, room_id, h, f): q_objects.add( Q(room_id=room_id) & ((Q(id__gte=h) & Q(id__lte=f) & Q(edited_times__gt=0) & Q(time__gt=get_milliseconds() - ONE_DAY)) | Q(id__gt=f)), Q.OR)
def save_room_settings(self, message): """ POST only, validates email during registration """ room_id = message[VarNames.ROOM_ID] room_name = message[VarNames.ROOM_NAME] creator_id = message.get( VarNames.ROOM_CREATOR_ID) # will be none for private room updated = RoomUsers.objects.filter( room_id=room_id, user_id=self.user_id).update( volume=message[VarNames.VOLUME], notifications=message[VarNames.NOTIFICATIONS]) if updated != 1: raise ValidationError("You don't have access to this room") room = Room.objects.get(id=room_id) update_all = False if not room.name: if room.p2p != message[VarNames.P2P]: room.p2p = message[VarNames.P2P] update_all = True elif room_id != settings.ALL_ROOM_ID: if room_name != room.name: room.name = room_name update_all = True if room.channel_id != message[VarNames.CHANNEL_ID]: room.channel_id = message[VarNames.CHANNEL_ID] if room.channel_id and room.channel_id not in self.get_users_channels_ids( ): raise ValidationError( "You don't have access to this channel") update_all = True if creator_id != room.creator_id: if room.creator_id != self.user_id: raise ValidationError( "Only an owner of this room can change its admin") users_id = RoomUsers.objects.filter( room_id=room.id).values_list('user_id', flat=True) if creator_id not in users_id: raise ValidationError( "You can only change admin to one of the users in this channels room" ) room.creator_id = creator_id update_all = True if message.get(VarNames.CHANNEL_ID): # will be nOne for private room channel = Channel.objects.get(id=message[VarNames.CHANNEL_ID]) channel_name = channel.name channel_creator_id = channel.creator_id else: channel_name = None channel_creator_id = None if update_all: room.save() room_users = list(RoomUsers.objects.filter(room_id=room_id)) for room_user in room_users: self.publish( { VarNames.EVENT: Actions.SAVE_ROOM_SETTINGS, VarNames.CHANNEL_ID: room.channel_id, VarNames.CB_BY_SENDER: self.id, VarNames.HANDLER_NAME: HandlerNames.CHANNELS, VarNames.CHANNEL_NAME: channel_name, VarNames.CHANNEL_CREATOR_ID: channel_creator_id, VarNames.ROOM_CREATOR_ID: room.creator_id, VarNames.ROOM_ID: room.id, VarNames.VOLUME: room_user.volume, VarNames.NOTIFICATIONS: room_user.notifications, VarNames.P2P: message[VarNames.P2P], VarNames.ROOM_NAME: room_name, VarNames.TIME: get_milliseconds(), VarNames.JS_MESSAGE_ID: message[VarNames.JS_MESSAGE_ID], }, RedisPrefix.generate_user(room_user.user_id)) else: self.publish( { VarNames.EVENT: Actions.SAVE_ROOM_SETTINGS, VarNames.CHANNEL_ID: room.channel_id, VarNames.CB_BY_SENDER: self.id, VarNames.CHANNEL_CREATOR_ID: channel_creator_id, VarNames.ROOM_CREATOR_ID: room.creator_id, VarNames.HANDLER_NAME: HandlerNames.CHANNELS, VarNames.CHANNEL_NAME: channel_name, VarNames.ROOM_ID: room.id, VarNames.VOLUME: message[VarNames.VOLUME], VarNames.NOTIFICATIONS: message[VarNames.NOTIFICATIONS], VarNames.P2P: message[VarNames.P2P], VarNames.ROOM_NAME: room_name, VarNames.TIME: get_milliseconds(), VarNames.JS_MESSAGE_ID: message[VarNames.JS_MESSAGE_ID], }, self.channel)
def create_new_room(self, message): room_name = message.get(VarNames.ROOM_NAME) users = message.get(VarNames.ROOM_USERS) channel_id = message.get(VarNames.CHANNEL_ID) users.append(self.user_id) users = list(set(users)) if room_name and len(room_name) > 16: raise ValidationError('Incorrect room name "{}"'.format(room_name)) create_room = True if not room_name and len(users) == 2: user_rooms = evaluate( Room.users.through.objects.filter( user_id=self.user_id, room__name__isnull=True).values('room_id')) user_id = users[0] if users[1] == self.user_id else users[1] try: room = RoomUsers.objects.filter(user_id=user_id, room__in=user_rooms).values( 'room__id', 'room__disabled').get() room_id = room['room__id'] if room['room__disabled']: # only a private room can be disabled Room.objects.filter(id=room_id).update( disabled=False, p2p=message[VarNames.P2P]) RoomUsers.objects.filter( user_id=self.user_id, room_id=room_id).update( volume=message[VarNames.VOLUME], notifications=message[VarNames.NOTIFICATIONS]) else: raise ValidationError('This room already exist') create_room = False except RoomUsers.DoesNotExist: pass elif not room_name: raise ValidationError( 'At least one user should be selected, or room should be public' ) if channel_id and channel_id not in self.get_users_channels_ids(): raise ValidationError("You don't have access to this channel") if channel_id: channel = Channel.objects.get(id=channel_id) channel_name = channel.name channel_creator_id = channel.creator_id else: channel_name = None channel_creator_id = None if create_room: room = Room(name=room_name, channel_id=channel_id, p2p=message[VarNames.P2P]) if not room_name: room.creator_id = self.user_id room.save() room_id = room.id max_id = Message.objects.all().aggregate(Max('id'))['id__max'] ru = [ RoomUsers(user_id=user_id, room_id=room_id, last_read_message_id=max_id, volume=message[VarNames.VOLUME], notifications=message[VarNames.NOTIFICATIONS]) for user_id in users ] RoomUsers.objects.bulk_create(ru) m = { VarNames.EVENT: Actions.CREATE_ROOM, VarNames.ROOM_ID: room_id, VarNames.ROOM_USERS: users, VarNames.CB_BY_SENDER: self.id, VarNames.INVITER_USER_ID: self.user_id, VarNames.HANDLER_NAME: HandlerNames.CHANNELS, VarNames.VOLUME: message[VarNames.VOLUME], VarNames.P2P: message[VarNames.P2P], VarNames.NOTIFICATIONS: message[VarNames.NOTIFICATIONS], VarNames.ROOM_NAME: room_name, VarNames.TIME: get_milliseconds(), VarNames.JS_MESSAGE_ID: message[VarNames.JS_MESSAGE_ID], } if channel_id: m[VarNames.CHANNEL_NAME] = channel_name m[VarNames.CHANNEL_ID] = channel_id m[VarNames.CHANNEL_CREATOR_ID] = channel_creator_id jsoned_mess = encode_message(m, True) for user in users: self.raw_publish(jsoned_mess, RedisPrefix.generate_user(user))
def create_new_room(self, message): room_name = message.get(VarNames.ROOM_NAME) users = message.get(VarNames.ROOM_USERS) users.append(self.user_id) users = list(set(users)) if room_name and len(room_name) > 16: raise ValidationError('Incorrect room name "{}"'.format(room_name)) create_user_rooms = True if not room_name and len(users) == 2: user_rooms = evaluate( Room.users.through.objects.filter( user_id=self.user_id, room__name__isnull=True).values('room_id')) user_id = users[0] if users[1] == self.user_id else users[1] try: room = RoomUsers.objects.filter(user_id=user_id, room__in=user_rooms).values( 'room__id', 'room__disabled').get() room_id = room['room__id'] if room['room__disabled']: Room.objects.filter(id=room_id).update(disabled=False) else: raise ValidationError('This room already exist') create_user_rooms = False except RoomUsers.DoesNotExist: pass elif not room_name: raise ValidationError( 'At least one user should be selected, or room should be public' ) if create_user_rooms: room = Room(name=room_name) do_db(room.save) room_id = room.id max_id = Message.objects.all().aggregate(Max('id'))['id__max'] ru = [ RoomUsers(user_id=user_id, room_id=room_id, last_read_message_id=max_id, volume=message[VarNames.VOLUME], notifications=message[VarNames.NOTIFICATIONS]) for user_id in users ] RoomUsers.objects.bulk_create(ru) m = { VarNames.EVENT: Actions.CREATE_ROOM_CHANNEL, VarNames.ROOM_ID: room_id, VarNames.ROOM_USERS: users, VarNames.CB_BY_SENDER: self.id, VarNames.INVITER_USER_ID: self.user_id, VarNames.HANDLER_NAME: HandlerNames.CHANNELS, VarNames.VOLUME: message[VarNames.VOLUME], VarNames.NOTIFICATIONS: message[VarNames.NOTIFICATIONS], VarNames.ROOM_NAME: room_name, VarNames.TIME: get_milliseconds(), VarNames.JS_MESSAGE_ID: message[VarNames.JS_MESSAGE_ID], } jsoned_mess = encode_message(m, True) for user in users: self.raw_publish(jsoned_mess, RedisPrefix.generate_user(user))
def ping_online(): message = encode_message(MessagesCreator.ping_client(get_milliseconds()), True) logger.info("Pinging clients: %s", message) async_redis_publisher.publish(ALL_ROOM_ID, message)
def edit_message_edit(self, data, message): action = Actions.EDIT_MESSAGE message.giphy = None tags = data[VarNames.MESSAGE_TAGS] files = UploadedFile.objects.filter(id__in=data.get(VarNames.FILES), user_id=self.user_id) if files or tags: update_symbols(files, tags, message) if tags: db_tags = MessageMention.objects.filter(message_id=message.id) update_or_create = [] update_or_create_dict = {} for db_tag in db_tags: if tags.get(db_tag.symbol) and tags.get(db_tag.symbol) != db_tag.user_id: update_or_create.append(MessageMention(message_id=message.id, symbol=db_tag.symbol, user_id=tags[db_tag.symbol])) update_or_create_dict[db_tag.symbol] = True if update_or_create: MessageMention.objects.bulk_update(update_or_create) create_tags = [] for (k, v) in tags.items(): if not update_or_create_dict.get(k): create_tags.append(MessageMention(message_id=message.id, symbol=k, user_id=v)) if create_tags: MessageMention.objects.bulk_create(create_tags) if files: up_files_to_img(files, message.id) if message.symbol: # fetch all, including that we just store db_images = Image.objects.filter(message_id=message.id) prep_files = MessagesCreator.prepare_img_video(db_images, message.id) else: prep_files = None Message.objects.filter(id=message.id).update(content=message.content, symbol=message.symbol, giphy=None, edited_times=get_milliseconds()) self.publish(self.message_creator.create_send_message(message, action, prep_files, tags), message.room_id)