Spaces:
Building
Building
Update config_provider.py
Browse files- config_provider.py +69 -9
config_provider.py
CHANGED
@@ -5,7 +5,7 @@ import threading
|
|
5 |
import os
|
6 |
import json
|
7 |
import commentjson
|
8 |
-
from typing import Optional, Dict,
|
9 |
from datetime import datetime
|
10 |
from pathlib import Path
|
11 |
import tempfile
|
@@ -258,7 +258,7 @@ class ConfigProvider:
|
|
258 |
|
259 |
return project
|
260 |
|
261 |
-
@classmethod
|
262 |
def update_project(cls, project_id: int, update_data: dict, username: str, expected_last_update: Optional[str] = None) -> ProjectConfig:
|
263 |
"""Update project with optimistic locking"""
|
264 |
with cls._lock:
|
@@ -425,6 +425,66 @@ class ConfigProvider:
|
|
425 |
)
|
426 |
|
427 |
return version
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
|
429 |
# ===================== API Methods =====================
|
430 |
|
@@ -469,8 +529,8 @@ class ConfigProvider:
|
|
469 |
return api
|
470 |
|
471 |
@classmethod
|
472 |
-
def update_api(cls, api_name: str, update_data: dict, username: str) -> APIConfig:
|
473 |
-
"""Update API
|
474 |
with cls._lock:
|
475 |
config = cls.get()
|
476 |
api = config.get_api(api_name)
|
@@ -479,20 +539,20 @@ class ConfigProvider:
|
|
479 |
raise ResourceNotFoundError("api", api_name)
|
480 |
|
481 |
# Check race condition
|
482 |
-
if
|
483 |
-
if api.last_update_date !=
|
484 |
raise RaceConditionError(
|
485 |
-
f"API '{
|
486 |
current_user=username,
|
487 |
last_update_user=api.last_update_user,
|
488 |
last_update_date=api.last_update_date,
|
489 |
entity_type="api",
|
490 |
-
entity_id=
|
491 |
)
|
492 |
|
493 |
# Update fields
|
494 |
for key, value in update_data.items():
|
495 |
-
if hasattr(api, key) and key not in ['name', 'created_date', 'created_by']:
|
496 |
setattr(api, key, value)
|
497 |
|
498 |
api.last_update_date = datetime.utcnow().isoformat()
|
|
|
5 |
import os
|
6 |
import json
|
7 |
import commentjson
|
8 |
+
from typing import Optional, Dict, List, Any
|
9 |
from datetime import datetime
|
10 |
from pathlib import Path
|
11 |
import tempfile
|
|
|
258 |
|
259 |
return project
|
260 |
|
261 |
+
@classmethod
|
262 |
def update_project(cls, project_id: int, update_data: dict, username: str, expected_last_update: Optional[str] = None) -> ProjectConfig:
|
263 |
"""Update project with optimistic locking"""
|
264 |
with cls._lock:
|
|
|
425 |
)
|
426 |
|
427 |
return version
|
428 |
+
|
429 |
+
@classmethod
|
430 |
+
def update_version(cls, project_id: int, version_no: int, update_data: dict, username: str, expected_last_update: Optional[str] = None) -> VersionConfig:
|
431 |
+
"""Update version with optimistic locking"""
|
432 |
+
with cls._lock:
|
433 |
+
config = cls.get()
|
434 |
+
project = cls.get_project(project_id)
|
435 |
+
|
436 |
+
if not project:
|
437 |
+
raise ResourceNotFoundError("project", project_id)
|
438 |
+
|
439 |
+
version = next((v for v in project.versions if v.no == version_no), None)
|
440 |
+
if not version:
|
441 |
+
raise ResourceNotFoundError("version", version_no)
|
442 |
+
|
443 |
+
# Published versions cannot be edited
|
444 |
+
if version.published:
|
445 |
+
raise ValidationError("Published versions cannot be modified")
|
446 |
+
|
447 |
+
# Check race condition
|
448 |
+
if expected_last_update is not None:
|
449 |
+
if version.last_update_date != expected_last_update:
|
450 |
+
raise RaceConditionError(
|
451 |
+
f"Version {version_no} was modified by another user",
|
452 |
+
current_user=username,
|
453 |
+
last_update_user=version.last_update_user,
|
454 |
+
last_update_date=version.last_update_date,
|
455 |
+
entity_type="version",
|
456 |
+
entity_id=f"{project_id}:{version_no}"
|
457 |
+
)
|
458 |
+
|
459 |
+
# Update fields
|
460 |
+
for key, value in update_data.items():
|
461 |
+
if hasattr(version, key) and key not in ['no', 'created_date', 'created_by', 'published', 'last_update_date']:
|
462 |
+
setattr(version, key, value)
|
463 |
+
|
464 |
+
version.last_update_date = datetime.utcnow().isoformat()
|
465 |
+
version.last_update_user = username
|
466 |
+
|
467 |
+
# Update project last update
|
468 |
+
project.last_update_date = datetime.utcnow().isoformat()
|
469 |
+
project.last_update_user = username
|
470 |
+
|
471 |
+
# Log activity
|
472 |
+
cls._add_activity(
|
473 |
+
config, username, "UPDATE_VERSION",
|
474 |
+
"version", f"{project.id}:{version.no}", f"{project.name} v{version.no}"
|
475 |
+
)
|
476 |
+
|
477 |
+
# Save
|
478 |
+
cls.save(config, username)
|
479 |
+
|
480 |
+
log_info(
|
481 |
+
"Version updated",
|
482 |
+
project_id=project.id,
|
483 |
+
version_no=version.no,
|
484 |
+
user=username
|
485 |
+
)
|
486 |
+
|
487 |
+
return version
|
488 |
|
489 |
# ===================== API Methods =====================
|
490 |
|
|
|
529 |
return api
|
530 |
|
531 |
@classmethod
|
532 |
+
def update_api(cls, api_name: str, update_data: dict, username: str, expected_last_update: Optional[str] = None) -> APIConfig:
|
533 |
+
"""Update API with optimistic locking"""
|
534 |
with cls._lock:
|
535 |
config = cls.get()
|
536 |
api = config.get_api(api_name)
|
|
|
539 |
raise ResourceNotFoundError("api", api_name)
|
540 |
|
541 |
# Check race condition
|
542 |
+
if expected_last_update is not None:
|
543 |
+
if api.last_update_date != expected_last_update:
|
544 |
raise RaceConditionError(
|
545 |
+
f"API '{api.name}' was modified by another user",
|
546 |
current_user=username,
|
547 |
last_update_user=api.last_update_user,
|
548 |
last_update_date=api.last_update_date,
|
549 |
entity_type="api",
|
550 |
+
entity_id=api.name
|
551 |
)
|
552 |
|
553 |
# Update fields
|
554 |
for key, value in update_data.items():
|
555 |
+
if hasattr(api, key) and key not in ['name', 'created_date', 'created_by', 'last_update_date']:
|
556 |
setattr(api, key, value)
|
557 |
|
558 |
api.last_update_date = datetime.utcnow().isoformat()
|