semblance/backend/scripts/populate_db.py
Vadym Samoilenko 3e1865edbd Apply Jintech security audit remediation (sprint 3) — 87/92 findings fixed
- Fix missing await on FocusGroup.get_messages() (N-L1)
- Replace time.sleep with asyncio.sleep in key_theme_service and focus_group_service (N-P10)
- Replace flask import with quart in focus_groups.py (N-S3)
- Add logger.error before all 500 returns in focus_groups.py (N-P6)
- Add logging to silent except blocks across routes (N-M10, N-M11)
- Add @rate_limit to 6 remaining AI endpoints (N-H4)
- Add --confirm flag to populate scripts before delete_many (S-H2)
- Remove hardcoded Azure ID fallbacks from msal_service.py and msalConfig.ts (A-M2, F-H4)
- Centralize make_serializable() in utils.py, remove duplicates from 3 route files (N-P7)
- Replace all datetime.utcnow() with datetime.now(timezone.utc) across entire backend (M-L2)
- AuthContext.tsx: only mark token validated on 200 success, not on non-401 errors (F-H2)
- Rename authType → auth_type in auth.py (N-S4)
- Add security_report.md and security_report.pdf with full 92-finding status

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 12:51:18 +00:00

612 lines
No EOL
29 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
import sys
import os
import json
import datetime
from pymongo import MongoClient
from getpass import getpass
# Add parent directory to path so we can import from app
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Import the modules we need
from app.models.persona import Persona
from app.models.focus_group import FocusGroup
# Custom MongoDB connection for the script
def get_script_db():
"""Get MongoDB connection using MONGO_URI or interactive credentials."""
print("Connecting to MongoDB...")
# Prefer MONGO_URI from environment
mongo_uri = os.environ.get('MONGO_URI')
if mongo_uri:
try:
client = MongoClient(mongo_uri, serverSelectionTimeoutMS=5000)
db = client.semblance_db
db.command('ping')
print("Successfully connected to MongoDB using MONGO_URI")
return client, db
except Exception as e:
print(f"Could not connect using MONGO_URI (credentials redacted from error)")
sys.exit(1)
# Try connecting without auth first
try:
client = MongoClient('mongodb://localhost:27017', serverSelectionTimeoutMS=2000)
db = client.semblance_db
db.command('ping')
print("Successfully connected to MongoDB without authentication")
return client, db
except Exception as e:
pass
# Ask for credentials if auth failed
print("\nMongoDB requires authentication. Set MONGO_URI env var to avoid this prompt.")
username = input("MongoDB username: ")
password = getpass("MongoDB password: ")
try:
from urllib.parse import quote_plus
uri = f"mongodb://{quote_plus(username)}:{quote_plus(password)}@localhost:27017/semblance_db?authSource=admin"
client = MongoClient(uri, serverSelectionTimeoutMS=5000)
db = client.semblance_db
db.command('ping')
print("Successfully connected to MongoDB with credentials")
return client, db
except Exception as e:
print(f"Error connecting to MongoDB with credentials: {e}")
sys.exit(1)
# Sample persona data from the frontend
sample_personas = [
{
"id": "0",
"name": "Oliver Reynolds",
"age": "42",
"gender": "Male",
"occupation": "Senior Investment Manager",
"education": "Master's degree (Business and Finance)",
"location": "Kensington, London, UK",
"techSavviness": 85,
"personality": "Discerning, sophisticated, detail-oriented, values heritage and craftsmanship",
"interests": "Classic automobiles, high-end timepieces, luxury real estate, fine dining, art exhibitions",
"brandLoyalty": 90,
"priceConsciousness": 30,
"environmentalConcern": 60,
"hasPurchasingPower": True,
"hasChildren": True,
"thinkFeelDo": {
"thinks": [
"How does this reflect my personal standards and values?",
"Is this truly the pinnacle of craftsmanship and quality?",
"Will this purchase stand the test of time as a lasting investment?",
"How can this be further personalized to my exact preferences?"
],
"feels": [
"Proud to associate with heritage brands that reflect my achievements",
"Gratified by bespoke experiences that acknowledge my unique tastes",
"Frustrated by standardized approaches that fail to recognize individual preferences",
"Reassured by transparent, detailed information about craftsmanship and materials"
],
"does": [
"Conducts thorough research before making significant purchasing decisions",
"Seeks personalized consultations with dedicated specialists",
"Expects seamless integration between digital and in-person experiences",
"Values and maintains long-term relationships with trusted luxury brands",
"Regularly attends exclusive events and private showings"
]
},
"oceanTraits": {
"openness": 85,
"conscientiousness": 90,
"extraversion": 60,
"agreeableness": 65,
"neuroticism": 25
},
"goals": [
"Build a legacy of discerning taste and refined investments",
"Access truly personalized experiences that acknowledge his status",
"Forge meaningful connections with brands that share his values",
"Discover unique, limited-edition items that few others will possess",
"Cultivate a network of trusted advisors across various luxury segments",
"Balance professional achievement with meaningful family experiences"
],
"frustrations": [
"Mass-market approaches disguised as premium experiences",
"Fragmented communication across different channels",
"Delays in response or service that waste valuable time",
"Sales representatives who lack deep product knowledge"
],
"motivations": [
"Recognition of his refined tastes and achievement",
"Access to exclusive, members-only opportunities",
"Building a collection of meaningful, high-quality possessions",
"Experiences that seamlessly blend heritage with innovation"
],
"scenarioType": "Life & Luxury Scenarios",
"scenarios": [
"Oliver is considering commissioning a bespoke luxury vehicle with custom interior features. He expects a dedicated consultant to guide him through the entire process, from initial design to delivery.",
"While traveling abroad, Oliver seeks remote access to his preferred brands and expects the same level of personalized service through digital channels.",
"Oliver is attending an exclusive product launch event where he anticipates VIP treatment and early access to limited-edition items.",
"When researching a significant purchase, Oliver consults both trusted peer networks and expects detailed information about materials, craftsmanship, and heritage.",
"Oliver is planning a milestone family celebration and wants to book a private dining experience at an exclusive venue that reflects his sophisticated taste."
]
},
{
"id": "1",
"name": "Fiona Caldwell",
"age": "38",
"gender": "Female",
"occupation": "Founder and Creative Director of a luxury lifestyle brand",
"education": "First-Class Honours degree from a prestigious university",
"location": "Chelsea, London, UK",
"ethnicity": "White British",
"socialGrade": "A/B",
"householdIncome": "Approximately £195,000 per annum",
"householdComposition": "Single professional with established network",
"livingSituation": "Stylish, modern flat in exclusive London district",
"techSavviness": 90,
"personality": "Innovative, discerning, detail-oriented, values quality and distinctiveness",
"interests": "Bespoke fashion, high-end design, contemporary art, exclusive dining experiences",
"mediaConsumption": "Premium publications (The Spectator, Tatler, Vogue) and digital influencers",
"deviceUsage": "High-performance smartphone, tablet, and ultrabook; active on luxury-focused social platforms",
"shoppingHabits": "Prefers bespoke shopping with personalized digital interfaces and in-person exclusivity",
"brandPreferences": "Brands combining heritage with innovation; appreciates tailored craftsmanship",
"brandLoyalty": 85,
"priceConsciousness": 25,
"environmentalConcern": 70,
"hasPurchasingPower": True,
"hasChildren": False,
"communicationPreferences": "Clear, direct, personalized communication through premium channels",
"thinkFeelDo": {
"thinks": [
"How does this complement my personal brand and creative vision?",
"Is this innovative yet timeless enough for my lifestyle?",
"Will this experience or product truly stand out from the mainstream?",
"How can this be tailored to reflect my unique aesthetic sensibilities?"
],
"feels": [
"Excited by innovative designs that push creative boundaries",
"Valued when brands recognize her accomplishments and creative influence",
"Frustrated by cookie-cutter luxury experiences that lack personality",
"Inspired by perfect execution of bespoke experiences that reflect attention to detail"
],
"does": [
"Engages with immersive digital platforms and virtual showrooms",
"Attends exclusive industry events and creative collaborations",
"Seeks one-to-one consultancy sessions for significant purchases",
"Shares refined experiences within her select network of peers",
"Collaborates with luxury brands that align with her creative vision"
]
},
"oceanTraits": {
"openness": 95,
"conscientiousness": 85,
"extraversion": 70,
"agreeableness": 65,
"neuroticism": 30
},
"goals": [
"Establish herself as a tastemaker in the luxury creative community",
"Experience highly personalized services that acknowledge her uniqueness",
"Discover innovative yet timeless designs that complement her lifestyle",
"Build meaningful connections with brands that share her creative vision",
"Balance digital innovation with high-touch personal experiences",
"Access exclusive opportunities before they reach the mainstream market"
],
"frustrations": [
"Generic luxury experiences that don't recognize her unique tastes",
"Disconnected online and offline brand experiences",
"Mass-market approaches disguised as premium services",
"Brands that prioritize heritage without embracing innovation"
],
"motivations": [
"Recognition of her creative influence and accomplishments",
"Access to limited-edition collaborations and early releases",
"Experiences that seamlessly blend digital innovation with personal service",
"Relationships with brands that value her feedback and perspective"
],
"scenarioType": "Lifestyle & Professional Scenarios",
"scenarios": [
"Fiona is considering collaborating with a luxury automotive brand on a limited-edition design concept, expecting a personalized presentation that respects her creative expertise.",
"While attending London Fashion Week, Fiona expects seamless integration between digital showcase tools and exclusive in-person appointments with designers.",
"Fiona is hosting a product launch event for her brand and wants to incorporate innovative digital experiences alongside traditional luxury elements.",
"When sourcing materials for a new collection, Fiona expects detailed information about craftsmanship, sustainability credentials, and exclusivity.",
"Fiona is planning a creative retreat and seeks a bespoke travel experience that combines luxury accommodations with artistic inspiration."
],
"coreValues": "Exceptional quality, distinctiveness, and high-touch service; balancing innovation with timeless elegance",
"lifestyleChoices": "Cultural experiences such as art gallery openings, theatre premieres, and curated travel destinations",
"socialActivities": "Networks with high-achieving professionals at exclusive events; active in industry panels and luxury brand collaborations",
"categoryKnowledge": "Well-informed about luxury offerings; appreciates intricate design details and distinctive craftsmanship",
"paymentMethods": "Premium digital payment systems and secure banking apps for high-net-worth individuals",
"purchaseBehaviour": "Decisions driven by emotional connection and design evaluation; perceives high-value purchases as integral to personal brand",
"decisionInfluences": "Brand heritage, exclusivity of customizations, and recommendations from discerning peer network",
"painPoints": "Cookie-cutter approaches in luxury retail; seeks recognition of her individuality and creative sensibilities",
"journeyContext": "Engages through immersive digital platforms complemented by in-person appointments",
"keyTouchpoints": "Exclusive previews, one-to-one consultancy, and personalized digital interactions",
"selfDeterminationNeeds": {
"autonomy": "Seeks independence in decision-making and values bespoke offerings reflecting uniqueness",
"competence": "Desires acknowledgment of refined tastes and expects flawless service",
"relatedness": "Values personalized relationships with brands understanding her lifestyle"
},
"fears": [
"Being treated as an anonymous customer in a mass-market approach",
"Loss of personal touch in increasingly digitized luxury experiences"
],
"narrative": "Fiona Caldwell is a pioneering creative entrepreneur blending artistic flair with unwavering commitment to quality. At 38, her taste reflects both innovation and timeless elegance. She thrives in exclusive circles where bespoke, high-touch service is expected at every stage of her luxury journey."
},
{
"id": "2",
"name": "Michael Chen",
"age": "37",
"gender": "Male",
"occupation": "Software Engineer",
"location": "San Francisco, USA",
"techSavviness": 95,
"personality": "Analytical, detail-oriented, values efficiency",
"thinkFeelDo": {
"thinks": ["I need to understand how things work", "Efficiency is key"],
"feels": ["Annoyed by bugs or performance issues", "Satisfied by clean, logical interfaces"],
"does": ["Tests edge cases", "Reads documentation thoroughly"]
},
"oceanTraits": {
"openness": 70,
"conscientiousness": 90,
"extraversion": 40,
"agreeableness": 55,
"neuroticism": 30
}
},
{
"id": "4",
"name": "David Kim",
"age": "22",
"gender": "Male",
"occupation": "Student",
"location": "Austin, USA",
"techSavviness": 90,
"personality": "Curious, experimental, price-conscious",
"thinkFeelDo": {
"thinks": ["How can I customize this?", "Is this worth my time?"],
"feels": ["Bored by traditional interfaces", "Excited by customization options"],
"does": ["Tries all settings and features", "Abandons apps that don't engage quickly"]
},
"oceanTraits": {
"openness": 90,
"conscientiousness": 50,
"extraversion": 65,
"agreeableness": 70,
"neuroticism": 40
}
},
{
"id": "5",
"name": "Lisa Patel",
"age": "41",
"gender": "Female",
"occupation": "Product Manager",
"location": "Seattle, USA",
"techSavviness": 80,
"personality": "Strategic thinker, detail-oriented, collaborative",
"thinkFeelDo": {
"thinks": ["How does this fit into the ecosystem?", "What problems does this solve?"],
"feels": ["Concerned about integration issues", "Satisfied by cohesive user journeys"],
"does": ["Evaluates the full user journey", "Compares with competing products"]
},
"oceanTraits": {
"openness": 75,
"conscientiousness": 85,
"extraversion": 60,
"agreeableness": 75,
"neuroticism": 35
}
},
{
"id": "7",
"name": "Olivia Brown",
"age": "31",
"gender": "Female",
"occupation": "UX Designer",
"location": "Portland, USA",
"techSavviness": 90,
"personality": "Creative, empathetic, user-centered",
"thinkFeelDo": {
"thinks": ["How does this make users feel?", "Is this accessible to everyone?"],
"feels": ["Frustrated by poor accessibility", "Inspired by elegant solutions"],
"does": ["Analyzes micro-interactions", "Considers edge cases and accessibility"]
},
"oceanTraits": {
"openness": 85,
"conscientiousness": 75,
"extraversion": 60,
"agreeableness": 80,
"neuroticism": 40
}
},
{
"id": "8",
"name": "Arash Montazeri",
"age": "46",
"gender": "Male",
"occupation": "Senior Executive at a leading technology firm",
"education": "Bachelor's degree in Engineering from a prestigious UK university",
"location": "Ascot, Berkshire, UK",
"ethnicity": "Iranian-British",
"householdIncome": "Approximately £240,000 per annum",
"socialGrade": "A",
"householdComposition": "Married with two grown-up children",
"livingSituation": "Elegant country estate near Ascot blending British comfort and Persian design",
"techSavviness": 94,
"personality": "Integrates heritage and innovation; values bespoke, culturally nuanced service and excellence",
"interests": "Classic cars, bespoke tailoring, fine wines, Persian and contemporary art, luxury travel, golfing at country clubs",
"brandLoyalty": 95,
"priceConsciousness": 40,
"environmentalConcern": 75,
"hasPurchasingPower": True,
"hasChildren": True,
"deviceUsage": "Uses latest smartphones, tablets, smart home tech; prefers personalized luxury interfaces",
"shoppingHabits": "Relationship-driven, high-touch purchasing process with bespoke consultations; expects seamless online-offline integration",
"brandPreferences": "Heritage-driven, premium brands merging traditional craftsmanship with innovation (e.g., RollsRoyce)",
"paymentMethods": "Secure digital banking, premium credit, bespoke financing for high-value purchases",
"mediaConsumption": "Reads Financial Times, The Economist, and select cultural journals reflecting Iranian heritage and global outlook",
"coreValues": "Strong emphasis on heritage and innovation; bespoke service honoring tradition and Iranian culture",
"lifestyleChoices": "Golfing, fine dining at gourmet restaurants, immersive luxury travel, and revisiting Iranian roots",
"socialActivities": "Active in elite clubs, attends high-profile charity/cultural events, celebrates diversity and craftsmanship",
"categoryKnowledge": "Well-versed in luxury automotive engineering and bespoke options; values modern and traditional artistry",
"purchaseBehaviour": "Balances rational analysis and emotional attachment; major purchases are investments in legacy and taste",
"decisionInfluences": "Brand heritage, craftsmanship events, peer endorsements, transparency, and personalized narratives",
"painPoints": "Frustrated by fragmented, impersonal journeys and digital/in-person integration gaps",
"journeyContext": "Engages via invitation-only showrooms, virtual tours, and bespoke digital experiences with seamless support",
"keyTouchpoints": "One-to-one consultations, private previews of new bespoke options, post-purchase concierge support",
"communicationPreferences": "Prefers direct, timely engagement via a relationship manager, comfortable in-person and with premium digital",
"oceanTraits": {
"openness": 93,
"conscientiousness": 97,
"extraversion": 68,
"agreeableness": 64,
"neuroticism": 18,
},
"selfDeterminationNeeds": {
"autonomy": "Seeks independence and offerings reflecting multifaceted identity",
"competence": "Desires recognition for refined taste and expects flawless service mirroring achievements",
"relatedness": "Wants personalized, respectful brand relationships honoring Iranian and British sophistication"
},
"motivations": [
"Pursuit of excellence in every aspect",
"Preserve cultural legacy through selective luxury experiences",
"Leave a lasting impact via refined, innovative purchases",
"Deep connections with heritage brands",
"Integrity and authenticity in every luxury engagement",
"Opportunities to express identity through bespoke, meaningful customization",
],
"fears": [
"Receiving subpar, impersonal service",
"Excessive digitization eroding tailored luxury experience"
],
"scenarioType": "Scenarios Across Life, Luxury, Technology, and Heritage",
"scenarios": [
"Arash attends a private RollsRoyce preview showcasing a bespoke vehicle that artfully blends British engineering with Persian design, collaborating one-on-one with brand artisans.",
"Invited to a virtual configurator experience, Arash works directly with a relationship manager to design a tailored vehicle from the comfort of his study, later completing the process with an in-person consultation.",
"At a high-profile cultural gala, Arash discusses his curated automotive and art collections, valuing brands that recognize and celebrate his unique heritage and refined taste.",
"Arash grows frustrated when a luxury brand's digital appointment system does not seamlessly coordinate with in-person experience, prompting him to seek out brands with superior omnichannel integration.",
"When considering a new bespoke vehicle, Arash weighs heritage, innovation, and family legacy, seeking a process that honors his background in every detail—from material selection to narrative storytelling.",
"Post-purchase, Arash values ongoing, dedicated aftercare provided by a trusted relationship manager, ensuring every aspect of ownership exceeds expectations and reflects his status."
],
"narrative": "Arash Montazeri exemplifies the modern luxury consumer who seamlessly integrates his Iranian heritage with contemporary British sophistication. As a successful senior executive, Arash demands a bespoke, integrated luxury experience that honours both tradition and innovation. His elevated conscientiousness ensures every detail is handled with precision, while his high openness allows him to embrace creative customisations that reflect his cultural legacy."
}
]
# Sample focus group data from the frontend
sample_focus_groups = [
{
"id": "1",
"name": "Mobile App UX Evaluation",
"status": "in-progress",
"participants": [
"1", "2", "4", "5", "7"
],
"date": "2023-06-12T15:30:00Z",
"duration": 60,
"topic": "user-experience",
"discussionGuide": """
# Discussion Guide: Mobile App UX Evaluation
## Introduction (5 minutes)
Welcome to our focus group discussion. Today we'll be exploring your experiences and opinions on our mobile app interface. There are no right or wrong answers, we're just interested in your honest thoughts.
## Warm-up Questions (10 minutes)
Let's start by introducing ourselves and sharing a bit about your daily smartphone usage.
## Navigation Experience Exploration (15 minutes)
Now, let's dive deeper into your experiences with the app navigation. What features do you find most intuitive? What frustrations have you encountered?
## Creative Testing (20 minutes)
We'll now show you some design concepts and get your feedback.
## Conclusion (10 minutes)
To wrap up, I'd like to hear your final thoughts on what we've discussed today and any additional insights you'd like to share.
"""
},
{
"id": "2",
"name": "Product Feature Feedback",
"status": "in-progress",
"participants": [
"1", "4", "5", "7"
],
"date": "2023-06-15T10:00:00Z",
"duration": 90,
"topic": "product-feedback",
"discussionGuide": """
# Discussion Guide: Product Feature Feedback
## Introduction (5 minutes)
Welcome to our focus group discussion. Today we'll be exploring your thoughts on our upcoming product features.
## Warm-up Questions (10 minutes)
Let's start by discussing your current experience with similar products.
## Feature Exploration (30 minutes)
We'll present several feature concepts and gather your feedback on each.
## Prioritization Exercise (15 minutes)
Help us understand which features would be most valuable to you.
## Conclusion (10 minutes)
Final thoughts and summary of the discussion.
"""
},
{
"id": "3",
"name": "Marketing Campaign Testing",
"status": "in-progress",
"participants": [
"2", "4", "7"
],
"date": "2023-06-12T15:30:00Z",
"duration": 45,
"topic": "creative-testing",
"discussionGuide": """
# Discussion Guide: Marketing Campaign Testing
## Introduction (5 minutes)
Welcome everyone. Today we're evaluating some marketing campaign concepts.
## Warm-up (5 minutes)
Brief discussion about marketing campaigns that have caught your attention recently.
## Campaign Concept Review (25 minutes)
We'll review several campaign directions and gather your impressions.
## Message Effectiveness (10 minutes)
Discussion about which messages resonate most strongly and why.
## Conclusion (5 minutes)
Final impressions and recommendations.
"""
}
]
def main():
import argparse
parser = argparse.ArgumentParser(description="Populate MongoDB with sample data (DEV ONLY)")
parser.add_argument('--dry-run', action='store_true', help='Preview actions without writing to DB')
parser.add_argument('--confirm', action='store_true', help='Required: confirm destructive delete_many operations')
args = parser.parse_args()
# S-M2: Block in production
env = os.environ.get('FLASK_ENV', os.environ.get('APP_ENV', 'development'))
if env == 'production':
print("ERROR: This script must not be run in production.")
sys.exit(1)
if args.dry_run:
print("[DRY RUN] No data will be written to the database.")
print(f"[DRY RUN] Would connect to MongoDB and create seed data.")
sys.exit(0)
if not args.confirm:
print("ERROR: This script will delete all personas and focus groups. Pass --confirm to proceed.")
sys.exit(1)
# Connect to MongoDB with authentication if needed
client, db = get_script_db()
print("\nPreparing to populate database...")
# Create a default user for reference
user_id = None
try:
import bcrypt
username = os.environ.get('SEED_ADMIN_USERNAME', 'dev_admin')
password = os.environ.get('SEED_ADMIN_PASSWORD', '')
if not password:
print("ERROR: Set SEED_ADMIN_PASSWORD env var before running this script.")
sys.exit(1)
users_collection = db.users
existing_user = users_collection.find_one({"username": username})
if not existing_user:
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
new_user = {
"username": username,
"email": f"{username}@example.com",
"password": password_hash,
"role": "admin", # S-M4
"created_at": str(datetime.datetime.now(datetime.timezone.utc))
}
result = users_collection.insert_one(new_user)
user_id = result.inserted_id
print(f"Created seed user '{username}'")
else:
user_id = existing_user["_id"]
print(f"Using existing user '{username}'")
except Exception as e:
print(f"Error with user setup: {e}")
from bson.objectid import ObjectId
user_id = ObjectId()
# Delete existing data to start fresh
try:
db.personas.delete_many({})
db.focus_groups.delete_many({})
print("Cleared existing personas and focus groups")
except Exception as e:
print(f"Error clearing collections: {e}")
print("\nAdding personas...")
id_mapping = {}
for persona_data in sample_personas:
try:
# Prepare persona data for MongoDB
# We need to remove the id from frontend to let MongoDB create a new one
frontend_id = persona_data.pop('id')
# Add created_by and created_at fields
persona_data['created_by'] = user_id
persona_data['created_at'] = str(datetime.datetime.now())
# Insert directly using PyMongo instead of the model
result = db.personas.insert_one(persona_data)
mongo_id = str(result.inserted_id)
# Store mapping for later use with focus groups
id_mapping[frontend_id] = mongo_id
print(f"Imported persona: {persona_data.get('name')} (frontend ID: {frontend_id} → MongoDB ID: {mongo_id})")
except Exception as e:
print(f"Error importing persona {persona_data.get('name')}: {e}")
print("\nAdding focus groups...")
for focus_group_data in sample_focus_groups:
try:
# Prepare focus group data for MongoDB
frontend_id = focus_group_data.pop('id')
# Map frontend participant IDs to MongoDB participant IDs
frontend_participants = focus_group_data.pop('participants', [])
participants = [id_mapping.get(p_id) for p_id in frontend_participants if p_id in id_mapping]
focus_group_data['participants'] = participants
# Add created_by and created_at fields
focus_group_data['created_by'] = user_id
focus_group_data['created_at'] = str(datetime.datetime.now())
# Insert directly using PyMongo
result = db.focus_groups.insert_one(focus_group_data)
focus_group_id = str(result.inserted_id)
print(f"Imported focus group: {focus_group_data.get('name')} (frontend ID: {frontend_id} → MongoDB ID: {focus_group_id})")
print(f" - Participants: {', '.join(participants)}")
except Exception as e:
print(f"Error importing focus group {focus_group_data.get('name')}: {e}")
print("\nDatabase population complete!")
client.close()
if __name__ == "__main__":
main()