diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml deleted file mode 100644 index 99349cf..0000000 --- a/.github/workflows/tag-release.yaml +++ /dev/null @@ -1,29 +0,0 @@ -on: - push: - # Sequence of patterns matched against refs/tags - tags: - - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 - -name: Auto-release d'un tag - -jobs: - build: - name: auto-release - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@master - - name: Get tag message - run: echo "TAG_MESSAGE=`git show ${{ github.ref_name }} | grep '^\- '`" >> "$GITHUB_ENV" - - name: Create Release - id: create_release - uses: actions/create-release@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token - TAG_MESSAGE: ${{ env.TAG_MESSAGE }} - with: - tag_name: ${{ github.ref }} - release_name: ${{ github.ref_name }} - body: ${{ env.TAG_MESSAGE }} - draft: false - prerelease: false diff --git a/README.md b/README.md index 9f7e1de..90bd5ac 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,13 @@ Ne pas oublier de mettre à jour les fichier .env. ## Notes de version +##### 2.2.1 (15 novembre 2025) + +- Le moteur de recherche ignore les tirets ("franche comté" trouve "Bourgogne-Franche-Comté) +- Phrase "tagline" au-dessus du champ de recherche +- Les infos de Contact rebasculent dans À propos +- Police de caractère "Open Sans" généralisée + #### 2.2.0 (13 novembre 2025) - Moteur de recherche (acheteurs et titulaires) en page d'accueil ([#58](https://github.com/ColinMaudry/decp.info/issues/58)) diff --git a/src/app.py b/src/app.py index f875669..06c4e31 100644 --- a/src/app.py +++ b/src/app.py @@ -92,9 +92,7 @@ app.layout = html.Div( ), html.Div( id="announcements", - children=dcc.Markdown( - "ℹ️ Le formulaire de contact, défectueux, a été remplacé par [une adresse email](/contact)." - ), + children=dcc.Markdown(""), ), html.Div( [ diff --git a/src/assets/style.css b/src/assets/style.css index dd7cd60..c009a16 100644 --- a/src/assets/style.css +++ b/src/assets/style.css @@ -65,7 +65,7 @@ td[data-dash-column="objet"],td[data-dash-column="titulaire_nom"],td[data-dash-c th.dash-header { background-color: #b33821; color: white; - font-family: sans-serif; + font-family: "Open Sans", sans-serif; text-align: left; } @@ -99,7 +99,7 @@ td[data-dash-column="objet"],td[data-dash-column="titulaire_nom"],td[data-dash-c overflow: hidden; height: 150px; text-wrap: wrap; - font-family: sans-serif; + font-family: "Open Sans", sans-serif; } /* Menu de masquage des colonnes */ @@ -131,11 +131,11 @@ td[data-dash-column="objet"],td[data-dash-column="titulaire_nom"],td[data-dash-c /* Alternance des couleurs pour les lignes */ .marches_table { - font-family: sans-serif; + font-family: "Open Sans", sans-serif; } .marches_table .cell-table tr:nth-child(even) td { background-color: #feeeee; - font-family: sans-serif; + font-family: "Open Sans", sans-serif; } #header > *, @@ -152,10 +152,17 @@ td[data-dash-column="objet"],td[data-dash-column="titulaire_nom"],td[data-dash-c /* Page de recherche */ +.tagline { + text-align: center; + font-size: 120%; + display: block; + margin-top: 50px; +} + #search { - margin: 50px auto 0px auto; - width: 450px; - font-size: 18px; + margin: 30px auto 0px auto; + width: 500px; + font-size: 16px; height: 30px; display: block; } diff --git a/src/pages/a-propos.py b/src/pages/a-propos.py index 3704d40..ade2993 100644 --- a/src/pages/a-propos.py +++ b/src/pages/a-propos.py @@ -36,13 +36,23 @@ les fonctionnalités actuelles de decp.info. Il est ainsi possible de rajouter - des alertes par email si des marchés correspondant à certains critères - le développement d'une API pour alimenter d'autres logiciels - ...et toutes les fonctionnalités auxquelles vous pourrez penser + """ ), + html.H4("Contact", id="contact"), + dcc.Markdown(""" + +- Email : [colin+decp@maudry.com](mailto:colin+decp@maudry.com) +- Bluesky : [@col1m.bsky.social](https://bsky.app/profile/col1m.bsky.social) +- Mastodon : [col1m@mamot.fr](https://mamot.fr/@col1m) +- LinkedIn : [colinmaudry](https://www.linkedin.com/in/colinmaudry/) + + """), html.H4("Pour contribuer", id="contribuer"), dcc.Markdown(""" - via l'achat d'une prestation de service (devis, prestation, facture), vous pouvez financer le développement de [fonctionnalités prévues](https://github.com/ColinMaudry/decp.info/issues), ou d'autres ! - ma société accepte aussi les dons (pas de réduction d'impôt possible) -- [écrivez-moi](/contact) et on discute ! +- écrivez-moi et on discute ! #### Pour explorer le projet diff --git a/src/pages/contact.py b/src/pages/contact.py deleted file mode 100644 index b098a22..0000000 --- a/src/pages/contact.py +++ /dev/null @@ -1,167 +0,0 @@ -import re -import time - -from dash import dcc, html, register_page -from flask import request - -from src.utils import meta_content - -name = "Contact" -register_page( - __name__, - path="/contact", - title=meta_content["title"], - name=name, - description=meta_content["description"], - image_url=meta_content["image_url"], - order=6, -) - -layout = html.Div( - className="container", - children=[ - html.H2("Contact", id="contact"), - # html.P( - # "Votre message arrivera directement dans ma boîte mail, et je reviendrai vers vous rapidement." - # ), - # html.Div( - # [ - # html.Label("Votre nom"), - # dcc.Input( - # id="input-name", - # type="text", - # style={"width": "100%", "padding": "8px", "margin": "8px 0"}, - # ), - # html.Label("Votre adresse email"), - # dcc.Input( - # id="input-email", - # type="email", - # style={"width": "100%", "padding": "8px", "margin": "8px 0"}, - # ), - # html.Label("Message"), - # dcc.Textarea( - # id="input-message", - # style={ - # "width": "100%", - # "height": 200, - # "padding": "8px", - # "margin": "8px 0", - # }, - # ), - # html.Button( - # "Envoyer ", - # id="submit-button", - # n_clicks=0, - # style={"marginTop": "10px"}, - # ), - # html.Div( - # id="output-message", style={"marginTop": "10px", "color": "green"} - # ), - # ], - # style={ - # "maxWidth": "600px", - # "margin": "auto", - # "padding": "20px", - # "lineHeight": "20px", - # }, - # ), - dcc.Markdown(""" -- Email : [colin+decp@maudry.com](mailto:colin+decp@maudry.com) -- Bluesky : [@col1m.bsky.social](https://bsky.app/profile/col1m.bsky.social) -- Mastodon : [col1m@mamot.fr](https://mamot.fr/@col1m) -- LinkedIn : [colinmaudry](https://www.linkedin.com/in/colinmaudry/) -- venez discuter de la transparence de la commande publique [sur le forum teamopendata.org](https://teamopendata.org/c/commande-publique/101) -"""), - ], -) - -rate_limit_store = {} # {ip: last_timestamp} -RATE_LIMIT_WINDOW = 300 # 5 minutes - - -def is_rate_limited(): - ip = request.remote_addr - now = time.time() - last_time = rate_limit_store.get(ip) - - if last_time and (now - last_time) < RATE_LIMIT_WINDOW: - return True # rate limited ! - rate_limit_store[ip] = now # màj du timestamp - return False - - -def sanitize_email(email): - return re.match(r"[^@]+@[^@]+\.[^@]+", email) - - -# @callback( -# Output("output-message", "children"), -# Input("submit-button", "n_clicks"), -# State("input-name", "value"), -# State("input-email", "value"), -# State("input-message", "value"), -# prevent_initial_call=True, -# ) -# def send_email(n_clicks, form_name, form_email, form_message): -# if not all([form_name, form_email, form_message]): -# return html.Div( -# "Veuillez s'il vous plaît remplir tous les champs.", style={"color": "red"} -# ) -# -# client_ip = request.remote_addr -# if is_rate_limited(): -# wait_time = int(RATE_LIMIT_WINDOW - (time.time() - rate_limit_store[client_ip])) -# return html.Div( -# f"⏳ J'ai mis en place une protection contre le spam, et vous m'avez écrit il y a moins de 5 minutes. " -# f"Veuillez s'il vous plaît attendre {wait_time} secondes avant de renvoyer un message.", -# style={"color": "black"}, -# ) -# -# try: -# # Configuration du serveur SMTP -# smtp_server = os.getenv("SENDER_SERVER_DOMAIN") -# smtp_port = 587 -# login_email = os.getenv("LOGIN_EMAIL") -# from_email = os.getenv("FROM_EMAIL") -# to_email = os.getenv("TO_EMAIL", from_email) -# login_password = os.getenv("LOGIN_PASSWORD") -# -# print( -# smtp_server, -# smtp_port, -# login_email, -# from_email, -# to_email, -# login_password, -# sep="\n", -# ) -# -# # Création de l'email -# email = MIMEMultipart() -# email["From"] = from_email -# email["To"] = to_email -# email["Subject"] = f"[decp.info] Message de {form_name}" -# -# body = f""" -# Nom : {form_name} -# Email : {form_email} -# -# Message : -# {form_message} -# """ -# email.attach(MIMEText(body, "plain")) -# -# # Send email -# server = smtplib.SMTP(smtp_server, smtp_port) -# server.starttls() -# server.login(login_email, login_password) -# server.sendmail(from_email, to_email, email.as_string()) -# server.quit() -# -# return html.Div("✅ Envoi réussi", style={"color": "green"}) -# -# except Exception as e: -# print(e) -# return html.Div( -# f"❌ Échec de l'envoi du message : {str(e)}", style={"color": "red"} -# ) diff --git a/src/pages/recherche.py b/src/pages/recherche.py index b8b4796..4ce7877 100644 --- a/src/pages/recherche.py +++ b/src/pages/recherche.py @@ -23,10 +23,16 @@ register_page( layout = html.Div( className="container", children=[ + html.Div( + className="tagline", + children=html.P( + "Exploration et téléchargement des données des marchés publics" + ), + ), dcc.Input( id="search", type="text", - placeholder="Nom d'acheteur, d'entreprise, SIREN...", + placeholder="Nom d'acheteur/entreprise, SIREN/SIRET, code département", autoFocus=True, ), # html.Div( diff --git a/src/utils.py b/src/utils.py index eaaf9a5..084938c 100644 --- a/src/utils.py +++ b/src/utils.py @@ -454,7 +454,9 @@ def search_org(dff: pl.DataFrame, query: str, org_type: str) -> pl.DataFrame: ] # Concatenate all fields into one string per row - org_str = pl.concat_str(pl.lit(" "), pl.col(cols), separator=" ") + org_str = pl.concat_str(pl.lit(" "), pl.col(cols), separator=" ").str.replace( + "-", " " + ) # For each token, create a boolean column: True if token is found token_matches = []