06/15 Phase 1 + 2 codes
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
"""Seed reference data: the four plans, and an optional admin account.
|
||||
|
||||
Usage:
|
||||
python seed.py # seed plans only
|
||||
python seed.py --admin EMAIL PASS # also create/upgrade an admin user
|
||||
"""
|
||||
import sys
|
||||
from app import create_app
|
||||
from app.extensions import db
|
||||
from app.models.plan import Plan
|
||||
from app.models.user import User
|
||||
from app.models.category import Category
|
||||
from app.models.geo import ZipGeo
|
||||
from app.models.enums import Role
|
||||
|
||||
PLANS = [
|
||||
{
|
||||
"slug": "free", "name": "Free", "price_monthly_cents": 0, "sort_order": 0,
|
||||
"config": {
|
||||
"active_listings": 3, "listing_life_days": 14, "images_per_listing": 3,
|
||||
"featured_per_month": 0, "auto_bump": None, "analytics": None,
|
||||
"storefront": False, "verified_badge": False, "ad_free": False,
|
||||
"scheduled_posting": False, "bulk_csv": False, "priority_support": False,
|
||||
},
|
||||
},
|
||||
{
|
||||
"slug": "basic", "name": "Basic", "price_monthly_cents": 999, "sort_order": 1,
|
||||
"config": {
|
||||
"active_listings": 15, "listing_life_days": 30, "images_per_listing": 8,
|
||||
"featured_per_month": 1, "auto_bump": None, "analytics": "basic",
|
||||
"storefront": False, "verified_badge": False, "ad_free": True,
|
||||
"scheduled_posting": False, "bulk_csv": False, "priority_support": False,
|
||||
},
|
||||
},
|
||||
{
|
||||
"slug": "pro", "name": "Pro", "price_monthly_cents": 2499, "sort_order": 2,
|
||||
"config": {
|
||||
"active_listings": 50, "listing_life_days": 60, "images_per_listing": 15,
|
||||
"featured_per_month": 5, "auto_bump": "weekly", "analytics": "full",
|
||||
"storefront": True, "verified_badge": True, "ad_free": True,
|
||||
"scheduled_posting": True, "bulk_csv": False, "priority_support": False,
|
||||
},
|
||||
},
|
||||
{
|
||||
"slug": "business", "name": "Business", "price_monthly_cents": 5999, "sort_order": 3,
|
||||
"config": {
|
||||
"active_listings": None, "listing_life_days": 90, "images_per_listing": 25,
|
||||
"featured_per_month": 20, "auto_bump": "daily", "analytics": "full_export",
|
||||
"storefront": True, "verified_badge": True, "ad_free": True,
|
||||
"scheduled_posting": True, "bulk_csv": True, "priority_support": True,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def seed_plans():
|
||||
for p in PLANS:
|
||||
existing = Plan.query.filter_by(slug=p["slug"]).first()
|
||||
if existing:
|
||||
existing.name = p["name"]
|
||||
existing.price_monthly_cents = p["price_monthly_cents"]
|
||||
existing.config = p["config"]
|
||||
existing.sort_order = p["sort_order"]
|
||||
else:
|
||||
db.session.add(Plan(**p))
|
||||
db.session.commit()
|
||||
print(f"Seeded {len(PLANS)} plans.")
|
||||
|
||||
|
||||
CATEGORIES = [
|
||||
{"slug": "for-sale", "name": "For Sale", "icon": "tag", "sort_order": 0,
|
||||
"field_schema": {"fields": [
|
||||
{"name": "condition", "label": "Condition", "type": "select", "required": True,
|
||||
"options": ["new", "like_new", "good", "fair"], "hot": True},
|
||||
{"name": "brand", "label": "Brand", "type": "text", "required": False, "max": 80},
|
||||
]},
|
||||
"children": ["Furniture", "Electronics", "Cars & Trucks", "Appliances"]},
|
||||
{"slug": "wanted", "name": "Wanted", "icon": "search", "sort_order": 1,
|
||||
"field_schema": {"fields": [
|
||||
{"name": "budget", "label": "Budget (USD)", "type": "number", "required": False, "min": 0},
|
||||
]},
|
||||
"children": ["Items Wanted", "Housing Wanted"]},
|
||||
{"slug": "jobs", "name": "Jobs", "icon": "briefcase", "sort_order": 2,
|
||||
"field_schema": {"fields": [
|
||||
{"name": "job_type", "label": "Job type", "type": "select", "required": True,
|
||||
"options": ["full_time", "part_time", "contract", "temp"], "hot": True},
|
||||
{"name": "salary_min", "label": "Salary min (USD/yr)", "type": "number",
|
||||
"required": False, "min": 0, "hot": True},
|
||||
{"name": "salary_max", "label": "Salary max (USD/yr)", "type": "number",
|
||||
"required": False, "min": 0, "hot": True},
|
||||
{"name": "remote", "label": "Remote", "type": "bool", "required": False},
|
||||
]},
|
||||
"children": ["Restaurant", "Salon & Spa", "Construction", "Office"]},
|
||||
{"slug": "services", "name": "Services", "icon": "tools", "sort_order": 3,
|
||||
"field_schema": {"fields": [
|
||||
{"name": "rate", "label": "Rate (USD/hr)", "type": "number", "required": False, "min": 0},
|
||||
]},
|
||||
"children": ["Home Services", "Beauty", "Tutoring", "Auto Repair"]},
|
||||
{"slug": "supplies", "name": "Supplies", "icon": "box", "sort_order": 4,
|
||||
"field_schema": {"fields": [
|
||||
{"name": "min_order", "label": "Min order qty", "type": "number", "required": False, "min": 1},
|
||||
{"name": "condition", "label": "Condition", "type": "select", "required": False,
|
||||
"options": ["new", "used"], "hot": True},
|
||||
]},
|
||||
"children": ["Wholesale", "Restaurant Supply", "Salon Supply"]},
|
||||
{"slug": "community", "name": "Community", "icon": "users", "sort_order": 5,
|
||||
"field_schema": {"fields": [
|
||||
{"name": "event_date", "label": "Event date", "type": "text", "required": False, "max": 40},
|
||||
]},
|
||||
"children": ["Events", "Announcements", "Free Stuff", "Classes"]},
|
||||
]
|
||||
|
||||
# Sample ZIPs for Vietnamese/Hispanic hubs (replace with full SimpleMaps/Census dataset).
|
||||
ZIP_SAMPLE = [
|
||||
("92683", "Westminster", "CA", 33.7513, -117.9939, "Orange County"),
|
||||
("92840", "Garden Grove", "CA", 33.7886, -117.9390, "Orange County"),
|
||||
("95111", "San Jose", "CA", 37.2956, -121.8200, "San Jose"),
|
||||
("95122", "San Jose", "CA", 37.3300, -121.8350, "San Jose"),
|
||||
("77036", "Houston", "TX", 29.7045, -95.5380, "Houston"),
|
||||
("77072", "Houston", "TX", 29.7060, -95.5930, "Houston"),
|
||||
("78228", "San Antonio", "TX", 29.4630, -98.5790, "San Antonio"),
|
||||
("33125", "Miami", "FL", 25.7840, -80.2370, "Miami"),
|
||||
("90250", "Hawthorne", "CA", 33.9130, -118.3490, "Los Angeles"),
|
||||
("22041", "Falls Church", "VA", 38.8480, -77.1370, "DC Metro"),
|
||||
]
|
||||
|
||||
|
||||
def seed_categories():
|
||||
for c in CATEGORIES:
|
||||
parent = Category.query.filter_by(slug=c["slug"]).first()
|
||||
if parent is None:
|
||||
parent = Category(slug=c["slug"], name=c["name"], icon=c.get("icon"),
|
||||
sort_order=c["sort_order"], field_schema=c["field_schema"])
|
||||
db.session.add(parent)
|
||||
db.session.flush()
|
||||
else:
|
||||
parent.field_schema = c["field_schema"]
|
||||
parent.sort_order = c["sort_order"]
|
||||
for i, child_name in enumerate(c.get("children", [])):
|
||||
cslug = f"{c['slug']}-{child_name.lower().replace(' & ', '-').replace(' ', '-')}"
|
||||
if Category.query.filter_by(slug=cslug).first() is None:
|
||||
db.session.add(Category(slug=cslug, name=child_name,
|
||||
parent_id=parent.id, sort_order=i,
|
||||
field_schema=c["field_schema"]))
|
||||
db.session.commit()
|
||||
print(f"Seeded {len(CATEGORIES)} top categories + subcategories.")
|
||||
|
||||
|
||||
def seed_zip_sample():
|
||||
for z, city, st, lat, lng, metro in ZIP_SAMPLE:
|
||||
if ZipGeo.query.get(z) is None:
|
||||
db.session.add(ZipGeo(zip=z, city=city, state=st, lat=lat, lng=lng, metro=metro))
|
||||
db.session.commit()
|
||||
print(f"Seeded {len(ZIP_SAMPLE)} sample ZIP rows.")
|
||||
|
||||
|
||||
def make_admin(email, password):
|
||||
user = User.query.filter_by(email=email.lower()).first()
|
||||
if user is None:
|
||||
user = User(email=email.lower(), display_name="Admin", role=Role.admin,
|
||||
email_verified=True)
|
||||
user.set_password(password)
|
||||
db.session.add(user)
|
||||
else:
|
||||
user.role = Role.admin
|
||||
user.email_verified = True
|
||||
user.set_password(password)
|
||||
db.session.commit()
|
||||
print(f"Admin ready: {email}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = create_app()
|
||||
with app.app_context():
|
||||
seed_plans()
|
||||
seed_categories()
|
||||
seed_zip_sample()
|
||||
if "--admin" in sys.argv:
|
||||
i = sys.argv.index("--admin")
|
||||
make_admin(sys.argv[i + 1], sys.argv[i + 2])
|
||||
Reference in New Issue
Block a user