# distribute_product_data.py import requests import json import re import os import time # --- Configuration --- try: with open("notion_token.txt", "r") as f: NOTION_TOKEN = f.read().strip() except FileNotFoundError: print("Error: notion_token.txt not found.") exit(1) NOTION_VERSION = "2022-06-28" NOTION_API_BASE_URL = "https://api.notion.com/v1" HEADERS = { "Authorization": f"Bearer {NOTION_TOKEN}", "Notion-Version": NOTION_VERSION, "Content-Type": "application/json", } # --- Database IDs (from Notion_Dashboard.md) --- DB_IDS = { "Product Master": "2e288f42-8544-81d8-96f5-c231f84f719a", "Sector & Persona Master": "2e288f42-8544-8113-b878-ec99c8a02a6b", "Messaging Matrix": "2e288f42-8544-81b0-83d4-c16623cc32d1", "Feature-to-Value Translator": "2e288f42-8544-8184-ba08-d6d736879f19", } # --- Helper Functions --- def create_notion_page(database_id, properties): """Creates a new page in a Notion database.""" url = f"{NOTION_API_BASE_URL}/pages" payload = {"parent": {"database_id": database_id}, "properties": properties} try: response = requests.post(url, headers=HEADERS, json=payload) response.raise_for_status() print(f"Successfully created page in DB {database_id}.") return response.json() except requests.exceptions.HTTPError as e: print(f"HTTP Error creating page in DB {database_id}: {e}\nResponse: {response.text}") return None def update_notion_page(page_id, properties): """Updates an existing page in Notion.""" url = f"{NOTION_API_BASE_URL}/pages/{page_id}" payload = {"properties": properties} try: response = requests.patch(url, headers=HEADERS, json=payload) response.raise_for_status() print(f"Successfully updated page {page_id}.") return response.json() except requests.exceptions.HTTPError as e: print(f"HTTP Error updating page {page_id}: {e}\nResponse: {response.text}") return None def find_notion_page_by_title(database_id, title): """Searches for a page in a Notion database by its title property.""" url = f"{NOTION_API_BASE_URL}/databases/{database_id}/query" filter_payload = {"filter": {"property": "Name", "title": {"equals": title}}} try: response = requests.post(url, headers=HEADERS, json=filter_payload) response.raise_for_status() results = response.json().get("results") return results[0] if results else None except requests.exceptions.HTTPError as e: print(f"HTTP Error searching page in DB {database_id}: {e}\nResponse: {response.text}") return None def get_page_property(page_id, property_id): """Retrieves a specific property from a Notion page.""" url = f"{NOTION_API_BASE_URL}/pages/{page_id}/properties/{property_id}" try: response = requests.get(url, headers=HEADERS) response.raise_for_status() return response.json() except requests.exceptions.HTTPError as e: print(f"HTTP Error retrieving property {property_id}: {e}\nResponse: {response.text}") return None def get_rich_text_content(property_object): """Extracts plain text from a Notion rich_text property object.""" if not property_object: return "" try: # The property endpoint returns a list in the 'results' key if 'results' in property_object and property_object['results']: # The actual content is in the 'rich_text' object within the first result rich_text_items = property_object['results'][0].get('rich_text', {}) # It can be a single dict or a list, we handle the main plain_text for simplicity here if isinstance(rich_text_items, dict) and 'plain_text' in rich_text_items: return rich_text_items.get('plain_text', '') # If it is a list of rich text objects (less common for a single property) elif isinstance(rich_text_items, list): return "".join(item.get("plain_text", "") for item in rich_text_items if isinstance(item, dict)) except (KeyError, IndexError, TypeError) as e: print(f"Error parsing rich text object: {e}") return "" return "" def format_rich_text(text): """Formats a string into Notion's rich text structure.""" if len(text) > 2000: print(f"Warning: Truncating text from {len(text)} to 2000 characters.") text = text[:2000] return {"rich_text": [{"type": "text", "text": {"content": text}}]} def format_title(text): """Formats a string into Notion's title structure.""" return {"title": [{"type": "text", "text": {"content": text}}]} def format_relation(page_ids): """Formats a list of page IDs into Notion's relation structure.""" if not isinstance(page_ids, list): page_ids = [page_ids] return {"relation": [{"id": page_id} for page_id in page_ids]} def parse_markdown_table(markdown_text): """Parses a generic markdown table into a list of dicts.""" lines = markdown_text.strip().split('\n') if len(lines) < 2: return [] headers = [h.strip() for h in lines[0].split('|') if h.strip()] data_rows = [] for line in lines[2:]: # Skip header and separator values = [v.strip() for v in line.split('|') if v.strip()] if len(values) == len(headers): data_rows.append(dict(zip(headers, values))) return data_rows # --- Main Logic --- def main(): PRODUCT_NAME = "Puma M20" print(f"--- Starting data distribution for product: {PRODUCT_NAME} ---") # 1. Get the product page from Product Master product_page = find_notion_page_by_title(DB_IDS["Product Master"], PRODUCT_NAME) if not product_page: print(f"Product '{PRODUCT_NAME}' not found. Aborting.") return product_page_id = product_page["id"] print(f"Found Product Page ID: {product_page_id}") # 2. Distribute Strategy Matrix Data strategy_matrix_prop_id = product_page["properties"]["Strategy Matrix"]["id"] strategy_matrix_obj = get_page_property(product_page_id, strategy_matrix_prop_id) strategy_matrix_text = get_rich_text_content(strategy_matrix_obj) if strategy_matrix_text: parsed_matrix = parse_markdown_table(strategy_matrix_text) if parsed_matrix: print("\n--- Distributing Strategy Matrix Data ---") sector_page_ids_for_product = [] for row in parsed_matrix: segment_name = row.get("Segment") pain_point = row.get("Pain Point") angle = row.get("Angle") differentiation = row.get("Differentiation") if not all([segment_name, pain_point, angle, differentiation]): print(f"Skipping row due to missing data: {row}") continue print(f"\nProcessing Segment: {segment_name}") # Find or Create Sector in Sector & Persona Master sector_page = find_notion_page_by_title(DB_IDS["Sector & Persona Master"], segment_name) if sector_page: sector_page_id = sector_page["id"] print(f"Found existing Sector page with ID: {sector_page_id}") update_notion_page(sector_page_id, {"Pains": format_rich_text(pain_point)}) else: print(f"Creating new Sector page for '{segment_name}'...") new_sector_page = create_notion_page(DB_IDS["Sector & Persona Master"], {"Name": format_title(segment_name), "Pains": format_rich_text(pain_point)}) if not new_sector_page: print(f"Failed to create sector page for '{segment_name}'. Skipping.") continue sector_page_id = new_sector_page["id"] sector_page_ids_for_product.append(sector_page_id) # Create entry in Messaging Matrix print(f"Creating Messaging Matrix entry for '{segment_name}'...") messaging_properties = { "Name": format_title(f"{PRODUCT_NAME} - {segment_name}"), "Satz 1": format_rich_text(angle), "Satz 2": format_rich_text(differentiation), "Product Master": format_relation(product_page_id), "Sector Master": format_relation(sector_page_id) } create_notion_page(DB_IDS["Messaging Matrix"], messaging_properties) # Update Product Master with relations to all processed sectors if sector_page_ids_for_product: print(f"\nUpdating Product Master with relations to {len(sector_page_ids_for_product)} sectors...") update_notion_page(product_page_id, {"Sector Master": format_relation(sector_page_ids_for_product)}) # Clean up redundant fields in Product Master print("Cleaning up redundant Strategy Matrix field in Product Master...") update_notion_page(product_page_id, {"Strategy Matrix": format_rich_text("")}) else: print("Strategy Matrix is empty. Skipping distribution.") # 3. Distribute Feature-to-Value Translator Data feature_translator_prop_id = product_page["properties"]["Feature-to-Value Translator"]["id"] feature_translator_obj = get_page_property(product_page_id, feature_translator_prop_id) feature_translator_text = get_rich_text_content(feature_translator_obj) if feature_translator_text: parsed_features = parse_markdown_table(feature_translator_text) if parsed_features: print("\n--- Distributing Feature-to-Value Translator Data ---") for item in parsed_features: feature = item.get("Feature") story = item.get("The Story (Benefit)") headline = item.get("Headline") if not all([feature, story, headline]): print(f"Skipping feature item due to missing data: {item}") continue print(f"Creating Feature-to-Value entry for: {feature}") create_notion_page( DB_IDS["Feature-to-Value Translator"], { "Feature": format_title(feature), "Story (Benefit)": format_rich_text(story), "Headline": format_rich_text(headline), "Product Master": format_relation(product_page_id) } ) # Clean up the source field print("Cleaning up redundant Feature-to-Value Translator field in Product Master...") update_notion_page(product_page_id, {"Feature-to-Value Translator": format_rich_text("")}) else: print("Feature-to-Value Translator is empty. Skipping distribution.") print("\n--- Data distribution process complete. ---") if __name__ == "__main__": main()