Example #1
0
    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)
Example #2
0
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
Example #3
0
    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()
Example #4
0
    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()
Example #5
0
    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()
Example #6
0
    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)
Example #7
0
    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()
Example #8
0
    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()