Merge to LOAF-PROD for Demo #27
Binary file not shown.
@@ -127,6 +127,10 @@ PERMISSIONS = [
|
||||
# ========== REGISTRATION MODULE (2) ==========
|
||||
{"code": "registration.view", "name": "View Registration Settings", "description": "View registration form schema and settings", "module": "registration"},
|
||||
{"code": "registration.manage", "name": "Manage Registration Form", "description": "Edit registration form schema, steps, and fields", "module": "registration"},
|
||||
|
||||
# ========== DIRECTORY MODULE (2) ==========
|
||||
{"code": "directory.view", "name": "View Directory Settings", "description": "View member directory field configuration", "module": "directory"},
|
||||
{"code": "directory.manage", "name": "Manage Directory Fields", "description": "Enable/disable directory fields shown in Profile and Directory pages", "module": "directory"},
|
||||
]
|
||||
|
||||
# Default system roles that must exist
|
||||
@@ -210,6 +214,8 @@ DEFAULT_ROLE_PERMISSIONS = {
|
||||
"payment_methods.delete", "payment_methods.set_default",
|
||||
# Registration form management
|
||||
"registration.view", "registration.manage",
|
||||
# Directory configuration
|
||||
"directory.view", "directory.manage",
|
||||
],
|
||||
|
||||
"superadmin": [
|
||||
|
||||
210
server.py
210
server.py
@@ -15,6 +15,7 @@ import uuid
|
||||
import secrets
|
||||
import csv
|
||||
import io
|
||||
import json
|
||||
|
||||
from database import engine, get_db, Base
|
||||
from models import User, Event, EventRSVP, UserStatus, UserRole, RSVPStatus, SubscriptionPlan, Subscription, SubscriptionStatus, StorageUsage, EventGallery, NewsletterArchive, FinancialReport, BylawsDocument, Permission, RolePermission, Role, UserInvitation, InvitationStatus, ImportJob, ImportJobStatus, ImportRollbackAudit, Donation, DonationType, DonationStatus, SystemSettings, PaymentMethod, PaymentMethodType
|
||||
@@ -2727,6 +2728,215 @@ async def get_field_types(
|
||||
return FIELD_TYPES
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Directory Configuration Endpoints
|
||||
# ============================================================================
|
||||
|
||||
# Default directory configuration - defines which fields are shown in Profile and Directory
|
||||
DEFAULT_DIRECTORY_CONFIG = {
|
||||
"version": "1.0",
|
||||
"fields": {
|
||||
"show_in_directory": {
|
||||
"enabled": True,
|
||||
"label": "Show in Directory",
|
||||
"description": "Allow members to opt-in to the member directory",
|
||||
"required": False,
|
||||
"editable": True # Whether this field can be disabled by admin
|
||||
},
|
||||
"directory_email": {
|
||||
"enabled": True,
|
||||
"label": "Directory Email",
|
||||
"description": "Email address visible to other members",
|
||||
"required": False,
|
||||
"editable": True
|
||||
},
|
||||
"directory_bio": {
|
||||
"enabled": True,
|
||||
"label": "Bio",
|
||||
"description": "Short biography for the directory",
|
||||
"required": False,
|
||||
"editable": True
|
||||
},
|
||||
"directory_address": {
|
||||
"enabled": True,
|
||||
"label": "Address",
|
||||
"description": "Address visible to other members",
|
||||
"required": False,
|
||||
"editable": True
|
||||
},
|
||||
"directory_phone": {
|
||||
"enabled": True,
|
||||
"label": "Phone",
|
||||
"description": "Phone number visible to other members",
|
||||
"required": False,
|
||||
"editable": True
|
||||
},
|
||||
"directory_dob": {
|
||||
"enabled": True,
|
||||
"label": "Birthday",
|
||||
"description": "Birthday visible to other members",
|
||||
"required": False,
|
||||
"editable": True
|
||||
},
|
||||
"directory_partner_name": {
|
||||
"enabled": True,
|
||||
"label": "Partner Name",
|
||||
"description": "Partner name visible to other members",
|
||||
"required": False,
|
||||
"editable": True
|
||||
},
|
||||
"volunteer_interests": {
|
||||
"enabled": True,
|
||||
"label": "Volunteer Interests",
|
||||
"description": "Volunteer interests shown in directory profile",
|
||||
"required": False,
|
||||
"editable": True
|
||||
},
|
||||
"social_media": {
|
||||
"enabled": True,
|
||||
"label": "Social Media Links",
|
||||
"description": "Social media links (Facebook, Instagram, Twitter, LinkedIn)",
|
||||
"required": False,
|
||||
"editable": True
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_directory_config(db: Session) -> dict:
|
||||
"""Get directory configuration from database or return default"""
|
||||
setting = db.query(SystemSettings).filter(
|
||||
SystemSettings.setting_key == "directory.config"
|
||||
).first()
|
||||
|
||||
if setting and setting.setting_value:
|
||||
try:
|
||||
return json.loads(setting.setting_value)
|
||||
except json.JSONDecodeError:
|
||||
return DEFAULT_DIRECTORY_CONFIG
|
||||
return DEFAULT_DIRECTORY_CONFIG
|
||||
|
||||
|
||||
def save_directory_config(db: Session, config: dict, user_id) -> dict:
|
||||
"""Save directory configuration to database"""
|
||||
setting = db.query(SystemSettings).filter(
|
||||
SystemSettings.setting_key == "directory.config"
|
||||
).first()
|
||||
|
||||
config_json = json.dumps(config)
|
||||
|
||||
if setting:
|
||||
setting.setting_value = config_json
|
||||
setting.updated_by = user_id
|
||||
setting.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
from models import SettingType
|
||||
setting = SystemSettings(
|
||||
setting_key="directory.config",
|
||||
setting_value=config_json,
|
||||
setting_type=SettingType.json,
|
||||
description="Member directory field configuration",
|
||||
updated_by=user_id
|
||||
)
|
||||
db.add(setting)
|
||||
|
||||
db.commit()
|
||||
db.refresh(setting)
|
||||
return json.loads(setting.setting_value)
|
||||
|
||||
|
||||
# Public endpoint - get directory field configuration
|
||||
@api_router.get("/directory/config")
|
||||
async def get_public_directory_config(db: Session = Depends(get_db)):
|
||||
"""Get directory field configuration (public endpoint for Profile page)"""
|
||||
config = get_directory_config(db)
|
||||
# Return only the fields and their enabled status for frontend
|
||||
return {
|
||||
"fields": {
|
||||
field_id: {
|
||||
"enabled": field_data.get("enabled", True),
|
||||
"label": field_data.get("label", field_id),
|
||||
"required": field_data.get("required", False)
|
||||
}
|
||||
for field_id, field_data in config.get("fields", {}).items()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Admin endpoint - get full directory configuration with metadata
|
||||
@api_router.get("/admin/directory/config")
|
||||
async def get_admin_directory_config(
|
||||
current_user: User = Depends(require_permission("directory.view")),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get full directory configuration for admin"""
|
||||
config = get_directory_config(db)
|
||||
|
||||
# Get metadata
|
||||
setting = db.query(SystemSettings).filter(
|
||||
SystemSettings.setting_key == "directory.config"
|
||||
).first()
|
||||
|
||||
return {
|
||||
"config": config,
|
||||
"metadata": {
|
||||
"updated_at": setting.updated_at.isoformat() if setting and setting.updated_at else None,
|
||||
"updated_by": setting.updated_by if setting else None,
|
||||
"is_default": setting is None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Admin endpoint - update directory configuration
|
||||
@api_router.put("/admin/directory/config")
|
||||
async def update_directory_config(
|
||||
request: Request,
|
||||
current_user: User = Depends(require_permission("directory.manage")),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Update directory field configuration"""
|
||||
try:
|
||||
body = await request.json()
|
||||
config = body.get("config", {})
|
||||
|
||||
# Validate config structure
|
||||
if "fields" not in config:
|
||||
raise HTTPException(status_code=400, detail="Config must contain 'fields' object")
|
||||
|
||||
# Ensure show_in_directory is always enabled (core functionality)
|
||||
if "show_in_directory" in config["fields"]:
|
||||
config["fields"]["show_in_directory"]["enabled"] = True
|
||||
|
||||
# Add version if not present
|
||||
if "version" not in config:
|
||||
config["version"] = "1.0"
|
||||
|
||||
saved_config = save_directory_config(db, config, current_user.id)
|
||||
|
||||
return {
|
||||
"message": "Directory configuration updated successfully",
|
||||
"config": saved_config
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating directory config: {str(e)}")
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
|
||||
# Admin endpoint - reset directory configuration to default
|
||||
@api_router.post("/admin/directory/config/reset")
|
||||
async def reset_directory_config(
|
||||
current_user: User = Depends(require_permission("directory.manage")),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Reset directory configuration to default"""
|
||||
saved_config = save_directory_config(db, DEFAULT_DIRECTORY_CONFIG, current_user.id)
|
||||
|
||||
return {
|
||||
"message": "Directory configuration reset to default",
|
||||
"config": saved_config
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Admin Routes
|
||||
# ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user