| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- package service
- import (
- "context"
- "net/http"
- "strings"
- "cmr-backend/internal/apperr"
- "cmr-backend/internal/store/postgres"
- )
- type EventPlayService struct {
- store *postgres.Store
- }
- type EventPlayInput struct {
- EventPublicID string
- UserID string
- }
- type EventPlayResult struct {
- Event struct {
- ID string `json:"id"`
- Slug string `json:"slug"`
- DisplayName string `json:"displayName"`
- Summary *string `json:"summary,omitempty"`
- Status string `json:"status"`
- } `json:"event"`
- Release *struct {
- ID string `json:"id"`
- ConfigLabel string `json:"configLabel"`
- ManifestURL string `json:"manifestUrl"`
- ManifestChecksumSha256 *string `json:"manifestChecksumSha256,omitempty"`
- RouteCode *string `json:"routeCode,omitempty"`
- } `json:"release,omitempty"`
- ResolvedRelease *ResolvedReleaseView `json:"resolvedRelease,omitempty"`
- Runtime *RuntimeSummaryView `json:"runtime,omitempty"`
- CurrentPresentation *PresentationSummaryView `json:"currentPresentation,omitempty"`
- CurrentContentBundle *ContentBundleSummaryView `json:"currentContentBundle,omitempty"`
- Play struct {
- AssignmentMode *string `json:"assignmentMode,omitempty"`
- CourseVariants []CourseVariantView `json:"courseVariants,omitempty"`
- CanLaunch bool `json:"canLaunch"`
- PrimaryAction string `json:"primaryAction"`
- Reason string `json:"reason"`
- LaunchSource string `json:"launchSource,omitempty"`
- OngoingSession *EntrySessionSummary `json:"ongoingSession,omitempty"`
- RecentSession *EntrySessionSummary `json:"recentSession,omitempty"`
- } `json:"play"`
- }
- func NewEventPlayService(store *postgres.Store) *EventPlayService {
- return &EventPlayService{store: store}
- }
- func (s *EventPlayService) GetEventPlay(ctx context.Context, input EventPlayInput) (*EventPlayResult, error) {
- input.EventPublicID = strings.TrimSpace(input.EventPublicID)
- input.UserID = strings.TrimSpace(input.UserID)
- if input.EventPublicID == "" {
- return nil, apperr.New(http.StatusBadRequest, "invalid_params", "event id is required")
- }
- if input.UserID == "" {
- return nil, apperr.New(http.StatusUnauthorized, "unauthorized", "user is required")
- }
- event, err := s.store.GetEventByPublicID(ctx, input.EventPublicID)
- if err != nil {
- return nil, err
- }
- if event == nil {
- return nil, apperr.New(http.StatusNotFound, "event_not_found", "event not found")
- }
- sessions, err := s.store.ListSessionsByUserAndEvent(ctx, input.UserID, event.ID, 10)
- if err != nil {
- return nil, err
- }
- result := &EventPlayResult{}
- result.Event.ID = event.PublicID
- result.Event.Slug = event.Slug
- result.Event.DisplayName = event.DisplayName
- result.Event.Summary = event.Summary
- result.Event.Status = event.Status
- variantPlan := resolveVariantPlan(event.ReleasePayloadJSON)
- result.Play.AssignmentMode = variantPlan.AssignmentMode
- if len(variantPlan.CourseVariants) > 0 {
- result.Play.CourseVariants = variantPlan.CourseVariants
- }
- if event.CurrentReleasePubID != nil && event.ConfigLabel != nil && event.ManifestURL != nil {
- result.Release = &struct {
- ID string `json:"id"`
- ConfigLabel string `json:"configLabel"`
- ManifestURL string `json:"manifestUrl"`
- ManifestChecksumSha256 *string `json:"manifestChecksumSha256,omitempty"`
- RouteCode *string `json:"routeCode,omitempty"`
- }{
- ID: *event.CurrentReleasePubID,
- ConfigLabel: *event.ConfigLabel,
- ManifestURL: *event.ManifestURL,
- ManifestChecksumSha256: event.ManifestChecksum,
- RouteCode: event.RouteCode,
- }
- }
- result.ResolvedRelease = buildResolvedReleaseFromEvent(event, LaunchSourceEventCurrentRelease)
- result.Runtime = buildRuntimeSummaryFromEvent(event)
- result.CurrentPresentation = buildPresentationSummaryFromEvent(event)
- if enrichedPresentation, err := loadPresentationSummaryByPublicID(ctx, s.store, event.PresentationID); err != nil {
- return nil, err
- } else if enrichedPresentation != nil {
- result.CurrentPresentation = enrichedPresentation
- }
- result.CurrentContentBundle = buildContentBundleSummaryFromEvent(event)
- if enrichedBundle, err := loadContentBundleSummaryByPublicID(ctx, s.store, event.ContentBundleID); err != nil {
- return nil, err
- } else if enrichedBundle != nil {
- result.CurrentContentBundle = enrichedBundle
- }
- if len(sessions) > 0 {
- recent := buildEntrySessionSummary(&sessions[0])
- result.Play.RecentSession = &recent
- }
- for i := range sessions {
- if isSessionOngoingStatus(sessions[i].Status) {
- ongoing := buildEntrySessionSummary(&sessions[i])
- result.Play.OngoingSession = &ongoing
- break
- }
- }
- canLaunch, launchReason := evaluateEventLaunchReadiness(event)
- result.Play.CanLaunch = canLaunch
- if canLaunch {
- result.Play.LaunchSource = LaunchSourceEventCurrentRelease
- }
- switch {
- case result.Play.OngoingSession != nil:
- result.Play.PrimaryAction = "continue"
- result.Play.Reason = "user has an ongoing session for this event"
- case canLaunch:
- result.Play.PrimaryAction = "start"
- result.Play.Reason = launchReason
- case result.Play.RecentSession != nil:
- result.Play.PrimaryAction = "review_last_result"
- result.Play.Reason = launchReason + ", but user has previous session history"
- default:
- result.Play.PrimaryAction = "unavailable"
- result.Play.Reason = launchReason
- }
- return result, nil
- }
|