diff --git a/.gitignore b/.gitignore index 4c49bd7..234fb18 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .env +MOBILE_APP_SPEC.md diff --git a/app.py b/app.py index 3ceeb63..bb2a5f7 100644 --- a/app.py +++ b/app.py @@ -1060,6 +1060,43 @@ def api_task_detail(user_id, task_id): # --- Logbook Detail / Edit API --- +@app.route('/api/logbook', methods=['GET']) +@token_required +def api_logbook_list(user_id): + # Fetch last 100 entries + entries = list(db.time_entries.find({'user_id': user_id}).sort('start_time', -1).limit(100)) + + result = [] + # Cache activities to avoid N+1 queries + activities = {a['_id']: a for a in db.activities.find({'user_id': user_id})} + + for entry in entries: + act = activities.get(entry.get('activity_id')) + + # Calculate duration string + duration_str = "Running" + total_seconds = 0 + if entry.get('end_time') and entry.get('start_time'): + diff = entry['end_time'] - entry['start_time'] + total_seconds = diff.total_seconds() + hours = int(total_seconds // 3600) + mins = int((total_seconds % 3600) // 60) + duration_str = f"{hours:02}:{mins:02}" + + result.append({ + 'id': str(entry['_id']), + 'activity_name': act['name'] if act else 'Unknown', + 'activity_color': act.get('color', '#ccc') if act else '#ccc', + 'start_time': entry['start_time'].isoformat(), + 'end_time': entry['end_time'].isoformat() if entry.get('end_time') else None, + 'duration_str': duration_str, + 'duration_seconds': total_seconds, + 'note': entry.get('note', ''), + 'subcategory': entry.get('subcategory', '') + }) + + return jsonify(result) + @app.route('/api/logbook/', methods=['GET', 'PUT', 'DELETE']) @token_required def api_log_entry(user_id, entry_id): @@ -1170,11 +1207,31 @@ def api_goals(user_id): }) return jsonify({'status': 'created'}) -@app.route('/api/goals/', methods=['DELETE']) +@app.route('/api/goals/', methods=['PUT', 'DELETE']) @token_required -def api_goal_delete(user_id, goal_id): - db.goals.delete_one({'_id': ObjectId(goal_id), 'user_id': user_id}) - return jsonify({'status': 'deleted'}) +def api_manage_goal(user_id, goal_id): + if request.method == 'DELETE': + db.goals.delete_one({'_id': ObjectId(goal_id), 'user_id': user_id}) + return jsonify({'status': 'deleted'}) + + if request.method == 'PUT': + data = request.get_json() + update_fields = {} + + if 'name' in data: update_fields['name'] = data['name'] + if 'target_hours' in data: update_fields['target_hours'] = float(data['target_hours']) + if 'frequency' in data: update_fields['frequency'] = data['frequency'] + if 'activity_id' in data: update_fields['activity_id'] = ObjectId(data['activity_id']) + if 'subcategory' in data: update_fields['subcategory'] = data['subcategory'] + + result = db.goals.update_one( + {'_id': ObjectId(goal_id), 'user_id': user_id}, + {'$set': update_fields} + ) + if result.matched_count == 0: + return jsonify({'message': 'Goal not found'}), 404 + + return jsonify({'status': 'updated'}) debug = os.getenv('DEBUG') == 'False' host = os.getenv('HOST')