From dd41cf773ba4623123fc0363f459705763ab9628 Mon Sep 17 00:00:00 2001 From: Andika Date: Mon, 2 Feb 2026 17:05:27 +0700 Subject: [PATCH] =?UTF-8?q?-=20Added=20DEFAULT=5FDIRECTORY=5FCONFIG=20cons?= =?UTF-8?q?tant=20with=20all=20directory=20fields=20-=20Added=20get=5Fdire?= =?UTF-8?q?ctory=5Fconfig()=20and=20save=5Fdirectory=5Fconfig()=20helper?= =?UTF-8?q?=20functions=20-=20Created=204=20new=20endpoints:=20=09-=20GET?= =?UTF-8?q?=20/api/directory/config=20-=20Public=20endpoint=20for=20fronte?= =?UTF-8?q?nd=20=09-=20GET=20/api/admin/directory/config=20-=20Admin=20vie?= =?UTF-8?q?w=20with=20metadata=20=09-=20PUT=20/api/admin/directory/config?= =?UTF-8?q?=20-=20Update=20configuration=20=09-=20POST=20/api/admin/direct?= =?UTF-8?q?ory/config/reset=20-=20Reset=20to=20defaults=20-=20Fixed=20a=20?= =?UTF-8?q?bug:=20Changed=20SystemSettings.key=20=E2=86=92=20SystemSetting?= =?UTF-8?q?s.setting=5Fkey=20(correct=20column=20name)=20-=20Added=20JSON?= =?UTF-8?q?=20serialization/deserialization=20for=20storing=20config=20in?= =?UTF-8?q?=20Text=20column?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/server.cpython-312.pyc | Bin 388200 -> 394626 bytes seed_permissions_rbac.py | 6 + server.py | 210 +++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) diff --git a/__pycache__/server.cpython-312.pyc b/__pycache__/server.cpython-312.pyc index e8c4dfa239ae3fbb3a345e58b2aa2a78fbb6e719..7eb827466589d23af089e82c667db4f01ed95601 100644 GIT binary patch delta 40314 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 N^pg`qdK3f;{|8u>&I|wm delta 35150 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

0Sgp!f~I)W-axO$s1Et95c)kQ*0SutXyOteF4Gy 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 n2mT~|2Xn7S?B(z1Nci*PcXSMV&2Ypm8W81XsT 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 # ============================================================================