def upload_profile_image(self, files): """ POST only, validates email during registration """ input_file = files['file'] up = UserProfile(photo=input_file, id=self.user_id) create_thumbnail(input_file, up) up.save(update_fields=('photo', 'thumbnail')) up = UserProfile.objects.values('sex', 'thumbnail', 'photo', 'username').get(id=self.user_id) payload = { VarNames.HANDLER_NAME: HandlerNames.WS, VarNames.EVENT: Actions.USER_PROFILE_CHANGED } payload.update( RedisPrefix.set_js_user_structure( self.user_id, up['username'], up['sex'], get_thumbnail_url(up['thumbnail']), )) global_redis.sync_redis.publish(settings.ALL_ROOM_ID, json.dumps(payload)) global_redis.sync_redis.publish( RedisPrefix.generate_user(self.user_id), json.dumps({ VarNames.HANDLER_NAME: HandlerNames.WS, VarNames.EVENT: Actions.SET_PROFILE_IMAGE, VarNames.CONTENT: get_thumbnail_url(up['photo']), })) return settings.VALIDATION_IS_OK
def invite_user(self, message): room_id = message[VarNames.ROOM_ID] user_id = message[VarNames.USER_ID] room = get_or_create_room(self.channels, room_id, user_id) users_in_room = { user.id: RedisPrefix.set_js_user_structure(user.username, user.sex) for user in room.users.all() } self.publish( self.add_user_to_room(room_id, user_id, users_in_room[user_id]), room_id) subscribe_message = self.invite_room_channel_message( room_id, user_id, room.name, users_in_room) self.publish(subscribe_message, RedisPrefix.generate_user(user_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 get_users_in_current_user_rooms(user_id): user_rooms = Room.objects.filter(users__id=user_id, disabled=False).values('id', 'name', 'roomusers__notifications', 'roomusers__volume') res = MessagesCreator.create_user_rooms(user_rooms) room_ids = (room_id for room_id in res) rooms_users = User.objects.filter(rooms__in=room_ids).values('id', 'username', 'sex', 'rooms__id') for user in rooms_users: dict = res[user['rooms__id']][VarNames.ROOM_USERS] dict[user['id']] = RedisPrefix.set_js_user_structure(user['username'], user['sex']) return res
def create_user_channel(self, message): user_id = message[VarNames.USER_ID] room_id = create_room(self.user_id, user_id) subscribe_message = self.subscribe_direct_channel_message( room_id, user_id, self.user_id != user_id) self.publish(subscribe_message, self.channel, True) other_channel = RedisPrefix.generate_user(user_id) if self.channel != other_channel: self.publish(subscribe_message, other_channel, True)
def upload_profile_image(self, files): """ POST only, validates email during registration """ up = UserProfile(photo=files['file'], id=self.user_id) up.save(update_fields=('photo',)) url = up.photo.url message = json.dumps(MessagesCreator.set_profile_image(url)) channel = RedisPrefix.generate_user(self.user_id) global_redis.sync_redis.publish(channel, message) return settings.VALIDATION_IS_OK
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 upload_profile_image(request): """ POST only, validates email during registration """ up = UserProfile(photo=request.FILES['file'], id=request.user.id) up.save(update_fields=('photo', )) url = up.photo.url message = json.dumps(MessagesCreator.set_profile_image(url)) channel = RedisPrefix.generate_user(request.user.id) global_redis.sync_redis.publish(channel, message) return HttpResponse(settings.VALIDATION_IS_OK, content_type='text/plain')
def register(self, username, password, email, sex): check_user(username) self.__check_password(password) self.__check_email__(email) user_profile = UserProfile(username=username, email=email, sex_str=sex) user_profile.set_password(password) user_profile.save() RoomUsers(user_id=user_profile.id, room_id=settings.ALL_ROOM_ID, notifications=False).save() user_data = { VarNames.ROOMS: [{ VarNames.ROOM_ID: settings.ALL_ROOM_ID, VarNames.ROOM_USERS: list( RoomUsers.objects.filter(room_id=ALL_ROOM_ID).values_list( 'user_id', flat=True)) }], VarNames.EVENT: Actions.CREATE_NEW_USER, VarNames.HANDLER_NAME: HandlerNames.ROOM, } user_data.update( RedisPrefix.set_js_user_structure(user_profile.id, user_profile.username, user_profile.sex, None)) global_redis.async_redis_publisher.publish( settings.ALL_ROOM_ID, json.dumps(user_data), ) if email: yield from self.__send_sign_up_email(user_profile) return MessagesCreator.get_session( self.__generate_session__(user_profile.id))
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 open(self): session_key = self.get_argument('sessionId', None) user_id = self.sync_redis.hget('sessions', session_key) if user_id is None: self.logger.warning('!! Session key %s has been rejected' % session_key) self.close(403, "Session key %s has been rejected" % session_key) return self.user_id = int(user_id) self.ip = self.get_client_ip() user_db = UserProfile.objects.get(id=self.user_id) self.generate_self_id() self.message_creator = WebRtcMessageCreator(self.user_id, self.id) self._logger = logging.LoggerAdapter(parent_logger, { 'id': self.id, 'ip': self.ip }) self.logger.debug("!! Incoming connection, session %s, thread hash %s", session_key, self.id) self.async_redis.connect() self.async_redis_publisher.sadd(RedisPrefix.ONLINE_VAR, self.id) # since we add user to online first, latest trigger will always show correct online online = self.get_dict_users_from_redis() # current user is already online my_online = online.setdefault(self.user_id, []) if self.id not in my_online: my_online.append(self.id) was_online = len(online.get( self.user_id)) > 1 # if other tabs are opened user_rooms_query = Room.objects.filter(users__id=self.user_id, disabled=False) \ .values('id', 'name', 'creator_id', 'channel_id', 'p2p', 'roomusers__notifications', 'roomusers__volume') room_users = [{ VarNames.ROOM_ID: room['id'], VarNames.ROOM_NAME: room['name'], VarNames.CHANNEL_ID: room['channel_id'], VarNames.ROOM_CREATOR_ID: room['creator_id'], VarNames.NOTIFICATIONS: room['roomusers__notifications'], VarNames.P2P: room['p2p'], VarNames.VOLUME: room['roomusers__volume'], VarNames.ROOM_USERS: [] } for room in user_rooms_query] user_rooms_dict = {room[VarNames.ROOM_ID]: room for room in room_users} channels_ids = [ channel[VarNames.CHANNEL_ID] for channel in room_users if channel[VarNames.CHANNEL_ID] ] channels_db = Channel.objects.filter(Q(id__in=channels_ids) | Q(creator=self.user_id), disabled=False) channels = [{ VarNames.CHANNEL_ID: channel.id, VarNames.CHANNEL_NAME: channel.name, VarNames.CHANNEL_CREATOR_ID: channel.creator_id } for channel in channels_db] room_ids = [room_id[VarNames.ROOM_ID] for room_id in room_users] rooms_users = RoomUsers.objects.filter(room_id__in=room_ids).values( 'user_id', 'room_id') for ru in rooms_users: user_rooms_dict[ru['room_id']][VarNames.ROOM_USERS].append( ru['user_id']) # get all missed messages self.channels = room_ids # py2 doesn't support clear() self.channels.append(self.channel) self.channels.append(self.id) self.listen(self.channels) # this was replaced to syncHistory method that's called from browser and passes existing ids # off_messages, history = self.get_offline_messages(room_users, was_online, self.get_argument('history', False)) # for room in room_users: # room_id = room[VarNames.ROOM_ID] # h = history.get(room_id) # o = off_messages.get(room_id) # if h: # room[VarNames.LOAD_MESSAGES_HISTORY] = h # if o: # room[VarNames.LOAD_MESSAGES_OFFLINE] = o if settings.SHOW_COUNTRY_CODE: fetched_users = User.objects.annotate(user_c=Count('id')).values( 'id', 'username', 'sex', 'userjoinedinfo__ip__country_code', 'userjoinedinfo__ip__country', 'userjoinedinfo__ip__region', 'userjoinedinfo__ip__city') user_dict = [ RedisPrefix.set_js_user_structure_flag( user['id'], user['username'], user['sex'], user['userjoinedinfo__ip__country_code'], user['userjoinedinfo__ip__country'], user['userjoinedinfo__ip__region'], user['userjoinedinfo__ip__city']) for user in fetched_users ] else: fetched_users = User.objects.values('id', 'username', 'sex') user_dict = [ RedisPrefix.set_js_user_structure(user['id'], user['username'], user['sex']) for user in fetched_users ] self.ws_write( self.message_creator.set_room(room_users, user_dict, online, user_db, channels)) online_user_names_mes = self.message_creator.room_online_login( online, user_db.username, user_db.sex_str) self.logger.info('!! First tab, sending refresh online for all') self.publish(online_user_names_mes, settings.ALL_ROOM_ID) self.logger.info("!! User %s subscribes for %s", self.user_id, self.channels) self.connected = True
def channel(self): return RedisPrefix.generate_user(self.user_id)
def open(self): session_key = self.get_argument('sessionId', None) user_id = self.sync_redis.hget('sessions', session_key) if user_id is None: self.logger.warning('!! Session key %s has been rejected' % session_key) self.close(403, "Session key %s has been rejected" % session_key) return self.user_id = int(user_id) self.ip = self.get_client_ip() user_db = UserProfile.objects.get(id=self.user_id) self.generate_self_id() self._logger = logging.LoggerAdapter(parent_logger, { 'id': self.id, 'ip': self.ip }) self.logger.debug("!! Incoming connection, session %s, thread hash %s", session_key, self.id) self.async_redis.connect() self.async_redis_publisher.sadd(RedisPrefix.ONLINE_VAR, self.id) # since we add user to online first, latest trigger will always show correct online was_online, online = self.get_online_and_status_from_redis() user_rooms_query = Room.objects.filter(users__id=self.user_id, disabled=False) \ .values('id', 'name', 'roomusers__notifications', 'roomusers__volume') room_users = [{ VarNames.ROOM_ID: room['id'], VarNames.ROOM_NAME: room['name'], VarNames.NOTIFICATIONS: room['roomusers__notifications'], VarNames.VOLUME: room['roomusers__volume'], VarNames.ROOM_USERS: [] } for room in user_rooms_query] user_rooms_dict = {room[VarNames.ROOM_ID]: room for room in room_users} room_ids = [room_id[VarNames.ROOM_ID] for room_id in room_users] rooms_users = RoomUsers.objects.filter(room_id__in=room_ids).values( 'user_id', 'room_id') for ru in rooms_users: user_rooms_dict[ru['room_id']][VarNames.ROOM_USERS].append( ru['user_id']) # get all missed messages self.channels = room_ids # py2 doesn't support clear() self.channels.append(self.channel) self.channels.append(self.id) self.listen(self.channels) off_messages, history = self.get_offline_messages( room_users, was_online, self.get_argument('history', False)) for room in room_users: room_id = room[VarNames.ROOM_ID] h = history.get(room_id) o = off_messages.get(room_id) if h: room[VarNames.LOAD_MESSAGES_HISTORY] = h if o: room[VarNames.LOAD_MESSAGES_OFFLINE] = o if settings.SHOW_COUNTRY_CODE: fetched_users = User.objects.annotate(user_c=Count('id')).values( 'id', 'username', 'sex', 'userjoinedinfo__ip__country_code', 'userjoinedinfo__ip__country', 'userjoinedinfo__ip__region', 'userjoinedinfo__ip__city') user_dict = [ RedisPrefix.set_js_user_structure_flag( user['id'], user['username'], user['sex'], user['userjoinedinfo__ip__country_code'], user['userjoinedinfo__ip__country'], user['userjoinedinfo__ip__region'], user['userjoinedinfo__ip__city']) for user in fetched_users ] else: fetched_users = User.objects.values('id', 'username', 'sex') user_dict = [ RedisPrefix.set_js_user_structure(user['id'], user['username'], user['sex']) for user in fetched_users ] if self.user_id not in online: online.append(self.user_id) self.ws_write(self.set_room(room_users, user_dict, online, user_db)) if not was_online: # if a new tab has been opened online_user_names_mes = self.room_online_login( online, user_db.username, user_db.sex_str) self.logger.info('!! First tab, sending refresh online for all') self.publish(online_user_names_mes, settings.ALL_ROOM_ID) self.logger.info("!! User %s subscribes for %s", self.user_id, self.channels) self.connected = True