Compare commits
2 Commits
62e418c473
...
488d5a6f0e
| Author | SHA1 | Date | |
|---|---|---|---|
| 488d5a6f0e | |||
| 3c2b559282 |
@@ -76,7 +76,7 @@ jobs:
|
||||
- name: Run tests
|
||||
run: python -m pytest tests/ -v --tb=short
|
||||
|
||||
architecture:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DATABASE_URL: "postgresql://dummy:dummy@localhost:5432/dummy"
|
||||
@@ -94,8 +94,8 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: uv pip install --system -r requirements.txt
|
||||
|
||||
- name: Validate architecture
|
||||
run: python scripts/validate/validate_architecture.py
|
||||
- name: Run all validators
|
||||
run: python scripts/validate/validate_all.py
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Security (non-blocking)
|
||||
@@ -116,32 +116,13 @@ jobs:
|
||||
- name: Run pip-audit
|
||||
run: pip-audit --requirement requirements.txt || true
|
||||
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: Install uv
|
||||
run: pip install uv
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv pip install --system -r requirements.txt -r requirements-dev.txt
|
||||
|
||||
- name: Run audit
|
||||
run: python scripts/validate/validate_audit.py
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Build (docs - only on push to master)
|
||||
# ---------------------------------------------------------------------------
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
needs: [ruff, pytest, architecture]
|
||||
needs: [ruff, pytest, validate]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -158,19 +139,13 @@ jobs:
|
||||
- name: Build docs
|
||||
run: mkdocs build
|
||||
|
||||
- name: Upload docs artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: docs-site
|
||||
path: site/
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Deploy (master-only, after lint + tests + architecture pass)
|
||||
# Deploy (master-only, after lint + tests + validate pass)
|
||||
# ---------------------------------------------------------------------------
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
needs: [ruff, pytest, architecture]
|
||||
needs: [ruff, pytest, validate]
|
||||
steps:
|
||||
- name: Deploy to production
|
||||
uses: appleboy/ssh-action@v1
|
||||
|
||||
17
Makefile
17
Makefile
@@ -104,22 +104,19 @@ init-prod:
|
||||
@echo "Step 0/6: Ensuring database exists (running migrations)..."
|
||||
@$(PYTHON) -m alembic upgrade heads
|
||||
@echo ""
|
||||
@echo "Step 1/6: Creating admin user and platform settings..."
|
||||
@echo "Step 1/5: Creating admin user and platform settings..."
|
||||
$(PYTHON) scripts/seed/init_production.py
|
||||
@echo ""
|
||||
@echo "Step 2/6: Initializing log settings..."
|
||||
@echo "Step 2/5: Initializing log settings..."
|
||||
$(PYTHON) scripts/seed/init_log_settings.py
|
||||
@echo ""
|
||||
@echo "Step 3/6: Creating default CMS content pages..."
|
||||
@echo "Step 3/5: Creating default CMS content pages..."
|
||||
$(PYTHON) scripts/seed/create_default_content_pages.py
|
||||
@echo ""
|
||||
@echo "Step 4/6: Creating platform pages and landing..."
|
||||
$(PYTHON) scripts/seed/create_platform_pages.py
|
||||
@echo ""
|
||||
@echo "Step 5/6: Seeding email templates..."
|
||||
@echo "Step 4/5: Seeding email templates..."
|
||||
$(PYTHON) scripts/seed/seed_email_templates.py
|
||||
@echo ""
|
||||
@echo "Step 6/6: Seeding subscription tiers..."
|
||||
@echo "Step 5/5: Seeding subscription tiers..."
|
||||
@echo " (Handled by init_production.py Step 6)"
|
||||
@echo ""
|
||||
@echo "✅ Production initialization completed"
|
||||
@@ -195,10 +192,6 @@ create-cms-defaults:
|
||||
$(PYTHON) scripts/seed/create_default_content_pages.py
|
||||
@echo "✅ CMS defaults created"
|
||||
|
||||
create-platform-pages:
|
||||
@echo "🏠 Creating platform pages and landing..."
|
||||
$(PYTHON) scripts/seed/create_platform_pages.py
|
||||
@echo "✅ Platform pages created"
|
||||
|
||||
init-logging:
|
||||
@echo "📝 Initializing log settings..."
|
||||
|
||||
@@ -192,7 +192,7 @@ The workflow file lives in `.gitea/workflows/ci.yml` (already created in this re
|
||||
| `services:` (top-level on job) | `services:` nested under each job with `options:` |
|
||||
| `allow_failure: true` | `continue-on-error: true` |
|
||||
| `rules: - if:` | `on:` triggers + `if:` conditionals per job |
|
||||
| `artifacts: paths:` | `actions/upload-artifact@v4` |
|
||||
| `artifacts: paths:` | `actions/upload-artifact@v4` (not supported on Gitea GHES) |
|
||||
| `cache: paths:` | `actions/cache@v4` |
|
||||
| `coverage: '/regex/'` | Use coverage action or parse in step |
|
||||
| CI/CD Variables (UI) | Repository **Settings > Secrets** |
|
||||
@@ -206,10 +206,13 @@ Configure these in your Gitea repository under **Settings > Actions > Secrets**:
|
||||
| Secret | Description | Used by |
|
||||
|--------|-------------|---------|
|
||||
| `DEPLOY_SSH_KEY` | Ed25519 private key for deployment | Deploy job |
|
||||
| `DEPLOY_HOST` | Production server IP (e.g. `127.0.0.1`) | Deploy job |
|
||||
| `DEPLOY_HOST` | Docker bridge gateway IP: `172.17.0.1` (see note below) | Deploy job |
|
||||
| `DEPLOY_USER` | SSH user on production server (e.g. `samir`) | Deploy job |
|
||||
| `DEPLOY_PATH` | App directory on server (e.g. `/home/samir/apps/orion`) | Deploy job |
|
||||
|
||||
!!! important "DEPLOY_HOST must be `172.17.0.1`, not `127.0.0.1`"
|
||||
The Gitea Actions runner executes CI jobs inside Docker containers. From inside the container, `127.0.0.1` refers to the container itself, not the host machine. Use `172.17.0.1` (the Docker bridge gateway) so the SSH action can reach the host's SSH daemon. When Gitea and Orion are split onto separate servers, update this to the Orion server's real IP.
|
||||
|
||||
---
|
||||
|
||||
## 8. Pipeline Overview
|
||||
@@ -220,14 +223,13 @@ The CI pipeline (`.gitea/workflows/ci.yml`) runs:
|
||||
push/PR to master
|
||||
├── ruff (lint)
|
||||
├── pytest (tests + PostgreSQL service)
|
||||
├── architecture (architecture validation)
|
||||
├── validate (all 4 validators: architecture, security, performance, audit)
|
||||
├── dependency-scanning (pip-audit, non-blocking)
|
||||
├── audit (custom audit, non-blocking)
|
||||
├── docs (mkdocs build, master-only, after lint+test pass)
|
||||
└── deploy (SSH deploy, master-only, after lint+test+arch pass)
|
||||
├── docs (mkdocs build, master-only, after lint+test+validate pass)
|
||||
└── deploy (SSH deploy, master-only, after lint+test+validate pass)
|
||||
```
|
||||
|
||||
All jobs run in parallel except `docs` and `deploy`, which wait for `ruff`, `pytest`, and `architecture` to pass. The `deploy` job only runs on push (not PRs).
|
||||
All jobs run in parallel except `docs` and `deploy`, which wait for `ruff`, `pytest`, and `validate` to pass. The `deploy` job only runs on push (not PRs).
|
||||
|
||||
---
|
||||
|
||||
@@ -239,7 +241,7 @@ The CI pipeline includes an automated deploy job that runs on every successful p
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
needs: [ruff, pytest, architecture]
|
||||
needs: [ruff, pytest, validate]
|
||||
steps:
|
||||
- name: Deploy to production
|
||||
uses: appleboy/ssh-action@v1
|
||||
@@ -270,6 +272,8 @@ See [Hetzner Server Setup — Step 16](hetzner-server-setup.md#step-16-continuou
|
||||
```bash
|
||||
sudo ufw allow OpenSSH
|
||||
sudo ufw allow 'Nginx Full'
|
||||
# Allow CI containers (Docker bridge) to SSH to the host for deployment
|
||||
sudo ufw allow from 172.17.0.0/16 to any port 22
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
|
||||
@@ -395,7 +395,6 @@ docker compose --profile full exec -e PYTHONPATH=/app api python -m alembic upgr
|
||||
docker compose --profile full exec -e PYTHONPATH=/app api python scripts/seed/init_production.py
|
||||
docker compose --profile full exec -e PYTHONPATH=/app api python scripts/seed/init_log_settings.py
|
||||
docker compose --profile full exec -e PYTHONPATH=/app api python scripts/seed/create_default_content_pages.py
|
||||
docker compose --profile full exec -e PYTHONPATH=/app api python scripts/seed/create_platform_pages.py
|
||||
docker compose --profile full exec -e PYTHONPATH=/app api python scripts/seed/seed_email_templates.py
|
||||
```
|
||||
|
||||
@@ -689,14 +688,14 @@ Verify the runner shows as **Online** in Gitea: **Site Administration > Actions
|
||||
|
||||
## Step 16: Continuous Deployment
|
||||
|
||||
Automate deployment on every successful push to master. The Gitea Actions runner and the app both run on the same server, so the deploy job SSHes from the CI Docker container to `127.0.0.1`.
|
||||
Automate deployment on every successful push to master. The Gitea Actions runner and the app both run on the same server, so the deploy job SSHes from the CI Docker container to `172.17.0.1` (Docker bridge gateway — see note in 16.2).
|
||||
|
||||
```
|
||||
push to master
|
||||
├── ruff ──────┐
|
||||
├── pytest ────┤
|
||||
└── architecture ─┤
|
||||
└── deploy (SSH → scripts/deploy.sh)
|
||||
└── validate ──┤
|
||||
└── deploy (SSH → scripts/deploy.sh)
|
||||
├── git stash / pull / pop
|
||||
├── docker compose up -d --build
|
||||
├── alembic upgrade heads
|
||||
@@ -717,10 +716,13 @@ In **Repository Settings > Actions > Secrets**, add:
|
||||
| Secret | Value |
|
||||
|---|---|
|
||||
| `DEPLOY_SSH_KEY` | Contents of `~/.ssh/deploy_ed25519` (private key) |
|
||||
| `DEPLOY_HOST` | `127.0.0.1` |
|
||||
| `DEPLOY_HOST` | `172.17.0.1` (Docker bridge gateway — **not** `127.0.0.1`) |
|
||||
| `DEPLOY_USER` | `samir` |
|
||||
| `DEPLOY_PATH` | `/home/samir/apps/orion` |
|
||||
|
||||
!!! important "Why `172.17.0.1` and not `127.0.0.1`?"
|
||||
CI jobs run inside Docker containers where `127.0.0.1` is the container, not the host. `172.17.0.1` is the Docker bridge gateway that routes to the host. Ensure the firewall allows SSH from the Docker bridge network: `sudo ufw allow from 172.17.0.0/16 to any port 22`. When Gitea and Orion are on separate servers, replace with the Orion server's IP.
|
||||
|
||||
### 16.3 Deploy Script
|
||||
|
||||
The deploy script lives at `scripts/deploy.sh` in the repository. It:
|
||||
@@ -736,13 +738,13 @@ Exit codes: `0` success, `1` git pull failed, `2` docker compose failed, `3` mig
|
||||
|
||||
### 16.4 CI Workflow
|
||||
|
||||
The deploy job in `.gitea/workflows/ci.yml` runs only on master push, after `ruff`, `pytest`, and `architecture` pass:
|
||||
The deploy job in `.gitea/workflows/ci.yml` runs only on master push, after `ruff`, `pytest`, and `validate` pass:
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
needs: [ruff, pytest, architecture]
|
||||
needs: [ruff, pytest, validate]
|
||||
steps:
|
||||
- name: Deploy to production
|
||||
uses: appleboy/ssh-action@v1
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
| Script | Purpose | In Makefile? | Issues |
|
||||
|--------|---------|--------------|--------|
|
||||
| `seed_demo.py` | Create merchants, stores, customers, products | ✅ Yes | ❌ Missing inventory creation |
|
||||
| `create_default_content_pages.py` | Create platform CMS pages (about, faq, etc.) | ✅ Yes (`create-cms-defaults`) | ✅ Good |
|
||||
| `create_default_content_pages.py` | Create platform CMS pages (homepage, about, faq, etc.) for ALL platforms | ✅ Yes (`create-cms-defaults`) | ✅ Good (consolidated) |
|
||||
| `create_inventory.py` | Create inventory for products | ❌ **NO** | ⚠️ Should be in seed_demo |
|
||||
| `create_landing_page.py` | Create landing pages for stores | ❌ **NO** | ⚠️ Should be in seed_demo |
|
||||
| `create_platform_pages.py` | Create platform pages | ❌ **NO** | 🔴 **DUPLICATE** of create_default_content_pages |
|
||||
| ~~`create_platform_pages.py`~~ | ~~Create platform pages~~ | - | ✅ **DELETED** (merged into create_default_content_pages) |
|
||||
| `init_production.py` | Create admin user + platform alerts | ✅ Yes (`init-prod`) | ✅ Good |
|
||||
| `init_log_settings.py` | Initialize log settings | ❌ NO | ⚠️ Should be in init_production? |
|
||||
|
||||
|
||||
@@ -67,8 +67,8 @@ app/
|
||||
│ └── content_page_service.py # CMS business logic
|
||||
└── main.py # Platform routes (lines 284-404)
|
||||
|
||||
scripts/
|
||||
└── create_platform_pages.py # Seeder script
|
||||
scripts/seed/
|
||||
└── create_default_content_pages.py # Seeder script (all platforms)
|
||||
|
||||
docs/features/
|
||||
└── platform-homepage.md # This file
|
||||
@@ -193,14 +193,17 @@ Manage all platform content pages from a single interface:
|
||||
|
||||
```bash
|
||||
# Create all default platform pages
|
||||
python scripts/seed/create_platform_pages.py
|
||||
python scripts/seed/create_default_content_pages.py
|
||||
```
|
||||
|
||||
This creates:
|
||||
This creates (for all platforms):
|
||||
- Platform Homepage (with modern template)
|
||||
- About Us
|
||||
- FAQ
|
||||
- Contact Us
|
||||
- FAQ
|
||||
- Shipping Policy
|
||||
- Return & Refund Policy
|
||||
- Privacy Policy
|
||||
- Terms of Service
|
||||
- Privacy Policy
|
||||
|
||||
@@ -568,7 +571,7 @@ return templates.TemplateResponse(
|
||||
**Solutions:**
|
||||
1. Run seeder script:
|
||||
```bash
|
||||
python scripts/seed/create_platform_pages.py
|
||||
python scripts/seed/create_default_content_pages.py
|
||||
```
|
||||
|
||||
2. Verify page exists:
|
||||
|
||||
@@ -11,10 +11,10 @@ Quick reference for setting up and customizing the platform homepage and content
|
||||
Run the seeder script to create all default platform pages:
|
||||
|
||||
```bash
|
||||
python scripts/seed/create_platform_pages.py
|
||||
python scripts/seed/create_default_content_pages.py
|
||||
```
|
||||
|
||||
This creates:
|
||||
This creates (for all platforms):
|
||||
- ✅ Platform Homepage (modern template)
|
||||
- ✅ About Us
|
||||
- ✅ FAQ
|
||||
@@ -253,7 +253,7 @@ Result in header: `About | FAQ | Contact`
|
||||
|
||||
**Fix:** Run seeder script
|
||||
```bash
|
||||
python scripts/seed/create_platform_pages.py
|
||||
python scripts/seed/create_default_content_pages.py
|
||||
```
|
||||
|
||||
### Navigation menu is empty
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
"""
|
||||
Create Default Platform Content Pages (CMS)
|
||||
|
||||
This script creates platform-level default content pages that all stores inherit.
|
||||
These pages serve as the baseline content for:
|
||||
This script creates platform-level default content pages for ALL platforms.
|
||||
Pages include:
|
||||
- Platform Homepage (platform marketing page)
|
||||
- About Us
|
||||
- Contact
|
||||
- FAQ
|
||||
@@ -12,14 +13,16 @@ These pages serve as the baseline content for:
|
||||
- Privacy Policy
|
||||
- Terms of Service
|
||||
|
||||
Pages are created per-platform (unique constraint: platform_id + store_id + slug).
|
||||
Stores can override any of these pages with their own custom content.
|
||||
|
||||
Prerequisites:
|
||||
- Database migrations must be applied
|
||||
- content_pages table must exist
|
||||
- Platforms must exist (run init_production.py first)
|
||||
|
||||
Usage:
|
||||
python scripts/create_default_content_pages.py
|
||||
python scripts/seed/create_default_content_pages.py
|
||||
|
||||
# Or with make:
|
||||
make create-cms-defaults
|
||||
@@ -59,7 +62,32 @@ from app.modules.cms.models import ContentPage
|
||||
from app.modules.tenancy.models import Platform
|
||||
|
||||
# ============================================================================
|
||||
# DEFAULT PAGE CONTENT
|
||||
# PLATFORM HOMEPAGE (is_platform_page=True)
|
||||
# ============================================================================
|
||||
|
||||
PLATFORM_HOMEPAGE = {
|
||||
"slug": "platform_homepage",
|
||||
"title": "Welcome to Our Multi-Store Marketplace",
|
||||
"content": """
|
||||
<p class="lead">
|
||||
Connect stores with customers worldwide. Build your online store and reach millions of shoppers.
|
||||
</p>
|
||||
<p>
|
||||
Our platform empowers entrepreneurs to launch their own branded e-commerce stores
|
||||
with minimal effort and maximum impact.
|
||||
</p>
|
||||
""",
|
||||
"meta_description": "Leading multi-store marketplace platform. Connect with thousands of stores and discover millions of products.",
|
||||
"meta_keywords": "marketplace, multi-store, e-commerce, online shopping, platform",
|
||||
"show_in_footer": False,
|
||||
"show_in_header": False,
|
||||
"is_platform_page": True,
|
||||
"template": "modern",
|
||||
"display_order": 0,
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# DEFAULT STORE CONTENT PAGES (is_platform_page=False)
|
||||
# ============================================================================
|
||||
|
||||
DEFAULT_PAGES = [
|
||||
@@ -479,9 +507,58 @@ DEFAULT_PAGES = [
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def _page_exists(db: Session, platform_id: int, slug: str) -> bool:
|
||||
"""Check if a page already exists for the given platform and slug."""
|
||||
existing = db.execute(
|
||||
select(ContentPage).where(
|
||||
ContentPage.platform_id == platform_id,
|
||||
ContentPage.store_id.is_(None),
|
||||
ContentPage.slug == slug,
|
||||
)
|
||||
).scalar_one_or_none()
|
||||
return existing is not None
|
||||
|
||||
|
||||
def _create_page(
|
||||
db: Session, platform_id: int, page_data: dict, *, is_platform_page: bool = False
|
||||
) -> bool:
|
||||
"""Create a single content page. Returns True if created, False if skipped."""
|
||||
slug = page_data["slug"]
|
||||
title = page_data["title"]
|
||||
|
||||
if _page_exists(db, platform_id, slug):
|
||||
print(f" Skipped: {title} (/{slug}) - already exists")
|
||||
return False
|
||||
|
||||
page = ContentPage(
|
||||
platform_id=platform_id,
|
||||
store_id=None,
|
||||
slug=slug,
|
||||
title=title,
|
||||
content=page_data["content"],
|
||||
content_format="html",
|
||||
template=page_data.get("template", "default"),
|
||||
meta_description=page_data["meta_description"],
|
||||
meta_keywords=page_data["meta_keywords"],
|
||||
is_platform_page=is_platform_page,
|
||||
is_published=True,
|
||||
published_at=datetime.now(UTC),
|
||||
show_in_footer=page_data.get("show_in_footer", True),
|
||||
show_in_header=page_data.get("show_in_header", False),
|
||||
show_in_legal=page_data.get("show_in_legal", False),
|
||||
display_order=page_data["display_order"],
|
||||
created_at=datetime.now(UTC),
|
||||
updated_at=datetime.now(UTC),
|
||||
)
|
||||
|
||||
db.add(page)
|
||||
print(f" Created: {title} (/{slug})")
|
||||
return True
|
||||
|
||||
|
||||
def create_default_pages(db: Session) -> None:
|
||||
"""
|
||||
Create default platform content pages.
|
||||
Create default platform content pages for ALL platforms.
|
||||
|
||||
This function is idempotent - it will skip pages that already exist.
|
||||
"""
|
||||
@@ -489,68 +566,52 @@ def create_default_pages(db: Session) -> None:
|
||||
print("Creating Default Platform Content Pages (CMS)")
|
||||
print("=" * 70 + "\n")
|
||||
|
||||
# Resolve OMS platform for platform_id
|
||||
oms_platform = db.execute(
|
||||
select(Platform).where(Platform.code == "oms")
|
||||
).scalar_one_or_none()
|
||||
if not oms_platform:
|
||||
print(" ⚠️ OMS platform not found. Run init_production.py first.")
|
||||
# Load all platforms
|
||||
platforms = db.execute(select(Platform)).scalars().all()
|
||||
if not platforms:
|
||||
print(" No platforms found. Run init_production.py first.")
|
||||
return
|
||||
platform_id = oms_platform.id
|
||||
|
||||
created_count = 0
|
||||
skipped_count = 0
|
||||
total_created = 0
|
||||
total_skipped = 0
|
||||
|
||||
for page_data in DEFAULT_PAGES:
|
||||
# Check if page already exists (platform default with this slug)
|
||||
existing = db.execute(
|
||||
select(ContentPage).where(
|
||||
ContentPage.store_id is None, ContentPage.slug == page_data["slug"]
|
||||
)
|
||||
).scalar_one_or_none()
|
||||
for platform in platforms:
|
||||
print(f" Platform: {platform.name} (code={platform.code})")
|
||||
|
||||
if existing:
|
||||
print(
|
||||
f" ⏭️ Skipped: {page_data['title']} (/{page_data['slug']}) - already exists"
|
||||
)
|
||||
created_count = 0
|
||||
skipped_count = 0
|
||||
|
||||
# Create platform homepage
|
||||
if _create_page(db, platform.id, PLATFORM_HOMEPAGE, is_platform_page=True):
|
||||
created_count += 1
|
||||
else:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# Create new platform default page
|
||||
page = ContentPage(
|
||||
platform_id=platform_id,
|
||||
store_id=None, # Platform default
|
||||
slug=page_data["slug"],
|
||||
title=page_data["title"],
|
||||
content=page_data["content"],
|
||||
content_format="html",
|
||||
meta_description=page_data["meta_description"],
|
||||
meta_keywords=page_data["meta_keywords"],
|
||||
is_published=True,
|
||||
published_at=datetime.now(UTC),
|
||||
show_in_footer=page_data.get("show_in_footer", True),
|
||||
show_in_header=page_data.get("show_in_header", False),
|
||||
show_in_legal=page_data.get("show_in_legal", False),
|
||||
display_order=page_data["display_order"],
|
||||
created_at=datetime.now(UTC),
|
||||
updated_at=datetime.now(UTC),
|
||||
)
|
||||
# Create default store content pages
|
||||
for page_data in DEFAULT_PAGES:
|
||||
if _create_page(db, platform.id, page_data):
|
||||
created_count += 1
|
||||
else:
|
||||
skipped_count += 1
|
||||
|
||||
db.add(page)
|
||||
print(f" ✅ Created: {page_data['title']} (/{page_data['slug']})")
|
||||
created_count += 1
|
||||
print(f" --- {created_count} created, {skipped_count} skipped")
|
||||
print()
|
||||
|
||||
total_created += created_count
|
||||
total_skipped += skipped_count
|
||||
|
||||
db.commit()
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print("=" * 70)
|
||||
print("Summary:")
|
||||
print(f" Created: {created_count} pages")
|
||||
print(f" Skipped: {skipped_count} pages (already exist)")
|
||||
print(f" Total: {created_count + skipped_count} pages")
|
||||
print(f" Platforms: {len(platforms)}")
|
||||
print(f" Created: {total_created} pages")
|
||||
print(f" Skipped: {total_skipped} pages (already exist)")
|
||||
print(f" Total: {total_created + total_skipped} pages")
|
||||
print("=" * 70 + "\n")
|
||||
|
||||
if created_count > 0:
|
||||
print("✅ Default platform content pages created successfully!\n")
|
||||
if total_created > 0:
|
||||
print("Default platform content pages created successfully!\n")
|
||||
print("Next steps:")
|
||||
print(
|
||||
" 1. View pages at: /about, /contact, /faq, /shipping, /returns, /privacy, /terms"
|
||||
@@ -558,7 +619,7 @@ def create_default_pages(db: Session) -> None:
|
||||
print(" 2. Stores can override these pages through the store dashboard")
|
||||
print(" 3. Edit platform defaults through the admin panel\n")
|
||||
else:
|
||||
print("ℹ️ All default pages already exist. No changes made.\n")
|
||||
print("All default pages already exist. No changes made.\n")
|
||||
|
||||
|
||||
# ============================================================================
|
||||
@@ -568,14 +629,14 @@ def create_default_pages(db: Session) -> None:
|
||||
|
||||
def main():
|
||||
"""Main execution function."""
|
||||
print("\n🚀 Starting Default Content Pages Creation Script...\n")
|
||||
print("\nStarting Default Content Pages Creation Script...\n")
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
create_default_pages(db)
|
||||
print("✅ Script completed successfully!\n")
|
||||
print("Script completed successfully!\n")
|
||||
except Exception as e:
|
||||
print(f"\n❌ Error: {e}\n")
|
||||
print(f"\nError: {e}\n")
|
||||
db.rollback()
|
||||
raise
|
||||
finally:
|
||||
|
||||
@@ -1,540 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Create Platform Content Pages
|
||||
|
||||
This script creates default platform-level content pages:
|
||||
- Platform Homepage (slug='platform_homepage')
|
||||
- About Us (slug='about')
|
||||
- FAQ (slug='faq')
|
||||
- Terms of Service (slug='terms')
|
||||
- Privacy Policy (slug='privacy')
|
||||
- Contact Us (slug='contact')
|
||||
|
||||
All pages are created with store_id=NULL (platform-level defaults).
|
||||
|
||||
Usage:
|
||||
python scripts/create_platform_pages.py
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add project root to path
|
||||
project_root = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
# Register all models with SQLAlchemy so string-based relationships resolve
|
||||
for _mod in [
|
||||
"app.modules.billing.models",
|
||||
"app.modules.inventory.models",
|
||||
"app.modules.cart.models",
|
||||
"app.modules.messaging.models",
|
||||
"app.modules.loyalty.models",
|
||||
"app.modules.catalog.models",
|
||||
"app.modules.customers.models",
|
||||
"app.modules.orders.models",
|
||||
"app.modules.marketplace.models",
|
||||
"app.modules.cms.models",
|
||||
]:
|
||||
with contextlib.suppress(ImportError):
|
||||
__import__(_mod)
|
||||
|
||||
from sqlalchemy import select
|
||||
|
||||
from app.core.database import SessionLocal
|
||||
from app.modules.cms.services import content_page_service
|
||||
from app.modules.tenancy.models import Platform
|
||||
|
||||
|
||||
def create_platform_pages():
|
||||
"""Create default platform content pages."""
|
||||
db = SessionLocal()
|
||||
|
||||
try:
|
||||
print("=" * 80)
|
||||
print("CREATING PLATFORM CONTENT PAGES")
|
||||
print("=" * 80)
|
||||
print()
|
||||
|
||||
# Import ContentPage for checking existing pages
|
||||
from app.modules.cms.models import ContentPage
|
||||
|
||||
# Resolve OMS platform
|
||||
oms_platform = db.execute(
|
||||
select(Platform).where(Platform.code == "oms")
|
||||
).scalar_one_or_none()
|
||||
if not oms_platform:
|
||||
print(" ⚠️ OMS platform not found. Run init_production.py first.")
|
||||
return
|
||||
platform_id = oms_platform.id
|
||||
|
||||
# ========================================================================
|
||||
# 1. PLATFORM HOMEPAGE
|
||||
# ========================================================================
|
||||
print("1. Creating Platform Homepage...")
|
||||
|
||||
# Check if already exists
|
||||
existing = (
|
||||
db.query(ContentPage)
|
||||
.filter_by(store_id=None, slug="platform_homepage")
|
||||
.first()
|
||||
)
|
||||
if existing:
|
||||
print(
|
||||
f" ⚠️ Skipped: Platform Homepage - already exists (ID: {existing.id})"
|
||||
)
|
||||
else:
|
||||
try:
|
||||
homepage = content_page_service.create_page(
|
||||
db,
|
||||
platform_id=platform_id,
|
||||
slug="platform_homepage",
|
||||
title="Welcome to Our Multi-Store Marketplace",
|
||||
content="""
|
||||
<p class="lead">
|
||||
Connect stores with customers worldwide. Build your online store and reach millions of shoppers.
|
||||
</p>
|
||||
<p>
|
||||
Our platform empowers entrepreneurs to launch their own branded e-commerce stores
|
||||
with minimal effort and maximum impact.
|
||||
</p>
|
||||
""",
|
||||
template="modern", # Uses platform/homepage-modern.html
|
||||
store_id=None, # Platform-level page
|
||||
is_published=True,
|
||||
show_in_header=False, # Homepage is not in menu (it's the root)
|
||||
show_in_footer=False,
|
||||
display_order=0,
|
||||
meta_description="Leading multi-store marketplace platform. Connect with thousands of stores and discover millions of products.",
|
||||
meta_keywords="marketplace, multi-store, e-commerce, online shopping, platform",
|
||||
)
|
||||
print(f" ✅ Created: {homepage.title} (/{homepage.slug})")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Error: Platform Homepage - {str(e)}")
|
||||
|
||||
# ========================================================================
|
||||
# 2. ABOUT US
|
||||
# ========================================================================
|
||||
print("2. Creating About Us page...")
|
||||
|
||||
existing = db.query(ContentPage).filter_by(store_id=None, slug="about").first()
|
||||
if existing:
|
||||
print(f" ⚠️ Skipped: About Us - already exists (ID: {existing.id})")
|
||||
else:
|
||||
try:
|
||||
about = content_page_service.create_page(
|
||||
db,
|
||||
platform_id=platform_id,
|
||||
slug="about",
|
||||
title="About Us",
|
||||
content="""
|
||||
<h2>Our Mission</h2>
|
||||
<p>
|
||||
We're on a mission to democratize e-commerce by providing powerful,
|
||||
easy-to-use tools for entrepreneurs worldwide.
|
||||
</p>
|
||||
|
||||
<h2>Our Story</h2>
|
||||
<p>
|
||||
Founded in 2024, our platform has grown to serve over 10,000 active stores
|
||||
and millions of customers around the globe. We believe that everyone should
|
||||
have the opportunity to build and grow their own online business.
|
||||
</p>
|
||||
|
||||
<h2>Why Choose Us?</h2>
|
||||
<ul>
|
||||
<li><strong>Easy to Start:</strong> Launch your store in minutes, not months</li>
|
||||
<li><strong>Powerful Tools:</strong> Everything you need to succeed in one platform</li>
|
||||
<li><strong>Scalable:</strong> Grow from startup to enterprise seamlessly</li>
|
||||
<li><strong>Reliable:</strong> 99.9% uptime guarantee with 24/7 support</li>
|
||||
</ul>
|
||||
|
||||
<h2>Our Values</h2>
|
||||
<ul>
|
||||
<li><strong>Innovation:</strong> We constantly improve and evolve our platform</li>
|
||||
<li><strong>Transparency:</strong> No hidden fees, no surprises</li>
|
||||
<li><strong>Community:</strong> We succeed when our stores succeed</li>
|
||||
<li><strong>Excellence:</strong> We strive for the highest quality in everything we do</li>
|
||||
</ul>
|
||||
""",
|
||||
store_id=None,
|
||||
is_published=True,
|
||||
show_in_header=True, # Show in header navigation
|
||||
show_in_footer=True, # Show in footer
|
||||
display_order=1,
|
||||
meta_description="Learn about our mission to democratize e-commerce and empower entrepreneurs worldwide.",
|
||||
meta_keywords="about us, mission, vision, values, merchant",
|
||||
)
|
||||
print(f" ✅ Created: {about.title} (/{about.slug})")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Error: About Us - {str(e)}")
|
||||
|
||||
# ========================================================================
|
||||
# 3. FAQ
|
||||
# ========================================================================
|
||||
print("3. Creating FAQ page...")
|
||||
|
||||
existing = db.query(ContentPage).filter_by(store_id=None, slug="faq").first()
|
||||
if existing:
|
||||
print(f" ⚠️ Skipped: FAQ - already exists (ID: {existing.id})")
|
||||
else:
|
||||
try:
|
||||
faq = content_page_service.create_page(
|
||||
db,
|
||||
platform_id=platform_id,
|
||||
slug="faq",
|
||||
title="Frequently Asked Questions",
|
||||
content="""
|
||||
<h2>Getting Started</h2>
|
||||
|
||||
<h3>How do I create a store account?</h3>
|
||||
<p>
|
||||
Contact our sales team to get started. We'll set up your account and provide
|
||||
you with everything you need to launch your store.
|
||||
</p>
|
||||
|
||||
<h3>How long does it take to set up my store?</h3>
|
||||
<p>
|
||||
Most stores can launch their store in less than 24 hours. Our team will guide
|
||||
you through the setup process step by step.
|
||||
</p>
|
||||
|
||||
<h2>Pricing & Payment</h2>
|
||||
|
||||
<h3>What are your pricing plans?</h3>
|
||||
<p>
|
||||
We offer flexible pricing plans based on your business needs. Contact us for
|
||||
detailed pricing information and to find the plan that's right for you.
|
||||
</p>
|
||||
|
||||
<h3>When do I get paid?</h3>
|
||||
<p>
|
||||
Payments are processed weekly, with funds typically reaching your account
|
||||
within 2-3 business days.
|
||||
</p>
|
||||
|
||||
<h2>Features & Support</h2>
|
||||
|
||||
<h3>Can I customize my store's appearance?</h3>
|
||||
<p>
|
||||
Yes! Our platform supports full theme customization including colors, fonts,
|
||||
logos, and layouts. Make your store truly yours.
|
||||
</p>
|
||||
|
||||
<h3>What kind of support do you provide?</h3>
|
||||
<p>
|
||||
We offer 24/7 email support for all stores, with priority phone support
|
||||
available for enterprise plans.
|
||||
</p>
|
||||
|
||||
<h2>Technical Questions</h2>
|
||||
|
||||
<h3>Do I need technical knowledge to use the platform?</h3>
|
||||
<p>
|
||||
No! Our platform is designed to be user-friendly for everyone. However, if you
|
||||
want to customize advanced features, our documentation and support team are here to help.
|
||||
</p>
|
||||
|
||||
<h3>Can I integrate with other tools?</h3>
|
||||
<p>
|
||||
Yes, we support integrations with popular payment gateways, shipping providers,
|
||||
and marketing tools.
|
||||
</p>
|
||||
""",
|
||||
store_id=None,
|
||||
is_published=True,
|
||||
show_in_header=True, # Show in header navigation
|
||||
show_in_footer=True,
|
||||
display_order=2,
|
||||
meta_description="Find answers to common questions about our marketplace platform.",
|
||||
meta_keywords="faq, frequently asked questions, help, support",
|
||||
)
|
||||
print(f" ✅ Created: {faq.title} (/{faq.slug})")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Error: FAQ - {str(e)}")
|
||||
|
||||
# ========================================================================
|
||||
# 4. CONTACT US
|
||||
# ========================================================================
|
||||
print("4. Creating Contact Us page...")
|
||||
|
||||
existing = (
|
||||
db.query(ContentPage).filter_by(store_id=None, slug="contact").first()
|
||||
)
|
||||
if existing:
|
||||
print(f" ⚠️ Skipped: Contact Us - already exists (ID: {existing.id})")
|
||||
else:
|
||||
try:
|
||||
contact = content_page_service.create_page(
|
||||
db,
|
||||
platform_id=platform_id,
|
||||
slug="contact",
|
||||
title="Contact Us",
|
||||
content="""
|
||||
<h2>Get in Touch</h2>
|
||||
<p>
|
||||
We'd love to hear from you! Whether you have questions about our platform,
|
||||
need technical support, or want to discuss partnership opportunities, our
|
||||
team is here to help.
|
||||
</p>
|
||||
|
||||
<h2>Contact Information</h2>
|
||||
<ul>
|
||||
<li><strong>Email:</strong> support@marketplace.com</li>
|
||||
<li><strong>Phone:</strong> +1 (555) 123-4567</li>
|
||||
<li><strong>Hours:</strong> Monday - Friday, 9 AM - 6 PM PST</li>
|
||||
</ul>
|
||||
|
||||
<h2>Office Address</h2>
|
||||
<p>
|
||||
123 Business Street, Suite 100<br>
|
||||
San Francisco, CA 94102<br>
|
||||
United States
|
||||
</p>
|
||||
|
||||
<h2>Sales Inquiries</h2>
|
||||
<p>
|
||||
Interested in launching your store on our platform?<br>
|
||||
Email: <a href="mailto:sales@marketplace.com">sales@marketplace.com</a>
|
||||
</p>
|
||||
|
||||
<h2>Technical Support</h2>
|
||||
<p>
|
||||
Need help with your store?<br>
|
||||
Email: <a href="mailto:support@marketplace.com">support@marketplace.com</a><br>
|
||||
24/7 email support for all stores
|
||||
</p>
|
||||
|
||||
<h2>Media & Press</h2>
|
||||
<p>
|
||||
For media inquiries and press releases:<br>
|
||||
Email: <a href="mailto:press@marketplace.com">press@marketplace.com</a>
|
||||
</p>
|
||||
""",
|
||||
store_id=None,
|
||||
is_published=True,
|
||||
show_in_header=True, # Show in header navigation
|
||||
show_in_footer=True,
|
||||
display_order=3,
|
||||
meta_description="Get in touch with our team. We're here to help you succeed.",
|
||||
meta_keywords="contact, support, email, phone, address",
|
||||
)
|
||||
print(f" ✅ Created: {contact.title} (/{contact.slug})")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Error: Contact Us - {str(e)}")
|
||||
|
||||
# ========================================================================
|
||||
# 5. TERMS OF SERVICE
|
||||
# ========================================================================
|
||||
print("5. Creating Terms of Service page...")
|
||||
|
||||
existing = db.query(ContentPage).filter_by(store_id=None, slug="terms").first()
|
||||
if existing:
|
||||
print(
|
||||
f" ⚠️ Skipped: Terms of Service - already exists (ID: {existing.id})"
|
||||
)
|
||||
else:
|
||||
try:
|
||||
terms = content_page_service.create_page(
|
||||
db,
|
||||
platform_id=platform_id,
|
||||
slug="terms",
|
||||
title="Terms of Service",
|
||||
content="""
|
||||
<p><em>Last updated: January 1, 2024</em></p>
|
||||
|
||||
<h2>1. Acceptance of Terms</h2>
|
||||
<p>
|
||||
By accessing and using this marketplace platform, you accept and agree to be
|
||||
bound by the terms and provisions of this agreement.
|
||||
</p>
|
||||
|
||||
<h2>2. Use License</h2>
|
||||
<p>
|
||||
Permission is granted to temporarily access the materials on our platform for
|
||||
personal, non-commercial transitory viewing only.
|
||||
</p>
|
||||
|
||||
<h2>3. Account Terms</h2>
|
||||
<ul>
|
||||
<li>You must be at least 18 years old to use our platform</li>
|
||||
<li>You must provide accurate and complete registration information</li>
|
||||
<li>You are responsible for maintaining the security of your account</li>
|
||||
<li>You are responsible for all activities under your account</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Store Responsibilities</h2>
|
||||
<ul>
|
||||
<li>Provide accurate product information and pricing</li>
|
||||
<li>Honor all orders and commitments made through the platform</li>
|
||||
<li>Comply with all applicable laws and regulations</li>
|
||||
<li>Maintain appropriate customer service standards</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Prohibited Activities</h2>
|
||||
<p>You may not use our platform to:</p>
|
||||
<ul>
|
||||
<li>Engage in any fraudulent or illegal activities</li>
|
||||
<li>Violate any intellectual property rights</li>
|
||||
<li>Transmit harmful code or malware</li>
|
||||
<li>Interfere with platform operations</li>
|
||||
</ul>
|
||||
|
||||
<h2>6. Termination</h2>
|
||||
<p>
|
||||
We reserve the right to terminate or suspend your account at any time for
|
||||
violation of these terms.
|
||||
</p>
|
||||
|
||||
<h2>7. Limitation of Liability</h2>
|
||||
<p>
|
||||
In no event shall our merchant be liable for any damages arising out of the
|
||||
use or inability to use our platform.
|
||||
</p>
|
||||
|
||||
<h2>8. Changes to Terms</h2>
|
||||
<p>
|
||||
We reserve the right to modify these terms at any time. We will notify users
|
||||
of any changes via email.
|
||||
</p>
|
||||
|
||||
<h2>9. Contact</h2>
|
||||
<p>
|
||||
If you have any questions about these Terms, please contact us at
|
||||
<a href="mailto:legal@marketplace.com">legal@marketplace.com</a>.
|
||||
</p>
|
||||
""",
|
||||
store_id=None,
|
||||
is_published=True,
|
||||
show_in_header=False, # Too legal for header
|
||||
show_in_footer=True, # Show in footer
|
||||
display_order=10,
|
||||
meta_description="Read our terms of service and platform usage policies.",
|
||||
meta_keywords="terms of service, terms, legal, policy, agreement",
|
||||
)
|
||||
print(f" ✅ Created: {terms.title} (/{terms.slug})")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Error: Terms of Service - {str(e)}")
|
||||
|
||||
# ========================================================================
|
||||
# 6. PRIVACY POLICY
|
||||
# ========================================================================
|
||||
print("6. Creating Privacy Policy page...")
|
||||
|
||||
existing = (
|
||||
db.query(ContentPage).filter_by(store_id=None, slug="privacy").first()
|
||||
)
|
||||
if existing:
|
||||
print(f" ⚠️ Skipped: Privacy Policy - already exists (ID: {existing.id})")
|
||||
else:
|
||||
try:
|
||||
privacy = content_page_service.create_page(
|
||||
db,
|
||||
platform_id=platform_id,
|
||||
slug="privacy",
|
||||
title="Privacy Policy",
|
||||
content="""
|
||||
<p><em>Last updated: January 1, 2024</em></p>
|
||||
|
||||
<h2>1. Information We Collect</h2>
|
||||
<p>We collect information you provide directly to us, including:</p>
|
||||
<ul>
|
||||
<li>Name, email address, and contact information</li>
|
||||
<li>Payment and billing information</li>
|
||||
<li>Store and product information</li>
|
||||
<li>Communications with us</li>
|
||||
</ul>
|
||||
|
||||
<h2>2. How We Use Your Information</h2>
|
||||
<p>We use the information we collect to:</p>
|
||||
<ul>
|
||||
<li>Provide, maintain, and improve our services</li>
|
||||
<li>Process transactions and send related information</li>
|
||||
<li>Send technical notices and support messages</li>
|
||||
<li>Respond to your comments and questions</li>
|
||||
<li>Monitor and analyze trends and usage</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Information Sharing</h2>
|
||||
<p>
|
||||
We do not sell your personal information. We may share information with:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Service providers who help us operate our platform</li>
|
||||
<li>Law enforcement when required by law</li>
|
||||
<li>Other parties with your consent</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Data Security</h2>
|
||||
<p>
|
||||
We implement appropriate security measures to protect your personal information.
|
||||
However, no method of transmission over the internet is 100% secure.
|
||||
</p>
|
||||
|
||||
<h2>5. Your Rights</h2>
|
||||
<p>You have the right to:</p>
|
||||
<ul>
|
||||
<li>Access your personal information</li>
|
||||
<li>Correct inaccurate information</li>
|
||||
<li>Request deletion of your information</li>
|
||||
<li>Opt-out of marketing communications</li>
|
||||
</ul>
|
||||
|
||||
<h2>6. Cookies</h2>
|
||||
<p>
|
||||
We use cookies and similar tracking technologies to track activity on our
|
||||
platform and hold certain information. You can instruct your browser to
|
||||
refuse cookies.
|
||||
</p>
|
||||
|
||||
<h2>7. Changes to This Policy</h2>
|
||||
<p>
|
||||
We may update this privacy policy from time to time. We will notify you of
|
||||
any changes by posting the new policy on this page.
|
||||
</p>
|
||||
|
||||
<h2>8. Contact Us</h2>
|
||||
<p>
|
||||
If you have questions about this Privacy Policy, please contact us at
|
||||
<a href="mailto:privacy@marketplace.com">privacy@marketplace.com</a>.
|
||||
</p>
|
||||
""",
|
||||
store_id=None,
|
||||
is_published=True,
|
||||
show_in_header=False, # Too legal for header
|
||||
show_in_footer=True, # Show in footer
|
||||
display_order=11,
|
||||
meta_description="Learn how we collect, use, and protect your personal information.",
|
||||
meta_keywords="privacy policy, privacy, data protection, gdpr, personal information",
|
||||
)
|
||||
print(f" ✅ Created: {privacy.title} (/{privacy.slug})")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Error: Privacy Policy - {str(e)}")
|
||||
|
||||
db.commit()
|
||||
|
||||
print()
|
||||
print("=" * 80)
|
||||
print("✅ Platform pages creation completed successfully!")
|
||||
print("=" * 80)
|
||||
print()
|
||||
print("Created pages:")
|
||||
print(" - Platform Homepage: http://localhost:8000/")
|
||||
print(" - About Us: http://localhost:8000/about")
|
||||
print(" - FAQ: http://localhost:8000/faq")
|
||||
print(" - Contact Us: http://localhost:8000/contact")
|
||||
print(" - Terms of Service: http://localhost:8000/terms")
|
||||
print(" - Privacy Policy: http://localhost:8000/privacy")
|
||||
print()
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ Error: {e}")
|
||||
db.rollback()
|
||||
raise
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
create_platform_pages()
|
||||
@@ -543,8 +543,7 @@ def main():
|
||||
init_scripts = [
|
||||
("init_production.py", "Admin user and platform settings"),
|
||||
("init_log_settings.py", "Log settings"),
|
||||
("create_default_content_pages.py", "Default CMS pages"),
|
||||
("create_platform_pages.py", "Platform pages and landing"),
|
||||
("create_default_content_pages.py", "Default CMS pages (all platforms)"),
|
||||
("seed_email_templates.py", "Email templates"),
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user