Пример #1
0
def test_inviting_a_speaker_adds_the_speaker(client: Client, user: User,
                                             send_mail: Mock) -> None:
    talk = Talk(title="My Talk", length=25)
    talk.add_speaker(user, InvitationStatus.CONFIRMED)
    db.session.add(talk)

    alice = User(email="*****@*****.**", fullname="Alice Example")
    db.session.add(alice)
    db.session.commit()

    # reload from DB to avoid "not attached to session" error
    talk = Talk.query.filter_by(title="My Talk").one()

    client.get("/test-login/{}".format(user.user_id))
    resp = client.get("/talks/{}/speakers".format(talk.talk_id))
    assert_html_response(resp)
    csrf_token = extract_csrf_from(resp)

    postdata = {"email": "*****@*****.**", "csrf_token": csrf_token}
    resp = client.post("/talks/{}/speakers".format(talk.talk_id),
                       data=postdata,
                       follow_redirects=True)

    assert_html_response_contains(resp, "Alice Example")

    send_mail.assert_called_once_with(to=["*****@*****.**"],
                                      template="email/co-presenter-invite",
                                      talk=ANY)

    _, kwargs = send_mail.call_args
    assert kwargs["talk"].talk_id == talk.talk_id

    assert_talk_has_speakers(talk, ["*****@*****.**"])
Пример #2
0
def email_magic_link_login(magic_link_token: str) -> Response:
    try:
        used_magic_link = UsedMagicLink(token=magic_link_token)
        db.session.add(used_magic_link)
        db.session.commit()
    except IntegrityError:
        # race condition, UsedMagicLink row exists
        db.session.rollback()
        return current_app.response_class(
            render_template("email_magic_link_used.html"), status=401)

    verified_email = parse_magic_link_token(magic_link_token)
    if verified_email is None:
        abort(404)

    user = User.query.filter_by(email=verified_email).first()
    if user:
        login_user(user)
        return redirect(url_for("views.talks_list"))

    user = User(email=verified_email, fullname=verified_email)
    db.session.add(user)
    db.session.commit()
    login_user(user)
    flash("Welcome! Please tell us your name.")
    return redirect(url_for("views.user_profile"))
Пример #3
0
def test_site_admins_can_access_admin(client: Client, user: User) -> None:
    client.get("/test-login/{}".format(user.user_id), follow_redirects=True)

    user.site_admin = True
    db.session.add(user)
    db.session.commit()

    resp = client.get("/manage/")
    assert_html_response(resp, status=200)
Пример #4
0
def test_talks_list_page_lists_talks(client: Client, user: User) -> None:
    alice = User(email="*****@*****.**", fullname="Alice Example")
    bob = User(email="*****@*****.**", fullname="Bob Example")
    db.session.add(alice)
    db.session.add(bob)
    db.session.commit()

    one_talk = Talk(title="My Talk", length=25)
    one_talk.add_speaker(user, InvitationStatus.CONFIRMED)

    two_talk = Talk(title="Our Talk", length=40)
    two_talk.add_speaker(user, InvitationStatus.CONFIRMED)
    two_talk.add_speaker(alice, InvitationStatus.CONFIRMED)

    all_talk = Talk(title="All Our Talk", length=25)
    all_talk.add_speaker(user, InvitationStatus.CONFIRMED)
    all_talk.add_speaker(alice, InvitationStatus.CONFIRMED)
    all_talk.add_speaker(bob, InvitationStatus.CONFIRMED)

    db.session.add(one_talk)
    db.session.add(two_talk)
    db.session.add(all_talk)
    db.session.commit()

    client.get("/test-login/{}".format(user.user_id))
    resp = client.get("/talks")
    body = assert_html_response(resp)
    soup = bs4.BeautifulSoup(body, "html.parser")

    talks = soup.find_all("div", class_="talk")
    assert len(talks) == 3

    talk_row_texts = [re.sub(r"\s+", " ", talk.get_text()).strip() for talk in talks]
    assert sorted(talk_row_texts) == sorted(
        [
            "My Talk (25 Minutes)",
            "Our Talk (40 Minutes, Alice Example and You)",
            "All Our Talk (25 Minutes, Alice Example, Bob Example, and You)",
        ]
    )
Пример #5
0
def test_manage_speakers_page_shows_other_speakers(client: Client,
                                                   user: User) -> None:
    alice = User(email="*****@*****.**", fullname="Alice Example")
    bob = User(email="*****@*****.**", fullname="Bob Example")
    charlie = User(email="*****@*****.**", fullname="Charlie Example")
    db.session.add(alice)
    db.session.add(bob)
    db.session.add(charlie)

    talk = Talk(title="My Talk", length=25)
    talk.add_speaker(user, InvitationStatus.CONFIRMED)
    talk.add_speaker(alice, InvitationStatus.PENDING)
    talk.add_speaker(bob, InvitationStatus.REJECTED)
    talk.add_speaker(charlie, InvitationStatus.DELETED)
    db.session.add(talk)
    db.session.commit()

    # reload from DB to avoid "not attached to session" error
    talk = Talk.query.filter_by(title="My Talk").one()

    client.get("/test-login/{}".format(user.user_id))
    resp = client.get("/talks/{}/speakers".format(talk.talk_id))

    body = assert_html_response(resp)
    soup = bs4.BeautifulSoup(body, "html.parser")

    speakers = soup.find_all("div", class_="speaker")
    assert len(speakers) == 4

    row_texts = [
        re.sub(r"\s+", " ", row.get_text()).strip() for row in speakers
    ]
    assert sorted(row_texts) == sorted([
        "{} ({}) Confirmed".format(user.fullname, user.email),
        "Alice Example ([email protected]) Pending Uninvite",
        "Bob Example ([email protected]) Rejected",
        "Charlie Example ([email protected]) Deleted Reinvite",
    ])
Пример #6
0
def test_talk_anonymization(client: Client, user: User,
                            send_mail: Mock) -> None:
    user.site_admin = True
    db.session.add(user)

    talk = Talk(
        title="Alice's Identifying Talk",
        description="This talk is by Alice",
        outline="Alice!",
        take_aways="Alice's point.",
        length=25,
    )
    talk.add_speaker(user, InvitationStatus.CONFIRMED)
    db.session.add(talk)
    db.session.commit()

    db.session.refresh(talk)

    client.get("/test-login/{}".format(user.user_id), follow_redirects=True)
    resp = client.get(f"/manage/anonymize/{talk.talk_id}")
    assert_html_response_contains(resp, "Alice's Identifying Talk")

    postdata = {
        "title": "(Speaker name redacted)'s Identifying Talk",
        "description": "This talk is by (Speaker name redacted)",
        "outline": "(Speaker name redacted)!",
        "take_aways": "(The speaker's) point.",
        "csrf_token": extract_csrf_from(resp),
    }
    client.post(f"/manage/anonymize/{talk.talk_id}", data=postdata)

    talk = Talk.query.get(talk.talk_id)
    assert talk.is_anonymized is True
    assert talk.has_anonymization_changes is True
    assert talk.anonymized_title == "(Speaker name redacted)'s Identifying Talk"
    assert talk.anonymized_description == "This talk is by (Speaker name redacted)"
    assert talk.anonymized_outline == "(Speaker name redacted)!"
    assert talk.anonymized_take_aways == "(The speaker's) point."
    assert talk.title == "Alice's Identifying Talk"
    assert talk.description == "This talk is by Alice"
    assert talk.outline == "Alice!"
    assert talk.take_aways == "Alice's point."

    send_mail.assert_called_once_with(
        to=[user.email],
        template="email/talk-anonymized",
        talk_id=talk.talk_id,
        title=talk.title,  # the original title
    )
Пример #7
0
def test_accept_button_accepts_the_talk(client: Client, user: User) -> None:
    alice = User(email="*****@*****.**", fullname="Alice Example")
    db.session.add(alice)

    talk = Talk(title="My Talk", length=25)
    talk.add_speaker(alice, InvitationStatus.CONFIRMED)  # original speaker
    talk.add_speaker(user, InvitationStatus.PENDING)
    db.session.add(talk)
    db.session.commit()

    client.get("/test-login/{}".format(user.user_id))
    client.get("/talks/1/speakers/accept")
    resp = client.get("/talks")

    assert_html_response_contains(resp, "My Talk",
                                  "(25 Minutes, Alice Example and You)")
    assert_html_response_doesnt_contain(resp, "Speaker Invitations:", "Reject",
                                        "Accept")
Пример #8
0
def test_talks_list_shows_invitations(client: Client, user: User) -> None:
    alice = User(email="*****@*****.**", fullname="Alice Example")
    db.session.add(alice)

    talk = Talk(title="My Talk", length=25)
    talk.add_speaker(alice, InvitationStatus.CONFIRMED)  # original speaker
    talk.add_speaker(user, InvitationStatus.PENDING)
    db.session.add(talk)
    db.session.commit()

    client.get("/test-login/{}".format(user.user_id))
    resp = client.get("/talks")

    assert_html_response_contains(
        resp,
        "Speaker Invitations:",
        "My Talk",
        "(25 Minutes, Alice Example and You)",
        '<a href="/talks/1/speakers/reject" class="btn btn-outline-danger btn-sm">Reject</a>',  # NOQA: B950
        '<a href="/talks/1/speakers/accept" class="btn btn-outline-primary btn-sm">Accept</a>',  # NOQA: B950
    )
Пример #9
0
def test_talk_anonymization_doesnt_set_is_anonymized_if_no_changes(
        client: Client, user: User, send_mail: Mock) -> None:
    user.site_admin = True
    db.session.add(user)

    talk = Talk(
        title="Alice's Identifying Talk",
        description="This talk is by Alice",
        outline="Alice!",
        take_aways="Alice's point.",
        length=25,
    )
    talk.add_speaker(user, InvitationStatus.CONFIRMED)
    db.session.add(talk)
    db.session.commit()

    db.session.refresh(talk)

    client.get("/test-login/{}".format(user.user_id), follow_redirects=True)
    resp = client.get(f"/manage/anonymize/{talk.talk_id}")
    assert_html_response_contains(resp, "Alice&#x27;s Identifying Talk")

    postdata = {
        "title": talk.title,
        "description": talk.description,
        "outline": talk.outline,
        "take_aways": talk.take_aways,
        "csrf_token": extract_csrf_from(resp),
    }
    client.post(f"/manage/anonymize/{talk.talk_id}", data=postdata)

    talk = Talk.query.get(talk.talk_id)
    assert talk.is_anonymized is True
    assert talk.has_anonymization_changes is False
    assert talk.anonymized_title == talk.title
    assert talk.anonymized_description == talk.anonymized_description
    assert talk.anonymized_outline == talk.outline
    assert talk.anonymized_take_aways == talk.take_aways

    assert not send_mail.called
Пример #10
0
def edit_speakers(talk_id: int) -> Response:
    talk = load_talk(talk_id)
    actions = {
        InvitationStatus.PENDING:
        [("Uninvite", "danger", "views.uninvite_speaker")],
        InvitationStatus.CONFIRMED: [],
        InvitationStatus.REJECTED: [],
        InvitationStatus.DELETED:
        [("Reinvite", "primary", "views.reinvite_speaker")],
    }

    speaker_emails = [s.user.email for s in talk.speakers]
    form = SpeakerEmailForm(speaker_emails)
    if form.validate_on_submit():
        email = form.email.data
        try:
            user = User(fullname=email, email=email)
            db.session.add(user)
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            user = User.query.filter_by(email=email).one()

        try:
            talk.add_speaker(user, InvitationStatus.PENDING)
            db.session.commit()
        except IntegrityError:
            db.session.rollback()

        mail.send_mail(to=[email],
                       template="email/co-presenter-invite",
                       talk=talk)

        return redirect(url_for("views.edit_speakers", talk_id=talk.talk_id))

    return render_template("edit_speakers.html",
                           talk=talk,
                           actions=actions,
                           form=form)
Пример #11
0
def test_profile_lets_you_delete_speaker_bio(client: Client, user: User) -> None:
    user.speaker_bio = "This is the speaker bio"
    db.session.add(user)
    db.session.commit()

    client.get("/test-login/{}".format(user.user_id), follow_redirects=True)
    resp = client.get("/profile")
    assert_html_response_contains(resp, "This is the speaker bio")

    csrf_token = extract_csrf_from(resp)
    postdata = {
        "email": "*****@*****.**",
        "fullname": "Jane Doe",
        "speaker_bio": "",
        "csrf_token": csrf_token,
    }
    resp = client.post("/profile", data=postdata, follow_redirects=True)
    assert_html_response_contains(resp, "Talks")

    db.session.add(user)
    db.session.refresh(user)
    assert user.fullname == "Jane Doe"
    assert user.speaker_bio == ""
    assert user.email == "*****@*****.**"  # the old address
Пример #12
0
def user(app: Application) -> User:
    user = User(fullname="Test User", email="*****@*****.**")
    db.session.add(user)
    db.session.commit()

    return user