def AvailableWriteReferences(self, request, context): # can't write anything for ourselves, but let's return empty so this can be used generically on profile page if request.to_user_id == context.user_id: return references_pb2.AvailableWriteReferencesRes() with session_scope() as session: if not session.execute( select(User).where_users_visible(context).where( User.id == request.to_user_id)).scalar_one_or_none(): context.abort(grpc.StatusCode.NOT_FOUND, errors.USER_NOT_FOUND) can_write_friend_reference = (session.execute( select(Reference).where( Reference.from_user_id == context.user_id).where( Reference.to_user_id == request.to_user_id).where( Reference.reference_type == ReferenceType.friend)). scalar_one_or_none()) is None q1 = (select(literal(True), HostRequest).outerjoin( Reference, and_( Reference.host_request_id == HostRequest.conversation_id, Reference.from_user_id == context.user_id, ), ).where(Reference.id == None).where( HostRequest.can_write_reference).where( HostRequest.surfer_user_id == context.user_id).where( HostRequest.host_user_id == request.to_user_id)) q2 = (select(literal(False), HostRequest).outerjoin( Reference, and_( Reference.host_request_id == HostRequest.conversation_id, Reference.from_user_id == context.user_id, ), ).where(Reference.id == None).where( HostRequest.can_write_reference).where( HostRequest.surfer_user_id == request.to_user_id).where( HostRequest.host_user_id == context.user_id)) union = union_all(q1, q2).order_by( HostRequest.end_time_to_write_reference.asc()).subquery() union = select(union.c[0].label("surfed"), aliased(HostRequest, union)) host_request_references = session.execute(union).all() return references_pb2.AvailableWriteReferencesRes( can_write_friend_reference=can_write_friend_reference, available_write_references=[ references_pb2.AvailableWriteReferenceType( host_request_id=host_request.conversation_id, reference_type=reftype2api[ ReferenceType.surfed if surfed else ReferenceType. hosted], time_expires=Timestamp_from_datetime( host_request.end_time_to_write_reference), ) for surfed, host_request in host_request_references ], )
def ListGroupChats(self, request, context): with session_scope() as session: page_size = request.number if request.number != 0 else DEFAULT_PAGINATION_LENGTH page_size = min(page_size, MAX_PAGE_SIZE) # select group chats where you have a subscription, and for each of # these, the latest message from them t = ( select( GroupChatSubscription.group_chat_id.label("group_chat_id"), func.max(GroupChatSubscription.id).label("group_chat_subscriptions_id"), func.max(Message.id).label("message_id"), ) .join(Message, Message.conversation_id == GroupChatSubscription.group_chat_id) .where(GroupChatSubscription.user_id == context.user_id) .where(Message.time >= GroupChatSubscription.joined) .where(or_(Message.time <= GroupChatSubscription.left, GroupChatSubscription.left == None)) .group_by(GroupChatSubscription.group_chat_id) .order_by(func.max(Message.id).desc()) .subquery() ) results = session.execute( select(t, GroupChat, GroupChatSubscription, Message) .join(Message, Message.id == t.c.message_id) .join(GroupChatSubscription, GroupChatSubscription.id == t.c.group_chat_subscriptions_id) .join(GroupChat, GroupChat.conversation_id == t.c.group_chat_id) .where(or_(t.c.message_id < request.last_message_id, request.last_message_id == 0)) .order_by(t.c.message_id.desc()) .limit(page_size + 1) ).all() return conversations_pb2.ListGroupChatsRes( group_chats=[ conversations_pb2.GroupChat( group_chat_id=result.GroupChat.conversation_id, title=result.GroupChat.title, # TODO: proper title for DMs, etc member_user_ids=_get_visible_members_for_subscription(result.GroupChatSubscription), admin_user_ids=_get_visible_admins_for_subscription(result.GroupChatSubscription), only_admins_invite=result.GroupChat.only_admins_invite, is_dm=result.GroupChat.is_dm, created=Timestamp_from_datetime(result.GroupChat.conversation.created), unseen_message_count=_unseen_message_count(session, result.GroupChatSubscription.id), last_seen_message_id=result.GroupChatSubscription.last_seen_message_id, latest_message=_message_to_pb(result.Message) if result.Message else None, mute_info=_mute_info(result.GroupChatSubscription), ) for result in results[:page_size] ], last_message_id=min(map(lambda g: g.Message.id if g.Message else 1, results[:page_size])) if len(results) > 0 else 0, # TODO no_more=len(results) <= page_size, )
def reference_to_pb(reference: Reference, context): return references_pb2.Reference( reference_id=reference.id, from_user_id=reference.from_user_id, to_user_id=reference.to_user_id, reference_type=reftype2api[reference.reference_type], text=reference.text, written_time=Timestamp_from_datetime( reference.time.replace(hour=0, minute=0, second=0, microsecond=0)), host_request_id=reference.host_request_id if context.user_id in [reference.from_user_id, reference.to_user_id] else None, )
def create_event(token, community_id, group_id, title, content, start_td): with events_session(token) as api: res = api.CreateEvent( events_pb2.CreateEventReq( title=title, content=content, offline_information=events_pb2.OfflineEventInformation( address="Near Null Island", lat=0.1, lng=0.2, ), start_time=Timestamp_from_datetime(now() + start_td), end_time=Timestamp_from_datetime(now() + start_td + timedelta(hours=2)), timezone="UTC", )) api.TransferEvent( events_pb2.TransferEventReq( event_id=res.event_id, new_owner_community_id=community_id, new_owner_group_id=group_id, ))
def GetDirectMessage(self, request, context): with session_scope(self._Session) as session: count = func.count(GroupChatSubscription.id).label("count") subquery = (session.query( GroupChatSubscription.group_chat_id).filter( or_( GroupChatSubscription.user_id == context.user_id, GroupChatSubscription.user_id == request.user_id, )).filter(GroupChatSubscription.left == None).join( GroupChat, GroupChat.conversation_id == GroupChatSubscription.group_chat_id).filter( GroupChat.is_dm == True).group_by( GroupChatSubscription.group_chat_id).having( count == 2).subquery()) result = (session.query( subquery, GroupChat, GroupChatSubscription, Message ).join( subquery, subquery.c.group_chat_id == GroupChat.conversation_id ).join( Message, Message.conversation_id == GroupChat.conversation_id ).filter(GroupChatSubscription.user_id == context.user_id).filter( GroupChatSubscription.group_chat_id == GroupChat. conversation_id).filter( Message.time >= GroupChatSubscription.joined).filter( or_(Message.time <= GroupChatSubscription.left, GroupChatSubscription.left == None)).order_by( Message.id.desc()).first()) if not result: context.abort(grpc.StatusCode.NOT_FOUND, "Couldn't find that chat.") return conversations_pb2.GroupChat( group_chat_id=result.GroupChat.conversation_id, title=result.GroupChat.title, member_user_ids=_get_visible_members_for_subscription( result.GroupChatSubscription), admin_user_ids=_get_visible_admins_for_subscription( result.GroupChatSubscription), only_admins_invite=result.GroupChat.only_admins_invite, is_dm=result.GroupChat.is_dm, created=Timestamp_from_datetime( result.GroupChat.conversation.created), unseen_message_count=result.GroupChatSubscription. unseen_message_count, last_seen_message_id=result.GroupChatSubscription. last_seen_message_id, latest_message=_message_to_pb(result.Message) if result.Message else None, )
def page_to_pb(page: Page, context): first_version = page.versions[0] current_version = page.versions[-1] owner_community_id = None owner_group_id = None if page.owner_cluster: if page.owner_cluster.is_official_cluster: owner_community_id = page.owner_cluster.parent_node_id else: owner_group_id = page.owner_cluster.id return pages_pb2.Page( page_id=page.id, type=pagetype2api[page.type], slug=current_version.slug, created=Timestamp_from_datetime(first_version.created), last_edited=Timestamp_from_datetime(current_version.created), last_editor_user_id=current_version.editor_user_id, creator_user_id=page.creator_user_id, owner_user_id=page.owner_user_id, owner_community_id=owner_community_id, owner_group_id=owner_group_id, thread=thread_to_pb(page.thread_id), title=current_version.title, content=current_version.content, photo_url=current_version.photo.full_url if current_version.photo_key else None, address=current_version.address, location=pages_pb2.Coordinate( lat=current_version.coordinates[0], lng=current_version.coordinates[1], ) if current_version.coordinates else None, editor_user_ids=remove_duplicates_retain_order([version.editor_user_id for version in page.versions]), can_edit=_is_page_owner(page, context.user_id), can_moderate=_can_moderate_page(page, context.user_id), )
def _message_to_pb(message: Message): """ Turns the given message to a protocol buffer """ if message.is_normal_message: return conversations_pb2.Message( message_id=message.id, author_user_id=message.author_id, time=Timestamp_from_datetime(message.time), text=conversations_pb2.MessageContentText(text=message.text), ) else: return conversations_pb2.Message( message_id=message.id, author_user_id=message.author_id, time=Timestamp_from_datetime(message.time), chat_created=conversations_pb2.MessageContentChatCreated() if message.message_type == MessageType.chat_created else None, chat_edited=conversations_pb2.MessageContentChatEdited() if message.message_type == MessageType.chat_edited else None, user_invited=conversations_pb2.MessageContentUserInvited(target_user_id=message.target_id) if message.message_type == MessageType.user_invited else None, user_left=conversations_pb2.MessageContentUserLeft() if message.message_type == MessageType.user_left else None, user_made_admin=conversations_pb2.MessageContentUserMadeAdmin(target_user_id=message.target_id) if message.message_type == MessageType.user_made_admin else None, user_removed_admin=conversations_pb2.MessageContentUserRemovedAdmin(target_user_id=message.target_id) if message.message_type == MessageType.user_removed_admin else None, group_chat_user_removed=conversations_pb2.MessageContentUserRemoved(target_user_id=message.target_id) if message.message_type == MessageType.user_removed else None, )
def group_to_pb(cluster: Cluster, context): with session_scope() as session: can_moderate = can_moderate_node(session, context.user_id, cluster.parent_node_id) member_count = session.execute( select(func.count()) .select_from(ClusterSubscription) .where_users_column_visible(context, ClusterSubscription.user_id) .where(ClusterSubscription.cluster_id == cluster.id) ).scalar_one() is_member = ( session.execute( select(ClusterSubscription) .where(ClusterSubscription.user_id == context.user_id) .where(ClusterSubscription.cluster_id == cluster.id) ).scalar_one_or_none() is not None ) admin_count = session.execute( select(func.count()) .select_from(ClusterSubscription) .where_users_column_visible(context, ClusterSubscription.user_id) .where(ClusterSubscription.cluster_id == cluster.id) .where(ClusterSubscription.role == ClusterRole.admin) ).scalar_one() is_admin = ( session.execute( select(ClusterSubscription) .where(ClusterSubscription.user_id == context.user_id) .where(ClusterSubscription.cluster_id == cluster.id) .where(ClusterSubscription.role == ClusterRole.admin) ).scalar_one_or_none() is not None ) return groups_pb2.Group( group_id=cluster.id, name=cluster.name, slug=cluster.slug, description=cluster.description, created=Timestamp_from_datetime(cluster.created), parents=_parents_to_pb(cluster), main_page=page_to_pb(cluster.main_page, context), member=is_member, admin=is_admin, member_count=member_count, admin_count=admin_count, can_moderate=can_moderate, )
def community_to_pb(node: Node, context): with session_scope() as session: can_moderate = can_moderate_node(session, context.user_id, node.id) member_count = session.execute( select(func.count()) .select_from(ClusterSubscription) .where_users_column_visible(context, ClusterSubscription.user_id) .where(ClusterSubscription.cluster_id == node.official_cluster.id) ).scalar_one() is_member = ( session.execute( select(ClusterSubscription) .where(ClusterSubscription.user_id == context.user_id) .where(ClusterSubscription.cluster_id == node.official_cluster.id) ).scalar_one_or_none() is not None ) admin_count = session.execute( select(func.count()) .select_from(ClusterSubscription) .where_users_column_visible(context, ClusterSubscription.user_id) .where(ClusterSubscription.cluster_id == node.official_cluster.id) .where(ClusterSubscription.role == ClusterRole.admin) ).scalar_one() is_admin = ( session.execute( select(ClusterSubscription) .where(ClusterSubscription.user_id == context.user_id) .where(ClusterSubscription.cluster_id == node.official_cluster.id) .where(ClusterSubscription.role == ClusterRole.admin) ).scalar_one_or_none() is not None ) return communities_pb2.Community( community_id=node.id, name=node.official_cluster.name, slug=node.official_cluster.slug, description=node.official_cluster.description, created=Timestamp_from_datetime(node.created), parents=_parents_to_pb(node.id), member=is_member, admin=is_admin, member_count=member_count, admin_count=admin_count, main_page=page_to_pb(node.official_cluster.main_page, context), can_moderate=can_moderate, )
def ListPendingReferencesToWrite(self, request, context): with session_scope() as session: q1 = (select(literal(True), HostRequest).outerjoin( Reference, and_( Reference.host_request_id == HostRequest.conversation_id, Reference.from_user_id == context.user_id, ), ).where_users_column_visible( context, HostRequest.host_user_id).where(Reference.id == None).where( HostRequest.can_write_reference).where( HostRequest.surfer_user_id == context.user_id)) q2 = (select(literal(False), HostRequest).outerjoin( Reference, and_( Reference.host_request_id == HostRequest.conversation_id, Reference.from_user_id == context.user_id, ), ).where_users_column_visible( context, HostRequest.surfer_user_id).where(Reference.id == None).where( HostRequest.can_write_reference).where( HostRequest.host_user_id == context.user_id)) union = union_all(q1, q2).order_by( HostRequest.end_time_to_write_reference.asc()).subquery() union = select(union.c[0].label("surfed"), aliased(HostRequest, union)) host_request_references = session.execute(union).all() return references_pb2.ListPendingReferencesToWriteRes( pending_references=[ references_pb2.AvailableWriteReferenceType( host_request_id=host_request.conversation_id, reference_type=reftype2api[ ReferenceType.surfed if surfed else ReferenceType. hosted], time_expires=Timestamp_from_datetime( host_request.end_time_to_write_reference), ) for surfed, host_request in host_request_references ], )
def paginate_references_result(request, query): total_matches = query.count() references = query.order_by(Reference.time.desc()).offset(request.start_at).limit(request.number).all() # order by time, pagination return api_pb2.GetReferencesRes( total_matches=total_matches, references=[ api_pb2.Reference( reference_id=reference.id, from_user_id=reference.from_user_id, to_user_id=reference.to_user_id, reference_type=reftype2api[reference.reference_type], text=reference.text, # Fuzz reference written time written_time=Timestamp_from_datetime(reference.time.replace(hour=0, minute=0, second=0, microsecond=0)), ) for reference in references ], )
def GetHostRequest(self, request, context): with session_scope(self._Session) as session: host_request = ( session.query(HostRequest) .filter(HostRequest.conversation_id == request.host_request_id) .filter(or_(HostRequest.from_user_id == context.user_id, HostRequest.to_user_id == context.user_id)) .one_or_none() ) if not host_request: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) initial_message = ( session.query(Message.time) .filter(Message.conversation_id == host_request.conversation_id) .order_by(Message.id.asc()) .limit(1) .one() ) latest_message = ( session.query(Message) .filter(Message.conversation_id == host_request.conversation_id) .order_by(Message.id.desc()) .limit(1) .one() ) send_host_request_email(host_request) return requests_pb2.HostRequest( host_request_id=host_request.conversation_id, from_user_id=host_request.from_user_id, to_user_id=host_request.to_user_id, status=hostrequeststatus2api[host_request.status], created=Timestamp_from_datetime(initial_message.time), from_date=host_request.from_date, to_date=host_request.to_date, last_seen_message_id=host_request.from_last_seen_message_id if context.user_id == host_request.from_user_id else host_request.to_last_seen_message_id, latest_message=message_to_pb(latest_message), )
def GetHostRequest(self, request, context): with session_scope() as session: host_request = session.execute( select(HostRequest).where_users_column_visible( context, HostRequest.surfer_user_id).where_users_column_visible( context, HostRequest.host_user_id). where(HostRequest.conversation_id == request.host_request_id).where( or_(HostRequest.surfer_user_id == context.user_id, HostRequest.host_user_id == context.user_id))).scalar_one_or_none() if not host_request: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) initial_message = session.execute( select(Message).where( Message.conversation_id == host_request.conversation_id).order_by( Message.id.asc()).limit(1)).scalar_one() latest_message = session.execute( select(Message).where( Message.conversation_id == host_request.conversation_id).order_by( Message.id.desc()).limit(1)).scalar_one() return requests_pb2.HostRequest( host_request_id=host_request.conversation_id, surfer_user_id=host_request.surfer_user_id, host_user_id=host_request.host_user_id, status=hostrequeststatus2api[host_request.status], created=Timestamp_from_datetime(initial_message.time), from_date=date_to_api(host_request.from_date), to_date=date_to_api(host_request.to_date), last_seen_message_id=host_request.surfer_last_seen_message_id if context.user_id == host_request.surfer_user_id else host_request.host_last_seen_message_id, latest_message=message_to_pb(latest_message), )
def community_to_pb(node: Node, user_id): with session_scope() as session: can_moderate = can_moderate_node(session, user_id, node.id) return communities_pb2.Community( community_id=node.id, name=node.official_cluster.name, slug=node.official_cluster.slug, description=node.official_cluster.description, created=Timestamp_from_datetime(node.created), parents=_parents_to_pb(node.id, user_id), main_page=page_to_pb(node.official_cluster.main_page, user_id), member=node.official_cluster.members.filter( User.id == user_id).one_or_none() is not None, admin=node.official_cluster.admins.filter( User.id == user_id).one_or_none() is not None, member_count=node.official_cluster.members.count(), admin_count=node.official_cluster.admins.count(), can_moderate=can_moderate, )
def group_to_pb(cluster: Cluster, user_id): with session_scope() as session: can_moderate = can_moderate_node(session, user_id, cluster.parent_node_id) return groups_pb2.Group( group_id=cluster.id, name=cluster.name, slug=cluster.slug, description=cluster.description, created=Timestamp_from_datetime(cluster.created), parents=_parents_to_pb(cluster, user_id), main_page=page_to_pb(cluster.main_page, user_id), member=cluster.members.filter(User.id == user_id).one_or_none() is not None, admin=cluster.admins.filter(User.id == user_id).one_or_none() is not None, member_count=cluster.members.count(), admin_count=cluster.admins.count(), can_moderate=can_moderate, )
def GetGroupChat(self, request, context): with session_scope(self._Session) as session: result = ( session.query(GroupChat, GroupChatSubscription, Message).join( Message, Message.conversation_id == GroupChatSubscription.group_chat_id).join( GroupChat, GroupChat.conversation_id == GroupChatSubscription.group_chat_id).filter( GroupChatSubscription.user_id == context.user_id). filter( GroupChatSubscription.group_chat_id == request. group_chat_id).filter( Message.time >= GroupChatSubscription.joined).filter( or_(Message.time <= GroupChatSubscription.left, GroupChatSubscription.left == None)).order_by( Message.id.desc()).first()) if not result: context.abort(grpc.StatusCode.NOT_FOUND, errors.CHAT_NOT_FOUND) return conversations_pb2.GroupChat( group_chat_id=result.GroupChat.conversation_id, title=result.GroupChat.title, member_user_ids=_get_visible_members_for_subscription( result.GroupChatSubscription), admin_user_ids=_get_visible_admins_for_subscription( result.GroupChatSubscription), only_admins_invite=result.GroupChat.only_admins_invite, is_dm=result.GroupChat.is_dm, created=Timestamp_from_datetime( result.GroupChat.conversation.created), unseen_message_count=result.GroupChatSubscription. unseen_message_count, last_seen_message_id=result.GroupChatSubscription. last_seen_message_id, latest_message=_message_to_pb(result.Message) if result.Message else None, )
def discussion_to_pb(discussion: Discussion, user_id): owner_community_id = None owner_group_id = None if discussion.owner_cluster.is_official_cluster: owner_community_id = discussion.owner_cluster.parent_node_id else: owner_group_id = discussion.owner_cluster.id with session_scope() as session: can_moderate = can_moderate_node(session, user_id, discussion.owner_cluster.parent_node_id) return discussions_pb2.Discussion( discussion_id=discussion.id, slug=discussion.slug, created=Timestamp_from_datetime(discussion.created), creator_user_id=discussion.creator_user_id, owner_community_id=owner_community_id, owner_group_id=owner_group_id, title=discussion.title, content=discussion.content, thread_id=pack_thread_id(discussion.thread_id, 0), can_moderate=can_moderate, )
def ListHostRequests(self, request, context): if request.only_sent and request.only_received: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.HOST_REQUEST_SENT_OR_RECEIVED) with session_scope() as session: pagination = request.number if request.number > 0 else DEFAULT_PAGINATION_LENGTH pagination = min(pagination, MAX_PAGE_SIZE) # By outer joining messages on itself where the second id is bigger, only the highest IDs will have # none as message_2.id. So just filter for these ones to get highest messages only. # See https://stackoverflow.com/a/27802817/6115336 message_2 = aliased(Message) query = (session.query( Message, HostRequest, Conversation).outerjoin( message_2, and_(Message.conversation_id == message_2.conversation_id, Message.id < message_2.id)).join( HostRequest, HostRequest.conversation_id == Message.conversation_id).join( Conversation, Conversation.id == HostRequest.conversation_id).filter( message_2.id == None).filter( or_( HostRequest.conversation_id < request.last_request_id, request.last_request_id == 0))) if request.only_sent: query = query.filter( HostRequest.from_user_id == context.user_id) elif request.only_received: query = query.filter(HostRequest.to_user_id == context.user_id) else: query = query.filter( or_(HostRequest.to_user_id == context.user_id, HostRequest.from_user_id == context.user_id)) # TODO: I considered having the latest control message be the single source of truth for # the HostRequest.status, but decided agains it because of this filter. # Another possibility is to filter in the python instead of SQL, but that's slower if request.only_active: query = query.filter( or_( HostRequest.status == HostRequestStatus.pending, HostRequest.status == HostRequestStatus.accepted, HostRequest.status == HostRequestStatus.confirmed, )) query = query.filter(HostRequest.end_time <= func.now()) query = query.order_by(Message.id.desc()).limit(pagination + 1) results = query.all() host_requests = [ requests_pb2.HostRequest( host_request_id=result.HostRequest.conversation_id, from_user_id=result.HostRequest.from_user_id, to_user_id=result.HostRequest.to_user_id, status=hostrequeststatus2api[result.HostRequest.status], created=Timestamp_from_datetime( result.Conversation.created), from_date=date_to_api(result.HostRequest.from_date), to_date=date_to_api(result.HostRequest.to_date), last_seen_message_id=result.HostRequest. from_last_seen_message_id if context.user_id == result.HostRequest.from_user_id else result.HostRequest.to_last_seen_message_id, latest_message=message_to_pb(result.Message), ) for result in results[:pagination] ] last_request_id = (min( map( lambda g: g.HostRequest.conversation_id if g.HostRequest else 1, results[:pagination])) if len(results) > 0 else 0) # TODO no_more = len(results) <= pagination return requests_pb2.ListHostRequestsRes( last_request_id=last_request_id, no_more=no_more, host_requests=host_requests)
def event_to_pb(session, occurrence: EventOccurrence, context): event = occurrence.event next_occurrence = (event.occurrences.where( EventOccurrence.end_time >= now()).order_by( EventOccurrence.end_time.asc()).first()) owner_community_id = None owner_group_id = None if event.owner_cluster: if event.owner_cluster.is_official_cluster: owner_community_id = event.owner_cluster.parent_node_id else: owner_group_id = event.owner_cluster.id attendance = occurrence.attendees.where( EventOccurrenceAttendee.user_id == context.user_id).one_or_none() attendance_state = attendance.attendee_status if attendance else None can_moderate = _can_moderate_event(session, event, context.user_id) going_count = session.execute( select(func.count()). select_from(EventOccurrenceAttendee).where_users_column_visible( context, EventOccurrenceAttendee.user_id).where( EventOccurrenceAttendee.occurrence_id == occurrence.id).where( EventOccurrenceAttendee.attendee_status == AttendeeStatus.going)).scalar_one() maybe_count = session.execute( select(func.count()). select_from(EventOccurrenceAttendee).where_users_column_visible( context, EventOccurrenceAttendee.user_id).where( EventOccurrenceAttendee.occurrence_id == occurrence.id).where( EventOccurrenceAttendee.attendee_status == AttendeeStatus.maybe)).scalar_one() organizer_count = session.execute( select(func.count()).select_from( EventOrganizer).where_users_column_visible( context, EventOrganizer.user_id).where( EventOrganizer.event_id == event.id)).scalar_one() subscriber_count = session.execute( select(func.count()).select_from( EventSubscription).where_users_column_visible( context, EventSubscription.user_id).where( EventSubscription.event_id == event.id)).scalar_one() return events_pb2.Event( event_id=occurrence.id, is_next=False if not next_occurrence else occurrence.id == next_occurrence.id, title=event.title, slug=event.slug, content=occurrence.content, photo_url=occurrence.photo.full_url if occurrence.photo else None, online_information=events_pb2.OnlineEventInformation( link=occurrence.link, ) if occurrence.link else None, offline_information=events_pb2.OfflineEventInformation( lat=occurrence.coordinates[0], lng=occurrence.coordinates[1], address=occurrence.address, ) if occurrence.geom else None, created=Timestamp_from_datetime(occurrence.created), last_edited=Timestamp_from_datetime(occurrence.last_edited), creator_user_id=occurrence.creator_user_id, start_time=Timestamp_from_datetime(occurrence.start_time), end_time=Timestamp_from_datetime(occurrence.end_time), timezone=occurrence.timezone, start_time_display=str(occurrence.start_time), end_time_display=str(occurrence.end_time), attendance_state=attendancestate2api[attendance_state], organizer=event.organizers.where( EventOrganizer.user_id == context.user_id).one_or_none() is not None, subscriber=event.subscribers.where( EventSubscription.user_id == context.user_id).one_or_none() is not None, going_count=going_count, maybe_count=maybe_count, organizer_count=organizer_count, subscriber_count=subscriber_count, owner_user_id=event.owner_user_id, owner_community_id=owner_community_id, owner_group_id=owner_group_id, thread=thread_to_pb(event.thread_id), can_edit=_is_event_owner(event, context.user_id), can_moderate=can_moderate, )
def user_model_to_pb(db_user, session, context): num_references = session.query(Reference.from_user_id).filter(Reference.to_user_id == db_user.id).count() # returns (lat, lng) # we put people without coords on null island # https://en.wikipedia.org/wiki/Null_Island lat, lng = db_user.coordinates or (0, 0) user = api_pb2.User( user_id=db_user.id, username=db_user.username, name=db_user.name, city=db_user.city, hometown=db_user.hometown, lat=lat, lng=lng, radius=db_user.geom_radius, verification=db_user.verification, community_standing=db_user.community_standing, num_references=num_references, gender=db_user.gender, pronouns=db_user.pronouns, age=db_user.age, joined=Timestamp_from_datetime(db_user.display_joined), last_active=Timestamp_from_datetime(db_user.display_last_active), hosting_status=hostingstatus2api[db_user.hosting_status], meetup_status=meetupstatus2api[db_user.meetup_status], occupation=db_user.occupation, education=db_user.education, about_me=db_user.about_me, my_travels=db_user.my_travels, things_i_like=db_user.things_i_like, about_place=db_user.about_place, languages=db_user.languages.split("|") if db_user.languages else [], countries_visited=db_user.countries_visited.split("|") if db_user.countries_visited else [], countries_lived=db_user.countries_lived.split("|") if db_user.countries_lived else [], additional_information=db_user.additional_information, friends=get_friends_status(session, context.user_id, db_user.id), mutual_friends=[ api_pb2.MutualFriend(user_id=mutual_friend.id, username=mutual_friend.username, name=mutual_friend.name) for mutual_friend in db_user.mutual_friends(context.user_id) ], smoking_allowed=smokinglocation2api[db_user.smoking_allowed], sleeping_arrangement=sleepingarrangement2api[db_user.sleeping_arrangement], parking_details=parkingdetails2api[db_user.parking_details], avatar_url=db_user.avatar.thumbnail_url if db_user.avatar else None, ) if db_user.max_guests is not None: user.max_guests.value = db_user.max_guests if db_user.last_minute is not None: user.last_minute.value = db_user.last_minute if db_user.has_pets is not None: user.has_pets.value = db_user.has_pets if db_user.accepts_pets is not None: user.accepts_pets.value = db_user.accepts_pets if db_user.pet_details is not None: user.pet_details.value = db_user.pet_details if db_user.has_kids is not None: user.has_kids.value = db_user.has_kids if db_user.accepts_kids is not None: user.accepts_kids.value = db_user.accepts_kids if db_user.kid_details is not None: user.kid_details.value = db_user.kid_details if db_user.has_housemates is not None: user.has_housemates.value = db_user.has_housemates if db_user.housemate_details is not None: user.housemate_details.value = db_user.housemate_details if db_user.wheelchair_accessible is not None: user.wheelchair_accessible.value = db_user.wheelchair_accessible if db_user.smokes_at_home is not None: user.smokes_at_home.value = db_user.smokes_at_home if db_user.drinking_allowed is not None: user.drinking_allowed.value = db_user.drinking_allowed if db_user.drinks_at_home is not None: user.drinks_at_home.value = db_user.drinks_at_home if db_user.other_host_info is not None: user.other_host_info.value = db_user.other_host_info if db_user.sleeping_details is not None: user.sleeping_details.value = db_user.sleeping_details if db_user.area is not None: user.area.value = db_user.area if db_user.house_rules is not None: user.house_rules.value = db_user.house_rules if db_user.parking is not None: user.parking.value = db_user.parking if db_user.camping_ok is not None: user.camping_ok.value = db_user.camping_ok return user
def CreateGroupChat(self, request, context): with session_scope() as session: recipient_user_ids = [ user_id for user_id in ( session.execute( select(User.id).where_users_visible(context).where(User.id.in_(request.recipient_user_ids)) ) .scalars() .all() ) ] # make sure all requested users are visible if len(recipient_user_ids) != len(request.recipient_user_ids): context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.USER_NOT_FOUND) if not recipient_user_ids: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.NO_RECIPIENTS) if len(recipient_user_ids) != len(set(recipient_user_ids)): # make sure there's no duplicate users context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_RECIPIENTS) if context.user_id in recipient_user_ids: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.CANT_ADD_SELF) if len(recipient_user_ids) == 1: # can only have one DM at a time between any two users other_user_id = recipient_user_ids[0] # the following sql statement selects subscriptions that are DMs and have the same group_chat_id, and have # user_id either this user or the recipient user. If you find two subscriptions to the same DM group # chat, you know they already have a shared group chat count = func.count(GroupChatSubscription.id).label("count") if session.execute( select(count) .where( or_( GroupChatSubscription.user_id == context.user_id, GroupChatSubscription.user_id == other_user_id, ) ) .where(GroupChatSubscription.left == None) .join(GroupChat, GroupChat.conversation_id == GroupChatSubscription.group_chat_id) .where(GroupChat.is_dm == True) .group_by(GroupChatSubscription.group_chat_id) .having(count == 2) ).scalar_one_or_none(): context.abort( grpc.StatusCode.FAILED_PRECONDITION, "You already have a direct message chat with this user." ) conversation = Conversation() session.add(conversation) group_chat = GroupChat( conversation=conversation, title=request.title.value, creator_id=context.user_id, is_dm=True if len(recipient_user_ids) == 1 else False, # TODO ) session.add(group_chat) your_subscription = GroupChatSubscription( user_id=context.user_id, group_chat=group_chat, role=GroupChatRole.admin, ) session.add(your_subscription) for recipient_id in request.recipient_user_ids: subscription = GroupChatSubscription( user_id=recipient_id, group_chat=group_chat, role=GroupChatRole.participant, ) session.add(subscription) _add_message_to_subscription(session, your_subscription, message_type=MessageType.chat_created) session.flush() return conversations_pb2.GroupChat( group_chat_id=group_chat.conversation_id, title=group_chat.title, member_user_ids=_get_visible_members_for_subscription(your_subscription), admin_user_ids=_get_visible_admins_for_subscription(your_subscription), only_admins_invite=group_chat.only_admins_invite, is_dm=group_chat.is_dm, created=Timestamp_from_datetime(group_chat.conversation.created), mute_info=_mute_info(your_subscription), )
def GetThread(self, request, context): database_id, depth = unpack_thread_id(request.thread_id) page_size = request.page_size if 0 < request.page_size < 100000 else 1000 page_start = unpack_thread_id(int(request.page_token))[0] if request.page_token else 2 ** 50 with session_scope() as session: if depth == 0: if not session.query(Thread).filter(Thread.id == database_id).one_or_none(): context.abort(grpc.StatusCode.NOT_FOUND, errors.THREAD_NOT_FOUND) res = ( session.query(Comment, func.count(Reply.id)) .outerjoin(Reply, Reply.comment_id == Comment.id) .filter(Comment.thread_id == database_id) .filter(Comment.id < page_start) .group_by(Comment.id) .order_by(Comment.created.desc()) .limit(page_size + 1) .all() ) replies = [ threads_pb2.Reply( thread_id=pack_thread_id(r.id, 1), content=r.content, author_user_id=r.author_user_id, created_time=Timestamp_from_datetime(r.created), num_replies=n, ) for r, n in res[:page_size] ] # get the total number of responses num_responses = ( session.query(func.count(Comment.id)).filter(Comment.thread_id == database_id).scalar() + session.query(func.count(Reply.id)) .join(Comment, Comment.id == Reply.comment_id) .filter(Comment.thread_id == database_id) .scalar() ) elif depth == 1: if not session.query(Comment).filter(Comment.id == database_id).one_or_none(): context.abort(grpc.StatusCode.NOT_FOUND, errors.THREAD_NOT_FOUND) res = ( session.query(Reply) .filter(Reply.comment_id == database_id) .filter(Reply.id < page_start) .order_by(Reply.created.desc()) .limit(page_size + 1) .all() ) replies = [ threads_pb2.Reply( thread_id=pack_thread_id(r.id, 2), content=r.content, author_user_id=r.author_user_id, created_time=Timestamp_from_datetime(r.created), num_replies=0, ) for r in res[:page_size] ] num_responses = session.query(func.count(Reply.id)).filter(Reply.comment_id == database_id).scalar() else: context.abort(grpc.StatusCode.NOT_FOUND, errors.THREAD_NOT_FOUND) if len(res) > page_size: # There's more! next_page_token = str(replies[-1].thread_id) else: next_page_token = "" return threads_pb2.GetThreadRes(replies=replies, next_page_token=next_page_token, num_responses=num_responses)
def _mute_info(subscription): (muted, muted_until) = subscription.muted_display() return conversations_pb2.MuteInfo( muted=muted, muted_until=Timestamp_from_datetime(muted_until) if muted_until else None, )
def CreateGroupChat(self, request, context): if len(request.recipient_user_ids) < 1: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.NO_RECIPIENTS) if len(request.recipient_user_ids) != len( set(request.recipient_user_ids)): # make sure there's no duplicate users context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_RECIPIENTS) if context.user_id in request.recipient_user_ids: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.CANT_ADD_SELF) with session_scope(self._Session) as session: if len(request.recipient_user_ids) == 1: # can only have one DM at a time between any two users other_user_id = request.recipient_user_ids[0] # the following query selects subscriptions that are DMs and have the same group_chat_id, and have # user_id either this user or the recipient user. If you find two subscriptions to the same DM group # chat, you know they already have a shared group chat count = func.count(GroupChatSubscription.id).label("count") if (session.query(count).filter( or_( GroupChatSubscription.user_id == context.user_id, GroupChatSubscription.user_id == other_user_id, )).filter(GroupChatSubscription.left == None).join( GroupChat, GroupChat.conversation_id == GroupChatSubscription.group_chat_id). filter(GroupChat.is_dm == True).group_by( GroupChatSubscription.group_chat_id).having( count == 2).one_or_none()): context.abort( grpc.StatusCode.FAILED_PRECONDITION, "You already have a direct message chat with this user." ) conversation = Conversation() session.add(conversation) group_chat = GroupChat( conversation=conversation, title=request.title.value, creator_id=context.user_id, is_dm=True if len(request.recipient_user_ids) == 1 else False, # TODO ) session.add(group_chat) your_subscription = GroupChatSubscription( user_id=context.user_id, group_chat=group_chat, role=GroupChatRole.admin, ) session.add(your_subscription) for recipient in request.recipient_user_ids: if get_friends_status( session, context.user_id, recipient) != api_pb2.User.FriendshipStatus.FRIENDS: if len(request.recipient_user_ids) > 1: context.abort(grpc.StatusCode.FAILED_PRECONDITION, errors.GROUP_CHAT_ONLY_ADD_FRIENDS) else: context.abort(grpc.StatusCode.FAILED_PRECONDITION, errors.DIRECT_MESSAGE_ONLY_FRIENDS) subscription = GroupChatSubscription( user_id=recipient, group_chat=group_chat, role=GroupChatRole.participant, ) session.add(subscription) _add_message_to_subscription(session, your_subscription, message_type=MessageType.chat_created) session.flush() return conversations_pb2.GroupChat( group_chat_id=group_chat.conversation_id, title=group_chat.title, member_user_ids=_get_visible_members_for_subscription( your_subscription), admin_user_ids=_get_visible_admins_for_subscription( your_subscription), only_admins_invite=group_chat.only_admins_invite, is_dm=group_chat.is_dm, created=Timestamp_from_datetime( group_chat.conversation.created), )
def user_model_to_pb(db_user, session, context): num_references = session.query(Reference.from_user_id).filter( Reference.to_user_id == db_user.id).count() user = api_pb2.User( user_id=db_user.id, username=db_user.username, name=db_user.name, city=db_user.city, verification=db_user.verification, community_standing=db_user.community_standing, num_references=num_references, gender=db_user.gender, age=db_user.age, color=db_user.color, joined=Timestamp_from_datetime(db_user.display_joined), last_active=Timestamp_from_datetime(db_user.display_last_active), hosting_status=hostingstatus2api[db_user.hosting_status], occupation=db_user.occupation, about_me=db_user.about_me, about_place=db_user.about_place, languages=db_user.languages.split("|") if db_user.languages else [], countries_visited=db_user.countries_visited.split("|") if db_user.countries_visited else [], countries_lived=db_user.countries_lived.split("|") if db_user.countries_lived else [], friends=get_friends_status(session, context.user_id, db_user.id), mutual_friends=[ api_pb2.MutualFriend(user_id=mutual_friend.id, username=mutual_friend.username, name=mutual_friend.name) for mutual_friend in db_user.mutual_friends(context.user_id) ], smoking_allowed=smokinglocation2api[db_user.smoking_allowed], avatar_url=db_user.avatar_url, ) if db_user.max_guests is not None: user.max_guests.value = db_user.max_guests if db_user.multiple_groups is not None: user.multiple_groups.value = db_user.multiple_groups if db_user.last_minute is not None: user.last_minute.value = db_user.last_minute if db_user.accepts_pets is not None: user.accepts_pets.value = db_user.accepts_pets if db_user.accepts_kids is not None: user.accepts_kids.value = db_user.accepts_kids if db_user.wheelchair_accessible is not None: user.wheelchair_accessible.value = db_user.wheelchair_accessible if db_user.sleeping_arrangement is not None: user.sleeping_arrangement.value = db_user.sleeping_arrangement if db_user.area is not None: user.area.value = db_user.area if db_user.house_rules is not None: user.house_rules.value = db_user.house_rules return user
def user_model_to_pb(db_user, session, context): num_references = session.query(Reference.from_user_id).filter( Reference.to_user_id == db_user.id).count() # returns (lat, lng) # we put people without coords on null island # https://en.wikipedia.org/wiki/Null_Island lat, lng = db_user.coordinates or (0, 0) pending_friend_request = None if db_user.id == context.user_id: friends_status = api_pb2.User.FriendshipStatus.NA else: friend_relationship = (session.query(FriendRelationship).filter( or_( and_(FriendRelationship.from_user_id == context.user_id, FriendRelationship.to_user_id == db_user.id), and_(FriendRelationship.from_user_id == db_user.id, FriendRelationship.to_user_id == context.user_id), )).filter( or_( FriendRelationship.status == FriendStatus.accepted, FriendRelationship.status == FriendStatus.pending, )).one_or_none()) if friend_relationship: if friend_relationship.status == FriendStatus.accepted: friends_status = api_pb2.User.FriendshipStatus.FRIENDS else: friends_status = api_pb2.User.FriendshipStatus.PENDING if friend_relationship.from_user_id == context.user_id: # we sent it pending_friend_request = api_pb2.FriendRequest( friend_request_id=friend_relationship.id, state=api_pb2.FriendRequest.FriendRequestStatus. PENDING, user_id=friend_relationship.to_user.id, sent=True, ) else: # we received it pending_friend_request = api_pb2.FriendRequest( friend_request_id=friend_relationship.id, state=api_pb2.FriendRequest.FriendRequestStatus. PENDING, user_id=friend_relationship.from_user.id, sent=False, ) else: friends_status = api_pb2.User.FriendshipStatus.NOT_FRIENDS user = api_pb2.User( user_id=db_user.id, username=db_user.username, name=db_user.name, city=db_user.city, hometown=db_user.hometown, lat=lat, lng=lng, radius=db_user.geom_radius, verification=db_user.verification, community_standing=db_user.community_standing, num_references=num_references, gender=db_user.gender, pronouns=db_user.pronouns, age=db_user.age, joined=Timestamp_from_datetime(db_user.display_joined), last_active=Timestamp_from_datetime(db_user.display_last_active), hosting_status=hostingstatus2api[db_user.hosting_status], meetup_status=meetupstatus2api[db_user.meetup_status], occupation=db_user.occupation, education=db_user.education, about_me=db_user.about_me, my_travels=db_user.my_travels, things_i_like=db_user.things_i_like, about_place=db_user.about_place, languages=db_user.languages.split("|") if db_user.languages else [], countries_visited=db_user.countries_visited.split("|") if db_user.countries_visited else [], countries_lived=db_user.countries_lived.split("|") if db_user.countries_lived else [], additional_information=db_user.additional_information, friends=friends_status, pending_friend_request=pending_friend_request, smoking_allowed=smokinglocation2api[db_user.smoking_allowed], sleeping_arrangement=sleepingarrangement2api[ db_user.sleeping_arrangement], parking_details=parkingdetails2api[db_user.parking_details], avatar_url=db_user.avatar.full_url if db_user.avatar else None, ) if db_user.max_guests is not None: user.max_guests.value = db_user.max_guests if db_user.last_minute is not None: user.last_minute.value = db_user.last_minute if db_user.has_pets is not None: user.has_pets.value = db_user.has_pets if db_user.accepts_pets is not None: user.accepts_pets.value = db_user.accepts_pets if db_user.pet_details is not None: user.pet_details.value = db_user.pet_details if db_user.has_kids is not None: user.has_kids.value = db_user.has_kids if db_user.accepts_kids is not None: user.accepts_kids.value = db_user.accepts_kids if db_user.kid_details is not None: user.kid_details.value = db_user.kid_details if db_user.has_housemates is not None: user.has_housemates.value = db_user.has_housemates if db_user.housemate_details is not None: user.housemate_details.value = db_user.housemate_details if db_user.wheelchair_accessible is not None: user.wheelchair_accessible.value = db_user.wheelchair_accessible if db_user.smokes_at_home is not None: user.smokes_at_home.value = db_user.smokes_at_home if db_user.drinking_allowed is not None: user.drinking_allowed.value = db_user.drinking_allowed if db_user.drinks_at_home is not None: user.drinks_at_home.value = db_user.drinks_at_home if db_user.other_host_info is not None: user.other_host_info.value = db_user.other_host_info if db_user.sleeping_details is not None: user.sleeping_details.value = db_user.sleeping_details if db_user.area is not None: user.area.value = db_user.area if db_user.house_rules is not None: user.house_rules.value = db_user.house_rules if db_user.parking is not None: user.parking.value = db_user.parking if db_user.camping_ok is not None: user.camping_ok.value = db_user.camping_ok return user