reports.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. """
  2. Reports API endpoints.
  3. Provides endpoints for:
  4. - GET /api/reports - Get paginated list of reports
  5. - GET /api/reports/detail - Get report details
  6. - GET /api/reports/download - Download report file
  7. - POST /api/reports/delete - Delete a report
  8. """
  9. import os
  10. from flask import jsonify, request, send_file, current_app
  11. from app.api import api_bp
  12. from app.services import login_required, get_current_user_from_context, get_accessible_reports
  13. from app.services.report_service import ReportService
  14. from app.models import Report, Task
  15. @api_bp.route('/reports', methods=['GET'])
  16. @login_required
  17. def get_reports():
  18. """
  19. Get paginated list of reports.
  20. Query Parameters:
  21. page: Page number (default: 1)
  22. page_size: Items per page (default: 20, max: 100)
  23. task_id: Optional filter by task ID
  24. Returns:
  25. JSON with 'data' array and 'pagination' object
  26. """
  27. current_user = get_current_user_from_context()
  28. page = request.args.get('page', 1, type=int)
  29. # Support both pageSize (frontend) and page_size (backend convention)
  30. page_size = request.args.get('pageSize', type=int) or request.args.get('page_size', type=int) or 20
  31. page_size = min(page_size, 100)
  32. task_id = request.args.get('task_id', type=int)
  33. # For regular users, only show their own reports
  34. user_id = None
  35. if current_user.role == 'user':
  36. user_id = current_user.id
  37. result = ReportService.get_reports(
  38. page=page,
  39. page_size=page_size,
  40. task_id=task_id,
  41. user_id=user_id
  42. )
  43. return jsonify(result), 200
  44. @api_bp.route('/reports/detail', methods=['GET'])
  45. @login_required
  46. def get_report_detail():
  47. """
  48. Get report details.
  49. Query Parameters:
  50. id: Report ID (required)
  51. Returns:
  52. JSON with report details
  53. """
  54. current_user = get_current_user_from_context()
  55. report_id = request.args.get('id', type=int)
  56. if not report_id:
  57. return jsonify({'error': {'code': 'MISSING_PARAMETER', 'message': 'Report ID is required'}}), 400
  58. report = ReportService.get_report_by_id(report_id)
  59. if not report:
  60. return jsonify({'error': {'code': 'NOT_FOUND', 'message': 'Report not found'}}), 404
  61. # Check access for regular users
  62. if current_user.role == 'user':
  63. task = Task.query.get(report.task_id)
  64. if not task or task.created_by != current_user.id:
  65. return jsonify({'error': {'code': 'FORBIDDEN', 'message': 'Access denied'}}), 403
  66. return jsonify(report.to_dict()), 200
  67. @api_bp.route('/reports/download', methods=['GET'])
  68. @login_required
  69. def download_report():
  70. """
  71. Download a report file.
  72. Query Parameters:
  73. id: Report ID (required)
  74. Returns:
  75. The report file as attachment
  76. """
  77. current_user = get_current_user_from_context()
  78. report_id = request.args.get('id', type=int)
  79. if not report_id:
  80. return jsonify({'error': {'code': 'MISSING_PARAMETER', 'message': 'Report ID is required'}}), 400
  81. report = ReportService.get_report_by_id(report_id)
  82. if not report:
  83. return jsonify({'error': {'code': 'NOT_FOUND', 'message': 'Report not found'}}), 404
  84. # Check access for regular users
  85. if current_user.role == 'user':
  86. task = Task.query.get(report.task_id)
  87. if not task or task.created_by != current_user.id:
  88. return jsonify({'error': {'code': 'FORBIDDEN', 'message': 'Access denied'}}), 403
  89. # Get file path
  90. file_path = ReportService.get_report_file_path(report_id)
  91. if not file_path:
  92. return jsonify({'error': {'code': 'FILE_NOT_FOUND', 'message': 'Report file not found'}}), 404
  93. return send_file(
  94. file_path,
  95. as_attachment=True,
  96. download_name=report.file_name,
  97. mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document'
  98. )
  99. @api_bp.route('/reports/delete', methods=['POST'])
  100. @login_required
  101. def delete_report():
  102. """
  103. Delete a report.
  104. Request Body:
  105. id: Report ID (required)
  106. Returns:
  107. JSON with success message
  108. """
  109. current_user = get_current_user_from_context()
  110. data = request.get_json() or {}
  111. report_id = data.get('id')
  112. if not report_id:
  113. return jsonify({'error': {'code': 'MISSING_PARAMETER', 'message': 'Report ID is required'}}), 400
  114. report = ReportService.get_report_by_id(report_id)
  115. if not report:
  116. return jsonify({'error': {'code': 'NOT_FOUND', 'message': 'Report not found'}}), 404
  117. # Only admins can delete reports, or users can delete their own
  118. if current_user.role == 'user':
  119. task = Task.query.get(report.task_id)
  120. if not task or task.created_by != current_user.id:
  121. return jsonify({'error': {'code': 'FORBIDDEN', 'message': 'Access denied'}}), 403
  122. success = ReportService.delete_report(report_id)
  123. if success:
  124. return jsonify({'message': 'Report deleted successfully'}), 200
  125. else:
  126. return jsonify({'error': {'code': 'DELETE_FAILED', 'message': 'Failed to delete report'}}), 500