def get_banned_users(self) -> dict: all_channels = self.redis.hgetall(RedisKeys.channels()) def get_banned_users_all_channels() -> dict: output = dict() for channel_id, _ in all_channels.items(): channel_id = str(channel_id, 'utf-8') bans = { 'name': b64e(self.get_channel_name(channel_id)), 'users': self.get_banned_users_for_channel(channel_id) } if len(bans['users']) > 0: output[channel_id] = bans return output def get_banned_users_all_rooms() -> dict: output = dict() for channel_id, _ in all_channels.items(): channel_id = str(channel_id, 'utf-8') rooms_for_channel = self.redis.hgetall(RedisKeys.rooms(channel_id)) for room_id, _ in rooms_for_channel.items(): room_id = str(room_id, 'utf-8') bans = { 'name': b64e(self.get_room_name(room_id)), 'users': self.get_banned_users_for_room(room_id) } if len(bans['users']) > 0: output[room_id] = bans return output return { 'global': self.get_banned_users_global(), 'channels': get_banned_users_all_channels(), 'rooms': get_banned_users_all_rooms() }
def get_channels(self) -> dict: all_channels = self.redis.hgetall(RedisKeys.channels()) clean = dict() for channel_id, channel_name in all_channels.items(): # second argument in tuple is sort order, but it's not supported with redis db clean[str(channel_id, 'utf-8')] = (str(channel_name, 'utf-8'), 1, 'normal') return clean
def channel_name_exists(self, channel_name: str) -> bool: cleaned = set() for candidate in self.redis.hvals(RedisKeys.channels()): cleaned.add(str(candidate, 'utf-8').lower()) if type(channel_name) == bytes: channel_name = str(channel_name, 'utf-8') return channel_name.lower() in cleaned
def remove_channel_exists(self, channel_id: str) -> None: key = RedisKeys.channel_exists() cache_key = '%s-%s' % (key, channel_id) self.redis.hdel(key, channel_id) self.cache.delete(cache_key) key = RedisKeys.channels() cache_key = '%s-name-%s' % (key, channel_id) self.cache.delete(cache_key) self.redis.hdel(key, channel_id)
def rename_channel(self, channel_id: str, channel_name: str) -> None: self.get_channel_name(channel_id) if self.channel_name_exists(channel_name): raise ChannelNameExistsException(channel_name) if channel_name is None or len(channel_name.strip()) == 0: raise EmptyChannelNameException(channel_id) self.redis.hset(RedisKeys.channels(), channel_id, channel_name) self.env.cache.set_channel_name(channel_id, channel_name)
def get_channel_name(self, channel_id: str) -> str: channel_name = self.env.cache.get_channel_name(channel_id) if channel_name is not None: return channel_name channel_name = self.redis.hget(RedisKeys.channels(), channel_id) if channel_name is None: raise NoSuchChannelException(channel_id) channel_name = str(channel_name, 'utf-8') self.env.cache.set_channel_name(channel_id, channel_name) return channel_name
def create_channel(self, channel_name, channel_id, user_id) -> None: if self.channel_exists(channel_id): raise ChannelExistsException(channel_id) if channel_name is None or len(channel_name.strip()) == 0: raise EmptyChannelNameException(channel_id) if self.channel_name_exists(channel_name): raise ChannelNameExistsException(channel_name) self.env.cache.set_channel_exists(channel_id) self.redis.hset(RedisKeys.channels(), channel_id, channel_name) self.set_owner_channel(channel_id, user_id)
def create_channel(self, room_id=None, room_name=None): if room_id is None: room_id = BaseTest.ROOM_ID if room_name is None: room_name = BaseTest.ROOM_NAME environ.env.db.redis.hset(RedisKeys.rooms(BaseTest.CHANNEL_ID), room_id, room_name) environ.env.db.redis.hset(RedisKeys.channels(), BaseTest.CHANNEL_ID, BaseTest.CHANNEL_NAME) environ.env.db.redis.hset(RedisKeys.channel_roles(BaseTest.CHANNEL_ID), BaseTest.USER_ID, RoleKeys.OWNER) environ.env.db.redis.hset(RedisKeys.auth_key(BaseTest.USER_ID), SessionKeys.user_name.value, BaseTest.USER_NAME) environ.env.db.redis.hset(RedisKeys.channel_for_rooms(), room_id, BaseTest.CHANNEL_ID) environ.env.db.redis.hset(RedisKeys.room_name_for_id(), room_id, room_name) environ.env.cache.set_channel_exists(BaseTest.CHANNEL_ID)
def get_channel_name(self, channel_id: str) -> str: key = RedisKeys.channels() cache_key = '%s-name-%s' % (key, channel_id) value = self.cache.get(cache_key) if value is not None: return value value = self.redis.hget(key, channel_id) if value is None: return None value = str(value, 'utf-8') self.cache.set(cache_key, value) return value
def test_get_channel_name_after_expired(self): self.assertIsNone( self.cache.get_channel_name(CacheRedisTest.CHANNEL_ID)) self.cache.set_channel_name(CacheRedisTest.CHANNEL_ID, CacheRedisTest.CHANNEL_NAME) self.assertEqual( CacheRedisTest.CHANNEL_NAME, self.cache.get_channel_name(CacheRedisTest.CHANNEL_ID)) key = RedisKeys.channels() cache_key = '%s-name-%s' % (key, CacheRedisTest.CHANNEL_ID) self.cache._del(cache_key) self.assertEqual( CacheRedisTest.CHANNEL_NAME, self.cache.get_channel_name(CacheRedisTest.CHANNEL_ID))
def set_channel_name(self, channel_id: str, channel_name: str) -> None: key = RedisKeys.channels() cache_key = '%s-name-%s' % (key, channel_id) self.cache.set(cache_key, channel_name) self.redis.hset(key, channel_id, channel_name)
def get_bans_for_user(self, user_id: str, session=None) -> dict: def _to_date(_timestamp): return datetime.fromtimestamp(int(_timestamp)).strftime(ConfigKeys.DEFAULT_DATE_FORMAT) now = datetime.utcnow() all_channels = self.redis.hgetall(RedisKeys.channels()) channel_ids = list() room_ids = list() output = { 'global': dict(), 'room': dict(), 'channel': dict() } for channel_id, _ in all_channels.items(): channel_ids.append(str(channel_id, 'utf-8')) for channel_id in channel_ids: all_rooms = self.redis.hgetall(RedisKeys.rooms(channel_id)) for room_id, _ in all_rooms.items(): room_ids.append(str(room_id, 'utf-8')) for channel_id in channel_ids: r_key = RedisKeys.banned_users_channel(channel_id) if not self.redis.hexists(r_key, user_id): continue ban_info = self.redis.hget(RedisKeys, r_key) ban_duration, ban_timestamp, _ = ban_info.split('|', 2) if datetime.fromtimestamp(int(ban_timestamp)) < now: self.redis.hdel(r_key, user_id) continue output['channel'][channel_id] = { 'name': b64e(self.get_channel_name(channel_id)), 'duration': ban_duration, 'timestamp': _to_date(ban_timestamp) } for room_id in room_ids: r_key = RedisKeys.banned_users(room_id) if not self.redis.hexists(r_key, user_id): continue ban_info = self.redis.hget(RedisKeys, r_key) ban_duration, ban_timestamp, _ = ban_info.split('|', 2) if datetime.fromtimestamp(int(ban_timestamp)) < now: self.redis.hdel(r_key, user_id) continue output['room'][room_id] = { 'name': b64e(self.get_room_name(room_id)), 'duration': ban_duration, 'timestamp': _to_date(ban_timestamp) } r_key = RedisKeys.banned_users() if self.redis.hexists(r_key, user_id): ban_info = self.redis.hget(RedisKeys.banned_users(), user_id) ban_duration, ban_timestamp, _ = ban_info.split('|', 2) if datetime.fromtimestamp(int(ban_timestamp)) < now: self.redis.hdel(r_key, user_id) else: output['global'] = { 'duration': ban_duration, 'timestamp': _to_date(ban_timestamp) } return output
def remove_channel(self, channel_id: str) -> None: self.redis.hdel(RedisKeys.channels(), channel_id) self.redis.hdel(RedisKeys.banned_users_channel(channel_id)) self.redis.hdel(RedisKeys.channel_acl(channel_id))
def channel_exists(self, channel_id) -> bool: if channel_id is None or channel_id == '': return False return self.redis.hexists(RedisKeys.channels(), channel_id)
def setUp(self): BaseTest.users_in_room.clear() BaseTest.emit_args.clear() BaseTest.emit_kwargs.clear() BaseTest.msgs_sent.clear() BaseTest.rendered_template = None self.session = { 'user_id': BaseTest.USER_ID, 'user_name': BaseTest.USER_NAME, 'age': BaseTest.AGE, 'gender': BaseTest.GENDER, 'membership': BaseTest.MEMBERSHIP, 'image': BaseTest.IMAGE, 'fake_checked': BaseTest.FAKE_CHECKED, 'has_webcam': BaseTest.HAS_WEBCAM, 'city': BaseTest.CITY, 'country': BaseTest.COUNTRY, 'token': '66968fad-2336-40c9-bc6d-0ecbcd91f4da' } environ.env.config = environ.ConfigDict() environ.env.config.set(ConfigKeys.TESTING, True) environ.env.config = environ.env.config.sub(**self.session) all_acls = [ 'age', 'gender', 'membership', 'group', 'country', 'city', 'image', 'has_webcam', 'fake_checked', 'owner', 'admin', 'moderator', 'superuser', 'crossroom', 'samechannel', 'sameroom', 'disallow' ] environ.env.config.set( ConfigKeys.ACL, { 'room': { 'join': { 'acls': all_acls }, 'message': { 'acls': all_acls }, 'history': { 'acls': all_acls }, 'crossroom': { 'acls': all_acls } }, 'channel': { 'message': { 'acls': all_acls }, 'list': { 'acls': all_acls }, 'crossroom': { 'acls': all_acls }, 'whisper': { 'acls': ['disallow'] }, }, 'available': { 'acls': all_acls }, 'validation': { 'superuser': { 'type': 'superuser', 'value': AclIsSuperUserValidator() }, 'admin': { 'type': 'admin', 'value': AclIsAdminValidator() }, 'samechannel': { 'type': 'samechannel', 'value': AclSameChannelValidator() }, 'sameroom': { 'type': 'sameroom', 'value': AclSameRoomValidator() }, 'country': { 'type': 'str_in_csv', 'value': AclStrInCsvValidator() }, 'disallow': { 'type': 'disallow', 'value': AclDisallowValidator() }, 'gender': { 'type': 'str_in_csv', 'value': AclStrInCsvValidator('m,f') }, 'membership': { 'type': 'str_in_csv', 'value': AclStrInCsvValidator() }, 'city': { 'type': 'str_in_csv', 'value': AclStrInCsvValidator() }, 'has_webcam': { 'type': 'str_in_csv', 'value': AclStrInCsvValidator('y,n') }, 'fake_checked': { 'type': 'str_in_csv', 'value': AclStrInCsvValidator('y,n') }, 'image': { 'type': 'str_in_csv', 'value': AclStrInCsvValidator('y,n') }, 'group': { 'type': 'str_in_csv', 'value': AclStrInCsvValidator('') }, 'age': { 'type': 'range', 'value': AclRangeValidator() } } }) environ.env.auth = AuthRedis('mock', env=environ.env) environ.env.storage = StorageRedis('mock') environ.env.db = DatabaseRedis(environ.env, 'mock') environ.env.storage.redis = environ.env.auth.redis environ.env.db.redis = environ.env.auth.redis environ.env.redis = environ.env.auth.redis environ.env.publish = BaseTest._mock_publish environ.env.disconnect = BaseTest._disconnect environ.env.stats = MockStats() environ.env.spam = MockSpam() environ.env.cache = CacheAllMiss() environ.env.auth.redis.flushall() environ.env.storage.redis.flushall() environ.env.db.redis.flushall() environ.env.cache._flushall() environ.env.auth.redis.hmset(RedisKeys.auth_key(BaseTest.USER_ID), self.session) environ.env.redis.hset(RedisKeys.room_name_for_id(), BaseTest.ROOM_ID, BaseTest.ROOM_NAME) environ.env.redis.sadd(RedisKeys.non_ephemeral_rooms(), BaseTest.ROOM_ID) environ.env.redis.hset(RedisKeys.channels(), BaseTest.CHANNEL_ID, BaseTest.CHANNEL_NAME) environ.env.db.redis.hset(RedisKeys.channels(), BaseTest.CHANNEL_ID, BaseTest.CHANNEL_NAME) environ.env.db.redis.hset(RedisKeys.auth_key(BaseTest.USER_ID), SessionKeys.user_name.value, BaseTest.USER_NAME) environ.env.db.redis.hset(RedisKeys.channel_for_rooms(), BaseTest.ROOM_ID, BaseTest.CHANNEL_ID) environ.env.db.redis.hset(RedisKeys.user_names(), BaseTest.USER_ID, BaseTest.USER_NAME) environ.env.db.redis.delete(RedisKeys.room_acl(BaseTest.ROOM_ID)) environ.env.render_template = BaseTest._render_template environ.env.emit = BaseTest._emit environ.env.join_room = BaseTest._join_room environ.env.send = BaseTest._send environ.env.leave_room = BaseTest._leave_room environ.env.redirect = BaseTest._redirect environ.env.url_for = BaseTest._url_for environ.env.send_from_directory = BaseTest._send_from_directory environ.env.request = BaseTest.Request() environ.env.SelectField = SelectField environ.env.SubmitField = SubmitField environ.env.StringField = StringField environ.env.DataRequired = DataRequired environ.env.Form = Form environ.env.logger = logger environ.env.session = self.session # TODO: don't do this here, but too many tests that doesn't do it themselves... should remove this base class # and only have test logic in each test class, separate it self.env = environ.env