def CreateHostRequest(self, request, context): with session_scope(self._Session) as session: if request.to_user_id == context.user_id: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.CANT_REQUEST_SELF) # just to check the host exists host = session.query(User).filter(User.id == request.to_user_id).one_or_none() if not host: context.abort(grpc.StatusCode.NOT_FOUND, errors.USER_NOT_FOUND) if not is_valid_date(request.from_date) or not is_valid_date(request.to_date): context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_DATE) if request.from_date >= request.to_date: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.DATE_FROM_AFTER_TO) if request.to_date < least_current_date(): context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.DATE_TO_BEFORE_TODAY) conversation = Conversation() session.add(conversation) session.flush() created_message = Message() created_message.conversation_id = conversation.id created_message.author_id = context.user_id created_message.message_type = MessageType.chat_created session.add(created_message) session.commit() message = Message() message.conversation_id = conversation.id message.author_id = context.user_id message.text = request.text message.message_type = MessageType.text session.add(message) session.flush() host_request = HostRequest() host_request.conversation_id = conversation.id host_request.from_user_id = context.user_id host_request.to_user_id = host.id host_request.from_date = request.from_date host_request.to_date = request.to_date host_request.status = HostRequestStatus.pending host_request.from_last_seen_message_id = message.id session.add(host_request) return requests_pb2.CreateHostRequestRes(host_request_id=host_request.conversation_id)
def test_host_request_email(db): with session_scope(db) as session: from_user, api_token_from = generate_user(db) to_user, api_token_to = generate_user(db) from_date = "2020-01-01" to_date = "2020-01-05" conversation = Conversation() message = Message() message.conversation_id = conversation.id message.author_id = from_user.id message.text = random_hex(64) host_request = HostRequest( conversation_id=conversation.id, from_user=from_user, to_user=to_user, from_date=from_date, to_date=to_date, status=HostRequestStatus.pending, from_last_seen_message_id=message.id, ) message_id = random_hex(64) @create_autospec def mock_send_email(sender_name, sender_email, recipient, subject, plain, html): assert recipient == to_user.email assert "host request" in subject.lower() assert to_user.name in plain assert to_user.name in html assert from_user.name in plain assert from_user.name in html assert from_date in plain assert from_date in html assert to_date in plain assert to_date in html assert from_user.avatar_url not in plain assert from_user.avatar_url in html assert f"{config['BASE_URL']}/hostrequests/" in plain assert f"{config['BASE_URL']}/hostrequests/" in html return message_id with patch("couchers.email.send_email", mock_send_email) as mock: send_host_request_email(host_request) assert mock.call_count == 1
def SendHostRequestMessage(self, request, context): if request.text == "": context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_MESSAGE) with session_scope() as session: host_request = (session.query(HostRequest).filter( HostRequest.conversation_id == request.host_request_id).one_or_none()) if not host_request: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) if host_request.from_user_id != context.user_id and host_request.to_user_id != context.user_id: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) # TODO: It is not very user-friendly to prevent messages for confirmed requests # but we also don't want people to use requests as normal messages... if (host_request.status == HostRequestStatus.rejected or host_request.status == HostRequestStatus.confirmed or host_request.status == HostRequestStatus.cancelled): context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.HOST_REQUEST_CLOSED) message = Message() message.conversation_id = host_request.conversation_id message.author_id = context.user_id message.message_type = MessageType.text message.text = request.text session.add(message) session.flush() if host_request.from_user_id == context.user_id: host_request.from_last_seen_message_id = message.id else: host_request.to_last_seen_message_id = message.id session.commit() return empty_pb2.Empty()
def SendHostRequestMessage(self, request, context): if request.text == "": context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_MESSAGE) with session_scope() as session: host_request = (session.query(HostRequest).filter( HostRequest.conversation_id == request.host_request_id).one_or_none()) if not host_request: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) if host_request.from_user_id != context.user_id and host_request.to_user_id != context.user_id: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) if host_request.status == HostRequestStatus.rejected or host_request.status == HostRequestStatus.cancelled: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.HOST_REQUEST_CLOSED) if host_request.end_time < now(): context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.HOST_REQUEST_IN_PAST) message = Message() message.conversation_id = host_request.conversation_id message.author_id = context.user_id message.message_type = MessageType.text message.text = request.text session.add(message) session.flush() if host_request.from_user_id == context.user_id: host_request.from_last_seen_message_id = message.id else: host_request.to_last_seen_message_id = message.id session.commit() return empty_pb2.Empty()
def RespondHostRequest(self, request, context): with session_scope() as session: host_request = (session.query(HostRequest).filter( HostRequest.conversation_id == request.host_request_id).one_or_none()) if not host_request: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) if host_request.from_user_id != context.user_id and host_request.to_user_id != context.user_id: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) if request.status == conversations_pb2.HOST_REQUEST_STATUS_PENDING: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) if host_request.end_time < now(): context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.HOST_REQUEST_IN_PAST) control_message = Message() if request.status == conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED: # only host can accept if context.user_id != host_request.to_user_id: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) # can't accept a cancelled or confirmed request (only reject), or already accepted if (host_request.status == HostRequestStatus.cancelled or host_request.status == HostRequestStatus.confirmed or host_request.status == HostRequestStatus.accepted): context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) control_message.host_request_status_target = HostRequestStatus.accepted host_request.status = HostRequestStatus.accepted if request.status == conversations_pb2.HOST_REQUEST_STATUS_REJECTED: # only host can reject if context.user_id != host_request.to_user_id: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) # can't reject a cancelled or already rejected request if (host_request.status == HostRequestStatus.cancelled or host_request.status == HostRequestStatus.rejected): context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) control_message.host_request_status_target = HostRequestStatus.rejected host_request.status = HostRequestStatus.rejected if request.status == conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED: # only hostee can confirm if context.user_id != host_request.from_user_id: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) # can only confirm an accepted request if host_request.status != HostRequestStatus.accepted: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) control_message.host_request_status_target = HostRequestStatus.confirmed host_request.status = HostRequestStatus.confirmed if request.status == conversations_pb2.HOST_REQUEST_STATUS_CANCELLED: # only hostee can cancel if context.user_id != host_request.from_user_id: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) # can't' cancel an already cancelled or rejected request if (host_request.status == HostRequestStatus.rejected or host_request.status == HostRequestStatus.cancelled): context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) control_message.host_request_status_target = HostRequestStatus.cancelled host_request.status = HostRequestStatus.cancelled control_message.message_type = MessageType.host_request_status_changed control_message.conversation_id = host_request.conversation_id control_message.author_id = context.user_id session.add(control_message) if request.text: latest_message = Message() latest_message.conversation_id = host_request.conversation_id latest_message.text = request.text latest_message.author_id = context.user_id latest_message.message_type = MessageType.text session.add(latest_message) else: latest_message = control_message session.flush() if host_request.from_user_id == context.user_id: host_request.from_last_seen_message_id = latest_message.id else: host_request.to_last_seen_message_id = latest_message.id session.commit() return empty_pb2.Empty()
def CreateHostRequest(self, request, context): with session_scope() as session: if request.to_user_id == context.user_id: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.CANT_REQUEST_SELF) # just to check the host exists host = session.query(User).filter( User.id == request.to_user_id).one_or_none() if not host: context.abort(grpc.StatusCode.NOT_FOUND, errors.USER_NOT_FOUND) if not is_valid_date(request.from_date) or not is_valid_date( request.to_date): context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_DATE) # today is not > from_date if least_current_date() > request.from_date: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.DATE_FROM_BEFORE_TODAY) # from_date is not >= to_date if request.from_date >= request.to_date: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.DATE_FROM_AFTER_TO) # No need to check today > to_date today = date.fromisoformat(largest_current_date()) today_plus_one_year = today.replace(year=today.year + 1).isoformat() if request.from_date > today_plus_one_year: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.DATE_FROM_AFTER_ONE_YEAR) from_date = date.fromisoformat(request.from_date) from_date_plus_one_year = (from_date.replace(year=from_date.year + 1)).isoformat() if request.to_date > from_date_plus_one_year: context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.DATE_TO_AFTER_ONE_YEAR) conversation = Conversation() session.add(conversation) session.flush() created_message = Message() created_message.conversation_id = conversation.id created_message.author_id = context.user_id created_message.message_type = MessageType.chat_created session.add(created_message) session.commit() message = Message() message.conversation_id = conversation.id message.author_id = context.user_id message.text = request.text message.message_type = MessageType.text session.add(message) session.flush() host_request = HostRequest() host_request.conversation_id = conversation.id host_request.from_user_id = context.user_id host_request.to_user_id = host.id host_request.from_date = request.from_date host_request.to_date = request.to_date host_request.status = HostRequestStatus.pending host_request.from_last_seen_message_id = message.id session.add(host_request) session.flush() send_host_request_email(host_request) return requests_pb2.CreateHostRequestRes( host_request_id=host_request.conversation_id)
def SendHostRequestMessage(self, request, context): if request.text == "": context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_MESSAGE) with session_scope() as session: host_request = session.execute( select(HostRequest).where( HostRequest.conversation_id == request.host_request_id)).scalar_one_or_none() if not host_request: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) if host_request.surfer_user_id != context.user_id and host_request.host_user_id != context.user_id: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) if host_request.status == HostRequestStatus.rejected or host_request.status == HostRequestStatus.cancelled: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.HOST_REQUEST_CLOSED) if host_request.end_time < now(): context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.HOST_REQUEST_IN_PAST) message = Message() message.conversation_id = host_request.conversation_id message.author_id = context.user_id message.message_type = MessageType.text message.text = request.text session.add(message) session.flush() if host_request.surfer_user_id == context.user_id: host_request.surfer_last_seen_message_id = message.id notify( user_id=host_request.host_user_id, topic="host_request", action="message", key=str(host_request.surfer_user_id), avatar_key=host_request.surfer.avatar.thumbnail_url if host_request.surfer.avatar else None, title= f"**{host_request.surfer.name}** sent a message in their host request", link=urls.host_request_link_host(), ) else: host_request.host_last_seen_message_id = message.id notify( user_id=host_request.surfer_user_id, topic="host_request", action="message", key=str(host_request.host_user_id), avatar_key=host_request.host.avatar.thumbnail_url if host_request.host.avatar else None, title= f"**{host_request.host.name}** sent a message in your host request", link=urls.host_request_link_guest(), ) session.commit() return empty_pb2.Empty()
def RespondHostRequest(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)).scalar_one_or_none() if not host_request: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) if host_request.surfer_user_id != context.user_id and host_request.host_user_id != context.user_id: context.abort(grpc.StatusCode.NOT_FOUND, errors.HOST_REQUEST_NOT_FOUND) if request.status == conversations_pb2.HOST_REQUEST_STATUS_PENDING: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) if host_request.end_time < now(): context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.HOST_REQUEST_IN_PAST) control_message = Message() if request.status == conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED: # only host can accept if context.user_id != host_request.host_user_id: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.NOT_THE_HOST) # can't accept a cancelled or confirmed request (only reject), or already accepted if (host_request.status == HostRequestStatus.cancelled or host_request.status == HostRequestStatus.confirmed or host_request.status == HostRequestStatus.accepted): context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) control_message.host_request_status_target = HostRequestStatus.accepted host_request.status = HostRequestStatus.accepted send_host_request_accepted_email_to_guest(host_request) notify( user_id=host_request.surfer_user_id, topic="host_request", action="accept", key=str(host_request.host_user_id), avatar_key=host_request.host.avatar.thumbnail_url if host_request.host.avatar else None, title= f"**{host_request.host.name}** accepted your host request", link=urls.host_request_link_guest(), ) if request.status == conversations_pb2.HOST_REQUEST_STATUS_REJECTED: # only host can reject if context.user_id != host_request.host_user_id: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) # can't reject a cancelled or already rejected request if (host_request.status == HostRequestStatus.cancelled or host_request.status == HostRequestStatus.rejected): context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) control_message.host_request_status_target = HostRequestStatus.rejected host_request.status = HostRequestStatus.rejected send_host_request_rejected_email_to_guest(host_request) notify( user_id=host_request.surfer_user_id, topic="host_request", action="reject", key=str(host_request.host_user_id), avatar_key=host_request.host.avatar.thumbnail_url if host_request.host.avatar else None, title= f"**{host_request.host.name}** rejected your host request", link=urls.host_request_link_guest(), ) if request.status == conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED: # only hostee can confirm if context.user_id != host_request.surfer_user_id: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) # can only confirm an accepted request if host_request.status != HostRequestStatus.accepted: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) control_message.host_request_status_target = HostRequestStatus.confirmed host_request.status = HostRequestStatus.confirmed send_host_request_confirmed_email_to_host(host_request) notify( user_id=host_request.host_user_id, topic="host_request", action="confirm", key=str(host_request.surfer_user_id), avatar_key=host_request.surfer.avatar.thumbnail_url if host_request.surfer.avatar else None, title= f"**{host_request.surfer.name}** confirmed their host request", link=urls.host_request_link_host(), ) if request.status == conversations_pb2.HOST_REQUEST_STATUS_CANCELLED: # only hostee can cancel if context.user_id != host_request.surfer_user_id: context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) # can't' cancel an already cancelled or rejected request if (host_request.status == HostRequestStatus.rejected or host_request.status == HostRequestStatus.cancelled): context.abort(grpc.StatusCode.PERMISSION_DENIED, errors.INVALID_HOST_REQUEST_STATUS) control_message.host_request_status_target = HostRequestStatus.cancelled host_request.status = HostRequestStatus.cancelled send_host_request_cancelled_email_to_host(host_request) notify( user_id=host_request.host_user_id, topic="host_request", action="cancel", key=str(host_request.surfer_user_id), avatar_key=host_request.surfer.avatar.thumbnail_url if host_request.surfer.avatar else None, title= f"**{host_request.surfer.name}** cancelled their host request", link=urls.host_request_link_host(), ) control_message.message_type = MessageType.host_request_status_changed control_message.conversation_id = host_request.conversation_id control_message.author_id = context.user_id session.add(control_message) if request.text: latest_message = Message() latest_message.conversation_id = host_request.conversation_id latest_message.text = request.text latest_message.author_id = context.user_id latest_message.message_type = MessageType.text session.add(latest_message) else: latest_message = control_message session.flush() if host_request.surfer_user_id == context.user_id: host_request.surfer_last_seen_message_id = latest_message.id else: host_request.host_last_seen_message_id = latest_message.id session.commit() return empty_pb2.Empty()