feat: US-001 - Backend: DELETE endpoint for uncheck (toggle support)
This commit is contained in:
@@ -80,7 +80,9 @@ class TaskBoardHandler(SimpleHTTPRequestHandler):
|
||||
self.send_error(404)
|
||||
|
||||
def do_DELETE(self):
|
||||
if self.path.startswith('/api/habits/'):
|
||||
if self.path.startswith('/api/habits/') and '/check' in self.path:
|
||||
self.handle_habits_uncheck()
|
||||
elif self.path.startswith('/api/habits/'):
|
||||
self.handle_habits_delete()
|
||||
else:
|
||||
self.send_error(404)
|
||||
@@ -1771,6 +1773,88 @@ class TaskBoardHandler(SimpleHTTPRequestHandler):
|
||||
except Exception as e:
|
||||
self.send_json({'error': str(e)}, 500)
|
||||
|
||||
def handle_habits_uncheck(self):
|
||||
"""Uncheck a habit (remove completion for a specific date)."""
|
||||
try:
|
||||
# Extract habit ID from path (/api/habits/{id}/check)
|
||||
path_parts = self.path.split('?')[0].split('/')
|
||||
if len(path_parts) < 5:
|
||||
self.send_json({'error': 'Invalid path'}, 400)
|
||||
return
|
||||
|
||||
habit_id = path_parts[3]
|
||||
|
||||
# Parse query string for date parameter
|
||||
parsed = urlparse(self.path)
|
||||
query_params = parse_qs(parsed.query)
|
||||
|
||||
# Get date from query string (required)
|
||||
if 'date' not in query_params:
|
||||
self.send_json({'error': 'date parameter is required (format: YYYY-MM-DD)'}, 400)
|
||||
return
|
||||
|
||||
target_date = query_params['date'][0]
|
||||
|
||||
# Validate date format
|
||||
try:
|
||||
datetime.fromisoformat(target_date)
|
||||
except ValueError:
|
||||
self.send_json({'error': 'Invalid date format. Use YYYY-MM-DD'}, 400)
|
||||
return
|
||||
|
||||
# Read existing habits
|
||||
if not HABITS_FILE.exists():
|
||||
self.send_json({'error': 'Habit not found'}, 404)
|
||||
return
|
||||
|
||||
with open(HABITS_FILE, 'r', encoding='utf-8') as f:
|
||||
habits_data = json.load(f)
|
||||
|
||||
# Find habit
|
||||
habit = None
|
||||
for h in habits_data.get('habits', []):
|
||||
if h['id'] == habit_id:
|
||||
habit = h
|
||||
break
|
||||
|
||||
if not habit:
|
||||
self.send_json({'error': 'Habit not found'}, 404)
|
||||
return
|
||||
|
||||
# Find and remove the completion for the specified date
|
||||
completions = habit.get('completions', [])
|
||||
completion_found = False
|
||||
for i, completion in enumerate(completions):
|
||||
if completion.get('date') == target_date:
|
||||
completions.pop(i)
|
||||
completion_found = True
|
||||
break
|
||||
|
||||
if not completion_found:
|
||||
self.send_json({'error': 'No completion found for the specified date'}, 404)
|
||||
return
|
||||
|
||||
# Recalculate streak after removing completion
|
||||
current_streak = habits_helpers.calculate_streak(habit)
|
||||
habit['streak']['current'] = current_streak
|
||||
|
||||
# Update best streak if needed (best never decreases, but we keep it for consistency)
|
||||
if current_streak > habit['streak']['best']:
|
||||
habit['streak']['best'] = current_streak
|
||||
|
||||
# Update timestamp
|
||||
habit['updatedAt'] = datetime.now().isoformat()
|
||||
habits_data['lastUpdated'] = habit['updatedAt']
|
||||
|
||||
# Save to file
|
||||
with open(HABITS_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(habits_data, f, indent=2)
|
||||
|
||||
# Return updated habit
|
||||
self.send_json(habit, 200)
|
||||
except Exception as e:
|
||||
self.send_json({'error': str(e)}, 500)
|
||||
|
||||
def handle_habits_skip(self):
|
||||
"""Skip a day using a life to preserve streak."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user