result_service.go 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "net/http"
  6. "cmr-backend/internal/apperr"
  7. "cmr-backend/internal/store/postgres"
  8. )
  9. type ResultService struct {
  10. store *postgres.Store
  11. }
  12. type SessionResultView struct {
  13. Session EntrySessionSummary `json:"session"`
  14. Result ResultSummaryPayload `json:"result"`
  15. }
  16. type ResultSummaryPayload struct {
  17. Status string `json:"status"`
  18. FinalDurationSec *int `json:"finalDurationSec,omitempty"`
  19. FinalScore *int `json:"finalScore,omitempty"`
  20. CompletedControls *int `json:"completedControls,omitempty"`
  21. TotalControls *int `json:"totalControls,omitempty"`
  22. DistanceMeters *float64 `json:"distanceMeters,omitempty"`
  23. AverageSpeedKmh *float64 `json:"averageSpeedKmh,omitempty"`
  24. MaxHeartRateBpm *int `json:"maxHeartRateBpm,omitempty"`
  25. Summary map[string]any `json:"summary,omitempty"`
  26. }
  27. func NewResultService(store *postgres.Store) *ResultService {
  28. return &ResultService{store: store}
  29. }
  30. func (s *ResultService) GetSessionResult(ctx context.Context, sessionPublicID, userID string) (*SessionResultView, error) {
  31. record, err := s.store.GetSessionResultByPublicID(ctx, sessionPublicID)
  32. if err != nil {
  33. return nil, err
  34. }
  35. if record == nil {
  36. return nil, apperr.New(http.StatusNotFound, "session_not_found", "session not found")
  37. }
  38. if userID != "" && record.UserID != userID {
  39. return nil, apperr.New(http.StatusForbidden, "session_forbidden", "session does not belong to current user")
  40. }
  41. return buildSessionResultView(record), nil
  42. }
  43. func (s *ResultService) ListMyResults(ctx context.Context, userID string, limit int) ([]SessionResultView, error) {
  44. if userID == "" {
  45. return nil, apperr.New(http.StatusUnauthorized, "unauthorized", "user is required")
  46. }
  47. records, err := s.store.ListSessionResultsByUserID(ctx, userID, limit)
  48. if err != nil {
  49. return nil, err
  50. }
  51. results := make([]SessionResultView, 0, len(records))
  52. for i := range records {
  53. results = append(results, *buildSessionResultView(&records[i]))
  54. }
  55. return results, nil
  56. }
  57. func buildSessionResultView(record *postgres.SessionResultRecord) *SessionResultView {
  58. view := &SessionResultView{
  59. Session: buildEntrySessionSummary(&record.Session),
  60. Result: ResultSummaryPayload{
  61. Status: record.Status,
  62. },
  63. }
  64. if record.Result != nil {
  65. view.Result.Status = record.Result.ResultStatus
  66. view.Result.FinalDurationSec = record.Result.FinalDurationSec
  67. view.Result.FinalScore = record.Result.FinalScore
  68. view.Result.CompletedControls = record.Result.CompletedControls
  69. view.Result.TotalControls = record.Result.TotalControls
  70. view.Result.DistanceMeters = record.Result.DistanceMeters
  71. view.Result.AverageSpeedKmh = record.Result.AverageSpeedKmh
  72. view.Result.MaxHeartRateBpm = record.Result.MaxHeartRateBpm
  73. if record.Result.SummaryJSON != "" {
  74. summary := map[string]any{}
  75. if err := json.Unmarshal([]byte(record.Result.SummaryJSON), &summary); err == nil && len(summary) > 0 {
  76. view.Result.Summary = summary
  77. }
  78. }
  79. }
  80. return view
  81. }