def emit_join_event(activity, user_id, user_name, image) -> None: room_id = activity.target.id room_name = utils.get_room_name(room_id) # if invisible, only sent 'invisible' join to admins in the room if utils.get_user_status(user_id) == UserKeys.STATUS_INVISIBLE: admins_in_room = environ.env.db.get_admins_in_room( room_id, user_id) if admins_in_room is None or len(admins_in_room) == 0: return room_name = utils.get_room_name(room_id) activity_json = utils.activity_for_user_joined_invisibly( user_id, user_name, room_id, room_name, image) for admin_id in admins_in_room: environ.env.out_of_scope_emit('gn_user_joined', activity_json, room=admin_id, broadcast=False, namespace='/ws') return activity_json = utils.activity_for_user_joined(user_id, user_name, room_id, room_name, image) environ.env.out_of_scope_emit('gn_user_joined', activity_json, room=room_id, broadcast=True, namespace='/ws') environ.env.publish(activity_json, external=True)
def set_user_offline(user_id, current_sid): try: if not utils.is_valid_id(user_id): logger.warning( 'got invalid id on disconnect for act: {}'.format( str(activity.id))) # TODO: sentry return environ.env.db.remove_sid_for_user(user_id, current_sid) all_sids = utils.get_sids_for_user_id(user_id) # if the user still has another session up we don't set the user as offline if all_sids is not None and len(all_sids) > 0: logger.debug( 'when setting user offline, found other sids: [%s]' % ','.join(all_sids)) return if utils.get_user_status(user_id) == UserKeys.STATUS_INVISIBLE: environ.env.cache.remove_from_multicast_on_disconnect( user_id) else: environ.env.db.set_user_offline(user_id) except Exception as e: logger.error('could not set user offline: %s' % str(e)) logger.debug('request for failed set_user_offline(): %s' % str(data)) logger.exception(traceback.format_exc())
def set_user_online_if_not_previously_invisible(arg: tuple) -> None: data, activity = arg user_id = activity.actor.id user_status = utils.get_user_status(user_id) if utils.is_super_user(user_id) or utils.is_global_moderator(user_id): try: info_message = \ 'op {} ({}) signed in; ' \ 'user status is currently set to {}; ' \ 'if not "3" (invisible), I will now change it to "1" (online)' info_message = info_message.format( user_id, utils.get_user_name_for(user_id), user_status) logger.info(info_message) except NoSuchUserException: logger.error( 'no username found for op user {}'.format(user_id)) except Exception as e: logger.error( 'exception while getting username for op {}: {}'.format( user_id, str(e))) logger.exception(e) environ.env.capture_exception(sys.exc_info()) if user_status != UserKeys.STATUS_INVISIBLE: logger.info('setting user {} to online'.format(user_id)) environ.env.db.set_user_online(user_id) else: # if login after server restart the cache value user:status:<user id> is non-existent, set to invisible environ.env.cache.set_user_invisible(user_id)
def publish_activity(arg: tuple) -> None: data, activity = arg user_id = activity.actor.id user_name = environ.env.session.get(SessionKeys.user_name.value) user_status = utils.get_user_status(user_id) activity_json = utils.activity_for_login( user_id, user_name, encode_attachments=False, user_status=user_status) environ.env.publish(activity_json, external=True)
def leave_room(arg: tuple) -> None: data, activity = arg user_id = activity.actor.id user_name = activity.actor.display_name room_id = activity.target.id try: room_name = utils.get_room_name(room_id) except NoSuchRoomException: room_name = '[removed]' utils.remove_sid_for_user_in_room(user_id, room_id, environ.env.request.sid) # multi-login, can be in same room as another session sids = utils.sids_for_user_in_room(user_id, room_id) if sids is not None and len(sids) > 0: if len(sids) > 1 or next(iter(sids)) != environ.env.request.sid: return utils.remove_user_from_room(user_id, user_name, room_id) # if invisible, only send 'invisible' leave to admins in the room if utils.get_user_status(user_id) == UserKeys.STATUS_INVISIBLE: admins_in_room = environ.env.db.get_admins_in_room( room_id, user_id) if admins_in_room is None or len(admins_in_room) == 0: return activity_left = utils.activity_for_leave(user_id, user_name, room_id, room_name) for admin_id in admins_in_room: environ.env.out_of_scope_emit('gn_user_left', activity_left, room=admin_id, broadcast=False, namespace='/ws') return activity_left = utils.activity_for_leave(user_id, user_name, room_id, room_name) environ.env.emit('gn_user_left', activity_left, room=room_id, broadcast=True, include_self=False, namespace='/ws') utils.check_if_should_remove_room(data, activity)
def set_visible(user_id: str, user_name: str) -> None: user_status = utils.get_user_status(user_id, skip_cache=True) if user_status in {UserKeys.STATUS_AVAILABLE, UserKeys.STATUS_CHAT}: return # status is UserKeys.STATUS_VISIBLE, but is in multicast so the user is online if environ.env.cache.user_is_in_multicast(user_id): OnStatusHooks.logger.info( 'setting user {} ({}) to visible (online), was invisible (online)' .format(user_id, user_name)) OnStatusHooks.set_online(user_id, user_name) # otherwise status is UserKeys.STATUS_INVISIBLE, but if not in multicast the user is offline else: OnStatusHooks.logger.info( 'setting user {} ({}) to visible (offline), was invisible (offline)' .format(user_id, user_name)) OnStatusHooks.set_offline(user_id, user_name)
def log_admin_activity(user_id, user_name, status): try: info_message = \ 'op {} ({}) requested to change status to {}; user status is currently set to {}'.format( user_id, user_name, status, utils.get_user_status(user_id) ) OnStatusHooks.logger.info(info_message) except NoSuchUserException: OnStatusHooks.logger.error( 'no username found for op user {}'.format(user_id)) except Exception as e: OnStatusHooks.logger.error( 'exception while getting username for op {}: {}'.format( user_id, str(e))) OnStatusHooks.logger.exception(e) environ.env.capture_exception(sys.exc_info())
def set_visible(user_id: str, user_name: str) -> None: user_status = utils.get_user_status(user_id, skip_cache=True) if user_status in {UserKeys.STATUS_AVAILABLE, UserKeys.STATUS_CHAT}: return # status is UserKeys.STATUS_VISIBLE, but is in multicast so the user is online if environ.env.cache.user_is_in_multicast(user_id): OnStatusHooks.logger.info( 'setting user {} ({}) to visible (online), was invisible (online)' .format(user_id, user_name)) OnStatusHooks.set_online(user_id, user_name) # otherwise status is UserKeys.STATUS_INVISIBLE, but if not in multicast the user is offline # TODO: when choosing to login invisibly, this is called before the user connects to dino, so should NOT do set_offline() # TODO: should visible login call set_status with 'online' or 'visible'? else: OnStatusHooks.logger.info( 'setting user {} ({}) to visible (offline), was invisible (offline)' .format(user_id, user_name)) OnStatusHooks.set_offline(user_id, user_name)
def leave_room(arg: tuple) -> None: data, activity = arg # todo: should handle invisibility here? don't broadcast leaving a room if invisible user_id = activity.actor.id user_name = activity.actor.display_name room_id = activity.target.id try: room_name = utils.get_room_name(room_id) except NoSuchRoomException: room_name = '[removed]' utils.remove_user_from_room(user_id, user_name, room_id) # if invisible, only send 'invisible' leave to admins in the room if utils.get_user_status(user_id) == UserKeys.STATUS_INVISIBLE: admins_in_room = environ.env.db.get_admins_in_room( room_id, user_id) if admins_in_room is None or len(admins_in_room) == 0: return activity_left = utils.activity_for_leave(user_id, user_name, room_id, room_name) for admin_id in admins_in_room: environ.env.out_of_scope_emit('gn_user_left', activity_left, room=admin_id, broadcast=False, namespace='/ws') return activity_left = utils.activity_for_leave(user_id, user_name, room_id, room_name) environ.env.emit('gn_user_left', activity_left, room=room_id, broadcast=True, include_self=False, namespace='/ws') utils.check_if_should_remove_room(data, activity)
def handle_ban(self, activity: Activity): banner_id = activity.actor.id if banner_id == '0' or banner_id is None: banner_id = '0' banner_name = 'admin' else: try: banner_name = utils.get_user_name_for(banner_id) except NoSuchUserException: # if banning from rest api the user might not exist logger.error('no such user when banning: %s' % banner_id) return banned_id = activity.object.id if not utils.is_valid_id(banned_id): logger.warning('got invalid id on ban activity: {}'.format( str(activity.id))) # TODO: sentry return banned_name = utils.get_user_name_for(banned_id) banned_sids = utils.get_sids_for_user_id(banned_id) namespace = activity.target.url or '/ws' target_type = activity.target.object_type if target_type == 'room': target_id = activity.target.id target_name = utils.get_room_name(target_id) elif target_type == 'channel': target_id = activity.target.id target_name = utils.get_channel_name(target_id) else: target_id = '' target_name = '' if len(banned_sids) == 0 or banned_sids == [None ] or banned_sids[0] == '': logger.warning('no sid(s) found for user id %s' % banned_id) return reason = None if hasattr(activity.object, 'content'): reason = activity.object.content activity_json = utils.activity_for_user_banned(banner_id, banner_name, banned_id, banned_name, target_id, target_name, reason) try: ban_activity = self.get_ban_activity(activity, target_type) self.env.out_of_scope_emit('gn_banned', ban_activity, json=True, namespace=namespace, room=banned_id) if target_id is None or target_id == '': rooms_for_user = self.env.db.rooms_for_user(banned_id) logger.info( 'user %s is in these rooms (will ban from all): %s' % (banned_id, str(rooms_for_user))) self.ban_globally(activity_json, activity, rooms_for_user, banned_id, banned_sids, namespace) if utils.get_user_status( banned_id) == UserKeys.STATUS_INVISIBLE: environ.env.cache.remove_from_multicast_on_disconnect( banned_id) else: environ.env.db.set_user_offline(banned_id) disconnect_activity = utils.activity_for_disconnect( banned_id, banned_name) self.env.publish(disconnect_activity, external=True) elif target_type == 'channel': rooms_in_channel = self.env.db.rooms_for_channel(target_id) self.ban_channel(activity_json, activity, rooms_in_channel, target_id, banned_id, banned_sids, namespace) else: self.ban_room(activity_json, activity, target_id, banned_id, banned_sids, namespace) except KeyError as ke: logger.error('could not ban: %s' % str(ke)) logger.exception(traceback.format_exc()) self.env.capture_exception(sys.exc_info())