feat: 4.0 - Backend API - Streak calculation utility

This commit is contained in:
Echo
2026-02-10 11:28:30 +00:00
parent 3a09e6c51a
commit 3927b7c393
2 changed files with 280 additions and 0 deletions

View File

@@ -35,6 +35,107 @@ GITEA_URL = os.environ.get('GITEA_URL', 'https://gitea.romfast.ro')
GITEA_ORG = os.environ.get('GITEA_ORG', 'romfast')
GITEA_TOKEN = os.environ.get('GITEA_TOKEN', '')
def calculate_streak(completions, frequency):
"""
Calculate the current streak for a habit based on completions array.
Args:
completions: List of ISO timestamp strings representing completion dates
frequency: 'daily' or 'weekly'
Returns:
int: The current streak count (days for daily, weeks for weekly)
Rules:
- Counts consecutive periods from most recent completion backwards
- Daily: counts consecutive days without gaps
- Weekly: counts consecutive 7-day periods
- Returns 0 for no completions
- Returns 0 if streak is broken (gap detected)
- Today's completion counts even if previous days were missed
"""
from datetime import datetime, timedelta
# No completions = no streak
if not completions:
return 0
# Parse all completion dates and sort descending (most recent first)
try:
completion_dates = []
for comp in completions:
dt = datetime.fromisoformat(comp.replace('Z', '+00:00'))
# Convert to date only (ignore time)
completion_dates.append(dt.date())
completion_dates = sorted(set(completion_dates), reverse=True)
except (ValueError, AttributeError):
return 0
if not completion_dates:
return 0
# Get today's date
today = datetime.now().date()
if frequency == 'daily':
# For daily habits, count consecutive days
streak = 0
expected_date = completion_dates[0]
# If most recent completion is today or yesterday, start counting
if expected_date < today - timedelta(days=1):
# Streak is broken (last completion was more than 1 day ago)
return 0
for completion in completion_dates:
if completion == expected_date:
streak += 1
expected_date -= timedelta(days=1)
elif completion < expected_date:
# Gap found, streak is broken
break
return streak
elif frequency == 'weekly':
# For weekly habits, count consecutive weeks (7-day periods)
streak = 0
# Most recent completion
most_recent = completion_dates[0]
# Check if most recent completion is within current week
days_since = (today - most_recent).days
if days_since > 6:
# Last completion was more than a week ago, streak is broken
return 0
# Start counting from the week of the most recent completion
current_week_start = most_recent - timedelta(days=most_recent.weekday())
for i in range(len(completion_dates)):
week_start = current_week_start - timedelta(days=i * 7)
week_end = week_start + timedelta(days=6)
# Check if there's a completion in this week
has_completion = any(
week_start <= comp <= week_end
for comp in completion_dates
)
if has_completion:
streak += 1
else:
# No completion in this week, streak is broken
break
return streak
return 0
class TaskBoardHandler(SimpleHTTPRequestHandler):
def do_POST(self):