entry_home_service.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package service
  2. import (
  3. "context"
  4. "net/http"
  5. "strings"
  6. "cmr-backend/internal/apperr"
  7. "cmr-backend/internal/store/postgres"
  8. )
  9. type EntryHomeService struct {
  10. store *postgres.Store
  11. }
  12. type EntryHomeInput struct {
  13. UserID string
  14. ChannelCode string
  15. ChannelType string
  16. PlatformAppID string
  17. TenantCode string
  18. }
  19. type EntryHomeResult struct {
  20. User struct {
  21. ID string `json:"id"`
  22. PublicID string `json:"publicId"`
  23. Status string `json:"status"`
  24. Nickname *string `json:"nickname,omitempty"`
  25. AvatarURL *string `json:"avatarUrl,omitempty"`
  26. } `json:"user"`
  27. Tenant struct {
  28. ID string `json:"id"`
  29. Code string `json:"code"`
  30. Name string `json:"name"`
  31. } `json:"tenant"`
  32. Channel struct {
  33. ID string `json:"id"`
  34. Code string `json:"code"`
  35. Type string `json:"type"`
  36. PlatformAppID *string `json:"platformAppId,omitempty"`
  37. DisplayName string `json:"displayName"`
  38. Status string `json:"status"`
  39. IsDefault bool `json:"isDefault"`
  40. } `json:"channel"`
  41. Cards []CardResult `json:"cards"`
  42. OngoingSession *EntrySessionSummary `json:"ongoingSession,omitempty"`
  43. RecentSession *EntrySessionSummary `json:"recentSession,omitempty"`
  44. }
  45. type EntrySessionSummary struct {
  46. ID string `json:"id"`
  47. Status string `json:"status"`
  48. EventID string `json:"eventId"`
  49. EventName string `json:"eventName"`
  50. ReleaseID *string `json:"releaseId,omitempty"`
  51. ConfigLabel *string `json:"configLabel,omitempty"`
  52. VariantID *string `json:"variantId,omitempty"`
  53. VariantName *string `json:"variantName,omitempty"`
  54. RouteCode *string `json:"routeCode,omitempty"`
  55. LaunchedAt string `json:"launchedAt"`
  56. StartedAt *string `json:"startedAt,omitempty"`
  57. EndedAt *string `json:"endedAt,omitempty"`
  58. }
  59. func NewEntryHomeService(store *postgres.Store) *EntryHomeService {
  60. return &EntryHomeService{store: store}
  61. }
  62. func (s *EntryHomeService) GetEntryHome(ctx context.Context, input EntryHomeInput) (*EntryHomeResult, error) {
  63. input.UserID = strings.TrimSpace(input.UserID)
  64. if input.UserID == "" {
  65. return nil, apperr.New(http.StatusUnauthorized, "unauthorized", "user is required")
  66. }
  67. user, err := s.store.GetUserByID(ctx, s.store.Pool(), input.UserID)
  68. if err != nil {
  69. return nil, err
  70. }
  71. if user == nil {
  72. return nil, apperr.New(http.StatusNotFound, "user_not_found", "user not found")
  73. }
  74. entry, err := s.store.FindEntryChannel(ctx, postgres.FindEntryChannelParams{
  75. ChannelCode: strings.TrimSpace(input.ChannelCode),
  76. ChannelType: strings.TrimSpace(input.ChannelType),
  77. PlatformAppID: strings.TrimSpace(input.PlatformAppID),
  78. TenantCode: strings.TrimSpace(input.TenantCode),
  79. })
  80. if err != nil {
  81. return nil, err
  82. }
  83. if entry == nil {
  84. return nil, apperr.New(http.StatusNotFound, "entry_channel_not_found", "entry channel not found")
  85. }
  86. cards, err := s.store.ListCardsForEntry(ctx, entry.TenantID, &entry.ID, "home_primary", nowUTC(), 20)
  87. if err != nil {
  88. return nil, err
  89. }
  90. sessions, err := s.store.ListSessionsByUserID(ctx, user.ID, 10)
  91. if err != nil {
  92. return nil, err
  93. }
  94. result := &EntryHomeResult{
  95. Cards: mapCards(cards),
  96. }
  97. result.User.ID = user.ID
  98. result.User.PublicID = user.PublicID
  99. result.User.Status = user.Status
  100. result.User.Nickname = user.Nickname
  101. result.User.AvatarURL = user.AvatarURL
  102. result.Tenant.ID = entry.TenantID
  103. result.Tenant.Code = entry.TenantCode
  104. result.Tenant.Name = entry.TenantName
  105. result.Channel.ID = entry.ID
  106. result.Channel.Code = entry.ChannelCode
  107. result.Channel.Type = entry.ChannelType
  108. result.Channel.PlatformAppID = entry.PlatformAppID
  109. result.Channel.DisplayName = entry.DisplayName
  110. result.Channel.Status = entry.Status
  111. result.Channel.IsDefault = entry.IsDefault
  112. if len(sessions) > 0 {
  113. recent := buildEntrySessionSummary(&sessions[0])
  114. result.RecentSession = &recent
  115. }
  116. for i := range sessions {
  117. if isSessionOngoingStatus(sessions[i].Status) {
  118. ongoing := buildEntrySessionSummary(&sessions[i])
  119. result.OngoingSession = &ongoing
  120. break
  121. }
  122. }
  123. return result, nil
  124. }
  125. func buildEntrySessionSummary(session *postgres.Session) EntrySessionSummary {
  126. summary := EntrySessionSummary{
  127. ID: session.SessionPublicID,
  128. Status: session.Status,
  129. VariantID: session.VariantID,
  130. VariantName: session.VariantName,
  131. RouteCode: session.RouteCode,
  132. LaunchedAt: session.LaunchedAt.Format(timeRFC3339),
  133. }
  134. if session.EventPublicID != nil {
  135. summary.EventID = *session.EventPublicID
  136. }
  137. if session.EventDisplayName != nil {
  138. summary.EventName = *session.EventDisplayName
  139. }
  140. summary.ReleaseID = session.ReleasePublicID
  141. summary.ConfigLabel = session.ConfigLabel
  142. if session.StartedAt != nil {
  143. value := session.StartedAt.Format(timeRFC3339)
  144. summary.StartedAt = &value
  145. }
  146. if session.EndedAt != nil {
  147. value := session.EndedAt.Format(timeRFC3339)
  148. summary.EndedAt = &value
  149. }
  150. return summary
  151. }