deploy ProspectOS workspace v2 final

This commit is contained in:
Marco0300
2026-09-06 20:17:29 +02:00
parent 7250f6d521
commit 05984c9ae6
8 changed files with 351 additions and 13 deletions
+42
View File
@@ -159,6 +159,33 @@ class BrowserOnlyAppTests(unittest.TestCase):
saved = server.db().execute("SELECT ai_probability,ai_recommendation,ai_reasoning FROM prospects WHERE id=1").fetchone()
self.assertEqual(tuple(saved), (84.0, "contact", "Active business with a clear website opportunity."))
def test_mockup_fallback_is_saved_and_public_share_link_works(self):
conn = server.db()
conn.execute("INSERT INTO prospects(name,domain,category,address,phone,emails,website,website_status,discovered_at) VALUES(?,?,?,?,?,?,?,?,?)", ("Acme Plumbing", "maps:acme", "plumbers", "Cape Town", "+27101234567", "info@acme.co.za", "", "no_detected_website", server.now()))
conn.commit(); conn.close()
status, created = self.request("POST", "/api/prospects/1/mockup", {"instructions": "Keep it friendly"})
self.assertEqual(status, 201)
self.assertIn("/mockups/", created["share_url"])
self.assertEqual(created["generation_source"], "fallback")
status, listed = self.request("GET", "/api/prospects/1/mockups")
self.assertEqual(status, 200)
self.assertEqual(listed["items"][0]["id"], created["id"])
preview_path = "/mockups/" + created["token"]
self.conn.request("GET", preview_path)
response = self.conn.getresponse()
body = response.read().decode("utf-8")
self.assertEqual(response.status, 200)
self.assertIn("text/html", response.getheader("Content-Type"))
self.assertIn("Acme Plumbing", body)
self.assertNotIn("<script", body.lower())
def test_mockup_sanitizer_removes_active_markup(self):
html = server.sanitize_mockup_html('<html><body onload="bad"><script>alert(1)</script><a href="javascript:bad()">Hi</a></body></html>')
self.assertIn("<html>", html)
self.assertNotIn("script", html.lower())
self.assertNotIn("onload", html.lower())
self.assertNotIn("javascript:", html.lower())
def test_browser_investigator_normalises_and_filters_candidates(self):
raw = '{"candidates":[{"url":"https://www.acme.co.za/about","confidence":88,"evidence":["name match"]},{"url":"https://facebook.com/acme","confidence":99},{"domain":"other.co.za","confidence":"42","evidence":"not a list"}]}'
candidates = browser_investigator._parse_agent_result(raw)
@@ -239,6 +266,21 @@ class BrowserOnlyAppTests(unittest.TestCase):
self.assertEqual(json.loads(saved[0]), body["unknowns"])
self.assertEqual(json.loads(saved[1]), body["evidence_used"])
def test_email_draft_can_include_latest_mockup_link(self):
conn = server.db()
conn.execute("INSERT INTO prospects(name,domain,category,discovered_at) VALUES(?,?,?,?)", ("Acme", "maps:acme", "plumber", server.now()))
conn.execute("INSERT INTO mockups(organization_id,prospect_id,token,title,html,created_at,updated_at) VALUES(?,?,?,?,?,?,?)", (1, 1, "a" * 24, "Acme · Website concept", "<html><body>Acme</body></html>", server.now(), server.now()))
for key, value in (("AI_PROVIDER", "custom"), ("AI_BASE_URL", "https://ai.example/v1"), ("AI_MODEL", "test-model"), ("AI_API_KEY", "test-key")):
conn.execute("INSERT INTO settings(key,value,updated_at) VALUES(?,?,?)", (key, value, server.now()))
conn.commit(); conn.close()
content = json.dumps({"subject": "A concept for Acme", "message": "Good day Acme,\n\nWe can help.", "rationale": "Uses the supplied record.", "recommended_offer": "Website", "unknowns": [], "evidence_used": ["prospect_record"], "follow_up": "Review before sending."})
with patch("api.server.http_json", return_value={"choices": [{"message": {"content": content}}]}):
status, body = self.request("POST", "/api/prospects/1/message", {"offer": "A modern website"})
self.assertEqual(status, 200)
self.assertIn("/mockups/", body["message"])
self.assertIn("mockup_preview", body["evidence_used"])
self.assertTrue(body["mockup_url"])
def test_logs_capture_api_actions_and_redact_credentials(self):
server.record_log("ai", "test_ai_call", details={"api_key": "do-not-store", "model": "test", "prompt": "hello"})
status, body = self.request("POST", "/api/logs", {"action": "ui_test", "details": {"button": "test"}})