Files
membership-be/permissions_seed.py
2025-12-16 20:03:50 +07:00

550 lines
16 KiB
Python

"""
Permission Seeding Script
This script populates the database with 60+ granular permissions for RBAC.
Permissions are organized into 9 modules: users, events, subscriptions,
financials, newsletters, bylaws, gallery, settings, and permissions.
Usage:
python permissions_seed.py
Environment Variables:
DATABASE_URL - PostgreSQL connection string
"""
import os
import sys
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from database import Base
from models import Permission, RolePermission, UserRole
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Database connection
DATABASE_URL = os.getenv("DATABASE_URL")
if not DATABASE_URL:
print("Error: DATABASE_URL environment variable not set")
sys.exit(1)
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# ============================================================
# Permission Definitions
# ============================================================
PERMISSIONS = [
# ========== USERS MODULE ==========
{
"code": "users.view",
"name": "View Users",
"description": "View user list and user profiles",
"module": "users"
},
{
"code": "users.create",
"name": "Create Users",
"description": "Create new users and send invitations",
"module": "users"
},
{
"code": "users.edit",
"name": "Edit Users",
"description": "Edit user profiles and information",
"module": "users"
},
{
"code": "users.delete",
"name": "Delete Users",
"description": "Delete user accounts",
"module": "users"
},
{
"code": "users.status",
"name": "Change User Status",
"description": "Change user status (active, inactive, etc.)",
"module": "users"
},
{
"code": "users.approve",
"name": "Approve/Validate Users",
"description": "Approve or validate user applications",
"module": "users"
},
{
"code": "users.export",
"name": "Export Users",
"description": "Export user data to CSV",
"module": "users"
},
{
"code": "users.import",
"name": "Import Users",
"description": "Import users from CSV",
"module": "users"
},
{
"code": "users.reset_password",
"name": "Reset User Password",
"description": "Reset user passwords via email",
"module": "users"
},
{
"code": "users.resend_verification",
"name": "Resend Verification Email",
"description": "Resend email verification links",
"module": "users"
},
# ========== EVENTS MODULE ==========
{
"code": "events.view",
"name": "View Events",
"description": "View event list and event details",
"module": "events"
},
{
"code": "events.create",
"name": "Create Events",
"description": "Create new events",
"module": "events"
},
{
"code": "events.edit",
"name": "Edit Events",
"description": "Edit existing events",
"module": "events"
},
{
"code": "events.delete",
"name": "Delete Events",
"description": "Delete events",
"module": "events"
},
{
"code": "events.publish",
"name": "Publish Events",
"description": "Publish or unpublish events",
"module": "events"
},
{
"code": "events.attendance",
"name": "Mark Event Attendance",
"description": "Mark user attendance for events",
"module": "events"
},
{
"code": "events.rsvps",
"name": "View Event RSVPs",
"description": "View and manage event RSVPs",
"module": "events"
},
{
"code": "events.calendar_export",
"name": "Export Event Calendar",
"description": "Export events to iCal format",
"module": "events"
},
# ========== SUBSCRIPTIONS MODULE ==========
{
"code": "subscriptions.view",
"name": "View Subscriptions",
"description": "View subscription list and details",
"module": "subscriptions"
},
{
"code": "subscriptions.create",
"name": "Create Subscriptions",
"description": "Create manual subscriptions for users",
"module": "subscriptions"
},
{
"code": "subscriptions.edit",
"name": "Edit Subscriptions",
"description": "Edit subscription details",
"module": "subscriptions"
},
{
"code": "subscriptions.cancel",
"name": "Cancel Subscriptions",
"description": "Cancel user subscriptions",
"module": "subscriptions"
},
{
"code": "subscriptions.activate",
"name": "Activate Subscriptions",
"description": "Manually activate subscriptions",
"module": "subscriptions"
},
{
"code": "subscriptions.plans",
"name": "Manage Subscription Plans",
"description": "Create and edit subscription plans",
"module": "subscriptions"
},
# ========== FINANCIALS MODULE ==========
{
"code": "financials.view",
"name": "View Financial Reports",
"description": "View financial reports and dashboards",
"module": "financials"
},
{
"code": "financials.create",
"name": "Create Financial Reports",
"description": "Upload and create financial reports",
"module": "financials"
},
{
"code": "financials.edit",
"name": "Edit Financial Reports",
"description": "Edit existing financial reports",
"module": "financials"
},
{
"code": "financials.delete",
"name": "Delete Financial Reports",
"description": "Delete financial reports",
"module": "financials"
},
{
"code": "financials.export",
"name": "Export Financial Data",
"description": "Export financial data to CSV/PDF",
"module": "financials"
},
{
"code": "financials.payments",
"name": "View Payment Details",
"description": "View detailed payment information",
"module": "financials"
},
# ========== NEWSLETTERS MODULE ==========
{
"code": "newsletters.view",
"name": "View Newsletters",
"description": "View newsletter archives",
"module": "newsletters"
},
{
"code": "newsletters.create",
"name": "Create Newsletters",
"description": "Upload and create newsletters",
"module": "newsletters"
},
{
"code": "newsletters.edit",
"name": "Edit Newsletters",
"description": "Edit existing newsletters",
"module": "newsletters"
},
{
"code": "newsletters.delete",
"name": "Delete Newsletters",
"description": "Delete newsletter archives",
"module": "newsletters"
},
{
"code": "newsletters.send",
"name": "Send Newsletters",
"description": "Send newsletter emails to subscribers",
"module": "newsletters"
},
{
"code": "newsletters.subscribers",
"name": "Manage Newsletter Subscribers",
"description": "View and manage newsletter subscribers",
"module": "newsletters"
},
# ========== BYLAWS MODULE ==========
{
"code": "bylaws.view",
"name": "View Bylaws",
"description": "View organization bylaws documents",
"module": "bylaws"
},
{
"code": "bylaws.create",
"name": "Create Bylaws",
"description": "Upload new bylaws documents",
"module": "bylaws"
},
{
"code": "bylaws.edit",
"name": "Edit Bylaws",
"description": "Edit existing bylaws documents",
"module": "bylaws"
},
{
"code": "bylaws.delete",
"name": "Delete Bylaws",
"description": "Delete bylaws documents",
"module": "bylaws"
},
{
"code": "bylaws.publish",
"name": "Publish Bylaws",
"description": "Mark bylaws as current/published version",
"module": "bylaws"
},
# ========== GALLERY MODULE ==========
{
"code": "gallery.view",
"name": "View Event Gallery",
"description": "View event gallery photos",
"module": "gallery"
},
{
"code": "gallery.upload",
"name": "Upload Photos",
"description": "Upload photos to event galleries",
"module": "gallery"
},
{
"code": "gallery.edit",
"name": "Edit Photos",
"description": "Edit photo captions and details",
"module": "gallery"
},
{
"code": "gallery.delete",
"name": "Delete Photos",
"description": "Delete photos from galleries",
"module": "gallery"
},
{
"code": "gallery.moderate",
"name": "Moderate Gallery Content",
"description": "Approve/reject uploaded photos",
"module": "gallery"
},
# ========== SETTINGS MODULE ==========
{
"code": "settings.view",
"name": "View Settings",
"description": "View application settings",
"module": "settings"
},
{
"code": "settings.edit",
"name": "Edit Settings",
"description": "Edit application settings",
"module": "settings"
},
{
"code": "settings.email_templates",
"name": "Manage Email Templates",
"description": "Edit email templates and notifications",
"module": "settings"
},
{
"code": "settings.storage",
"name": "Manage Storage",
"description": "View and manage storage usage",
"module": "settings"
},
{
"code": "settings.backup",
"name": "Backup & Restore",
"description": "Create and restore database backups",
"module": "settings"
},
{
"code": "settings.logs",
"name": "View System Logs",
"description": "View application and audit logs",
"module": "settings"
},
# ========== PERMISSIONS MODULE (SUPERADMIN ONLY) ==========
{
"code": "permissions.view",
"name": "View Permissions",
"description": "View permission definitions and assignments",
"module": "permissions"
},
{
"code": "permissions.assign",
"name": "Assign Permissions",
"description": "Assign permissions to roles (SUPERADMIN ONLY)",
"module": "permissions"
},
{
"code": "permissions.manage_roles",
"name": "Manage Roles",
"description": "Create and manage user roles",
"module": "permissions"
},
{
"code": "permissions.audit",
"name": "View Permission Audit Log",
"description": "View permission change audit logs",
"module": "permissions"
},
]
# Default permission assignments for each role
DEFAULT_ROLE_PERMISSIONS = {
UserRole.guest: [], # Guests have no admin permissions
UserRole.member: [
# Members can view public content
"events.view",
"events.rsvps",
"events.calendar_export",
"newsletters.view",
"bylaws.view",
"gallery.view",
],
UserRole.admin: [
# Admins have most permissions except RBAC management
"users.view",
"users.create",
"users.edit",
"users.status",
"users.approve",
"users.export",
"users.import",
"users.reset_password",
"users.resend_verification",
"events.view",
"events.create",
"events.edit",
"events.delete",
"events.publish",
"events.attendance",
"events.rsvps",
"events.calendar_export",
"subscriptions.view",
"subscriptions.create",
"subscriptions.edit",
"subscriptions.cancel",
"subscriptions.activate",
"subscriptions.plans",
"financials.view",
"financials.create",
"financials.edit",
"financials.delete",
"financials.export",
"financials.payments",
"newsletters.view",
"newsletters.create",
"newsletters.edit",
"newsletters.delete",
"newsletters.send",
"newsletters.subscribers",
"bylaws.view",
"bylaws.create",
"bylaws.edit",
"bylaws.delete",
"bylaws.publish",
"gallery.view",
"gallery.upload",
"gallery.edit",
"gallery.delete",
"gallery.moderate",
"settings.view",
"settings.edit",
"settings.email_templates",
"settings.storage",
"settings.logs",
],
# Superadmin gets all permissions automatically in code,
# so we don't need to explicitly assign them
UserRole.superadmin: []
}
def seed_permissions():
"""Seed permissions and default role assignments"""
db = SessionLocal()
try:
print("🌱 Starting permission seeding...")
# Step 1: Clear existing permissions and role_permissions
print("\n📦 Clearing existing permissions and role assignments...")
db.query(RolePermission).delete()
db.query(Permission).delete()
db.commit()
print("✓ Cleared existing data")
# Step 2: Create permissions
print(f"\n📝 Creating {len(PERMISSIONS)} permissions...")
permission_map = {} # Map code to permission object
for perm_data in PERMISSIONS:
permission = Permission(
code=perm_data["code"],
name=perm_data["name"],
description=perm_data["description"],
module=perm_data["module"]
)
db.add(permission)
permission_map[perm_data["code"]] = permission
db.commit()
print(f"✓ Created {len(PERMISSIONS)} permissions")
# Step 3: Assign default permissions to roles
print("\n🔐 Assigning default permissions to roles...")
for role, permission_codes in DEFAULT_ROLE_PERMISSIONS.items():
if not permission_codes:
print(f"{role.value}: No default permissions (handled in code)")
continue
for code in permission_codes:
if code not in permission_map:
print(f" ⚠️ Warning: Permission '{code}' not found for role {role.value}")
continue
role_permission = RolePermission(
role=role,
permission_id=permission_map[code].id
)
db.add(role_permission)
db.commit()
print(f"{role.value}: Assigned {len(permission_codes)} permissions")
# Step 4: Summary
print("\n" + "="*60)
print("📊 Seeding Summary:")
print("="*60)
# Count permissions by module
modules = {}
for perm in PERMISSIONS:
module = perm["module"]
modules[module] = modules.get(module, 0) + 1
print("\nPermissions by module:")
for module, count in sorted(modules.items()):
print(f"{module.capitalize()}: {count} permissions")
print(f"\nTotal permissions: {len(PERMISSIONS)}")
print("\n✅ Permission seeding completed successfully!")
except Exception as e:
db.rollback()
print(f"\n❌ Error seeding permissions: {str(e)}")
raise
finally:
db.close()
if __name__ == "__main__":
seed_permissions()