22
33import typing
44
5+ from django .utils import timezone
6+
57from audit .models import AuditLog
68from audit .related_object_type import RelatedObjectType
7- from experimentation .constants import WAREHOUSE_CONNECTION_FLAG
9+ from experimentation .constants import EXPERIMENT_FLAG , WAREHOUSE_CONNECTION_FLAG
810from integrations .flagsmith .client import get_openfeature_client
911
1012if typing .TYPE_CHECKING :
11- from experimentation .models import WarehouseConnection
13+ from experimentation .models import Experiment , WarehouseConnection
1214 from organisations .models import Organisation
1315 from users .models import FFAdminUser
1416
@@ -21,6 +23,22 @@ def is_warehouse_feature_enabled(organisation: Organisation) -> bool:
2123 )
2224
2325
26+ def is_experiment_feature_enabled (organisation : Organisation ) -> bool :
27+ return get_openfeature_client ().get_boolean_value (
28+ EXPERIMENT_FLAG ,
29+ default_value = False ,
30+ evaluation_context = organisation .openfeature_evaluation_context ,
31+ )
32+
33+
34+ def _resolve_audit_log_author (
35+ user : FFAdminUser ,
36+ ) -> dict [str , int | None ]:
37+ if getattr (user , "is_master_api_key_user" , False ):
38+ return {"author_id" : None , "master_api_key_id" : user .key .id }
39+ return {"author_id" : user .pk , "master_api_key_id" : None }
40+
41+
2442def create_warehouse_audit_log (
2543 connection : WarehouseConnection ,
2644 user : FFAdminUser ,
@@ -30,11 +48,55 @@ def create_warehouse_audit_log(
3048 AuditLog .objects .create (
3149 environment = connection .environment ,
3250 project = connection .environment .project ,
33- author = user ,
51+ ** _resolve_audit_log_author ( user ) ,
3452 related_object_id = connection .id ,
3553 related_object_type = RelatedObjectType .WAREHOUSE_CONNECTION .name ,
3654 log = (
3755 f"Warehouse connection { action } for environment "
3856 f"{ connection .environment .name } "
3957 ),
4058 )
59+
60+
61+ def create_experiment_audit_log (
62+ experiment : Experiment ,
63+ user : FFAdminUser ,
64+ * ,
65+ action : str ,
66+ ) -> None :
67+ AuditLog .objects .create (
68+ environment = experiment .environment ,
69+ project = experiment .environment .project ,
70+ ** _resolve_audit_log_author (user ),
71+ related_object_id = experiment .id ,
72+ related_object_type = RelatedObjectType .EXPERIMENT .name ,
73+ log = (
74+ f"Experiment '{ experiment .name } ' { action } for environment "
75+ f"{ experiment .environment .name } "
76+ ),
77+ )
78+
79+
80+ def transition_experiment_status (
81+ experiment : Experiment ,
82+ target_status : str ,
83+ user : FFAdminUser ,
84+ ) -> Experiment :
85+ from experimentation .models import VALID_STATUS_TRANSITIONS , ExperimentStatus
86+
87+ valid_targets = VALID_STATUS_TRANSITIONS .get (experiment .status , set ())
88+ if target_status not in valid_targets :
89+ raise ValueError (
90+ f"Cannot transition from '{ experiment .status } ' to '{ target_status } '."
91+ )
92+
93+ experiment .status = target_status
94+
95+ if target_status == ExperimentStatus .RUNNING and not experiment .started_at :
96+ experiment .started_at = timezone .now ()
97+ elif target_status == ExperimentStatus .COMPLETED :
98+ experiment .ended_at = timezone .now ()
99+
100+ experiment .save ()
101+ create_experiment_audit_log (experiment , user , action = target_status )
102+ return experiment
0 commit comments