@@ -1914,20 +1914,16 @@ def calculate_retention_period_days(challenge_end_date, challenge=None):
1914
1914
# Default 30-day retention when host has consented
1915
1915
return 30
1916
1916
1917
- # No host consent - use conservative default (longer retention )
1918
- # Default retention calculation (90 days after challenge ends for safety)
1917
+ # No host consent - use indefinite retention (no automatic cleanup )
1918
+ # Without consent, data is retained indefinitely for safety
1919
1919
if challenge_end_date > now :
1920
- # Challenge is still active, retain until end date + 90 days
1921
- # Round up to the nearest day to avoid flakiness
1922
- seconds_until_end = (challenge_end_date - now ).total_seconds ()
1923
- days_until_end = math .ceil (seconds_until_end / (24 * 3600.0 ))
1924
- return int (days_until_end ) + 90
1920
+ # Challenge is still active, retain indefinitely
1921
+ # Return a very large number to effectively make it indefinite
1922
+ return 3653 # Maximum AWS CloudWatch retention period (10 years)
1925
1923
else :
1926
- # Challenge has ended, retain for 90 more days
1927
- # Round down to match original behavior of .days
1928
- seconds_since_end = (now - challenge_end_date ).total_seconds ()
1929
- days_since_end = math .floor (seconds_since_end / (24 * 3600.0 ))
1930
- return max (90 - int (days_since_end ), 1 ) # At least 1 day
1924
+ # Challenge has ended, retain indefinitely
1925
+ # Return maximum retention period
1926
+ return 3653 # Maximum AWS CloudWatch retention period (10 years)
1931
1927
1932
1928
1933
1929
def map_retention_days_to_aws_values (days ):
@@ -1993,7 +1989,7 @@ def set_cloudwatch_log_retention(challenge_pk, retention_days=None):
1993
1989
return {
1994
1990
"error" : f"Challenge { challenge_pk } host has not consented to retention policy. "
1995
1991
"Please obtain consent before applying retention policies. "
1996
- "Without consent, data is retained for 90 days for safety." ,
1992
+ "Without consent, data is retained indefinitely for safety." ,
1997
1993
"requires_consent" : True ,
1998
1994
"challenge_id" : challenge_pk ,
1999
1995
}
@@ -2045,7 +2041,7 @@ def set_cloudwatch_log_retention(challenge_pk, retention_days=None):
2045
2041
"retention_days" : aws_retention_days ,
2046
2042
"log_group" : log_group_name ,
2047
2043
"message" : f"Retention policy set to { aws_retention_days } days "
2048
- f"({ '30-day policy applied' if challenge_obj .retention_policy_consent else '90-day safety retention' } )" ,
2044
+ f"({ '30-day policy applied' if challenge_obj .retention_policy_consent else 'indefinite retention (no consent) ' } )" ,
2049
2045
"host_consent" : challenge_obj .retention_policy_consent ,
2050
2046
}
2051
2047
@@ -2076,7 +2072,7 @@ def calculate_submission_retention_date(challenge_phase):
2076
2072
challenge_phase: ChallengePhase object
2077
2073
2078
2074
Returns:
2079
- datetime: Date when submission artifacts can be deleted
2075
+ datetime: Date when submission artifacts can be deleted, or None if indefinite retention
2080
2076
"""
2081
2077
from datetime import timedelta
2082
2078
@@ -2092,17 +2088,14 @@ def calculate_submission_retention_date(challenge_phase):
2092
2088
2093
2089
# Check if challenge has host consent
2094
2090
if challenge .retention_policy_consent :
2095
- # Use challenge-level retention policy
2091
+ # Use challenge-level retention policy (30 days)
2096
2092
retention_days = calculate_retention_period_days (
2097
2093
challenge_phase .end_date , challenge
2098
2094
)
2095
+ return challenge_phase .end_date + timedelta (days = retention_days )
2099
2096
else :
2100
- # No host consent, use default retention period
2101
- retention_days = calculate_retention_period_days (
2102
- challenge_phase .end_date , challenge
2103
- )
2104
-
2105
- return challenge_phase .end_date + timedelta (days = retention_days )
2097
+ # No host consent - indefinite retention (no automatic cleanup)
2098
+ return None
2106
2099
2107
2100
2108
2101
def delete_submission_files_from_storage (submission ):
@@ -2209,7 +2202,9 @@ def cleanup_expired_submission_artifacts():
2209
2202
# Find submissions eligible for cleanup
2210
2203
now = timezone .now ()
2211
2204
eligible_submissions = Submission .objects .filter (
2212
- retention_eligible_date__lte = now , is_artifact_deleted = False
2205
+ retention_eligible_date__lte = now ,
2206
+ retention_eligible_date__isnull = False , # Exclude indefinite retention
2207
+ is_artifact_deleted = False ,
2213
2208
).select_related ("challenge_phase__challenge" )
2214
2209
2215
2210
cleanup_stats = {
@@ -2307,36 +2302,26 @@ def update_submission_retention_dates():
2307
2302
2308
2303
for phase in ended_phases :
2309
2304
try :
2310
- # Process submissions by type
2311
- for submission_type in [
2312
- "participant" ,
2313
- "host" ,
2314
- "baseline" ,
2315
- "evaluation_output" ,
2316
- ]:
2317
- retention_date = calculate_submission_retention_date (
2318
- phase , submission_type
2319
- )
2320
- if retention_date :
2321
- # Update submissions for this phase and type
2322
- submissions_updated = Submission .objects .filter (
2323
- challenge_phase = phase ,
2324
- submission_type = submission_type ,
2325
- retention_eligible_date__isnull = True ,
2326
- is_artifact_deleted = False ,
2327
- ).update (retention_eligible_date = retention_date )
2328
-
2329
- updated_count += submissions_updated
2330
-
2331
- if submissions_updated > 0 :
2332
- logger .info (
2333
- f"Updated { submissions_updated } { submission_type } submissions for phase { phase .pk } "
2334
- f"({ phase .challenge .title } ) with retention date { retention_date } "
2335
- )
2336
- else :
2337
- logger .debug (
2338
- f"No retention date calculated for phase { phase .pk } submission type { submission_type } - phase may still be public"
2305
+ retention_date = calculate_submission_retention_date (phase )
2306
+ if retention_date :
2307
+ # Update submissions for this phase
2308
+ submissions_updated = Submission .objects .filter (
2309
+ challenge_phase = phase ,
2310
+ retention_eligible_date__isnull = True ,
2311
+ is_artifact_deleted = False ,
2312
+ ).update (retention_eligible_date = retention_date )
2313
+
2314
+ updated_count += submissions_updated
2315
+
2316
+ if submissions_updated > 0 :
2317
+ logger .info (
2318
+ f"Updated { submissions_updated } submissions for phase { phase .pk } "
2319
+ f"({ phase .challenge .title } ) with retention date { retention_date } "
2339
2320
)
2321
+ else :
2322
+ logger .debug (
2323
+ f"No retention date calculated for phase { phase .pk } - phase may still be public or indefinite retention"
2324
+ )
2340
2325
2341
2326
except Exception as e :
2342
2327
error_msg = f"Failed to update retention dates for phase { phase .pk } : { str (e )} "
@@ -2480,6 +2465,7 @@ def weekly_retention_notifications_and_consent_log():
2480
2465
warning_date = timezone .now () + timedelta (days = 14 )
2481
2466
warning_submissions = Submission .objects .filter (
2482
2467
retention_eligible_date__date = warning_date .date (),
2468
+ retention_eligible_date__isnull = False , # Exclude indefinite retention
2483
2469
is_artifact_deleted = False ,
2484
2470
).select_related ("challenge_phase__challenge__creator" )
2485
2471
0 commit comments