[35588f42] Keine Zusammenfassung angegeben.

Keine Zusammenfassung angegeben.
This commit is contained in:
2026-05-15 21:10:18 +00:00
parent 1084b960cf
commit 07e34808be
10 changed files with 1 additions and 337 deletions

View File

@@ -1 +1 @@
{"task_id": "35588f42-8544-800a-9eb7-e62ce4ce30e4", "token": "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", "readme_path": "readme.md", "session_start_time": "2026-05-15T21:06:40.526244"}
{"task_id": "35588f42-8544-800a-9eb7-e62ce4ce30e4", "token": "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", "readme_path": "readme.md", "session_start_time": "2026-05-15T21:10:17.162200"}

View File

@@ -1,18 +0,0 @@
import sys
with open('fotograf-de-scraper/frontend/src/App.tsx', 'r') as f:
content = f.read()
# Robust cleaning logic
new_cleaning = ".replace(/\\(JOB\\d+\\)/gi, '').replace(/Kindergarten/gi, '').replace(/\\d{4}/g, '').replace(/\\s+/g, ' ').trim()"
# Old cleaning pattern (multi-line)
old_pattern = """selectedJob.name.replace(/\\(JOB\\d+\\)\\s*/, '').replace(/Kindergarten\\s+/gi, '').replace(/\\s+\\d{4}$/, '').trim()"""
if old_pattern in content:
content = content.replace(old_pattern, new_cleaning)
with open('fotograf-de-scraper/frontend/src/App.tsx', 'w') as f:
f.write(content)
print("Cleaning logic updated")
else:
print("Old cleaning pattern not found")

View File

@@ -1,19 +0,0 @@
import sys
with open('fotograf-de-scraper/frontend/src/App.tsx', 'r') as f:
content = f.read()
new_cleaning = ".replace(/\\(JOB\\d+\\)/gi, '').replace(/Kindergarten/gi, '').replace(/\\d{4}/g, '').replace(/\\s+/g, ' ').trim()"
old_pattern = """.replace(/\\(JOB\\d+\\)\\s*/, '')
.replace(/Kindergarten\\s+/gi, '') // Remove "Kindergarten" prefix
.replace(/\\s+\\d{4}$/, '') // Remove year at the end
.trim()"""
if old_pattern in content:
content = content.replace(old_pattern, new_cleaning)
with open('fotograf-de-scraper/frontend/src/App.tsx', 'w') as f:
f.write(content)
print("Cleaning logic updated for release feature")
else:
print("Old cleaning pattern not found")

View File

@@ -1,39 +0,0 @@
import sys
with open('fotograf-de-scraper/backend/main.py', 'r') as f:
content = f.read()
old_code = """ # 1. Get emails that have ALREADY purchased anything (in ANY job we have in DB)
purchased_emails = set()
if exclude_purchased_emails:
from sqlalchemy import or_
# We look globally across the whole job_participants table
purchased_results = db.query(JobParticipant.email_eltern).filter(
or_(JobParticipant.has_orders == 1, JobParticipant.digital_package_ordered == 1),
JobParticipant.email_eltern != "",
JobParticipant.email_eltern != None
).all()
purchased_emails = {r[0].lower() for r in purchased_results}
logger.info(f"Task {task_id}: Found {len(purchased_emails)} unique emails with existing purchases in DB to exclude.")"""
new_code = """ # 1. Get emails that have ALREADY purchased anything (in THIS specific job)
purchased_emails = set()
if exclude_purchased_emails:
from sqlalchemy import or_
# We look ONLY within the CURRENT job to find siblings that were already purchased
purchased_results = db.query(JobParticipant.email_eltern).filter(
JobParticipant.job_id == job_id,
or_(JobParticipant.has_orders == 1, JobParticipant.digital_package_ordered == 1),
JobParticipant.email_eltern != "",
JobParticipant.email_eltern != None
).all()
purchased_emails = {r[0].lower() for r in purchased_results}
logger.info(f"Task {task_id}: Found {len(purchased_emails)} unique emails with existing purchases in THIS job to exclude.")"""
if old_code in content:
content = content.replace(old_code, new_code)
with open('fotograf-de-scraper/backend/main.py', 'w') as f:
f.write(content)
print("Filter logic patched successfully")
else:
print("Old code not found")

View File

@@ -1,15 +0,0 @@
import sys
with open('fotograf-de-scraper/frontend/src/App.tsx', 'r') as f:
content = f.read()
old_body = """ const [emailBody, setEmailBody] = useState("Hallo {Name Käufer},<br><br>deine Fotos sind fertig und warten auf dich! Kopiere einfach deinen Zugangscode und klicke auf den Link zum Shop, um dich einzuloggen:<br><br>{LinksHTML}<br><br>Viel Spaß beim Anschauen!");"""
new_body = """ const [emailBody, setEmailBody] = useState("Hallo {Name Käufer},<br><br>deine Fotos sind fertig und warten auf dich! Klicke einfach auf die Links unten, um direkt zu den Galerien zu gelangen:<br><br>{LinksHTML}<br><br>Viel Spaß beim Anschauen!");"""
if old_body in content:
content = content.replace(old_body, new_body)
with open('fotograf-de-scraper/frontend/src/App.tsx', 'w') as f:
f.write(content)
print("Frontend patched")
else:
print("Frontend code not found")

View File

@@ -1,60 +0,0 @@
import sys
with open('fotograf-de-scraper/frontend/src/App.tsx', 'r') as f:
content = f.read()
# Replace the generic subject
old_subject = 'const [emailSubject, setEmailSubject] = useState("Fotos von {Kindernamen}");'
new_subject = 'const [emailSubject, setEmailSubject] = useState("Die Kindergarten-Fotos von {Kindernamen} sind da! 📸");'
# Replace the generic body
old_body = 'const [emailBody, setEmailBody] = useState("Hallo {Name Käufer},<br><br>deine Fotos sind fertig und warten auf dich! Klicke einfach auf die Links unten, um direkt zu den Galerien zu gelangen:<br><br>{LinksHTML}<br><br>Viel Spaß beim Anschauen!");'
new_body = 'const [emailBody, setEmailBody] = useState("Hallo {Name Käufer},<br><br>ich hoffe, es geht euch gut! 😊<br><br>Wir haben die wunderschönen Bilder vom Fotoshooting fertiggestellt. Die Fotos von {Kindernamen} sind wirklich ganz toll geworden und warten nun darauf, von euch entdeckt zu werden!<br><br>Klicke einfach auf den untenstehenden Link, um direkt, sicher und bequem zu eurer persönlichen Galerie zu gelangen:<br><br>{LinksHTML}<br><br>Wenn ihr Fragen habt, meldet euch gerne jederzeit bei mir.<br><br>Viel Freude beim Anschauen und Aussuchen der Erinnerungen!");'
if old_subject in content and old_body in content:
content = content.replace(old_subject, new_subject)
content = content.replace(old_body, new_body)
# We also need to add dynamic Einrichtungsname replacement to the parser
old_parser = """ let subject = emailSubject.replace(/{Kindernamen}/g, row["Kindernamen"]);
let body = emailBody
.replace(/{Name Käufer}/g, row["Name Käufer"])
.replace(/{Kindernamen}/g, row["Kindernamen"])
.replace(/{LinksHTML}/g, row["LinksHTML"])
.replace(/\\n/g, "<br>");"""
new_parser = """ let einrichtung = selectedJob
? selectedJob.name.replace(/\\(JOB\\d+\\)\\s*/, '').replace(/Kindergarten\\s+/gi, '').replace(/\\s+\\d{4}$/, '').trim()
: "eurer Einrichtung";
let subject = emailSubject
.replace(/{Kindernamen}/g, row["Kindernamen"])
.replace(/{Einrichtung}/g, einrichtung);
let body = emailBody
.replace(/{Name Käufer}/g, row["Name Käufer"])
.replace(/{Kindernamen}/g, row["Kindernamen"])
.replace(/{Einrichtung}/g, einrichtung)
.replace(/{LinksHTML}/g, row["LinksHTML"])
.replace(/\\n/g, "<br>");"""
content = content.replace(old_parser, new_parser)
# Note: We need to replace the parser in the send function too
old_sender = """ let subject = emailSubject.replace(/{Kindernamen}/g, row["Kindernamen"]);
let body = emailBody
.replace(/{Name Käufer}/g, row["Name Käufer"])
.replace(/{Kindernamen}/g, row["Kindernamen"])
.replace(/{LinksHTML}/g, row["LinksHTML"])
.replace(/\\n/g, "<br>");"""
content = content.replace(old_sender, new_parser)
# Add {Einrichtung} to the hint text in the UI
old_hint = 'Platzhalter: {Name Käufer}, {Kindernamen}, {LinksHTML}'
new_hint = 'Platzhalter: {Name Käufer}, {Kindernamen}, {Einrichtung}, {LinksHTML}'
content = content.replace(old_hint, new_hint)
with open('fotograf-de-scraper/frontend/src/App.tsx', 'w') as f:
f.write(content)
print("Frontend email template patched")
else:
print("Frontend code not found")

View File

@@ -1,19 +0,0 @@
import sys
with open('fotograf-de-scraper/frontend/src/App.tsx', 'r') as f:
content = f.read()
# Fix default text to include the new parameter
old_subject = 'const [emailSubject, setEmailSubject] = useState("Die Kindergarten-Fotos von {Kindernamen} sind da! 📸");'
new_subject = 'const [emailSubject, setEmailSubject] = useState("Eure Bilder aus {Einrichtung} sind da! 📸");'
old_body = 'const [emailBody, setEmailBody] = useState("Hallo {Name Käufer},<br><br>ich hoffe, es geht euch gut! 😊<br><br>Wir haben die wunderschönen Bilder vom Fotoshooting fertiggestellt. Die Fotos von {Kindernamen} sind wirklich ganz toll geworden und warten nun darauf, von euch entdeckt zu werden!<br><br>Klicke einfach auf den untenstehenden Link, um direkt, sicher und bequem zu eurer persönlichen Galerie zu gelangen:<br><br>{LinksHTML}<br><br>Wenn ihr Fragen habt, meldet euch gerne jederzeit bei mir.<br><br>Viel Freude beim Anschauen und Aussuchen der Erinnerungen!");'
new_body = 'const [emailBody, setEmailBody] = useState("Hallo {Name Käufer},<br><br>ich hoffe, es geht euch gut! 😊<br><br>Wir haben die wunderschönen Bilder vom Fotoshooting in {Einrichtung} fertiggestellt. Die Fotos von {Kindernamen} sind wirklich ganz toll geworden und warten nun darauf, von euch entdeckt zu werden!<br><br>Klicke einfach auf den untenstehenden Link, um direkt, sicher und bequem zu eurer persönlichen Galerie zu gelangen:<br><br>{LinksHTML}<br><br>Wenn ihr Fragen habt, meldet euch gerne jederzeit bei mir.<br><br>Viel Freude beim Anschauen und Aussuchen der Erinnerungen!");'
content = content.replace(old_subject, new_subject)
content = content.replace(old_body, new_body)
with open('fotograf-de-scraper/frontend/src/App.tsx', 'w') as f:
f.write(content)
print("Frontend email template patched 2")

View File

@@ -1,21 +0,0 @@
import sys
with open('fotograf-de-scraper/frontend/src/App.tsx', 'r') as f:
content = f.read()
#Approved Subject
old_subject = 'const [emailSubject, setEmailSubject] = useState("Eure Bilder aus {Einrichtung} sind da! 📸");'
new_subject = 'const [emailSubject, setEmailSubject] = useState("{Einrichtung}: Bilder von {Kindernamen} sind da! 📸");'
#Approved Body
old_body = 'const [emailBody, setEmailBody] = useState("Hallo {Name Käufer},<br><br>ich hoffe, es geht euch gut! 😊<br><br>Wir haben die wunderschönen Bilder vom Fotoshooting in {Einrichtung} fertiggestellt. Die Fotos von {Kindernamen} sind wirklich ganz toll geworden und warten nun darauf, von euch entdeckt zu werden!<br><br>Klicke einfach auf den untenstehenden Link, um direkt, sicher und bequem zu eurer persönlichen Galerie zu gelangen:<br><br>{LinksHTML}<br><br>Wenn ihr Fragen habt, meldet euch gerne jederzeit bei mir.<br><br>Viel Freude beim Anschauen und Aussuchen der Erinnerungen!");'
new_body = 'const [emailBody, setEmailBody] = useState("Hallo {Name Käufer},<br><br>wir haben die Bilder vom Fototag ({Einrichtung}) fertiggestellt. Die Fotos von {Kindernamen} sind wirklich ganz toll geworden und warten nun darauf, von euch entdeckt zu werden!<br><br>Klicke einfach auf den untenstehenden Link, um direkt, sicher und bequem zu eurer persönlichen Galerie zu gelangen:<br><br>{LinksHTML}<br><br>Wenn ihr Fragen habt, meldet euch gerne jederzeit bei uns.<br><br>Viel Freude beim Anschauen und Aussuchen der Erinnerungen!");'
if old_subject in content and old_body in content:
content = content.replace(old_subject, new_subject)
content = content.replace(old_body, new_body)
with open('fotograf-de-scraper/frontend/src/App.tsx', 'w') as f:
f.write(content)
print("Frontend email template finalized")
else:
print("Old template strings not found")

View File

@@ -1,15 +0,0 @@
import sys
with open('fotograf-de-scraper/README.md', 'r') as f:
content = f.read()
old_text = "* **Quick-Login Automation:** Die Login-Links (`https://www.kinderfotos-erding.de/a/{code}`) werden automatisch generiert."
new_text = "* **Quick-Login Automation:** Komfortabler \"One-Click\" Login-Link. Das System nutzt bevorzugt den via 'Link Magic' gesammelten Direkt-Link (`/gc/xyz`) oder fällt sicher auf die generische Anmeldung (`/login/ZUGANGSCODE`) inkl. automatischer Code-Übergabe zurück."
if old_text in content:
content = content.replace(old_text, new_text)
with open('fotograf-de-scraper/README.md', 'w') as f:
f.write(content)
print("README patched")
else:
print("Old text not found in README")

View File

@@ -1,130 +0,0 @@
import sys
with open('fotograf-de-scraper/backend/main.py', 'r') as f:
content = f.read()
old_code = """ # 3. Aggregate results by Email
aggregation = {}
missing_links_count = 0
for c in candidates:
email = c.email_eltern.lower()
# Skip if this email already has a purchase for ANOTHER child
if exclude_purchased_emails and email in purchased_emails:
continue
# STRICT LINK CHECK: If we don't have a scraped Quick Login URL, skip this child.
# We don't want to send broken /login/access/ links.
if not c.quick_login_url:
missing_links_count += 1
continue
if email not in aggregation:
aggregation[email] = {
"email": email,
"parent_name": c.vorname_eltern if c.vorname_eltern else "Liebe Eltern",
"children": [],
"links": []
}
# Add child name
child_name = c.vorname_kind or ""
child_label = "Familienbilder" if child_name.lower() == "familie" else child_name
if child_label and child_label not in aggregation[email]["children"]:
aggregation[email]["children"].append(child_label)
# Add Quick Login Link (Guaranteed to exist here)
html_link = f'<a href="{c.quick_login_url}">Fotos von {child_label}</a>'
if html_link not in aggregation[email]["links"]:
aggregation[email]["links"].append(html_link)
# 4. Format for Supermailer/Gmail
final_result = []
for email, data in aggregation.items():
children_str = " und ".join(data["children"]) if len(data["children"]) > 1 else (data["children"][0] if data["children"] else "Eurem Kind")
links_html = "".join([f"{l}<br>" for l in data["links"]])
final_result.append({
"E-Mail-Adresse Käufer": email,
"Name Käufer": data["parent_name"],
"Kindernamen": children_str,
"Anzahl Kinder": len(data["children"]),
"LinksHTML": links_html
})
progress_msg = f"Analyse fertig! {len(final_result)} Empfänger identifiziert."
if missing_links_count > 0:
progress_msg += f" (Hinweis: {missing_links_count} Kinder ignoriert, da Quick-Login-Link fehlt. Bitte vorher 'Daten abgleichen' drücken!)"
task_store[task_id] = {"""
new_code = """ # 3. Aggregate results by Email
aggregation = {}
missing_links_count = 0
base_url = "https://kinderfoto-erding.fotograf.de" if account_type == "kiga" else "https://kinderfotos-erding.fotograf.de"
for c in candidates:
email = c.email_eltern.lower()
# Skip if this email already has a purchase for ANOTHER child
if exclude_purchased_emails and email in purchased_emails:
continue
if email not in aggregation:
aggregation[email] = {
"email": email,
"parent_name": c.vorname_eltern if c.vorname_eltern else "Liebe Eltern",
"children": [],
"links": []
}
# Add child name
child_name = c.vorname_kind or ""
child_label = "Familienbilder" if child_name.lower() == "familie" else child_name
if child_label and child_label not in aggregation[email]["children"]:
aggregation[email]["children"].append(child_label)
# Determine best link
if c.quick_login_url and "/gc/" in c.quick_login_url:
# Use scraped direct link if available
final_link = c.quick_login_url
link_text = f"Fotos von {child_label}"
else:
# Fallback to direct code navigation link
final_link = f"{base_url}/login/{c.zugangscode}"
link_text = f"Fotos von {child_label}"
missing_links_count += 1
html_link = f'<a href="{final_link}">{link_text}</a>'
if html_link not in aggregation[email]["links"]:
aggregation[email]["links"].append(html_link)
# 4. Format for Supermailer/Gmail
final_result = []
for email, data in aggregation.items():
children_str = " und ".join(data["children"]) if len(data["children"]) > 1 else (data["children"][0] if data["children"] else "Eurem Kind")
links_html = "".join([f"{l}<br>" for l in data["links"]])
final_result.append({
"E-Mail-Adresse Käufer": email,
"Name Käufer": data["parent_name"],
"Kindernamen": children_str,
"Anzahl Kinder": len(data["children"]),
"LinksHTML": links_html
})
progress_msg = f"Analyse fertig! {len(final_result)} Empfänger identifiziert."
if missing_links_count > 0:
progress_msg += f" (Hinweis: {missing_links_count} Links wurden generiert, da sie noch nicht gescraped wurden.)"
task_store[task_id] = {"""
if old_code in content:
content = content.replace(old_code, new_code)
with open('fotograf-de-scraper/backend/main.py', 'w') as f:
f.write(content)
print("Patched successfully")
else:
print("Old code not found")