Beispiel #1
0
def test_get_totp_image(client, user_info, test_config):
    register_user(client, user_info)
    assert client.get(url_for("admin.get_totp_image")).status_code == 404
    promote_user_to_admin(client, user_info)
    rv = client.get(url_for("admin.get_totp_image"))
    assert rv.status_code == 200
    assert rv.content_type == "image/png"
Beispiel #2
0
def test_admin_totp_auth_flow(client, user_info, test_config):
    register_user(client, user_info)
    assert client.get(url_for("admin.auth")).status_code == 404
    promote_user_to_admin(client, user_info)
    rv = client.get(url_for("admin.auth"), follow_redirects=True)
    assert rv.status_code == 200
    assert b"TOTP setup" in rv.data
    user = User.get(User.name == user_info["username"])
    user_secret = UserMetadata.get((UserMetadata.uid == user.uid)
                                   & (UserMetadata.key == "totp_secret"))
    totp = pyotp.TOTP(user_secret.value)

    data = {"csrf_token": csrf_token(rv.data), "totp": totp.now()}

    rv = client.post(url_for("admin.auth"), data=data, follow_redirects=False)
    assert rv.status_code == 302
    assert rv.location == url_for("admin.index")

    # Try again with bad token
    data["totp"] = "1"
    rv = client.post(url_for("admin.auth"), data=data, follow_redirects=False)
    assert rv.status_code == 200
    assert b"Invalid or expired token." in rv.data

    # Check if we're actually logged in.
    assert client.get(url_for("admin.index")).status_code == 200

    # Get QR code after we already set up TOTP
    assert client.get(url_for("admin.get_totp_image")).status_code == 403

    # Try logging out.
    client.post(url_for("admin.logout"), data=data)
    assert client.get(url_for("admin.index"),
                      follow_redirects=False).status_code == 302
Beispiel #3
0
def test_admin_can_ban_email_domain(client, user_info):
    register_user(client, user_info)
    promote_user_to_admin(client, user_info)

    rv = client.get(url_for('admin.domains', domain_type='email'))
    rv = client.post(url_for('do.ban_domain', domain_type='email'),
                     data=dict(csrf_token=csrf_token(rv.data),
                               domain='spam4u.com'),
                     follow_redirects=True)
    reply = json.loads(rv.data.decode('utf-8'))
    assert reply['status'] == 'ok'

    log_out_current_user(client)
    rv = client.get(url_for('auth.register'))
    with mail.record_messages() as outbox:
        data = dict(csrf_token=csrf_token(rv.data),
                    username='******',
                    password='******',
                    confirm='Safe123#$@lolnot',
                    email_required='*****@*****.**',
                    invitecode='',
                    accept_tos=True,
                    captcha='xyzzy')
        rv = client.post(url_for('auth.register'),
                         data=data,
                         follow_redirects=True)
        assert len(outbox) == 0
        assert b'do not accept emails' in rv.data
        assert b'Register' in rv.data
        assert b'Log out' not in rv.data
Beispiel #4
0
def test_admin_can_ban_email_domain(client, user_info, test_config):
    register_user(client, user_info)
    promote_user_to_admin(client, user_info)

    rv = client.get(url_for("admin.domains", domain_type="email"))
    rv = client.post(
        url_for("do.ban_domain", domain_type="email"),
        data=dict(csrf_token=csrf_token(rv.data), domain="spam4u.com"),
        follow_redirects=True,
    )
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    log_out_current_user(client)
    rv = client.get(url_for("auth.register"))
    with mail.record_messages() as outbox:
        data = dict(
            csrf_token=csrf_token(rv.data),
            username="******",
            password="******",
            confirm="Safe123#$@lolnot",
            email_required="*****@*****.**",
            invitecode="",
            accept_tos=True,
            captcha="xyzzy",
        )
        rv = client.post(url_for("auth.register"), data=data, follow_redirects=True)
        assert len(outbox) == 0
        assert b"do not accept emails" in rv.data
        assert b"Register" in rv.data
        assert b"Log out" not in rv.data
Beispiel #5
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))
    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)

    rv = client.get(url_for("user.view", user=username))
    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)
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
Beispiel #7
0
def test_invite_code_required_for_registration(client, user_info, user2_info):
    """If invite codes are required, trying to register without one will fail."""
    register_user(client, user_info)
    promote_user_to_admin(client, user_info)

    # Enable invite codes.
    rv = client.get(url_for("admin.invitecodes"))
    data = dict(csrf_token=csrf_token(rv.data),
                enableinvitecode=True,
                minlevel=3,
                maxcodes=10)

    rv = client.post(url_for("do.use_invite_code"),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode("utf-8"))
    assert reply["status"] == "ok"

    # Create an invite code.
    rv = client.get(url_for("admin.invitecodes"))
    data = dict(csrf_token=csrf_token(rv.data),
                code="abcde",
                uses=10,
                expires="")
    client.post(url_for("admin.invitecodes"), data=data, follow_redirects=True)

    log_out_current_user(client)

    # Now try to register a new user without an invite code.
    rv = client.get(url_for("auth.register"))
    data = dict(
        csrf_token=csrf_token(rv.data),
        username=user2_info["username"],
        password=user2_info["password"],
        confirm=user2_info["password"],
        invitecode="",
        email_optional=user2_info["email"],
        accept_tos=True,
        captcha="xyzzy",
    )

    rv = client.post(url_for("auth.register"),
                     data=data,
                     follow_redirects=True)
    assert b"Invalid invite code" in rv.data

    # Now try to register a new user with an incorrect invite code.
    rv = client.get(url_for("auth.register"))
    data = dict(
        csrf_token=csrf_token(rv.data),
        username=user2_info["username"],
        password=user2_info["password"],
        confirm=user2_info["password"],
        invitecode="xyzzy",
        email_optional=user2_info["email"],
        accept_tos=True,
        captcha="xyzzy",
    )

    rv = client.post(url_for("auth.register"),
                     data=data,
                     follow_redirects=True)
    assert b"Invalid invite code" in rv.data

    # Now try to register a new user with a valid invite code.
    rv = client.get(url_for("auth.register"))
    data = dict(
        csrf_token=csrf_token(rv.data),
        username=user2_info["username"],
        password=user2_info["password"],
        confirm=user2_info["password"],
        invitecode="abcde",
        email_optional=user2_info["email"],
        accept_tos=True,
        captcha="xyzzy",
    )

    rv = client.post(url_for("auth.register"),
                     data=data,
                     follow_redirects=True)
    assert b"Log out" in rv.data
Beispiel #8
0
def test_invite_code_required_for_registration(client, user_info, user2_info):
    "If invite codes are required, trying to register without one will fail."
    register_user(client, user_info)
    promote_user_to_admin(client, user_info)

    # Enable invite codes.
    rv = client.get(url_for('admin.invitecodes'))
    data = dict(csrf_token=csrf_token(rv.data),
                enableinvitecode=True,
                minlevel=3,
                maxcodes=10)

    rv = client.post(url_for('do.use_invite_code'),
                     data=data,
                     follow_redirects=True)
    reply = json.loads(rv.data.decode('utf-8'))
    assert reply['status'] == 'ok'

    # Create an invite code.
    rv = client.get(url_for('admin.invitecodes'))
    data = dict(csrf_token=csrf_token(rv.data),
                code="abcde",
                uses=10,
                expires='')
    rv = client.post(url_for('admin.invitecodes'),
                     data=data,
                     follow_redirects=True)

    log_out_current_user(client)

    # Now try to register a new user without an invite code.
    rv = client.get(url_for('auth.register'))
    data = dict(csrf_token=csrf_token(rv.data),
                username=user2_info['username'],
                password=user2_info['password'],
                confirm=user2_info['password'],
                invitecode='',
                email_optional=user2_info['email'],
                accept_tos=True,
                captcha='xyzzy')

    rv = client.post(url_for('auth.register'),
                     data=data,
                     follow_redirects=True)
    assert b'Invalid invite code' in rv.data

    # Now try to register a new user with an incorrect invite code.
    rv = client.get(url_for('auth.register'))
    data = dict(csrf_token=csrf_token(rv.data),
                username=user2_info['username'],
                password=user2_info['password'],
                confirm=user2_info['password'],
                invitecode='xyzzy',
                email_optional=user2_info['email'],
                accept_tos=True,
                captcha='xyzzy')

    rv = client.post(url_for('auth.register'),
                     data=data,
                     follow_redirects=True)
    assert b'Invalid invite code' in rv.data

    # Now try to register a new user with a valid invite code.
    rv = client.get(url_for('auth.register'))
    data = dict(csrf_token=csrf_token(rv.data),
                username=user2_info['username'],
                password=user2_info['password'],
                confirm=user2_info['password'],
                invitecode='abcde',
                email_optional=user2_info['email'],
                accept_tos=True,
                captcha='xyzzy')

    rv = client.post(url_for('auth.register'),
                     data=data,
                     follow_redirects=True)
    assert b'Log out' in rv.data
Beispiel #9
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"
Beispiel #10
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"]
Beispiel #11
0
def test_totp_required(client, user_info, test_config):
    register_user(client, user_info)
    promote_user_to_admin(client, user_info)
    rv = client.get(url_for("admin.index"))
    assert rv.status_code == 302
    assert rv.location == url_for("admin.auth")