def activity_for_going_visible(user_id: str) -> dict: return ActivityBuilder.enrich({ 'actor': { 'id': user_id }, 'verb': 'visible' })
def activity_for_list_channels(activity: Activity, channels: dict) -> dict: response = ActivityBuilder.enrich({ 'object': { 'objectType': 'channels' }, 'verb': 'list' }) response['object']['attachments'] = list() for channel_id, (channel_name, sort_order) in channels.items(): object_type = is_channel_static_or_temporary_or_mix(channel_id) response['object']['attachments'].append({ 'id': channel_id, 'url': sort_order, 'displayName': b64e(channel_name), 'objectType': object_type }) response['object']['attachments'] = sorted( response['object']['attachments'], key=lambda k: k['url']) return response
def activity_for_list_rooms(activity: Activity, rooms: dict) -> dict: response = ActivityBuilder.enrich({ 'object': { 'url': activity.object.url, 'objectType': 'rooms' }, 'verb': 'list' }) response['object']['attachments'] = list() for room_id, room_details in rooms.items(): room_name = room_details['name'] nr_users_in_room = room_details['users'] object_type = 'static' if 'ephemeral' in room_details and room_details['ephemeral']: object_type = 'temporary' response['object']['attachments'].append({ 'id': room_id, 'url': room_details['sort_order'], 'displayName': b64e(room_name), 'summary': nr_users_in_room, 'objectType': object_type, 'content': room_details['roles'] }) return response
def activity_for_user_kicked(kicker_id: str, kicker_name: str, kicked_id: str, kicked_name: str, room_id: str, room_name: str, reason=None) -> dict: activity = ActivityBuilder.enrich({ 'actor': { 'id': kicker_id, 'displayName': b64e(kicker_name) }, 'object': { 'id': kicked_id }, 'target': { 'id': room_id, 'displayName': b64e(room_name) }, 'verb': 'kick' }) if not is_base64(kicked_name): kicked_name = b64e(kicked_name) activity['object']['displayName'] = kicked_name if reason is not None: if is_base64(reason): activity['object']['content'] = reason else: logger.warning('ignoring reason for kick activity, not base64') logger.debug('request with non-base64 reason: %s' % activity) return activity
def do_post(self): is_valid, msg, json = self.validate_json() if not is_valid: logger.error('invalid json: %s' % msg) raise RuntimeError('invalid json') if json is None: raise RuntimeError('no json in request') if not isinstance(json, dict): raise RuntimeError('need a dict') logger.debug('POST request: %s' % str(json)) if 'id' not in json: raise RuntimeError('no id parameter in request') if 'status' not in json: raise RuntimeError('no status parameter in request') user_id = json.get('id') status = json.get('status') all_statuses = {'online', 'offline', 'invisible', 'visible'} if status not in all_statuses: raise RuntimeError('unknown status [{}], need one of [{}]'.format( status, ','.join(all_statuses))) try: environ.env.db.create_user(user_id, str(user_id)) except UserExistsException: pass activity_base = {'actor': {'id': user_id}, 'verb': status} data = ActivityBuilder.enrich(activity_base) activity = parse(data) environ.env.observer.emit('on_status', (data, activity))
def activity_for_disconnect(user_id: str, user_name: str) -> dict: return ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'displayName': b64e(user_name) }, 'verb': 'disconnect' })
def activity_for_broadcast(body: str, verb: str = 'broadcast') -> dict: return ActivityBuilder.enrich({ 'actor': { 'displayName': ADMIN_B64, # 'Admin' in base64 'id': '0' }, 'content': body, 'verb': verb })
def activity_for_sid_disconnect(user_id: str, user_name: str, current_sid: str) -> dict: return ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'displayName': b64e(user_name), 'content': current_sid, }, 'verb': 'ended' })
def activity_for_connect(user_id: str, user_name: str) -> dict: return ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'displayName': b64e(user_name), 'attachments': get_user_info_attachments_for(user_id, include_user_agent=True) }, 'verb': 'connect' })
def activity_for_login(user_id: str, user_name: str, include_unread_history: bool = False, encode_attachments: bool = True, heartbeat_sid=False, user_status=UserKeys.STATUS_AVAILABLE) -> dict: if heartbeat_sid: sid = 'hb-{}'.format(user_id) else: try: sid = environ.env.request.sid except Exception as e: logger.error('could not get sid for user "{}": {}'.format( user_id, str(e))) logger.exception(traceback.format_exc()) environ.env.capture_exception(sys.exc_info()) sid = '' include_user_agent = True if heartbeat_sid: include_user_agent = False response = ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'summary': _user_status_int_to_str(str(user_status)), 'displayName': b64e(user_name), 'content': sid, 'attachments': get_user_info_attachments_for( user_id, encode_attachments, include_user_agent=include_user_agent) }, 'verb': 'login' }) if include_unread_history: messages = get_unacked_messages(user_id) if len(messages) > 0: history_activity = activity_for_history(as_parser(response), messages) response['object'] = { 'objectType': 'history', 'attachments': history_activity['object']['attachments'] } return response
def activity_for_users_in_room(activity: Activity, users_orig: dict) -> dict: users = users_orig.copy() response = ActivityBuilder.enrich({ 'target': { 'id': activity.target.id, 'displayName': b64e(activity.target.display_name) }, 'object': { 'objectType': 'users' }, 'verb': 'list' }) response['object']['attachments'] = list() this_user_id = environ.env.session.get(SessionKeys.user_id.value) this_user_is_super_user = is_super_user( this_user_id) or is_global_moderator(this_user_id) for user_id, user_name in users.items(): user_info = get_user_info_attachments_for(user_id) if this_user_is_super_user: user_ip = '' try: user_ip = environ.env.request.remote_addr except Exception as e: logger.error('could not get remote address of user %s: %s' % (user_info, str(e))) logger.exception(traceback.format_exc()) environ.env.capture_exception(sys.exc_info()) user_info.append({'objectType': 'ip', 'content': b64e(user_ip)}) # temporary fix for avoiding dead users if len(user_info) == 0: environ.env.db.leave_room(user_id, activity.target.id) continue user_roles = environ.env.db.get_user_roles_in_room( user_id, activity.target.id) user_attachment = { 'id': user_id, 'displayName': b64e(user_name), 'attachments': user_info, 'content': ','.join(user_roles), 'objectType': 'user' } if this_user_is_super_user and user_is_invisible(user_id): user_attachment['objectType'] = 'invisible' response['object']['attachments'].append(user_attachment) return response
def activity_for_message(user_id: str, user_name: str) -> dict: """ user for sending event to other system to do statistics for how active a user is :param user_id: the id of the user :param user_name: the name of the user :return: an activity streams dict """ return ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'displayName': b64e(user_name) }, 'verb': 'send' })
def activity_for_leave(user_id: str, user_name: str, room_id: str, room_name: str) -> dict: return ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'displayName': user_name if is_base64(user_name) else b64e(user_name) }, 'target': { 'id': room_id, 'displayName': room_name if is_base64(room_name) else b64e(room_name) }, 'verb': 'leave' })
def activity_for_msg_status(activity: Activity, statuses: dict) -> dict: act = ActivityBuilder.enrich({ 'object': { 'objectType': 'statuses', 'attachments': list() }, 'target': { 'id': activity.target.id, }, 'verb': 'check' }) for msg_id, status in statuses.items(): act['object']['attachments'].append({'id': msg_id, 'content': status}) return act
def activity_for_room_removed(activity: Activity, room_name: str, reason: str = None) -> dict: act = ActivityBuilder.enrich({ 'target': { 'id': activity.target.id, 'displayName': b64e(room_name), 'objectType': 'room' }, 'verb': 'removed' }) if reason is not None and len(reason.strip()) > 0: act['object'] = {'content': b64e(reason)} return act
def check_if_remove_room_owner(activity: Activity): user_id = activity.actor.id user_name = environ.env.session.get(SessionKeys.user_name.value) room_id = activity.target.id room_name = get_room_name(room_id) channel_id = get_channel_for_room(room_id) if not environ.env.db.is_room_ephemeral(room_id): logger.info('room %s (%s) is not ephemeral, not considering removal' % (room_name, room_id)) return owners = get_owners_for_room(room_id) users_in_room = get_users_in_room(room_id) if user_id in users_in_room: del users_in_room[user_id] for owner_id, owner_name in owners.items(): if owner_id in users_in_room: logger.info( 'owner %s (%s) is still in room %s (%s), not considering removal' % (owner_name, owner_id, room_name, room_id)) return for user_id_still_in_room, user_name_still_in_room in users_in_room.items( ): kick_activity = ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'displayName': b64e(user_name) }, 'verb': 'kick', 'object': { 'id': user_id_still_in_room, 'displayName': b64e(user_name_still_in_room), 'content': b64e('All owners have left the room') }, 'target': { 'url': environ.env.request.namespace, 'id': room_id, 'displayName': b64e(room_name) } }) environ.env.publish(kick_activity) remove_room(channel_id, room_id, user_id, user_name, room_name)
def activity_for_join(activity: Activity, acls: dict, messages: list, owners: dict, users: dict) -> dict: response = ActivityBuilder.enrich({ 'object': { 'objectType': 'room', 'attachments': list() }, 'verb': 'join', 'target': { 'id': activity.target.id, 'displayName': b64e(get_room_name(activity.target.id)) } }) acl_activity = activity_for_get_acl(activity, acls) response['object']['attachments'].append({ 'objectType': 'acl', 'attachments': acl_activity['object']['attachments'] }) history_activity = activity_for_history(activity, messages) response['object']['attachments'].append({ 'objectType': 'history', 'attachments': history_activity['object']['attachments'] }) owners_activity = activity_for_owners(activity, owners) response['object']['attachments'].append({ 'objectType': 'owner', 'attachments': owners_activity['object']['attachments'] }) users_in_room_activity = activity_for_users_in_room(activity, users) response['object']['attachments'].append({ 'objectType': 'user', 'attachments': users_in_room_activity['object']['attachments'] }) return response
def autojoin_rooms(arg: tuple) -> None: data, activity = arg if not str(environ.env.config.get(ConfigKeys.AUTOJOIN_ENABLED, 'false')).lower() in {'true', 'yes', '1', 'y'}: return try: room_acls = environ.env.db.get_room_acls_for_action(ApiActions.AUTOJOIN) except Exception as e: logger.error('could not get autojoin acls: {}'.format(str(e))) return for room_id, acls in room_acls.items(): # sometimes room_id is None, if no autojoin rooms exist if room_id is None or len(room_id.strip()) == 0: continue # needed for validation join_data = data.copy() join_data['target'] = { 'id': room_id, 'objectType': 'room' } is_valid, error_msg = validation.acl.validate_acl_for_action( activitystreams.parse(join_data), ApiTargets.ROOM, ApiActions.JOIN, acls ) if not is_valid: continue join_data = ActivityBuilder.enrich({ 'verb': 'join', 'actor': { 'id': activity.actor.id }, 'target': { 'id': room_id } }) environ.env.observer.emit('on_join', (join_data, activitystreams.parse(join_data)))
def activity_for_whisper(message: str, whisperer_id: str, whisperer_name: str, room_id: str, room_name: str, channel_id: str, channel_name: str) -> dict: return ActivityBuilder.enrich({ 'actor': { 'id': whisperer_id, 'displayName': b64e(whisperer_name) }, 'verb': 'whisper', 'object': { 'content': message, 'url': channel_id, 'displayName': b64e(channel_name) }, 'target': { 'id': room_id, 'displayName': b64e(room_name) } })
def activity_for_invite(inviter_id: str, inviter_name: str, room_id: str, room_name: str, channel_id: str, channel_name: str) -> dict: return ActivityBuilder.enrich({ 'actor': { 'id': inviter_id, 'displayName': b64e(inviter_name), 'attachments': get_user_info_attachments_for(inviter_id) }, 'verb': 'invite', 'object': { 'url': channel_id, 'displayName': b64e(channel_name) }, 'target': { 'id': room_id, 'displayName': b64e(room_name) } })
def activity_for_report(activity: Activity) -> dict: return ActivityBuilder.enrich({ 'actor': { 'id': activity.actor.id, # user id of the one reporting 'displayName': b64e(activity.actor.display_name) }, 'object': { 'summary': activity.object.summary, # free-text reason for reporting 'content': activity.object.content, # the reported message 'id': activity.object.id # id of the reported message }, 'target': { 'id': activity.target.id, # user id of user who sent to reported message 'displayName': activity.target.display_name }, 'verb': 'report' })
def activity_for_user_joined(user_id: str, user_name: str, room_id: str, room_name: str, image_url: str) -> dict: user_roles = environ.env.db.get_user_roles_in_room(user_id, room_id) return ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'displayName': b64e(user_name), 'image': { 'url': image_url }, 'attachments': get_user_info_attachments_for(user_id), 'content': ','.join(user_roles) }, 'target': { 'id': room_id, 'displayName': b64e(room_name) }, 'verb': 'join' })
def publish_startup_done_event() -> None: if len(environ.env.config) == 0 or environ.env.config.get( ConfigKeys.TESTING, False): # assume we're testing return if environ.env.node != 'web': # avoid publishing duplicate events by only letting the web node publish external events return json_event = ActivityBuilder.enrich({ 'verb': 'restart', 'content': environ.env.config.get(ConfigKeys.ENVIRONMENT), }) logger.debug('publishing restart-done event to external queue: %s' % str(json_event)) environ.env.publish(json_event, external=True)
def activity_for_blacklisted_word(activity: Activity, blacklisted_word: str = None) -> dict: if blacklisted_word is not None: blacklisted_word = b64e(blacklisted_word) return ActivityBuilder.enrich({ 'actor': { 'id': activity.actor.id, 'displayName': activity.actor.display_name }, 'object': { 'content': activity.object.content, 'summary': blacklisted_word }, 'target': { 'id': activity.target.id, 'displayName': b64e(activity.target.display_name) }, 'verb': 'blacklisted' })
def activity_for_owners(activity: Activity, owners: dict) -> dict: response = ActivityBuilder.enrich({ 'object': { 'objectType': 'owner' }, 'target': { 'id': activity.target.id, 'displayName': b64e(activity.target.display_name) }, 'verb': 'list' }) response['object']['attachments'] = list() for user_id, user_name in owners.items(): response['object']['attachments'].append({ 'id': user_id, 'displayName': b64e(user_name) }) return response
def activity_for_message(user_id: str, user_name: str, message_id: str = None) -> dict: """ user for sending event to other system to do statistics for how active a user is :param user_id: the id of the user :param user_name: the name of the user :param message_id: the id of the message stored in db, is None if using REST to send, not stored :return: an activity streams dict """ data = { 'actor': { 'id': user_id, 'displayName': b64e(user_name) }, 'verb': 'send' } if message_id is not None: data['object'] = {'id': message_id} return ActivityBuilder.enrich(data)
def activity_for_remove_room(user_id: str, user_name: str, room_id: str, room_name: str, reason: str = None) -> dict: act = ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'displayName': b64e(user_name) }, 'target': { 'id': room_id, 'displayName': b64e(room_name) }, 'verb': 'remove' }) if reason is not None and len(reason.strip()) > 0: act['object'] = {'content': b64e(reason)} return act
def activity_for_get_acl(activity: Activity, acl_values: dict) -> dict: response = ActivityBuilder.enrich({ 'object': { 'objectType': 'acl' }, 'verb': 'get' }) if hasattr(activity, 'target') and hasattr(activity.target, 'id'): response['target'] = {'id': activity.target.id} response['object']['attachments'] = list() for api_action, acls in acl_values.items(): for acl_type, acl_value in acls.items(): response['object']['attachments'].append({ 'objectType': acl_type, 'content': acl_value, 'summary': api_action }) return response
def activity_for_request_admin(user_id: str, user_name: str, room_id: str, room_name: str, message: str, admin_room_id: str): return ActivityBuilder.enrich({ 'actor': { 'id': user_id, 'displayName': b64e(user_name), 'attachments': get_user_info_attachments_for(user_id) }, 'verb': 'request', 'object': { 'content': message }, 'target': { 'id': admin_room_id, 'displayName': b64e('Admins') }, 'generator': { 'id': room_id, 'displayName': b64e(room_name) } })
def activity_for_create_room(data: dict, activity: Activity) -> dict: response = ActivityBuilder.enrich({ 'actor': { 'id': activity.actor.id, 'displayName': b64e(activity.actor.display_name), 'attachments': get_user_info_attachments_for(activity.actor.id) }, 'object': { 'url': activity.object.url }, 'target': { 'id': activity.target.id, 'displayName': activity.target.display_name, 'objectType': 'temporary' # all rooms created using the api are temporary }, 'verb': 'create' }) if 'object' in data and 'attachments' in data['object']: response['object']['attachments'] = data['object']['attachments'] return response