Пример #1
0
def test_reset_password(client, user_info):
    """A user can reset their password using a link sent to their email."""
    new_password = "******"
    assert new_password != user_info["password"]
    register_user(client, user_info)
    log_out_current_user(client)

    with mail.record_messages() as outbox:
        rv = client.get(url_for("user.password_recovery"))
        rv = client.post(
            url_for("user.password_recovery"),
            data=dict(
                csrf_token=csrf_token(rv.data),
                email=user_info["email"],
                captcha="xyzzy",
            ),
        )
        message = outbox.pop()
        assert message.send_to == {user_info["email"]}
        soup = BeautifulSoup(message.html, "html.parser")
        token = soup.a["href"].split("/")[-1]
        rv = client.get(url_for("user.password_reset", token=token),
                        follow_redirects=True)
        rv = client.post(
            url_for("do.reset"),
            data=dict(
                csrf_token=csrf_token(rv.data),
                user=get_value(rv.data, "user"),
                key=get_value(rv.data, "key"),
                password=new_password,
                confirm=new_password,
            ),
        )

        log_out_current_user(client)
        user_info["password"] = new_password
        log_in_user(client, user_info, expect_success=True)
Пример #2
0
def test_admin_can_ban_and_unban_user(client, user_info, user2_info):
    register_user(client, user_info)
    register_user(client, user2_info)
    promote_user_to_admin(client, user2_info)

    username = user_info['username']

    rv = client.get(url_for('user.view', user=username))
    rv = client.post(url_for('do.ban_user', username=username),
                     data=dict(csrf_token=csrf_token(rv.data)),
                     follow_redirects=True)

    # For now, banning makes you unable to log in.
    log_out_current_user(client)
    log_in_user(client, user_info, expect_success=False)
    log_in_user(client, user2_info, expect_success=True)

    rv = client.get(url_for('user.view', user=username))
    rv = client.post(url_for('do.unban_user', username=username),
                     data=dict(csrf_token=csrf_token(rv.data)),
                     follow_redirects=True)

    log_out_current_user(client)
    log_in_user(client, user_info, expect_success=True)
Пример #3
0
def test_mod_invite_notification(client, user_info, user2_info):
    "Notifications are sent for mod invites."
    config.update_value("site.sub_creation_min_level", 0)
    receiver, mod = user_info, user2_info

    register_user(client, receiver)
    receiver_uid = User.get(User.name == receiver["username"]).uid
    log_out_current_user(client)

    register_user(client, mod)
    mod_uid = User.get(User.name == mod["username"]).uid
    create_sub(client, name="test_janitor")
    create_sub(client, name="test_mod")

    # Mod invites receiver as moderator.
    rv_index = client.get(url_for("home.index", sub="test_mod"))
    data = {
        "csrf_token": csrf_token(rv_index.data),
        "user": receiver["username"],
        "level": "1",
    }
    rv = client.post(
        url_for("do.inv_mod", sub="test_mod"),
        data=data,
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # Mod invites receiver as janitor.
    data = {
        "csrf_token": csrf_token(rv_index.data),
        "user": receiver["username"],
        "level": "2",
    }
    rv = client.post(
        url_for("do.inv_mod", sub="test_janitor"),
        data=data,
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    # Receiver blocks mod.
    log_in_user(client, receiver)
    data = {
        "csrf_token": csrf_token(rv_index.data),
        "view_messages": "show",
        "view_content": "hide",
    }
    rv = client.post(url_for("do.edit_ignore", uid=mod_uid),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # Receiver checks notifications.  They should not be ignored,
    # because they are mod actions.
    assert get_notification_count(receiver_uid)["notifications"] == 2
    rv = client.get(url_for("messages.view_notifications"))
    assert b"invited you to moderate" in rv.data
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    assert soup.find(href=url_for("sub.edit_sub_mods", sub="test_mod"))
    assert soup.find(href=url_for("sub.edit_sub_mods", sub="test_janitor"))

    # After checking, the notification is marked read.
    assert get_notification_count(receiver_uid)["notifications"] == 0

    # Receiver unblocks mod.
    data = {
        "csrf_token": csrf_token(rv.data),
        "view_messages": "show",
        "view_content": "show",
    }
    rv = client.post(url_for("do.edit_ignore", uid=mod_uid),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # Receiver checks notifications again.
    rv = client.get(url_for("messages.view_notifications"))
    assert b"invited you to moderate" in rv.data
    assert soup.find(href=url_for("sub.edit_sub_mods", sub="test_mod"))
    assert soup.find(href=url_for("sub.edit_sub_mods", sub="test_janitor"))
Пример #4
0
def test_post_delete_notification(client, user_info, user2_info, user3_info):
    "Notifications are sent for post delete and undelete."
    config.update_value("site.sub_creation_min_level", 0)
    receiver, admin, mod = user_info, user2_info, user3_info

    register_user(client, receiver)
    receiver_uid = User.get(User.name == receiver["username"]).uid
    log_out_current_user(client)

    register_user(client, admin)
    promote_user_to_admin(client, admin)
    log_out_current_user(client)

    register_user(client, mod)
    mod_uid = User.get(User.name == mod["username"]).uid
    create_sub(client)
    log_out_current_user(client)

    # Receiver makes a post.
    log_in_user(client, receiver)
    rv_post = client.get(url_for("subs.submit", ptype="text", sub="test"))
    csrf = csrf_token(rv_post.data)
    data = {
        "csrf_token": csrf,
        "title": "the title",
        "ptype": "text",
        "content": "the content",
    }
    rv = client.post(
        url_for("subs.submit", ptype="text", sub="test"),
        data=data,
        follow_redirects=False,
    )
    assert rv.status == "302 FOUND"
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    link = soup.a.get_text()
    pid = link.split("/")[-1]
    log_out_current_user(client)

    # Mod deletes the post.
    log_in_user(client, mod)
    data = {
        "csrf_token": csrf,
        "post": pid,
        "reason": "serious reason",
        "send_to_admin": False,
    }
    rv = client.post(
        url_for("do.delete_post"),
        data=data,
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    # Admin un-deletes the post.
    log_in_user(client, admin)
    data = {
        "csrf_token": csrf,
        "post": pid,
        "reason": "frivolous reason",
    }
    rv = client.post(
        url_for("do.undelete_post"),
        data=data,
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    # Receiver blocks mod.
    log_in_user(client, receiver)
    data = {
        "csrf_token": csrf,
        "view_messages": "show",
        "view_content": "hide",
    }
    rv = client.post(url_for("do.edit_ignore", uid=mod_uid),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # Receiver checks notifications.  They should not be ignored,
    # because they are mod actions.
    assert get_notification_count(receiver_uid)["notifications"] == 2
    rv = client.get(url_for("messages.view_notifications"))
    assert b" deleted your post" in rv.data
    assert b"un-deleted your post" in rv.data
    assert b"serious reason" in rv.data
    assert b"frivolous reason" in rv.data

    # After checking, the notification is marked read.
    assert get_notification_count(receiver_uid)["notifications"] == 0

    # Receiver unblocks mod.
    data = {
        "csrf_token": csrf_token(rv.data),
        "view_messages": "show",
        "view_content": "show",
    }
    rv = client.post(url_for("do.edit_ignore", uid=mod_uid),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # Receiver checks notifications again.
    rv = client.get(url_for("messages.view_notifications"))
    assert b" deleted your post" in rv.data
    assert b"un-deleted your post" in rv.data
    assert b"serious reason" in rv.data
    assert b"frivolous reason" in rv.data
Пример #5
0
def test_ban_notification(client, user_info, user2_info):
    "Notifications are sent for sub bans."
    config.update_value("site.sub_creation_min_level", 0)
    receiver, mod = user_info, user2_info

    register_user(client, receiver)
    receiver_uid = User.get(User.name == receiver["username"]).uid
    log_out_current_user(client)

    register_user(client, mod)
    mod_uid = User.get(User.name == mod["username"]).uid
    create_sub(client)
    log_out_current_user(client)

    # Receiver blocks mod.
    log_in_user(client, receiver)
    rv_index = client.get(url_for("home.index", sub="test"))
    csrf = csrf_token(rv_index.data)
    data = {
        "csrf_token": csrf,
        "view_messages": "show",
        "view_content": "hide",
    }
    rv = client.post(url_for("do.edit_ignore", uid=mod_uid),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    # Mod bans receiver.
    log_in_user(client, mod)
    data = {
        "csrf_token": csrf,
        "user": receiver["username"],
        "reason": "serious reason",
        "expires": None,
    }
    rv = client.post(
        url_for("do.ban_user_sub", sub="test"),
        data=data,
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # Mod un-bans receiver.
    rv = client.post(
        url_for("do.remove_sub_ban", sub="test", user=receiver["username"]),
        data={"csrf_token": csrf},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    # Receiver checks notifications.  They should not be ignored,
    # because they are mod actions.
    log_in_user(client, receiver)
    assert get_notification_count(receiver_uid)["notifications"] == 2
    rv = client.get(url_for("messages.view_notifications"))
    assert b"banned you from" in rv.data
    assert b"serious reason" in rv.data
    assert b"unbanned you from" in rv.data

    # After checking, the notification is marked read.
    assert get_notification_count(receiver_uid)["notifications"] == 0

    # Receiver unblocks mod.
    data = {
        "csrf_token": csrf_token(rv.data),
        "view_messages": "show",
        "view_content": "show",
    }
    rv = client.post(url_for("do.edit_ignore", uid=mod_uid),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # Receiver checks notifications again.
    rv = client.get(url_for("messages.view_notifications"))
    assert b"banned you from" in rv.data
    assert b"serious reason" in rv.data
    assert b"unbanned you from" in rv.data
Пример #6
0
def test_reply_notification(client, sub_mod, user_info, user2_info,
                            user3_info):
    "Notifications are sent for post and comment replies."
    sender, receiver, mod = user_info, user2_info, user3_info
    config.update_value("site.sub_creation_min_level", 0)

    register_user(client, sender)
    sender_uid = User.get(User.name == sender["username"]).uid
    if sub_mod == "sender":
        create_sub(client)
    log_out_current_user(client)

    register_user(client, receiver)
    receiver_uid = User.get(User.name == receiver["username"]).uid
    if sub_mod == "receiver":
        create_sub(client)
    log_out_current_user(client)

    if sub_mod == "neither":
        register_user(client, mod)
        create_sub(client)
        log_out_current_user(client)

    # Receiver makes a post that can be replied to
    log_in_user(client, receiver)
    rv = client.get(url_for("subs.submit", ptype="text", sub="test"))
    csrf = csrf_token(rv.data)
    data = {
        "csrf_token": csrf,
        "title": "the title",
        "ptype": "text",
        "content": "the content",
    }
    rv = client.post(
        url_for("subs.submit", ptype="text", sub="test"),
        data=data,
        follow_redirects=False,
    )
    assert rv.status == "302 FOUND"
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    link = soup.a.get_text()
    pid = link.split("/")[-1]

    # Receiver makes a comment that can be replied to.
    rv = client.get(link, follow_redirects=True)
    assert b"the title |  test" in rv.data
    data = {
        "csrf_token": csrf,
        "post": pid,
        "parent": "0",
        "comment": "OP reply",
    }
    rv = client.post(url_for("do.create_comment", pid=pid),
                     data=data,
                     follow_redirects=False)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    cid = reply["cid"]

    # Receiver blocks sender.
    data = {
        "csrf_token": csrf,
        "view_messages": "show",
        "view_content": "hide",
    }
    rv = client.post(url_for("do.edit_ignore", uid=sender_uid),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    # Sender replies to the post.
    log_in_user(client, sender)
    rv = client.get(link, follow_redirects=True)
    assert b"the title |  test" in rv.data
    data = {
        "csrf_token": csrf,
        "post": pid,
        "parent": "0",
        "comment": "the comment",
    }
    rv = client.post(url_for("do.create_comment", pid=pid),
                     data=data,
                     follow_redirects=True)
    assert b"the comment" in rv.data

    # Sender replies to the comment.
    rv = client.get(link, follow_redirects=True)
    data = {
        "csrf_token": csrf_token(rv.data),
        "post": pid,
        "parent": cid,
        "comment": "comment reply",
    }
    rv = client.post(url_for("do.create_comment", pid=pid),
                     data=data,
                     follow_redirects=True)
    log_out_current_user(client)

    # Depending on who is the mod of the sub, should these notifications
    # be visible when the receiver has the sender blocked?
    expected = {"sender": True, "receiver": True, "neither": False}[sub_mod]
    assert get_notification_count(receiver_uid)["notifications"] == (
        2 if expected else 0)

    # Receiver checks notifications.
    log_in_user(client, receiver)
    rv = client.get(url_for("messages.view_notifications"))
    assert (b"replied to your post" in rv.data) == expected
    assert (b"the comment" in rv.data) == expected
    assert (b"replied to your comment" in rv.data) == expected
    assert (b"comment reply" in rv.data) == expected

    # Receiver unblocks sender.
    data = {
        "csrf_token": csrf,
        "view_messages": "show",
        "view_content": "show",
    }
    rv = client.post(url_for("do.edit_ignore", uid=sender_uid),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # Receiver checks notifications.
    rv = client.get(url_for("messages.view_notifications"))
    assert b"replied to your post" in rv.data
    assert b"the comment" in rv.data
    assert b"replied to your comment" in rv.data
    assert b"comment reply" in rv.data

    # Notifications should be marked read.
    assert get_notification_count(receiver_uid)["notifications"] == 0
Пример #7
0
def test_mod_comment_delete(client, user_info, user2_info, user3_info):
    config.update_value("site.sub_creation_min_level", 0)
    user, admin, mod = user_info, user2_info, user3_info
    register_user(client, admin)
    promote_user_to_admin(client, admin)
    log_out_current_user(client)

    register_user(client, mod)
    create_sub(client)
    log_out_current_user(client)

    register_user(client, user)

    # User makes a post.
    rv = client.get(url_for("subs.submit", ptype="text", sub="test"))
    csrf = csrf_token(rv.data)
    data = {
        "csrf_token": csrf,
        "title": "the title",
        "ptype": "text",
        "content": "the content",
    }
    rv = client.post(
        url_for("subs.submit", ptype="text", sub="test"),
        data=data,
        follow_redirects=False,
    )
    assert rv.status == "302 FOUND"
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    link = soup.a.get_text()
    pid = link.split("/")[-1]

    # User adds some comments.
    rv = client.get(link, follow_redirects=True)
    assert b"the title |  test" in rv.data
    cids = {}
    comments = [
        "delete_user",
        "delete_admin",
        "delete_then_undelete_by_admin",
        "delete_mod",
        "delete_then_undelete_by_mod",
        "delete_undelete_by_mod_then_admin",
    ]
    for comment in comments:
        data = {
            "csrf_token": csrf,
            "post": pid,
            "parent": "0",
            "comment": comment,
        }
        rv = client.post(
            url_for("do.create_comment", pid=pid), data=data, follow_redirects=False
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "ok"
        cids[comment] = reply["cid"]

    # User reloads the page and can see all the comments.
    rv = client.get(link, follow_redirects=True)
    data = rv.data.decode("utf-8")
    for comment in comments:
        assert comment in data
    # Check for the css class on the bottombar delete links.
    assert len(re.findall("[^n]delete-comment", data)) == len(comments)

    rv = client.post(
        url_for("do.delete_comment"),
        data={"csrf_token": csrf, "cid": cids["delete_user"]},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # User can no longer see deleted comment.
    rv = client.get(link, follow_redirects=True)
    data = rv.data.decode("utf-8")
    for comment in comments:
        if comment == "delete_user":
            assert comment not in data
        else:
            assert comment in data
    log_out_current_user(client)

    # Admin sees deleted comment content, and n-1 delete links.
    log_in_user(client, admin)
    rv = client.get(link, follow_redirects=True)
    data = rv.data.decode("utf-8")
    for comment in comments:
        assert comment in data
    # Check for the css class on the bottombar delete links.
    assert len(re.findall("[^n]delete-comment", data)) == len(comments) - 1
    assert "undelete-comment" not in data

    # Admin tries to remove user's deleted comment.
    rv = client.post(
        url_for("do.delete_comment"),
        data={"csrf_token": csrf, "cid": cids["delete_user"]},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "error"
    assert reply["error"] == "Comment is already deleted"

    # Admin removes two comments.
    for comment in ["delete_admin", "delete_then_undelete_by_admin"]:
        rv = client.post(
            url_for("do.delete_comment"),
            data={"csrf_token": csrf, "cid": cids[comment]},
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "ok"

    # Admin can still see all comment content and now has two undelete links.
    rv = client.get(link, follow_redirects=True)
    data = rv.data.decode("utf-8")
    for comment in comments:
        assert comment in data
    # Check for the css class on the bottombar delete links.
    assert len(re.findall("undelete-comment", data)) == 2
    assert len(re.findall("[^n]delete-comment", data)) == len(comments) - 3

    # Admin undeletes a comment.
    rv = client.post(
        url_for("do.undelete_comment"),
        data={"csrf_token": csrf, "cid": cids["delete_then_undelete_by_admin"]},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    # Mod sees content of deleted and undeleted comments.
    log_in_user(client, mod)
    rv = client.get(link, follow_redirects=True)
    data = rv.data.decode("utf-8")
    for comment in comments:
        assert comment in data
    # Mod should see delete links for undeleted comments.
    assert len(re.findall("[^n]delete-comment", data)) == len(comments) - 2
    assert len(re.findall("undelete-comment", data)) == 0

    # Mod tries to remove already deleted comments.
    for comment in ["delete_user", "delete_admin"]:
        rv = client.post(
            url_for("do.delete_comment"),
            data={"csrf_token": csrf, "cid": cids[comment]},
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "error"
        assert reply["error"] == "Comment is already deleted"

    # Mod tries to undelete comment deleted by admin.
    rv = client.post(
        url_for("do.undelete_comment"),
        data={"csrf_token": csrf, "cid": cids["delete_admin"]},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "error"
    assert reply["error"] == "Not authorized"

    # Mod removes some comments.
    for comment in [
        "delete_mod",
        "delete_then_undelete_by_mod",
        "delete_undelete_by_mod_then_admin",
    ]:
        rv = client.post(
            url_for("do.delete_comment"),
            data={"csrf_token": csrf, "cid": cids[comment]},
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "ok"

    # Mod sees content of all comments, and now has two undelete links.
    rv = client.get(link, follow_redirects=True)
    data = rv.data.decode("utf-8")
    for comment in comments:
        assert comment in data
    # Mod should see delete links for undeleted comments.
    assert len(re.findall("[^n]delete-comment", data)) == len(comments) - 5
    assert len(re.findall("undelete-comment", data)) == 3

    # Mod undeletes a comment.
    rv = client.post(
        url_for("do.undelete_comment"),
        data={"csrf_token": csrf, "cid": cids["delete_then_undelete_by_mod"]},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    log_in_user(client, admin)
    # Admin has undelete links for the content admin deleted as well as
    # the content the mod deleted.
    assert len(re.findall("undelete-comment", data)) == 3

    # Admin can undelete a comment deleted by the mod.
    rv = client.post(
        url_for("do.undelete_comment"),
        data={"csrf_token": csrf, "cid": cids["delete_undelete_by_mod_then_admin"]},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    log_in_user(client, user)
    # User can see comments which are not deleted.
    undeleted = [
        "delete_then_undelete_by_admin",
        "delete_then_undelete_by_mod",
        "delete_undelete_by_mod_then_admin",
    ]
    rv = client.get(link, follow_redirects=True)
    data = rv.data.decode("utf-8")
    for comment in comments:
        if comment in undeleted:
            assert comment in data
        else:
            assert comment not in data

    # User should see delete links for undeleted comments.
    assert len(re.findall("[^n]delete-comment", data)) == len(undeleted)
    assert len(re.findall("undelete-comment", data)) == 0

    # User can't undelete any comment
    for comment in comments:
        rv = client.post(
            url_for("do.undelete_comment"),
            data={"csrf_token": csrf, "cid": cids[comment]},
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "error"
        if comment in undeleted:
            assert reply["error"] == "Comment is not deleted"
        elif comment == "delete_user":
            assert reply["error"] == "Can not un-delete a self-deleted comment"
        else:
            assert reply["error"] == "Not authorized"
Пример #8
0
def test_logout_and_login_again(client, user_info):
    """A logged in user can log out and back in again."""
    register_user(client, user_info)
    assert b"Log out" in client.get(url_for("home.index")).data
    log_out_current_user(client, verify=True)
    log_in_user(client, user_info, expect_success=True)
Пример #9
0
def test_mod_post_delete(client, user_info, user2_info, user3_info):
    config.update_value("site.sub_creation_min_level", 0)
    user, admin, mod = user_info, user2_info, user3_info
    register_user(client, admin)
    promote_user_to_admin(client, admin)
    log_out_current_user(client)

    register_user(client, mod)
    create_sub(client)
    log_out_current_user(client)

    register_user(client, user)

    # User makes several posts.
    pids = {}
    posts = [
        "delete_user",
        "delete_admin",
        "delete_then_undelete_by_admin",
        "delete_mod",
        "delete_then_undelete_by_mod",
        "delete_undelete_by_mod_then_admin",
    ]
    rv = client.get(url_for("subs.submit", ptype="text", sub="test"))
    csrf = csrf_token(rv.data)
    for post in posts:
        rv = client.post(
            url_for("subs.submit", ptype="text", sub="test"),
            data={
                "csrf_token": csrf,
                "title": post,
                "ptype": "text",
                "content": "the content",
            },
            follow_redirects=False,
        )
        assert rv.status == "302 FOUND"
        soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
        link = soup.a.get_text()
        pids[post] = link.split("/")[-1]

    # User can see all the posts.
    rv = client.get(url_for("sub.view_sub", sub="test"), follow_redirects=True)
    data = rv.data.decode("utf-8")
    for post in posts:
        assert post in data

    # User has a delete link on a single-post page.
    rv = client.get(
        url_for("sub.view_post", sub="test", pid=pids["delete_user"]),
        follow_redirects=True,
    )
    assert len(re.findall("[^n]delete-post", rv.data.decode("utf-8"))) == 1

    # User deletes a post.
    rv = client.post(
        url_for("do.delete_post"),
        data={"csrf_token": csrf, "post": pids["delete_user"]},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # User can now not see deleted post
    rv = client.get(url_for("sub.view_sub", sub="test"), follow_redirects=True)
    data = rv.data.decode("utf-8")
    for post in posts:
        if post == "delete_user":
            assert post not in data
        else:
            assert post in data

    # User can go to deleted post page but there is no delete or undelete link.
    rv = client.get(
        url_for("sub.view_post", sub="test", pid=pids["delete_user"]),
        follow_redirects=True,
    )
    data = rv.data.decode("utf-8")
    assert "the content" not in data
    assert len(re.findall("delete-post", data)) == 0

    log_out_current_user(client)

    # Admin sees deleted post content, and no delete or undelete link.
    log_in_user(client, admin)
    rv = client.get(
        url_for("sub.view_post", sub="test", pid=pids["delete_user"]),
        follow_redirects=True,
    )
    data = rv.data.decode("utf-8")
    assert "the content" in data
    assert len(re.findall("delete-post", data)) == 0

    # Admin tries to remove user's deleted post.
    rv = client.post(
        url_for("do.delete_post"),
        data={"csrf_token": csrf, "post": pids["delete_user"]},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "error"
    assert reply["error"] == ["Post was already deleted"]

    # Admin deletes two posts.
    for post in ["delete_admin", "delete_then_undelete_by_admin"]:
        rv = client.post(
            url_for("do.delete_post"),
            data={"csrf_token": csrf, "post": pids[post], "reason": "admin"},
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "ok"

    # Admin can still see the post content and now has undelete links.
    for post in ["delete_admin", "delete_then_undelete_by_admin"]:
        rv = client.get(
            url_for("sub.view_post", sub="test", pid=pids[post]), follow_redirects=True
        )
        data = rv.data.decode("utf-8")
        assert "the content" in data
        # Check for the css class on the bottombar delete links.
        assert len(re.findall("undelete-post", data)) == 1
        assert len(re.findall("[^n]delete-post", data)) == 0

    # Admin undeletes a post.
    rv = client.post(
        url_for("do.undelete_post"),
        data={
            "csrf_token": csrf,
            "post": pids["delete_then_undelete_by_admin"],
            "reason": "admin",
        },
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    # Mod can see content of all posts.  Mod sees delete links for the
    # posts which are not deleted, and does not have delete or
    # undelete links for the deleted posts.
    log_in_user(client, mod)
    for post in posts:
        rv = client.get(
            url_for("sub.view_post", sub="test", pid=pids[post]), follow_redirects=True
        )
        data = rv.data.decode("utf-8")
        assert post in data
        assert "the content" in data
        if post in ["delete_user", "delete_admin"]:
            assert len(re.findall("delete-post", data)) == 0
        else:
            assert len(re.findall("undelete-post", data)) == 0
            assert len(re.findall("[^n]delete-post", data)) == 1

    # Mod tries to remove already deleted posts.
    for post in ["delete_user", "delete_admin"]:
        rv = client.post(
            url_for("do.delete_post"),
            data={"csrf_token": csrf, "post": pids[post], "reason": "mod"},
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "error"
        assert reply["error"] == ["Post was already deleted"]

    # Mod can't undelete post deleted by admin.
    rv = client.post(
        url_for("do.undelete_post"),
        data={"csrf_token": csrf, "post": pids["delete_admin"], "reason": "mod"},
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "error"
    assert reply["error"] == ["Not authorized"]

    # Mod deletes some posts.
    for post in [
        "delete_mod",
        "delete_then_undelete_by_mod",
        "delete_undelete_by_mod_then_admin",
    ]:
        rv = client.post(
            url_for("do.delete_post"),
            data={"csrf_token": csrf, "post": pids[post], "reason": "mod"},
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "ok"

    # Mod sees content of all posts, and now has two undelete links.
    for post in posts:
        rv = client.get(
            url_for("sub.view_post", sub="test", pid=pids[post]), follow_redirects=True
        )
        data = rv.data.decode("utf-8")
        assert post in data
        assert "the content" in data
        if post in ["delete_user", "delete_admin"]:
            assert len(re.findall("delete-post", data)) == 0
        elif post in [
            "delete_mod",
            "delete_then_undelete_by_mod",
            "delete_undelete_by_mod_then_admin",
        ]:
            assert len(re.findall("[^n]delete-post", data)) == 0
            assert len(re.findall("undelete-post", data)) == 1
        else:
            assert len(re.findall("undelete-post", data)) == 0
            assert len(re.findall("[^n]delete-post", data)) == 1

    # Mod undeletes a post.
    rv = client.post(
        url_for("do.undelete_post"),
        data={
            "csrf_token": csrf,
            "post": pids["delete_then_undelete_by_mod"],
            "reason": "mod",
        },
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    log_in_user(client, admin)
    # Admin has undelete links for the content admin deleted as well as
    # the content the mod deleted.
    for post in posts:
        rv = client.get(
            url_for("sub.view_post", sub="test", pid=pids[post]), follow_redirects=True
        )
        data = rv.data.decode("utf-8")
        assert post in data
        assert "the content" in data
        if post == "delete_user":
            assert len(re.findall("delete-post", data)) == 0
        elif post in [
            "delete_admin",
            "delete_mod",
            "delete_undelete_by_mod_then_admin",
        ]:
            assert len(re.findall("[^n]delete-post", data)) == 0
            assert len(re.findall("undelete-post", data)) == 1
        else:
            assert len(re.findall("undelete-post", data)) == 0
            assert len(re.findall("[^n]delete-post", data)) == 1

    # Admin can undelete a post deleted by the mod.
    rv = client.post(
        url_for("do.undelete_post"),
        data={
            "csrf_token": csrf,
            "post": pids["delete_undelete_by_mod_then_admin"],
            "reason": "admin",
        },
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"
    log_out_current_user(client)

    log_in_user(client, user)
    # User can see posts which were deleted by mod or admin.
    undeleted = [
        "delete_then_undelete_by_admin",
        "delete_then_undelete_by_mod",
        "delete_undelete_by_mod_then_admin",
    ]
    for post in posts:
        rv = client.get(
            url_for("sub.view_post", sub="test", pid=pids[post]), follow_redirects=True
        )
        data = rv.data.decode("utf-8")
        assert post in data
        if post != "delete_user":
            assert "the content" in data
        # User has a delete link for posts which are not deleted, and
        # no undelete links.
        if post in undeleted:
            assert len(re.findall("[^n]delete-post", data)) == 1
        else:
            assert len(re.findall("[^n]delete-post", data)) == 0
        assert len(re.findall("undelete-post", data)) == 0

    for post in posts:
        if post not in undeleted:
            # User can't delete anything which has already been deleted.
            rv = client.post(
                url_for("do.delete_post"),
                data={
                    "csrf_token": csrf,
                    "post": pids["delete_user"],
                    "reason": "user",
                },
            )
            reply = json.loads(rv.data.decode("utf-8"))
            assert reply["status"] == "error"
            assert reply["error"] == ["Post was already deleted"]

    # User can't undelete any posts.
    for post in posts:
        rv = client.post(
            url_for("do.undelete_post"),
            data={"csrf_token": csrf, "post": pids[post], "reason": "user"},
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "error"
        if post == "delete_user":
            assert reply["error"] == ["Can not un-delete a self-deleted post"]
        elif "undelete" in post:
            assert reply["error"] == ["Post is not deleted"]
        else:
            assert reply["error"] == ["Not authorized"]
Пример #10
0
def test_block_pm(client, user_info, user2_info):
    """Block and unblock private messages from a user."""
    username = user_info["username"]
    register_user(client, user_info)
    register_user(client, user2_info)

    # User2 sends User a message.
    rv = client.get(url_for("user.view", user=username))
    assert rv.status == "200 OK"
    client.post(
        url_for("do.create_sendmsg"),
        data=dict(
            csrf_token=csrf_token(rv.data),
            to=username,
            subject="Testing",
            content="Test Content",
        ),
        follow_redirects=True,
    )

    log_out_current_user(client, verify=True)
    log_in_user(client, user_info, expect_success=True)

    # User blocks User2.
    user2 = User.get(User.name == user2_info["username"])
    rv = client.post(
        url_for("do.ignore_user", uid=user2.uid),
        data=dict(csrf_token=csrf_token(rv.data)),
    )

    # User doesn't have a notification for blocked message.
    rv = client.get(url_for("home.index"), follow_redirects=True)
    assert rv.status == "200 OK"
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    link = soup.find(href=url_for("messages.inbox_sort"))
    assert link.get_text().strip() == "0"

    # Message not visible in User's inbox.
    rv = client.get(url_for("messages.inbox_sort"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user2_info["username"], "Testing", "Test Content"], exclude=True
    )

    # User2 shows up on User's ignore page.
    rv = client.get(url_for("user.view_ignores"))
    assert rv.status == "200 OK"
    assert user2_info["username"].encode("utf-8") in rv.data

    # User unblocks User2.
    rv = client.post(
        url_for("do.ignore_user", uid=user2.uid),
        data=dict(csrf_token=csrf_token(rv.data)),
    )

    # User now has a notification for message.
    rv = client.get(url_for("home.index"), follow_redirects=True)
    assert rv.status == "200 OK"
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    link = soup.find(href=url_for("messages.inbox_sort"))
    assert link.get_text().strip() == "1"

    # Message now visible in User's inbox.
    rv = client.get(url_for("messages.inbox_sort"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user2_info["username"], "Testing", "Test Content"]
    )
Пример #11
0
def test_exchange_pm(client, user_info, user2_info):
    """Send a private message and have an exchange of replies."""
    username = user_info["username"]
    register_user(client, user_info)
    register_user(client, user2_info)

    # User2 sends User a message.
    rv = client.get(url_for("user.view", user=username))
    assert rv.status == "200 OK"
    rv = client.post(
        url_for("do.create_sendmsg"),
        data=dict(
            csrf_token=csrf_token(rv.data),
            to=username,
            subject="Testing",
            content="Test Content",
        ),
        follow_redirects=True,
    )
    assert b"error" not in rv.data

    log_out_current_user(client, verify=True)
    log_in_user(client, user_info, expect_success=True)

    # User sees the message on the inbox page.
    rv = client.get(url_for("messages.inbox_sort"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user2_info["username"], "Testing", "Test Content"]
    )

    # User replies to the message.
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    tag = soup.find(lambda tag: tag.has_attr("data-mid"))
    mid = tag.attrs["data-mid"]

    rv = client.post(
        url_for("do.create_replymsg"),
        data=dict(
            csrf_token=csrf_token(rv.data), mid=mid, content="Test reply content"
        ),
    )
    assert b"error" not in rv.data

    # User sees the message in Sent Messages.
    rv = client.get(url_for("messages.view_messages_sent"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user2_info["username"], "Re: Testing", "Test reply content"]
    )

    log_out_current_user(client, verify=True)
    log_in_user(client, user2_info, expect_success=True)

    # User2 has one new message.
    rv = client.get(url_for("home.index"), follow_redirects=True)
    assert rv.status == "200 OK"
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    link = soup.find(href=url_for("messages.inbox_sort"))
    assert link.get_text().strip() == "1"

    # User2 sees the message on the inbox page.
    rv = client.get(url_for("messages.inbox_sort"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user_info["username"], "Re: Testing", "Test reply content"]
    )

    # User2 replies to the reply.
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    tag = soup.find(lambda tag: tag.has_attr("data-mid"))
    mid = tag.attrs["data-mid"]
    rv = client.post(
        url_for("do.create_replymsg"),
        data=dict(
            csrf_token=csrf_token(rv.data), mid=mid, content="Test 2nd reply content"
        ),
    )
    assert b"error" not in rv.data

    # User2 sees reply in Sent Messages.
    rv = client.get(url_for("messages.view_messages_sent"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user_info["username"], "Re: Testing", "Test 2nd reply content"]
    )
    assert b"Re: Re: Testing" not in rv.data

    log_out_current_user(client, verify=True)
    log_in_user(client, user_info, expect_success=True)

    # User now has two new messages.
    rv = client.get(url_for("home.index"), follow_redirects=True)
    assert rv.status == "200 OK"
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    link = soup.find(href=url_for("messages.inbox_sort"))
    assert link.get_text().strip() == "2"

    # User sees the message on the inbox page.
    rv = client.get(url_for("messages.inbox_sort"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert b"Test 2nd reply content" in rv.data

    # User uses the mark all as read link.
    rv = client.post(url_for("do.readall_msgs"), data={})
    assert b"error" not in rv.data

    # User now has no new messages.
    rv = client.get(url_for("home.index"), follow_redirects=True)
    assert rv.status == "200 OK"
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    link = soup.find(href=url_for("messages.inbox_sort"))
    assert link.get_text().strip() == "0"
Пример #12
0
def test_save_and_delete_pm(client, user_info, user2_info):
    """Save and delete a private message."""
    username = user_info["username"]
    register_user(client, user_info)
    register_user(client, user2_info)

    # User2 sends User a message.
    rv = client.get(url_for("user.view", user=username))
    assert rv.status == "200 OK"
    client.post(
        url_for("do.create_sendmsg"),
        data=dict(
            csrf_token=csrf_token(rv.data),
            to=username,
            subject="Testing",
            content="Test Content",
        ),
        follow_redirects=True,
    )

    # Switch users.
    log_out_current_user(client, verify=True)
    log_in_user(client, user_info, expect_success=True)

    # Message visible in User's inbox.
    rv = client.get(url_for("messages.inbox_sort"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user2_info["username"], "Testing", "Test Content"]
    )

    # User saves the message.
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    tag = soup.find(lambda tag: tag.has_attr("data-mid"))
    mid = tag.attrs["data-mid"]
    rv = client.post(
        url_for("do.save_pm", mid=mid),
        data=dict(csrf_token=csrf_token(rv.data)),
        follow_redirects=True,
    )
    assert b"error" not in rv.data

    # Message now no longer appears in inbox.
    rv = client.get(url_for("messages.inbox_sort"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user2_info["username"], "Testing", "Test Content"], exclude=True
    )

    # Message appears in saved messages.
    rv = client.get(url_for("messages.view_saved_messages"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user2_info["username"], "Testing", "Test Content"]
    )

    # User deletes message from saved messages.
    rv = client.post(
        url_for("do.delete_pm", mid=mid),
        data=dict(csrf_token=csrf_token(rv.data)),
        follow_redirects=True,
    )
    assert b"error" not in rv.data

    # Message is no longer in saved messages.
    rv = client.get(url_for("messages.view_saved_messages"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user2_info["username"], "Testing", "Test Content"], exclude=True
    )

    # Message is not in User's inbox either.
    rv = client.get(url_for("messages.inbox_sort"), follow_redirects=True)
    assert rv.status == "200 OK"
    assert substrings_present(
        rv.data, [user2_info["username"], "Testing", "Test Content"], exclude=True
    )
Пример #13
0
def test_comment_sort(client, user_info):
    "Comments can be sorted by best, top and new."
    config.update_value("site.sub_creation_min_level", 0)

    # Create a mod and a sub.
    mod = user_info
    register_user(client, mod)
    create_sub(client)
    log_out_current_user(client)

    # Create some users to read and vote.
    users = [
        dict(username=f"user{i}",
             email=f"user{i}@example.com",
             password="******") for i in range(10)
    ]
    for user in users:
        register_user(client, user)
        log_out_current_user(client)

    # Mod makes a post and adds three comments to it.
    log_in_user(client, mod)
    rv = client.get(url_for("subs.submit", ptype="text", sub="test"))
    csrf = csrf_token(rv.data)
    data = {
        "csrf_token": csrf,
        "title": "the title",
        "ptype": "text",
        "content": "the content",
    }
    rv = client.post(
        url_for("subs.submit", ptype="text", sub="test"),
        data=data,
        follow_redirects=False,
    )
    assert rv.status == "302 FOUND"
    soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
    link = soup.a.get_text()
    pid = link.split("/")[-1]

    rv = client.get(link, follow_redirects=True)
    assert b"the title |  test" in rv.data
    cids = {}
    for comment in ["oldest", "middle", "newest"]:
        data = {
            "csrf_token": csrf,
            "post": pid,
            "parent": "0",
            "comment": "This comment is: " + comment,
        }
        rv = client.post(url_for("do.create_comment", pid=pid),
                         data=data,
                         follow_redirects=False)
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "ok"
        cids[comment] = reply["cid"]
    log_out_current_user(client)

    # The other users visit and vote the comments as follows:
    # oldest - 10 visits, 5 upvotes, 1 downvote
    # middle - 2 visits, 2 upvotes
    # newest - 0 visits, 0 upvotes
    expected_results = {
        "new": ["newest", "middle", "oldest"],
        "top": ["oldest", "middle", "newest"],
        "best": ["middle", "newest", "oldest"],
    }

    for num, user in enumerate(users):
        log_in_user(client, user)

        # View some comments.
        if num < 2:
            views = [cids["oldest"], cids["middle"]]
        else:
            views = [cids["oldest"]]
        rv = client.post(
            url_for("do.mark_comments_viewed"),
            data={
                "csrf_token": csrf,
                "cids": json.dumps(views)
            },
        )
        reply = json.loads(rv.data.decode("utf-8"))
        assert reply["status"] == "ok"

        # Upvote some comments.
        if num < 5:
            rv = client.post(
                url_for("do.upvotecomment", cid=cids["oldest"], value="up"),
                data={"csrf_token": csrf},
            )
            assert rv.status == "200 OK"

        if num < 2:
            rv = client.post(
                url_for("do.upvotecomment", cid=cids["middle"], value="up"),
                data={"csrf_token": csrf},
            )
            assert rv.status == "200 OK"

        # Downvote a comment
        if num == 0:
            rv = client.post(
                url_for("do.upvotecomment", cid=cids["oldest"], value="down"),
                data={"csrf_token": csrf},
            )
            assert rv.status == "200 OK"

        log_out_current_user(client)

    for sort, order in expected_results.items():
        rv = client.get(
            url_for("sub.view_post", pid=pid, sub="test", slug="", sort=sort),
            follow_redirects=True,
        )
        assert rv.status == "200 OK"
        soup = BeautifulSoup(rv.data, "html.parser", from_encoding="utf-8")
        comments = [
            c.get_text() for c in soup.find_all("div", class_="content")
        ]
        for expected, comment in zip(order, comments):
            assert comment.find(expected) != -1