ciyidogan commited on
Commit
88b8f86
·
verified ·
1 Parent(s): c294b06

Update admin_routes.py

Browse files
Files changed (1) hide show
  1. admin_routes.py +129 -27
admin_routes.py CHANGED
@@ -453,24 +453,35 @@ async def update_project(
453
  update: ProjectUpdate,
454
  username: str = Depends(verify_token)
455
  ):
456
- """Update project"""
457
- # Validate supported locales
458
- from locale_manager import LocaleManager
459
-
460
- invalid_locales = LocaleManager.validate_project_languages(update.supported_locales)
461
- if invalid_locales:
462
- available_locales = LocaleManager.get_available_locales_with_names()
463
- available_codes = [locale['code'] for locale in available_locales]
 
 
 
 
 
 
 
464
  raise HTTPException(
465
- status_code=400,
466
- detail=f"Unsupported locales: {', '.join(invalid_locales)}. Available locales: {', '.join(available_codes)}"
 
 
 
 
 
467
  )
468
-
469
- # Update via ConfigProvider
470
- updated_project = ConfigProvider.update_project(project_id, update.model_dump(), username)
471
-
472
- log_info(f"✅ Project '{updated_project.name}' updated by {username}")
473
- return updated_project.model_dump()
474
 
475
  @router.delete("/projects/{project_id}")
476
  async def delete_project(project_id: int, username: str = Depends(verify_token)):
@@ -525,14 +536,54 @@ async def update_version(
525
  project_id: int,
526
  version_id: int,
527
  update: VersionUpdate,
 
528
  username: str = Depends(verify_token)
529
  ):
530
- """Update version"""
531
- updated_version = ConfigProvider.update_version(project_id, version_id, update.model_dump(), username)
532
-
533
- log_info(f"✅ Version {version_id} updated for project {project_id} by {username}")
534
- return updated_version.model_dump()
535
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
  @router.post("/projects/{project_id}/versions/{version_id}/publish")
537
  async def publish_version(
538
  project_id: int,
@@ -691,11 +742,34 @@ async def update_api(
691
  update: APIUpdate,
692
  username: str = Depends(verify_token)
693
  ):
694
- """Update API"""
695
- updated_api = ConfigProvider.update_api(api_name, update.model_dump(), username)
696
-
697
- log_info(f"✅ API '{api_name}' updated by {username}")
698
- return updated_api.model_dump()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
699
 
700
  @router.delete("/apis/{api_name}")
701
  async def delete_api(api_name: str, username: str = Depends(verify_token)):
@@ -901,6 +975,34 @@ async def notify_llm_startup(project, version):
901
  log_error("❌ Error notifying LLM provider", e)
902
  raise
903
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
904
  # ===================== Cleanup Task =====================
905
  def cleanup_activity_log():
906
  """Cleanup old activity log entries"""
 
453
  update: ProjectUpdate,
454
  username: str = Depends(verify_token)
455
  ):
456
+ """Update existing project with race condition handling"""
457
+ try:
458
+ # Optimistic locking kontrolü
459
+ result = ConfigProvider.update_project(
460
+ project_id,
461
+ update.model_dump(),
462
+ username,
463
+ expected_last_update=update.last_update_date
464
+ )
465
+
466
+ log_info(f"✅ Project {project_id} updated by {username}")
467
+ return result
468
+
469
+ except RaceConditionError as e:
470
+ log_warning(f"⚠️ Race condition detected for project {project_id}")
471
  raise HTTPException(
472
+ status_code=409,
473
+ detail={
474
+ "message": e.message,
475
+ "last_update_user": e.last_update_user,
476
+ "last_update_date": e.last_update_date,
477
+ "type": "race_condition"
478
+ }
479
  )
480
+ except ResourceNotFoundError:
481
+ raise HTTPException(status_code=404, detail="Project not found")
482
+ except Exception as e:
483
+ log_error(f"❌ Error updating project {project_id}", e)
484
+ raise HTTPException(status_code=500, detail=str(e))
 
485
 
486
  @router.delete("/projects/{project_id}")
487
  async def delete_project(project_id: int, username: str = Depends(verify_token)):
 
536
  project_id: int,
537
  version_id: int,
538
  update: VersionUpdate,
539
+ force: bool = Query(default=False, description="Force update despite conflicts"),
540
  username: str = Depends(verify_token)
541
  ):
542
+ """Update version with race condition handling"""
543
+ try:
544
+ # Force parametresi kontrolü
545
+ if force:
546
+ log_warning(f"⚠️ Force update requested for version {version_id} by {username}")
547
+
548
+ result = ConfigProvider.update_version(
549
+ project_id,
550
+ version_id,
551
+ update.model_dump(),
552
+ username,
553
+ expected_last_update=update.last_update_date if not force else None
554
+ )
555
+
556
+ log_info(f"✅ Version {version_id} updated by {username}")
557
+ return result
558
+
559
+ except RaceConditionError as e:
560
+ if force:
561
+ # Force modunda race condition'ı yoksay
562
+ result = ConfigProvider.update_version(
563
+ project_id,
564
+ version_id,
565
+ update.model_dump(),
566
+ username,
567
+ expected_last_update=None
568
+ )
569
+ return result
570
+ else:
571
+ log_warning(f"⚠️ Race condition detected for version {version_id}")
572
+ raise HTTPException(
573
+ status_code=409,
574
+ detail={
575
+ "message": e.message,
576
+ "last_update_user": e.last_update_user,
577
+ "last_update_date": e.last_update_date,
578
+ "type": "race_condition"
579
+ }
580
+ )
581
+ except ResourceNotFoundError:
582
+ raise HTTPException(status_code=404, detail="Version not found")
583
+ except Exception as e:
584
+ log_error(f"❌ Error updating version {version_id}", e)
585
+ raise HTTPException(status_code=500, detail=str(e))
586
+
587
  @router.post("/projects/{project_id}/versions/{version_id}/publish")
588
  async def publish_version(
589
  project_id: int,
 
742
  update: APIUpdate,
743
  username: str = Depends(verify_token)
744
  ):
745
+ """Update API configuration with race condition handling"""
746
+ try:
747
+ result = ConfigProvider.update_api(
748
+ api_name,
749
+ update.model_dump(),
750
+ username,
751
+ expected_last_update=update.last_update_date
752
+ )
753
+
754
+ log_info(f"✅ API '{api_name}' updated by {username}")
755
+ return result
756
+
757
+ except RaceConditionError as e:
758
+ log_warning(f"⚠️ Race condition detected for API '{api_name}'")
759
+ raise HTTPException(
760
+ status_code=409,
761
+ detail={
762
+ "message": e.message,
763
+ "last_update_user": e.last_update_user,
764
+ "last_update_date": e.last_update_date,
765
+ "type": "race_condition"
766
+ }
767
+ )
768
+ except ResourceNotFoundError:
769
+ raise HTTPException(status_code=404, detail="API not found")
770
+ except Exception as e:
771
+ log_error(f"❌ Error updating API '{api_name}'", e)
772
+ raise HTTPException(status_code=500, detail=str(e))
773
 
774
  @router.delete("/apis/{api_name}")
775
  async def delete_api(api_name: str, username: str = Depends(verify_token)):
 
975
  log_error("❌ Error notifying LLM provider", e)
976
  raise
977
 
978
+ def create_token(username: str) -> str:
979
+ """Create JWT token with secure random"""
980
+ import secrets
981
+
982
+ cfg = ConfigProvider.get()
983
+
984
+ # Token için secure random jti (JWT ID) ekle
985
+ jti = secrets.token_urlsafe(16)
986
+
987
+ payload = {
988
+ "sub": username,
989
+ "exp": datetime.now(timezone.utc) + timedelta(hours=24),
990
+ "iat": datetime.now(timezone.utc),
991
+ "jti": jti # Unique token ID
992
+ }
993
+
994
+ # Store token ID for revocation if needed
995
+ if not hasattr(cfg, '_active_tokens'):
996
+ cfg._active_tokens = set()
997
+ cfg._active_tokens.add(jti)
998
+
999
+ secret = os.environ.get("JWT_SECRET", "your-secret-key")
1000
+ token = jwt.encode(payload, secret, algorithm="HS256")
1001
+
1002
+ if isinstance(token, bytes):
1003
+ token = token.decode()
1004
+
1005
+ return token
1006
  # ===================== Cleanup Task =====================
1007
  def cleanup_activity_log():
1008
  """Cleanup old activity log entries"""