Beispiel #1
0
async def test_create_user_as_supervisor(users, supervisor1_client):
    new_user = get_fake_user()
    new_user.pop("id")

    # Valid
    res = await supervisor1_client.post("/users", json=new_user)
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)

    all_users = await User.query.gino.all()
    assert len(all_users) == len(users) + 1
    assert profile_created_from_origin(new_user, all_users[-1].to_dict())

    # Valid
    new_user = get_fake_user()
    new_user.pop("id")
    res = await supervisor1_client.post("/users", json=new_user)
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)

    all_users = await User.query.gino.all()
    assert len(all_users) == len(users) + 2
    assert profile_created_from_origin(new_user, all_users[-1].to_dict())

    # Create an existing user
    res = await supervisor1_client.post("/users", json=new_user)
    assert res.status == 400
async def test_create_visitor_without_token(client, visitors):
    new_visitor = get_fake_visitor()
    new_visitor.pop("id")

    # Missing token
    res = await client.post("/visitors", json=new_visitor)
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)

    all_visitors = await Visitor.query.gino.all()
    assert len(all_visitors) == len(visitors) + 1
    assert profile_created_from_origin(new_visitor, all_visitors[-1].to_dict())

    # Valid
    new_user = get_fake_visitor()
    new_user.pop("id")
    res = await client.post("/visitors", json=new_user)
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)

    all_users = await Visitor.query.gino.all()
    assert len(all_users) == len(visitors) + 2
    assert profile_created_from_origin(new_user, all_users[-1].to_dict())

    # Create an existing user
    res = await client.post("/visitors", json=new_user)
    assert res.status == 400
Beispiel #3
0
async def test_get_flagged_chats_of_online_visitors(supervisor1_client):
    # Create some visitors
    visitors = []
    chats = []
    for _ in range(30):
        new_visitor = get_fake_visitor()
        new_visitor.pop("id")

        res = await supervisor1_client.post("/visitors", json=new_visitor)
        assert res.status == 200
        body = await res.json()
        visitors.append(body["data"])
        chat = await Chat.get_or_create(visitor_id=body["data"]["id"])
        chats.append(chat)

    # Flag some chats
    index = 7
    for visitor in visitors[7:26]:
        chat = await Chat.get_or_create(visitor_id=visitor["id"])
        sleep(0.001)
        updated_chat = await Chat.modify(
            {"id": chat["id"]},
            {"severity_level": DEFAULT_SEVERITY_LEVEL_OF_CHAT + 1})
        chats[index] = updated_chat
        index += 1

    # Get the first 15 flagged chats
    online_visitors = [visitor["id"] for visitor in visitors]
    flagged_chats = await get_flagged_chats_of_online_visitors(
        Visitor, Chat, in_values=online_visitors)
    assert len(flagged_chats) == 15
    for expected, visitor in zip(reversed(visitors[11:26]), flagged_chats):
        # room = flag_chat["room"]
        # visitor = flag_chat["visitor"]

        # Compare
        chat = await Chat.get(visitor_id=visitor["id"])
        # assert profile_created_from_origin(room, chat)
        # assert profile_created_from_origin(expected, visitor)
        assert profile_created_from_origin({**chat, **expected}, visitor)

    # Unflag some chats
    for chat in chats[11:25]:
        await Chat.modify({"id": chat["id"]},
                          {"severity_level": DEFAULT_SEVERITY_LEVEL_OF_CHAT})

    # Get the remained flagged chats
    flagged_chats = await get_flagged_chats_of_online_visitors(
        Visitor, Chat, in_values=online_visitors)
    assert len(flagged_chats) == 5
    for expected, visitor in zip(reversed(visitors[7:11] + visitors[25:26]),
                                 flagged_chats):
        # room = flag_chat["room"]
        # visitor = flag_chat["user"]

        # Compare
        chat = await Chat.get(visitor_id=visitor["id"])
        # assert profile_created_from_origin(room, chat)
        # assert profile_created_from_origin(expected, visitor)
        assert profile_created_from_origin({**chat, **expected}, visitor)
Beispiel #4
0
async def test_get_chat_messages_as_supervisor(supervisor1_client, visitors,
                                               users):
    visitor_id = visitors[-1]["id"]

    # Create some dummy chat messages
    chat = await Chat.add(visitor_id=visitor_id)
    messages = []
    for sequence_num in range(1, 25):
        content = {"value": fake.sentence(nb_words=10)}
        sender = users[-6]["id"] if randint(0, 1) else None
        chat_msg = {
            "chat_id": chat["id"],
            "sequence_num": sequence_num,
            "content": content,
            "sender": sender,
        }
        await ChatMessage.add(**chat_msg)
        chat_msg["sender"] = users[-6] if sender else None
        messages.append(chat_msg)

    # Try getting the chat messages
    res = await supervisor1_client.get(
        "/visitors/{}/messages".format(visitor_id))
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 15  # The limit

    for expected, actual in zip(messages[9:], body["data"]):
        assert profile_created_from_origin(expected, actual, ignore={"sender"})
        assert profile_created_from_origin(expected["sender"],
                                           actual["sender"])

    # Ensure that getting the next messages work too
    prev_page_link = get_prev_page_link(body)
    res = await supervisor1_client.get(prev_page_link)
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 9

    for expected, actual in zip(messages[:9], body["data"]):
        assert profile_created_from_origin(expected, actual, ignore={"sender"})
        assert profile_created_from_origin(expected["sender"],
                                           actual["sender"])

    # Ensure that getting the next messages are empty
    prev_page_link = get_prev_page_link(body)
    res = await supervisor1_client.get(prev_page_link)
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert not body["data"]
    assert isinstance(body["links"], dict)
    assert not body["links"]
Beispiel #5
0
async def test_get_visitor_bookmark_of_staff(supervisor1_client, users):
    # Create some visitors
    visitors = []
    for _ in range(32):
        new_visitor = get_fake_visitor()
        new_visitor.pop("id")

        res = await supervisor1_client.post("/visitors", json=new_visitor)
        assert res.status == 200
        body = await res.json()
        visitors.append(body["data"])

    # Bookmark some visitors
    for visitor in visitors:
        res = await supervisor1_client.patch(
            "/visitors/{}/bookmark".format(visitor["id"]), json={"is_bookmarked": True}
        )
        assert res.status == 200

    visitors = visitors[::-1]

    # Get the bookmarked visitors
    res = await supervisor1_client.get("/visitors/bookmarked")
    body = await res.json()
    assert res.status == 200
    assert "data" in body
    assert isinstance(body["data"], list)
    assert "links" in body and "next" in body["links"]
    assert len(body["data"]) == 15
    for expected, actual in zip(visitors[:15], body["data"]):
        assert profile_created_from_origin(expected, actual)

    # Next page
    next_page_link = get_next_page_link(body)
    res = await supervisor1_client.get(next_page_link)
    body = await res.json()
    assert res.status == 200
    assert "data" in body
    assert isinstance(body["data"], list)
    assert "links" in body and "next" in body["links"]
    assert len(body["data"]) == 15
    for expected, actual in zip(visitors[15:30], body["data"]):
        assert profile_created_from_origin(expected, actual)

    # Last page
    next_page_link = get_next_page_link(body)
    res = await supervisor1_client.get(next_page_link)
    body = await res.json()
    assert res.status == 200
    assert "data" in body
    assert isinstance(body["data"], list)
    assert "links" in body and "next" in body["links"]
    assert len(body["data"]) == 2

    for expected, actual in zip(visitors[30:], body["data"]):
        assert profile_created_from_origin(expected, actual)
Beispiel #6
0
async def test_get_all_agents(users, supervisor1_client):
    res = await supervisor1_client.get("/users?role_id={}".format(
        ROLES.inverse["agent"]))
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert all(user["role_id"] == ROLES.inverse["agent"]
               for user in body["data"])

    for expected, actual in zip(users[-6:-4], body["data"][-2:]):
        profile_created_from_origin(expected, actual)
async def test_get_many_visitors(supervisor1_client):
    # Create some visitors
    visitors = []
    for _ in range(33):
        new_visitor = get_fake_visitor()
        new_visitor.pop("id")

        res = await supervisor1_client.post("/visitors", json=new_visitor)
        assert res.status == 200
        body = await res.json()
        visitors.append(body["data"])

    visitors = visitors[::-1]
    # Get the visitor (sorted by created order)
    res = await supervisor1_client.get("/visitors")
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 15
    assert "links" in body and "next" in body["links"]

    for expected, actual in zip(visitors[:15], body["data"]):
        assert profile_created_from_origin(expected, actual)

    # Get the next page of visitors
    next_page_link = get_next_page_link(body)
    res = await supervisor1_client.get(next_page_link)
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 15
    assert "links" in body and "next" in body["links"]

    for expected, actual in zip(visitors[15:30], body["data"]):
        assert profile_created_from_origin(expected, actual)

    # Get the last page of visitors
    next_page_link = get_next_page_link(body)
    res = await supervisor1_client.get(next_page_link)
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 10  # = 3 (created just now) + 7 (in fixtures)
    assert "links" in body and "next" in body["links"]

    for expected, actual in zip(visitors[30:], body["data"]):
        assert profile_created_from_origin(expected, actual)
Beispiel #8
0
async def test_update_one_user_as_supervisor(users, supervisor1_client):
    new_changes = {
        "full_name": "this name surely doesnt exist",
        "password": "******",
    }

    # With id
    res = await supervisor1_client.patch("/users/{}".format(users[0]["id"]),
                                         json=new_changes)
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)
    updated_user = await get_one(User, internal_id=1)
    updated_user = updated_user.to_dict()

    ## Assert the new password has been updated
    assert profile_created_from_origin(
        {
            **body["data"], "password": hash_password(new_changes["password"])
        },
        updated_user,
    )

    # User doesnt exist
    res = await supervisor1_client.patch("/users/{}".format("9" * 32),
                                         json=new_changes)
    assert res.status == 404

    # Update to a weak password
    new_changes = {"password": "******"}
    res = await supervisor1_client.patch("/users/{}".format(users[1]["id"]),
                                         json=new_changes)
    assert res.status == 400
async def test_update_anonymous_as_self(visitors, anonymous1_client):
    new_changes = {
        "name": "this name surely doesnt exist",
        "password": "******",
    }

    # With id
    res = await anonymous1_client.patch("/visitors/{}".format(
        visitors[-4]["id"]),
                                        json=new_changes)
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)
    updated_user = await get_one(Visitor, id=visitors[-4]["id"])
    updated_user = updated_user.to_dict()

    ## Assert the new password has been updated
    assert profile_created_from_origin(
        {
            **body["data"], "password": hash_password(new_changes["password"])
        },
        updated_user,
        ignore={"updated_at"},
    )
async def test_get_one_anonymous(visitor1_client, visitors):
    res = await visitor1_client.get("/visitors/{}".format(visitors[-3]["id"]))
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)
    assert profile_created_from_origin(visitors[-3], body["data"])
Beispiel #11
0
async def test_update_user_as_admin(users, admin1_client):
    new_changes = {
        "full_name": "this name surely doesnt exist",
        "password": "******",
    }
    res = await admin1_client.patch("/users/{}".format(users[5]["id"]),
                                    json=new_changes)
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)
    updated_user = await get_one(User, internal_id=6)
    updated_user = updated_user.to_dict()

    ## Assert the new password has been updated
    assert profile_created_from_origin(
        {
            **body["data"], "password": hash_password(new_changes["password"])
        },
        updated_user,
    )

    # Admin can update supervisor
    res = await admin1_client.patch("/users/{}".format(users[-3]["id"]),
                                    json=new_changes)
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)
    updated_user = await get_one(User, id=users[-3]["id"])
    updated_user = updated_user.to_dict()

    ## Assert the new password has been updated
    assert profile_created_from_origin(
        {
            **body["data"], "password": hash_password(new_changes["password"])
        },
        updated_user,
    )
Beispiel #12
0
async def test_update_visitor_bookmark(supervisor1_client, visitors, users):
    visitor_id = visitors[4]["id"]
    res = await supervisor1_client.patch("/visitors/{}/bookmark".format(visitor_id))
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)
    assert profile_created_from_origin(
        {"staff_id": users[-4]["id"], "visitor_id": visitor_id, "is_bookmarked": False},
        body["data"],
    )
Beispiel #13
0
async def test_login_visitor(client, visitors):
    for user in visitors[:-4] + visitors[-2:]:
        res = await client.post(
            "/visitor/login",
            json={
                "email": user["email"],
                "password": user["password"]
            },
        )
        assert res.status == 200

        body = await res.json()
        assert isinstance(body, dict)
        assert "access_token" in body and "refresh_token" not in body
        assert "user" in body
        assert "access_token" in res.cookies
        assert "refresh_token" in res.cookies
        assert profile_created_from_origin(body["user"],
                                           user,
                                           ignore={"is_anonymous", "disabled"})
        assert not body["user"]["is_anonymous"]
        assert not body["user"]["disabled"]

    # Login with wrong password
    user = visitors[-1]
    res = await client.post("/visitor/login",
                            json={
                                "email": user["email"],
                                "password": "******"
                            })
    assert res.status == 401

    # Login with weak password
    user = visitors[-1]
    res = await client.post("/visitor/login",
                            json={
                                "email": user["email"],
                                "password": "******"
                            })
    assert res.status == 401

    # Login with missing password
    user = visitors[-1]
    res = await client.post("/visitor/login", json={"email": user["email"]})
    assert res.status == 400

    # Login with missing email
    user = visitors[-1]
    res = await client.post("/visitor/login",
                            json={"password": user["password"]})
    assert res.status == 400
async def test_get_one_visitor(visitor1_client, visitors):
    res = await visitor1_client.get("/visitors/{}".format(visitors[2]["id"]))
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)
    assert profile_created_from_origin(visitors[2], body["data"])

    # User doesnt exist
    res = await visitor1_client.get("/visitors/{}".format("9" * 32))
    assert res.status == 404

    res = await visitor1_client.get("/visitors/true")
    assert res.status == 404
Beispiel #15
0
async def test_visitor_send_first_msg(sio_client_visitor, server_path,
                                      token_visitor_1, visitors):
    # Get the visitor info
    visitor = await Visitor.get(id=visitors[-1]["id"])

    await sio_client_visitor.connect(
        server_path, headers={"Authorization": token_visitor_1})
    chat = await get_one(Chat, visitor_id=visitor["id"])
    assert chat is not None
    assert await cache.exists(chat.id)

    # Get the queue room
    org = (await Organisation.query.gino.all())[0]
    queue_room = "{}{}".format(UNCLAIMED_CHATS_PREFIX, org.id)
    unclaimed_chats = await cache.get(queue_room)
    assert unclaimed_chats is None

    # Get the chat room
    chat_room = await Chat.get(visitor_id=visitor["id"])

    # Send the first message
    new_content = {"value": "This is the first message"}
    await sio_client_visitor.call("visitor_first_msg", new_content, timeout=1)

    # Ensure the cache has the sent message
    unclaimed_chats = await cache.get(queue_room)
    assert unclaimed_chats == [{
        "user": visitor,
        "room": chat_room,
        "contents": [new_content]
    }]

    # Check if the message has been updated to backend
    messages = await ChatMessage.get(chat_id=chat_room["id"])
    assert len(messages) == 1
    assert profile_created_from_origin(
        {
            "sequence_num": 1,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": new_content,
            "sender": None,
        },
        messages[0],
    )

    await sio_client_visitor.disconnect()
Beispiel #16
0
async def test_login_user(client, users):
    for user in users[-4:-1]:
        res = await client.post("/login",
                                json={
                                    "email": user["email"],
                                    "password": user["password"]
                                })
        assert res.status == 200

        body = await res.json()
        assert isinstance(body, dict)
        assert "access_token" in body and "refresh_token" not in body
        assert "user" in body
        assert "access_token" in res.cookies
        assert "refresh_token" in res.cookies
        assert profile_created_from_origin(user, body["user"])

    # Login with wrong password
    user = users[-1]
    res = await client.post("/login",
                            json={
                                "email": user["email"],
                                "password": "******"
                            })
    assert res.status == 401

    # Login with weak password
    user = users[-1]
    res = await client.post("/login",
                            json={
                                "email": user["email"],
                                "password": "******"
                            })
    assert res.status == 401

    # Login with missing password
    user = users[-1]
    res = await client.post("/login", json={"email": user["email"]})
    assert res.status == 400

    # Login with missing email
    user = users[-1]
    res = await client.post("/login", json={"password": user["password"]})
    assert res.status == 400
Beispiel #17
0
async def test_login_anonymous(client):
    """Anonymous login means creating a new accoun"""
    res = await client.post("/anonymous/login", json={"name": "George"})
    assert res.status == 200

    body = await res.json()
    assert isinstance(body, dict)
    assert "access_token" in body and "refresh_token" not in body
    assert "user" in body
    assert "access_token" in res.cookies
    assert "refresh_token" in res.cookies
    assert profile_created_from_origin(
        body["user"],
        {
            "name": "George",
            "is_anonymous": True,
            "email": None,
            "disabled": False
        },
        ignore={"id"},
    )
Beispiel #18
0
async def test_get_users_with_after_id(users, supervisor1_client):
    # Use after_id in query parameter.
    res = await supervisor1_client.get("/users?after_id={}".format(
        users[2]["id"]))
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 8

    # Check if all profiles match from id 4 to 19
    assert all(
        profile_created_from_origin(origin, created)
        for origin, created in zip(users[3:20], body["data"]))

    # Invalid after_id
    res = await supervisor1_client.get("/users?after_id=2")
    assert res.status == 404

    res = await supervisor1_client.get("/users?after_id=")
    assert res.status == 400
Beispiel #19
0
async def test_update_visitor_bookmark_existing(supervisor1_client, visitors, users):
    visitor_id = visitors[4]["id"]

    # A bookmark will be auto created on GET/UPDATE
    res = await supervisor1_client.get(
        "/visitors/{}/bookmark".format(visitors[2]["id"])
    )
    assert res.status == 200

    res = await supervisor1_client.patch(
        "/visitors/{}/bookmark".format(visitor_id), json={"is_bookmarked": True}
    )
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], dict)

    assert profile_created_from_origin(
        {"staff_id": users[-4]["id"], "visitor_id": visitor_id, "is_bookmarked": True},
        body["data"],
    )
async def test_get_visitors_most_recent(users, supervisor1_client):
    # Create a lot more visitors to test
    visitors = [get_fake_visitor() for _ in range(32)]
    for visitor in visitors:
        _visitor = deepcopy(visitor)

        # Anonymous users don't have passwords
        if "password" in _visitor:
            _visitor["password"] = hash_password(_visitor["password"])
        await Visitor(**_visitor).create()

    # Create some dummy chat messages
    created_at = 1
    staff = users[-5]
    for visitor in visitors[::-1]:
        chat = await Chat.add(visitor_id=visitor["id"])
        for sequence_num in range(3):
            content = {"content": fake.sentence(nb_words=10)}
            chat_msg = {
                "chat_id": chat["id"],
                "sequence_num": sequence_num,
                "content": content,
                "sender": None,
                "created_at": created_at,
            }
            created_at += 1
            await ChatMessage.add(**chat_msg)

        # Let a staff send a message, as staffs can only fetch visitors
        # that chatted with the staffs from his org
        await ChatMessage.add(
            **{
                "chat_id": chat["id"],
                "sequence_num": sequence_num + 1,
                "content": {
                    "content": fake.sentence(nb_words=10)
                },
                "sender": staff["id"],
                "created_at": created_at,
            })

    # Get the most recent visitors that chatted with the staffs from org
    res = await supervisor1_client.get("/visitors/most_recent")
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 15
    assert "links" in body and "next" in body["links"]
    for expected, actual in zip(visitors, body["data"]):
        assert profile_created_from_origin(expected, actual)

    # Ensure that the next links work as well
    next_page_link = get_next_page_link(body)
    res = await supervisor1_client.get(next_page_link)
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 15
    assert "links" in body and "next" in body["links"]
    for expected, actual in zip(visitors[15:], body["data"]):
        assert profile_created_from_origin(expected, actual)

    # Last page
    next_page_link = get_next_page_link(body)
    res = await supervisor1_client.get(next_page_link)
    assert res.status == 200
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 2
    assert "links" in body and "next" in body["links"]
    for expected, actual in zip(visitors[30:], body["data"]):
        assert profile_created_from_origin(expected, actual)
Beispiel #21
0
async def test_visitor_send_msg_before_a_staff_join(
    sio_client_visitor,
    server_path,
    token_visitor_1,
    sio_client_agent1,
    token_agent_1,
    visitors,
):
    # Get the visitor info
    visitor = await Visitor.get(id=visitors[-1]["id"])

    await sio_client_visitor.connect(
        server_path, headers={"Authorization": token_visitor_1})

    # Get the queue room
    org = (await Organisation.query.gino.all())[0]
    queue_room = "{}{}".format(UNCLAIMED_CHATS_PREFIX, org.id)
    unclaimed_chats = await cache.get(queue_room)
    assert unclaimed_chats is None

    # Get the chat room
    chat_room = await Chat.get(visitor_id=visitor["id"])

    # Send the first message
    new_content = {"value": "This is the first message"}
    await sio_client_visitor.call("visitor_first_msg", new_content)

    # A staff connects and receive the message
    await sio_client_agent1.connect(server_path,
                                    headers={"Authorization": token_agent_1})
    await sio_client_agent1.sleep(1)

    # Assert no errors are raised when the staff connects
    excs = await cache.get("exceptions", [])
    assert not excs

    # Visitor sends another message (chat is still unclaimed)
    second_content = {"value": "Second message"}
    await sio_client_visitor.call("visitor_msg_unclaimed", second_content)

    # Check if the message has been updated to backend
    messages = await ChatMessage.get(chat_id=chat_room["id"])
    assert len(messages) == 2
    expected_msgs = [
        {
            "sequence_num": 1,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": new_content,
            "sender": None,
        },
        {
            "sequence_num": 2,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": second_content,
            "sender": None,
        },
    ]
    for expected, message in zip(expected_msgs, messages):
        assert profile_created_from_origin(expected, message)

    # Ensure that the chat in queue room is also updated
    unclaimed_chats = await cache.get(queue_room)
    assert unclaimed_chats == [{
        "user": visitor,
        "room": chat_room,
        "contents": [new_content, second_content]
    }]

    # Assert no errors are raised when the visitor sends the 2nd msg
    excs = await cache.get("exceptions", [])
    assert not excs

    await sio_client_visitor.disconnect()
    await sio_client_agent1.disconnect()
Beispiel #22
0
async def test_visitor_second_session(
    sio_client_visitor,
    server_path,
    token_visitor_1,
    sio_client_agent1,
    token_agent_1,
    visitors,
    users,
):
    # Get the visitor info
    visitor = await Visitor.get(id=visitors[-1]["id"])
    agent = await User.get(id=users[-6]["id"])

    # Get the queue room
    org = (await Organisation.query.gino.all())[0]
    queue_room = "{}{}".format(UNCLAIMED_CHATS_PREFIX, org.id)
    unclaimed_chats = await cache.get(queue_room)
    assert unclaimed_chats is None

    # A staff connects first
    await sio_client_agent1.connect(server_path,
                                    headers={"Authorization": token_agent_1})
    await sio_client_agent1.sleep(1)

    # Then the visitor connects
    await sio_client_visitor.connect(
        server_path, headers={"Authorization": token_visitor_1})

    # Get the chat room
    chat_room = await Chat.get(visitor_id=visitor["id"])

    # Send the first message
    new_content = {"value": "This is the first message"}
    await sio_client_visitor.call("visitor_first_msg", new_content)

    # Staff claim the chat
    await sio_client_agent1.call("staff_join", {"room": chat_room["id"]},
                                 timeout=1)

    # Staff sends a message
    staff_first_content = {"value": "I am an agent."}
    await sio_client_agent1.call("staff_msg", {
        "room": chat_room["id"],
        "content": staff_first_content
    })

    # Visitor sends back a message
    visitor_third_content = {"value": "Hello stranger."}
    await sio_client_visitor.call("visitor_msg",
                                  visitor_third_content,
                                  timeout=1)

    # Agent leaves the chat
    await sio_client_agent1.call("staff_leave_room", {"room": chat_room["id"]})

    # Visitor disconnects to connect again, in a new session
    await sio_client_visitor.disconnect()

    # The room has been cleared from cache after visitor disconnects
    assert not await cache.exists(chat_room["id"])
    await sio_client_visitor.connect(
        server_path, headers={"Authorization": token_visitor_1})

    # Send a new message on the new session
    another_content = {"value": "First message in new session"}
    await sio_client_visitor.call("visitor_first_msg", another_content)

    messages = await ChatMessage.get(chat_id=chat_room["id"])
    assert len(messages) == 6
    expected_msgs = [
        {
            "sequence_num": 1,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": new_content,
            "sender": None,
        },
        {
            "sequence_num": 2,
            "type_id": 0,
            "content": {
                "value": "join room"
            },
            "sender": agent,
            "chat_id": chat_room["id"],
        },
        {
            "sequence_num": 3,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": staff_first_content,
            "sender": agent,
        },
        {
            "sequence_num": 4,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": visitor_third_content,
            "sender": None,
        },
        {
            "sequence_num": 5,
            "type_id": 0,
            "content": {
                "value": "leave room"
            },
            "sender": agent,
            "chat_id": chat_room["id"],
        },
        {
            "sequence_num": 6,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": another_content,
            "sender": None,
        },
    ]
    for expected, message in zip(expected_msgs, messages):
        assert profile_created_from_origin(expected,
                                           message,
                                           ignore={"sender"})
        assert profile_created_from_origin(expected["sender"],
                                           message["sender"])

    await sio_client_visitor.disconnect()
    await sio_client_agent1.disconnect()
Beispiel #23
0
async def test_get_all_users(supervisor1_client, users):
    res = await supervisor1_client.get("/users")
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 11  # Default offset for User is 11
    assert all(
        profile_created_from_origin(origin, created)
        for origin, created in zip(users, body["data"]))

    # GET request will have its body ignored.
    res = await supervisor1_client.get("/users", json={"id": 3})
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 11  # Default offset for User is 11

    # Get one user by id
    res = await supervisor1_client.get("/users?id={}".format(users[2]["id"]))
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 1
    assert profile_created_from_origin(users[2], body["data"][0])

    ## LIMIT ##
    # No users
    res = await supervisor1_client.get("/users?limit=0")
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert not body["data"]

    # 10 users
    res = await supervisor1_client.get("/users?limit=10")
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 10
    assert all(
        profile_created_from_origin(origin, created)
        for origin, created in zip(users[:10], body["data"]))

    # Get the next 10 users
    next_page_link = body["links"]["next"]
    # Strip the host, as it is a testing host
    next_page_link = "/" + "/".join(next_page_link.split("/")[3:])
    res = await supervisor1_client.get(next_page_link)
    assert res.status == 200

    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 1
    assert all(
        profile_created_from_origin(origin, created)
        for origin, created in zip(users[10:11], body["data"]))

    # -1 users
    res = await supervisor1_client.get("/users?limit=-1")
    assert res.status == 400
Beispiel #24
0
async def test_get_unread_visitors_for_staff(supervisor1_client):
    # Create some visitors
    visitors = []
    for _ in range(30):
        new_visitor = get_fake_visitor()
        new_visitor.pop("id")

        res = await supervisor1_client.post("/visitors", json=new_visitor)
        assert res.status == 200
        body = await res.json()
        visitors.append(body["data"])

    # Create some dummy chat messages
    created_at = 1
    chat_messages = {}
    chats = []
    for visitor in visitors:
        chat = await Chat.add(visitor_id=visitor["id"])
        chats.append(chat)
        for sequence_num in range(4):
            content = {"content": fake.sentence(nb_words=10)}
            chat_msg = {
                "chat_id": chat["id"],
                "sequence_num": sequence_num,
                "content": content,
                "sender": None,
                "created_at": created_at,
            }
            created_at += 1
            created_msg = await ChatMessage.add(**chat_msg)
            chat_messages.setdefault(visitor["id"], []).append(created_msg)

    # Mark some visitors as read
    for visitor in visitors[12:17] + visitors[22:26]:
        res = await supervisor1_client.patch(
            "/visitors/{}/last_seen".format(visitor["id"]),
            json={"last_seen_msg_id": chat_messages[visitor["id"]][-1]["id"]},
        )
        assert res.status == 200

    # Mark some visitors as partially read
    for visitor in visitors[5:10]:
        res = await supervisor1_client.patch(
            "/visitors/{}/last_seen".format(visitor["id"]),
            json={"last_seen_msg_id": chat_messages[visitor["id"]][2]["id"]},
        )
        assert res.status == 200

    # Get the first unread visitors
    res = await supervisor1_client.get("/visitors/unread")
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert "links" not in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 15
    for expected_visitor, expected_chat, item in zip(
            reversed(visitors[:12] + visitors[17:22] + visitors[26:]),
            reversed(chats[:12] + chats[17:22] + chats[26:]),
            body["data"],
    ):
        actual_visitor = item["user"]
        actual_chat = item["room"]
        assert profile_created_from_origin(expected_visitor, actual_visitor)
        assert profile_created_from_origin(expected_chat, actual_chat)

    # Mark some visitors as fully read
    for visitor in visitors[2:8] + visitors[26:29]:
        res = await supervisor1_client.patch(
            "/visitors/{}/last_seen".format(visitor["id"]),
            json={"last_seen_msg_id": chat_messages[visitor["id"]][3]["id"]},
        )
        assert res.status == 200

    # Get the second unread visitors
    res = await supervisor1_client.get("/visitors/unread")
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert "links" not in body
    assert isinstance(body["data"], list)
    assert len(body["data"]) == 12
    for expected_visitor, expected_chat, item in zip(
            reversed(visitors[:2] + visitors[8:12] + visitors[17:22] +
                     visitors[29:]),
            reversed(chats[:2] + chats[8:12] + chats[17:22] + chats[29:]),
            body["data"],
    ):
        actual_visitor = item["user"]
        actual_chat = item["room"]
        assert profile_created_from_origin(expected_visitor, actual_visitor)
        assert profile_created_from_origin(expected_chat, actual_chat)

    # Mark all visitors as read
    for visitor in visitors:
        res = await supervisor1_client.patch(
            "/visitors/{}/last_seen".format(visitor["id"]),
            json={"last_seen_msg_id": chat_messages[visitor["id"]][-1]["id"]},
        )
        assert res.status == 200

    # Get the last unread visitors
    res = await supervisor1_client.get("/visitors/unread")
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert "links" not in body
    assert isinstance(body["data"], list)
    assert not body["data"]
Beispiel #25
0
async def test_staff_claim_a_visitor(
    sio_client_visitor,
    server_path,
    token_visitor_1,
    sio_client_agent1,
    token_agent_1,
    visitors,
    users,
):
    # Get the visitor info
    visitor = await Visitor.get(id=visitors[-1]["id"])
    agent = await User.get(id=users[-6]["id"])

    # Get the queue room
    org = (await Organisation.query.gino.all())[0]
    queue_room = "{}{}".format(UNCLAIMED_CHATS_PREFIX, org.id)
    unclaimed_chats = await cache.get(queue_room)
    assert unclaimed_chats is None

    # A staff connects first
    await sio_client_agent1.connect(server_path,
                                    headers={"Authorization": token_agent_1})
    await sio_client_agent1.sleep(1)

    # Assert no errors are raised when the staff connects
    excs = await cache.get("exceptions", [])
    assert not excs

    # Then the visitor connects
    await sio_client_visitor.connect(
        server_path, headers={"Authorization": token_visitor_1})

    # Get the chat room
    chat_room = await Chat.get(visitor_id=visitor["id"])

    # Send the first message
    new_content = {"value": "This is the first message"}
    await sio_client_visitor.call("visitor_first_msg", new_content)

    # There are no staffs assigned yet
    cache_chat_room = await cache.get(chat_room["id"])
    assert cache_chat_room["staff"] is None

    # Staff claim the chat
    await sio_client_agent1.call("staff_join", {"room": chat_room["id"]},
                                 timeout=1)

    # Assert no errors are raised when the staff claims the chat
    excs = await cache.get("exceptions", [])
    assert not excs

    # Ensure that the chat in queue room is also updated
    unclaimed_chats = await cache.get(queue_room)
    assert unclaimed_chats == []

    # Staff sends a message
    staff_first_content = {"value": "I am an agent."}
    await sio_client_agent1.call("staff_msg", {
        "room": chat_room["id"],
        "content": staff_first_content
    })

    # Visitor sends back a message
    visitor_third_content = {"value": "Hello stranger."}
    await sio_client_visitor.call("visitor_msg",
                                  visitor_third_content,
                                  timeout=1)

    # Agent leaves the chat
    await sio_client_agent1.call("staff_leave_room", {"room": chat_room["id"]})

    messages = await ChatMessage.get(chat_id=chat_room["id"])
    assert len(messages) == 5
    expected_msgs = [
        {
            "sequence_num": 1,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": new_content,
            "sender": None,
        },
        {
            "sequence_num": 2,
            "type_id": 0,
            "content": {
                "value": "join room"
            },
            "sender": agent,
            "chat_id": chat_room["id"],
        },
        {
            "sequence_num": 3,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": staff_first_content,
            "sender": agent,
        },
        {
            "sequence_num": 4,
            "chat_id": chat_room["id"],
            "type_id": 1,
            "content": visitor_third_content,
            "sender": None,
        },
        {
            "sequence_num": 5,
            "type_id": 0,
            "content": {
                "value": "leave room"
            },
            "sender": agent,
            "chat_id": chat_room["id"],
        },
    ]
    for expected, message in zip(expected_msgs, messages):
        assert profile_created_from_origin(expected,
                                           message,
                                           ignore={"sender"})
        assert profile_created_from_origin(expected["sender"],
                                           message["sender"])

    await sio_client_visitor.disconnect()
    await sio_client_agent1.disconnect()
Beispiel #26
0
async def test_get_messages_unread_from_top(supervisor1_client, visitors,
                                            users):
    visitor_id = visitors[-1]["id"]

    # Create some dummy chat messages
    chat = await Chat.add(visitor_id=visitor_id)
    messages = []
    for sequence_num in range(1, 37):
        content = {"value": fake.sentence(nb_words=10)}
        sender = users[-6]["id"] if randint(0, 1) else None
        chat_msg = {
            "chat_id": chat["id"],
            "sequence_num": sequence_num,
            "content": content,
            "sender": sender,
        }
        created_msg = await ChatMessage.add(**chat_msg)
        created_msg["sender"] = users[-6] if sender else None
        messages.append(created_msg)

    # When the chat has no unread, starts from top
    res = await supervisor1_client.get(
        "/visitors/{}/messages?starts_from_unread=true".format(visitor_id))
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert "links" in body and "next" in body["links"] and "prev" in body[
        "links"]
    assert len(body["data"]) == 15
    for expected, actual in zip(messages[:15], body["data"]):
        assert profile_created_from_origin(expected, actual, ignore={"sender"})
        assert profile_created_from_origin(expected["sender"],
                                           actual["sender"])

    next_page_link = get_next_page_link(body)
    prev_page_link = get_prev_page_link(body)

    # Get the prev pages until no more
    res = await supervisor1_client.get(prev_page_link)
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert ("links" in body and "next" not in body["links"]
            and "prev" not in body["links"])
    assert not body["data"]

    # Get the next messages from unread til most recent
    res = await supervisor1_client.get(next_page_link)
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert "links" in body and "next" in body["links"] and "prev" in body[
        "links"]
    assert len(body["data"]) == 15
    for expected, actual in zip(messages[15:30], body["data"]):
        assert profile_created_from_origin(expected, actual, ignore={"sender"})
        assert profile_created_from_origin(expected["sender"],
                                           actual["sender"])

    # Get the next messages until end
    next_page_link = get_next_page_link(body)
    res = await supervisor1_client.get(next_page_link)
    assert res.status == 200
    body = await res.json()
    assert "data" in body
    assert isinstance(body["data"], list)
    assert "links" in body and "next" in body["links"] and "prev" in body[
        "links"]
    assert len(body["data"]) == 6
    for expected, actual in zip(messages[30:], body["data"]):
        assert profile_created_from_origin(expected, actual, ignore={"sender"})
        assert profile_created_from_origin(expected["sender"],
                                           actual["sender"])