Example #1
0
def test_column_filtering_by_checkbox(
    wsgi_server,
    driver,
    lecture_an,
    lecture_an_url,
    article1_an,
    amendements_an,
    user_david_table_an,
    column_index,
    kind,
    initial,
    filtered,
):
    from zam_repondeur.models import Amendement, DBSession

    with transaction.manager:
        DBSession.add(user_david_table_an)
        amendement = Amendement.create(
            lecture=lecture_an,
            article=article1_an,
            num=777,
            position=3,
            auteur="LE GOUVERNEMENT",
        )
        user_david_table_an.add_amendement(amendement)

    driver.get(f"{lecture_an_url}/amendements/")
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == initial
    label = driver.find_element_by_css_selector(
        f"thead tr.filters th:nth-child({column_index}) label[for='{kind}']")
    label.click()
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == filtered
    assert driver.current_url == f"{lecture_an_url}/amendements/?{kind}=1"

    # Restore initial state.
    label.click()
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == initial
    assert driver.current_url == f"{lecture_an_url}/amendements/"

    # Check filters are active on URL (re)load.
    driver.get(f"{lecture_an_url}/amendements/?{kind}=1")
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == filtered
    label = driver.find_element_by_css_selector(
        f"thead tr.filters th:nth-child({column_index}) label[for='{kind}']")
    label.click()
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == initial
    assert driver.current_url == f"{lecture_an_url}/amendements/"
Example #2
0
def test_column_filtering_by_value_with_shared_tables(
    wsgi_server,
    driver,
    lecture_an,
    lecture_an_url,
    article1_an,
    amendements_an,
    user_david_table_an,
    shared_table_lecture_an,
    column_index,
    input_text,
    kind,
    initial,
    filtered,
):
    from zam_repondeur.models import DBSession

    with transaction.manager:
        DBSession.add(user_david_table_an)
        DBSession.add(shared_table_lecture_an)

        user_david_table_an.add_amendement(amendements_an[0])
        shared_table_lecture_an.add_amendement(amendements_an[1])

    driver.get(f"{lecture_an_url}/amendements")
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == initial
    input_field = driver.find_element_by_css_selector(
        f"thead tr.filters th:nth-child({column_index}) input")
    input_field.send_keys(input_text)
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == filtered
    assert (
        driver.current_url ==
        f"{lecture_an_url}/amendements?{kind}={input_text.replace(' ', '+')}")

    # Restore initial state.
    input_field.send_keys(Keys.BACKSPACE * len(input_text))
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == initial
    assert driver.current_url == f"{lecture_an_url}/amendements"

    # Check filters are active on URL (re)load.
    driver.get(f"{lecture_an_url}/amendements?{kind}={input_text}")
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == filtered
    input_field = driver.find_element_by_css_selector(
        f"thead tr.filters th:nth-child({column_index}) input")
    input_field.send_keys(Keys.BACKSPACE * len(input_text))
    trs = driver.find_elements_by_css_selector(f"tbody tr:not(.hidden-{kind})")
    assert extract_column_text(column_index, trs) == initial
    assert driver.current_url == f"{lecture_an_url}/amendements"
Example #3
0
def test_amendement_parent_relationship(amendements_an):
    from zam_repondeur.models import Amendement, DBSession

    a, b = DBSession.query(Amendement).all()

    assert a.parent is None
    assert b.parent is None

    b.parent = a

    # Note: when updating a relationship, the foreign key is only updated on a flush
    DBSession.flush()
    assert b.parent_pk == a.pk
Example #4
0
def amendements_an(db, lecture_an, article1_an):
    from zam_repondeur.models import Amendement, DBSession

    with transaction.manager:
        amendements = [
            Amendement.create(
                lecture=lecture_an, article=article1_an, num=num, position=position
            )
            for position, num in enumerate((666, 999), 1)
        ]

    DBSession.add_all(amendements)
    return amendements
Example #5
0
    def test_not_possible_to_regular_user(self, app, user_sgg, user_david, user_ronan):
        from zam_repondeur.models import DBSession, User

        with transaction.manager:
            user_david.admin_at = datetime.utcnow()
            DBSession.add(user_david)
        assert DBSession.query(User).filter(User.admin_at.isnot(None)).count() == 2

        resp = app.post("/admins/", {"user_pk": user_david.pk}, user=user_ronan)

        assert resp.status_code == 302
        assert resp.location == "https://zam.test/"
        assert DBSession.query(User).filter(User.admin_at.isnot(None)).count() == 2
Example #6
0
def test_reponses_without_textes(app, dummy_lecture, dummy_amendements):
    from zam_repondeur.models import DBSession

    with transaction.manager:
        for amendement in dummy_amendements:
            amendement.avis = "Favorable"
            amendement.observations = f"Observations pour {amendement.num}"
            amendement.reponse = f"Réponse pour {amendement.num}"
        DBSession.add_all(dummy_amendements)

    resp = app.get("http://localhost/lectures/an.15.269.PO717460/reponses")

    assert len(resp.parser.css("#content-article-1")) == 0
Example #7
0
def setup_database(config: Configurator, settings: dict) -> None:

    config.include("pyramid_tm")

    engine = engine_from_config(
        settings,
        "sqlalchemy.",
        connect_args={"application_name": "zam_webapp"})
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine

    if asbool(settings.get("zam.log_sql_queries_with_origin")):
        event.listen(engine, "before_cursor_execute", log_query_with_origin)
Example #8
0
def setup_database(config: Configurator, settings: dict) -> None:

    # Make sure the SQLAlchemy connection pool is large enough for worker threads
    pool_size = max(5, settings["huey.workers"])

    config.include("pyramid_tm")

    engine = engine_from_config(settings, "sqlalchemy.", pool_size=pool_size)
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine

    if asbool(settings.get("zam.log_sql_queries_with_origin")):
        event.listen(engine, "before_cursor_execute", log_query_with_origin)
Example #9
0
    def test_additional_articles_without_avis_are_not_listed(
            self, app, article1_an, article1av_an, amendements_an, user_david):
        from zam_repondeur.models import DBSession

        with transaction.manager:
            amendements_an[0].article = article1av_an
            DBSession.add_all(amendements_an)

        resp = app.get("/lectures/an.15.269.PO717460/articles/",
                       user=user_david)
        assert resp.status_code == 200
        titles = [node.text().strip() for node in resp.parser.css(".article")]
        assert titles == ["Article 1"]
Example #10
0
    def test_upload_success_event(self, app, user_david, lecture_an):
        from zam_repondeur.models import DBSession

        with transaction.manager:
            DBSession.add(user_david)

        self._upload_backup(app, "backup.json", user_david).follow()

        DBSession.add(lecture_an)
        assert len(lecture_an.events) == 1
        assert lecture_an.events[0].render_summary() == (
            "<abbr title='*****@*****.**'>David</abbr> "
            "a importé des réponses d’un fichier JSON.")
Example #11
0
def test_fetch_amendements_with_errored(
    app, source_an, lecture_an, article1_an, amendements_an
):
    from zam_repondeur.models import Amendement, DBSession
    from zam_repondeur.services.fetch.an.amendements import ANDerouleurData
    from zam_repondeur.services.fetch.exceptions import NotFound

    DBSession.add(lecture_an)

    with patch(
        "zam_repondeur.services.fetch.an.amendements.fetch_discussion_list"
    ) as mock_fetch_discussion_list, patch(
        "zam_repondeur.services.fetch.an.amendements._retrieve_amendement_data_from_first_working_url"  # noqa
    ) as mock_retrieve_amendement:
        mock_fetch_discussion_list.return_value = ANDerouleurData(
            lecture_an,
            {
                "amdtsParOrdreDeDiscussion": {
                    "amendements": {
                        "amendement": [
                            {
                                "@numero": "6",
                                "@discussionCommune": "",
                                "@discussionIdentique": "",
                                "@position": "1/3",
                            },
                            {
                                "@numero": "7",
                                "@discussionCommune": "",
                                "@discussionIdentique": "",
                                "@position": "2/3",
                            },
                            {
                                "@numero": "9",
                                "@discussionCommune": "",
                                "@discussionIdentique": "",
                                "@position": "3/3",
                            },
                        ]
                    }
                }
            },
        )
        mock_retrieve_amendement.side_effect = NotFound

        result = source_an.fetch(lecture_an)

    assert result.fetched == set()
    assert result.created == set()
    assert result.errored == {6, 7, 9}
    assert DBSession.query(Amendement).count() == len(amendements_an) == 2
Example #12
0
    def test_sous_amendements(self, app, source, dossier_plfss2018,
                              texte_plfss2018_an_premiere_lecture):
        from zam_repondeur.models import DBSession, Lecture

        with transaction.manager:
            texte_plfss2018_an_premiere_lecture.numero = 911
            lecture = Lecture.create(
                chambre="an",
                session="15",
                texte=texte_plfss2018_an_premiere_lecture,
                titre="Titre lecture",
                organe="PO717460",
                dossier=dossier_plfss2018,
            )

        DBSession.add(lecture)

        with setup_mock_responses(
                lecture=lecture,
                liste=read_sample_data("an/911/liste.xml"),
                amendements=(
                    ("1", read_sample_data("an/911/1.xml")),
                    ("2", read_sample_data("an/911/2.xml")),
                    ("3", read_sample_data("an/911/3.xml")),
                ),
        ):
            amendements, created, errored = source.fetch(lecture=lecture)

        assert len(amendements) == 3

        assert amendements[0].num == 1
        assert amendements[0].position == 1
        assert amendements[0].id_discussion_commune == 3448
        assert amendements[0].id_identique == 8496

        assert amendements[1].num == 2
        assert amendements[1].position == 2
        assert amendements[1].id_discussion_commune is None
        assert amendements[1].id_identique is None

        assert amendements[2].num == 3
        assert amendements[2].position == 3
        assert amendements[2].id_discussion_commune is None
        assert amendements[1].id_identique is None

        for amendement in amendements[1:]:
            assert amendement.parent is amendements[0]
            assert amendement.parent_pk == amendements[0].pk

        assert created == 3
        assert errored == []
Example #13
0
def test_aspire_senat_plf2019_1re_partie(app, texte_senat, dossier_plf):
    from zam_repondeur.fetch.senat.amendements import Senat
    from zam_repondeur.models import DBSession, Lecture

    with transaction.manager:
        texte_senat.numero = 146
        lecture = Lecture.create(
            chambre="senat",
            session="2018-2019",
            texte=texte_senat,
            partie=1,
            titre="Numéro lecture – Titre lecture sénat",
            organe="PO78718",
            dossier=dossier_plf,
        )

    sample_data = read_sample_data("jeu_complet_2018-2019_146.csv")

    responses.add(
        responses.GET,
        "https://www.senat.fr/amendements/2018-2019/146/jeu_complet_2018-2019_146.csv",
        body=sample_data,
        status=200,
    )

    odsen_data = read_sample_data("ODSEN_GENERAL.csv")

    responses.add(
        responses.GET,
        "https://data.senat.fr/data/senateurs/ODSEN_GENERAL.csv",
        body=odsen_data,
        status=200,
    )

    json_data = json.loads(read_sample_data("liste_discussion_103393.json"))

    responses.add(
        responses.GET,
        "https://www.senat.fr/enseance/2018-2019/146/liste_discussion_103393.json",
        json=json_data,
        status=200,
    )

    DBSession.add(lecture)

    source = Senat()

    amendements, created, errored = source.fetch(lecture)

    # All amendements from part 1 are fetched
    assert len(amendements) == 1005
Example #14
0
def test_post_form_seance(app, dummy_lecture, dummy_amendements):
    from zam_repondeur.models import DBSession, Amendement

    with transaction.manager:
        dummy_lecture.num_texte = 575
        dummy_lecture.titre = "Première lecture – Séance publique"

        amendement = dummy_amendements[0]
        amendement.num_texte = 575
        amendement.subdiv_num = "2"

        # The objects are no longer bound to a session here, as they were created in a
        # previous transaction, so we add them to the current session to make sure that
        # our changes will be committed with the current transaction
        DBSession.add(dummy_lecture)
        DBSession.add(amendement)

    responses.add(
        responses.GET,
        "http://www.assemblee-nationale.fr/15/projets/pl0575.asp",
        status=404,
    )
    responses.add(
        responses.GET,
        "http://www.assemblee-nationale.fr/15/projets/pl0575.asp",
        status=404,
    )
    responses.add(
        responses.GET,
        "http://www.assemblee-nationale.fr/15/ta-commission/r0575-a0.asp",
        body=(Path(__file__).parent / "sample_data" /
              "r0575-a0.html").read_text("utf-8", "ignore"),
        status=200,
    )

    form = app.get("/lectures/an.15.575.PO717460/").forms["retrieve-textes"]

    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == "http://localhost/lectures/an.15.575.PO717460/"

    resp = resp.follow()

    assert resp.status_code == 200
    assert "Articles récupérés" in resp.text

    amendement = DBSession.query(Amendement).filter(
        Amendement.num == 666).first()
    assert amendement.subdiv_contenu["001"].startswith(
        "Le code des relations entre")
def test_abandoned_before_seance(lecture_senat):
    """
    An amendement that is either withdrawn by its author or declared invalid
    will be removed from the "liste_discussion"
    """

    from zam_repondeur.fetch.senat.amendements import Senat
    from zam_repondeur.models import DBSession

    responses.add(
        responses.GET,
        "https://www.senat.fr/amendements/2017-2018/63/jeu_complet_2017-2018_63.csv",
        body=read_sample_data("jeu_complet_2017-2018_63-short.csv"),
        status=200,
    )
    responses.add(
        responses.GET,
        "https://data.senat.fr/data/senateurs/ODSEN_GENERAL.csv",
        body=read_sample_data("ODSEN_GENERAL-short.csv"),
        status=200,
    )
    responses.add(
        responses.GET,
        "https://www.senat.fr/enseance/2017-2018/63/liste_discussion.json",
        body=read_sample_data("liste_discussion_63-short.json"),
        status=200,
    )
    responses.add(
        responses.GET,
        "https://www.senat.fr/enseance/2017-2018/63/liste_discussion.json",
        body=read_sample_data("liste_discussion_63-short-retire.json"),
        status=200,
    )

    DBSession.add(lecture_senat)

    source = Senat()

    source.fetch(lecture_senat)

    assert {amdt.num: amdt.position for amdt in lecture_senat.amendements} == {
        31: 1,
        443: 2,
    }

    source.fetch(lecture_senat)

    assert {amdt.num: amdt.position for amdt in lecture_senat.amendements} == {
        31: 1,
        443: None,
    }
def test_post_amendement_edit_form_switch_table(
    app,
    lecture_an,
    amendements_an,
    user_david,
    user_david_table_an,
    user_ronan,
    user_ronan_table_an,
):
    from zam_repondeur.models import Amendement, DBSession

    amendement = amendements_an[1]
    with transaction.manager:
        DBSession.add(user_david_table_an)
        user_david_table_an.amendements.append(amendement)

    resp = app.get(
        "/lectures/an.15.269.PO717460/amendements/999/amendement_edit",
        user=user_david)
    form = resp.forms["edit-amendement"]
    form["avis"] = "Favorable"
    form["objet"] = "Un objet très pertinent"
    form["reponse"] = "Une réponse <strong>très</strong> appropriée"
    form["comments"] = "Avec des <table><tr><td>commentaires</td></tr></table>"

    # Table switch just before submitting the form.
    with transaction.manager:
        DBSession.add(user_ronan_table_an)
        user_ronan_table_an.amendements.append(amendement)

    resp = form.submit("save")

    assert resp.status_code == 302
    assert (
        resp.location ==
        "https://zam.test/lectures/an.15.269.PO717460/tables/[email protected]/"
    )
    resp = resp.maybe_follow()
    assert "Les modifications n’ont PAS été enregistrées" in resp.text
    assert "Il est actuellement sur la table de Ronan" in resp.text

    amendement = DBSession.query(Amendement).filter(
        Amendement.num == 999).one()
    assert amendement.user_content.avis is None
    assert amendement.user_content.objet is None
    assert amendement.user_content.reponse is None
    assert amendement.user_content.comments is None

    # Should NOT create events.
    assert len(amendement.events) == 0
def test_position_changed(lecture_senat):
    """
    The discussion order of amendements may change
    """

    from zam_repondeur.fetch.senat.amendements import Senat
    from zam_repondeur.models import DBSession

    responses.add(
        responses.GET,
        "https://www.senat.fr/amendements/2017-2018/63/jeu_complet_2017-2018_63.csv",
        body=read_sample_data("jeu_complet_2017-2018_63-short.csv"),
        status=200,
    )
    responses.add(
        responses.GET,
        "https://data.senat.fr/data/senateurs/ODSEN_GENERAL.csv",
        body=read_sample_data("ODSEN_GENERAL-short.csv"),
        status=200,
    )
    responses.add(
        responses.GET,
        "https://www.senat.fr/enseance/2017-2018/63/liste_discussion.json",
        body=read_sample_data("liste_discussion_63-short.json"),
        status=200,
    )
    responses.add(
        responses.GET,
        "https://www.senat.fr/enseance/2017-2018/63/liste_discussion.json",
        body=read_sample_data("liste_discussion_63-short-position.json"),
        status=200,
    )

    DBSession.add(lecture_senat)

    source = Senat()

    source.fetch(lecture_senat)

    assert {amdt.num: amdt.position for amdt in lecture_senat.amendements} == {
        31: 1,
        443: 2,
    }

    source.fetch(lecture_senat)

    assert {amdt.num: amdt.position for amdt in lecture_senat.amendements} == {
        31: 2,
        443: 1,
    }
def test_remove_parent_amendement(lecture_senat):
    """
    The targeted article may change
    """

    from zam_repondeur.fetch.senat.amendements import Senat
    from zam_repondeur.models import DBSession

    responses.add(
        responses.GET,
        "https://www.senat.fr/amendements/2017-2018/63/jeu_complet_2017-2018_63.csv",
        body=read_sample_data("jeu_complet_2017-2018_63-short.csv"),
        status=200,
    )
    responses.add(
        responses.GET,
        "https://data.senat.fr/data/senateurs/ODSEN_GENERAL.csv",
        body=read_sample_data("ODSEN_GENERAL-short.csv"),
        status=200,
    )
    responses.add(
        responses.GET,
        "https://www.senat.fr/enseance/2017-2018/63/liste_discussion.json",
        body=read_sample_data("liste_discussion_63-short-parent.json"),
        status=200,
    )
    responses.add(
        responses.GET,
        "https://www.senat.fr/enseance/2017-2018/63/liste_discussion.json",
        body=read_sample_data("liste_discussion_63-short.json"),
        status=200,
    )

    DBSession.add(lecture_senat)

    source = Senat()

    source.fetch(lecture_senat)

    assert {
        amdt.num: amdt.parent.num if amdt.parent else None
        for amdt in lecture_senat.amendements
    } == {31: None, 443: 31}

    source.fetch(lecture_senat)

    assert {
        amdt.num: amdt.parent.num if amdt.parent else None
        for amdt in lecture_senat.amendements
    } == {31: None, 443: None}
def test_team_member_can_access_owned_lecture(
    app, lecture_an, team_zam, user_david, amendements_an
):
    from zam_repondeur.models import DBSession

    with transaction.manager:
        lecture_an.owned_by_team = team_zam
        user_david.teams.append(team_zam)
        DBSession.add(team_zam)

    resp = app.get("/lectures/an.15.269.PO717460/amendements", user=user_david)

    assert resp.status_code == 200
    assert "Dossier de banc" not in resp.text
Example #20
0
def test_post_article_edit_form_title_redirect_next_with_apres(
        app, lecture_an, amendements_an, user_david):
    from zam_repondeur.models import Amendement, Article, DBSession

    with transaction.manager:
        article_1_apres = Article.create(lecture=lecture_an,
                                         type="article",
                                         num="1",
                                         pos="après")
        DBSession.add(article_1_apres)
        article_2 = Article.create(lecture=lecture_an, type="article", num="2")
        DBSession.add(article_2)
        DBSession.add(lecture_an)

    amendement = DBSession.query(Amendement).filter(
        Amendement.num == 999).one()
    assert amendement.article.user_content.title == ""

    resp = app.get(
        "/dossiers/plfss-2018/lectures/an.15.269.PO717460/articles/article.1../",
        user=user_david,
    )
    form = resp.forms["edit-article"]
    form["title"] = "Titre article"
    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == (
        "https://zam.test"
        "/dossiers/plfss-2018/lectures/an.15.269.PO717460/articles/article.2../"
    )

    amendement = DBSession.query(Amendement).filter(
        Amendement.num == 999).one()
    assert amendement.article.user_content.title == "Titre article"
Example #21
0
def export_pdf(context: LectureResource, request: Request) -> Response:
    lecture = context.model(
        noload("amendements"),
        DOSSIER_OPTIONS,
        subqueryload("articles").options(joinedload("user_content")),
    )
    nums, article_param = parse_params(request, lecture=lecture)
    if article_param == "all":
        article_amendements = (
            DBSession.query(Amendement)
            .join(Article)
            .filter(Amendement.lecture == lecture,)
            .options(USER_CONTENT_OPTIONS, LOCATION_OPTIONS)
        )
    else:
        article_type, article_num, article_mult, article_pos = article_param.split(".")
        article_amendements = (
            DBSession.query(Amendement)
            .filter(
                Article.pk == Amendement.article_pk,
                Amendement.lecture == lecture,
                Article.type == article_type,
                Article.num == article_num,
                Article.mult == article_mult,
                Article.pos == article_pos,
            )
            .options(USER_CONTENT_OPTIONS, LOCATION_OPTIONS,)
        )

    amendements = [
        amendement for amendement in article_amendements if amendement.num in nums
    ]
    expanded_amendements = list(Batch.expanded_batches(amendements))

    with NamedTemporaryFile() as file_:
        tmp_file_path = os.path.abspath(file_.name)
        write_pdf_multiple(
            lecture=lecture,
            amendements=amendements,
            article_amendements=AmendementList(article_amendements),
            filename=tmp_file_path,
            request=request,
        )
        return write_response(
            tmp_file_path=tmp_file_path,
            fmt="pdf",
            lecture=lecture,
            article_param=article_param,
            amendements=expanded_amendements,
        )
Example #22
0
def dummy_lecture_commission(app):
    from zam_repondeur.models import DBSession, Lecture

    with transaction.manager:
        lecture = Lecture(
            chambre="an",
            session="15",
            num_texte=269,
            titre="Titre lecture",
            organe="PO420120",
        )
        DBSession.add(lecture)

    return lecture
Example #23
0
def test_visionneuse_articles(wsgi_server, driver, lecture_an_url,
                              article7bis_an, amendements_an):
    from zam_repondeur.models import DBSession

    with transaction.manager:
        amendements_an[0].article = article7bis_an
        DBSession.add_all(amendements_an)

    driver.get(f"{lecture_an_url}/articles/")
    articles = driver.find_elements_by_css_selector("section.article")
    assert len(articles) == 2
    assert articles[0].find_element_by_css_selector("h2").text == "Article 1"
    assert articles[1].find_element_by_css_selector(
        "h2").text == "Article 7 bis"
Example #24
0
def test_export_excel_columns(lecture_an, article1_an, tmpdir):
    from openpyxl import load_workbook

    from zam_repondeur.export.spreadsheet import write_xlsx
    from zam_repondeur.models import DBSession, Amendement

    filename = str(tmpdir.join("test.xlsx"))

    amendement = Amendement.create(
        lecture=lecture_an,
        article=article1_an,
        num=333,
        position=1,
        avis="Favorable",
        objet="Un objet très pertinent",
        reponse="Une réponse très appropriée",
        comments="Avec des commentaires",
    )
    DBSession.add(amendement)
    DBSession.add(lecture_an)

    counter = write_xlsx(lecture_an, filename, request={})

    assert counter["amendements"] == 1

    wb = load_workbook(filename, read_only=True)
    ws = wb.active
    header_row = next(ws.rows)
    headers = [cell.value for cell in header_row]

    assert headers == [
        "Num article",
        "Titre article",
        "Num amdt",
        "Rectif",
        "Parent (sous-amdt)",
        "Auteur",
        "Groupe",
        "Gouvernemental",
        "Corps amdt",
        "Exposé amdt",
        "Identique",
        "Avis du Gouvernement",
        "Objet amdt",
        "Réponse",
        "Commentaires",
        "Affectation (email)",
        "Affectation (nom)",
        "Sort",
    ]
Example #25
0
def test_reponses_menu(app, dummy_lecture, dummy_amendements):
    from zam_repondeur.models import DBSession

    with transaction.manager:
        for amendement in dummy_amendements:
            amendement.avis = "Favorable"
            amendement.observations = f"Observations pour {amendement.num}"
            amendement.reponse = f"Réponse pour {amendement.num}"
        DBSession.add_all(dummy_amendements)

    resp = app.get("http://localhost/lectures/an.15.269.PO717460/reponses")

    assert len(resp.parser.css(".menu a")) == 1
    assert resp.parser.css_first(".menu a").text() == "Art. 1"
Example #26
0
def test_amendement_batches(amendements_an):
    from zam_repondeur.models import Amendement, Batch, DBSession

    a, b = DBSession.query(Amendement).all()

    assert a.location.batch is None
    assert b.location.batch is None

    batch = Batch.create()
    a.location.batch = batch
    b.location.batch = batch

    a, b = DBSession.query(Amendement).all()
    assert a.location.batch == b.location.batch == batch
def test_get_amendements_with_gouvernemental(
    app, lecture_an, amendements_an, user_david
):
    from zam_repondeur.models import DBSession

    with transaction.manager:
        amendement = amendements_an[0]
        amendement.auteur = "LE GOUVERNEMENT"
        DBSession.add(amendement)

    resp = app.get("/lectures/an.15.269.PO717460/amendements", user=user_david)

    assert resp.status_code == 200
    assert "Dossier de banc" in resp.text
Example #28
0
def test_post_amendement_edit_form_and_transfer(app, lecture_an_url,
                                                amendements_an, user_david,
                                                user_david_table_an):
    from zam_repondeur.models import Amendement, DBSession

    amendement = amendements_an[1]
    with transaction.manager:
        DBSession.add(user_david_table_an)
        user_david_table_an.add_amendement(amendement)

    amendement = DBSession.query(Amendement).filter(
        Amendement.num == 999).one()
    assert amendement.user_content.avis is None
    assert amendement.user_content.objet is None
    assert amendement.user_content.reponse is None

    resp = app.get(f"{lecture_an_url}/amendements/999/", user=user_david)
    form = resp.forms["edit-amendement"]
    form["avis"] = "Favorable"
    form["objet"] = "Un objet très pertinent"
    form["reponse"] = "Une réponse <strong>très</strong> appropriée"
    form["comments"] = "Avec des <table><tr><td>commentaires</td></tr></table>"
    resp = form.submit("save-and-transfer")

    assert resp.status_code == 302
    assert resp.location == ("https://zam.test"
                             "/dossiers/plfss-2018"
                             "/lectures/an.15.269.PO717460"
                             "/transfer_amendements"
                             "?n=999&from_save=1&"
                             "back=https%3A%2F%2Fzam.test"
                             "%2Fdossiers%2Fplfss-2018"
                             "%2Flectures%2Fan.15.269.PO717460"
                             "%2Ftables%2Fdavid%40exemple.gouv.fr"
                             "%2F%23amdt-999")

    amendement = DBSession.query(Amendement).filter(
        Amendement.num == 999).one()
    assert amendement.user_content.avis == "Favorable"
    assert amendement.user_content.objet == "Un objet très pertinent"
    assert (amendement.user_content.reponse ==
            "Une réponse <strong>très</strong> appropriée")
    assert (
        amendement.user_content.comments ==
        "Avec des <table><tbody><tr><td>commentaires</td></tr></tbody></table>"
    )

    # Should create events.
    assert len(amendement.events) == 4
Example #29
0
def test_amendement_unicity(amendements_an, article1av_an):
    from zam_repondeur.models import Amendement, DBSession

    existing = amendements_an[0]
    with transaction.manager, pytest.raises(IntegrityError) as error_info:
        Amendement.create(
            lecture=existing.lecture,
            num=existing.num,
            rectif=existing.rectif + 1,
            article=article1av_an,
            parent=None,
            objet="don't worry, this is an expected error",
        )
        DBSession.flush()
    assert "constraint" in error_info.value._message()
def test_non_team_member_cannot_access_owned_lecture(
    app, lecture_an, team_zam, user_david, amendements_an
):
    from zam_repondeur.models import DBSession

    with transaction.manager:
        lecture_an.owned_by_team = team_zam
        DBSession.add(team_zam)

    resp = app.get("/lectures/an.15.269.PO717460/amendements", user=user_david)

    assert resp.status_code == 302
    resp = resp.maybe_follow()

    assert "L’accès à cette lecture est réservé aux personnes autorisées." in resp.text