diff --git a/src/pages/contact.py b/src/pages/contact.py new file mode 100644 index 0000000..a6f4051 --- /dev/null +++ b/src/pages/contact.py @@ -0,0 +1,170 @@ +import os +import re +import smtplib +import time +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +from dash import Input, Output, State, callback, 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(""" +- 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"} + )