Skip to content

fix(video): restrict StreamSchedule to livestream rooms only#2758

Closed
Ruksana7 wants to merge 3 commits intofossasia:developmentfrom
Ruksana7:fix/final-clean
Closed

fix(video): restrict StreamSchedule to livestream rooms only#2758
Ruksana7 wants to merge 3 commits intofossasia:developmentfrom
Ruksana7:fix/final-clean

Conversation

@Ruksana7
Copy link
Copy Markdown

@Ruksana7 Ruksana7 commented Mar 13, 2026

  • Add livestream.hls to inferType() in room-types.js
  • Replace fragile v-if in EditForm.vue with showStreamSchedule computed
  • Add _room_supports_streaming() guard to StreamScheduleViewSet
  • Add CheckConstraint to StreamSchedule Meta for DB-level enforcement

Fixes #1138

Summary by Sourcery

Restrict the new StreamSchedule functionality to livestream rooms by introducing a dedicated stream scheduling model, API viewset, and admin UI integration for stage-type rooms only.

New Features:

  • Add a StreamSchedule model for defining time-based livestream schedules per room with validation against overlapping slots.
  • Expose StreamSchedule CRUD operations through a dedicated DRF ViewSet tied to rooms and event notifications.
  • Introduce a room edit form in the admin video UI that infers room types and shows a stream schedule management component for stage-type rooms.

Enhancements:

  • Add centralized room type definitions and inference helpers in the frontend to determine room capabilities based on configured modules.

- Add livestream.hls to inferType() in room-types.js
- Replace fragile v-if in EditForm.vue with showStreamSchedule computed
- Add _room_supports_streaming() guard to StreamScheduleViewSet
- Add CheckConstraint to StreamSchedule Meta for DB-level enforcement

Fixes fossasia#1138
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Mar 13, 2026

Reviewer's Guide

Implements a new StreamSchedule model and API restricted to livestream-capable rooms, wires it into the admin room edit UI for stage-type rooms, and centralizes room type inference logic in a shared room-types helper used by the frontend.

Sequence diagram for StreamSchedule create and update with broadcast and notifications

sequenceDiagram
    actor Admin
    participant WebApp as WebApp_Frontend
    participant API as StreamScheduleViewSet
    participant RoomModel as Room
    participant StreamScheduleModel as StreamSchedule
    participant Broadcaster as broadcast_stream_change
    participant Notifier as notify_event_change

    Admin->>WebApp: Open admin room edit form
    WebApp->>WebApp: inferType(config) == stage
    WebApp->>WebApp: Show StreamSchedule component

    Admin->>WebApp: Create or edit stream schedule
    WebApp->>API: POST or PUT /rooms/{room_pk}/stream_schedules

    API->>API: get_room()
    API->>RoomModel: get_current_stream()
    RoomModel-->>API: previous_stream
    API->>StreamScheduleModel: validate and save
    StreamScheduleModel-->>API: instance
    API->>RoomModel: get_current_stream()
    RoomModel-->>API: current_stream

    API->>API: Compare previous_stream and current_stream
    alt Stream changed
        API->>Broadcaster: broadcast_stream_change(room_id, current_stream, reload=True)
    end

    API->>Notifier: notify_event_change(event_id)
    API-->>WebApp: 200 OK with StreamSchedule data
    WebApp-->>Admin: Updated schedule shown
Loading

ER diagram for Room and StreamSchedule relationship and constraints

erDiagram
    ROOM {
        int id PK
        varchar name
        int event_id FK
    }

    STREAM_SCHEDULE {
        int id PK
        int room_id FK
        varchar title
        varchar url
        datetime start_time
        datetime end_time
        varchar stream_type
        json config
        datetime created_at
        datetime updated_at
    }

    ROOM ||--o{ STREAM_SCHEDULE : has
Loading

Class diagram for StreamSchedule model and related backend components

classDiagram
    class Room {
        +int id
        +str name
        +int event_id
        +Event event
        +StreamSchedule get_current_stream()
    }

    class StreamSchedule {
        +int id
        +Room room
        +str title
        +str url
        +datetime start_time
        +datetime end_time
        +str stream_type
        +dict config
        +datetime created_at
        +datetime updated_at
        +bool is_active(at_time)
        +void clean()
        +void save(*args, **kwargs)
        +str __str__()
    }

    class StreamScheduleSerializer {
        +StreamSchedule create(validated_data)
        +StreamSchedule update(instance, validated_data)
    }

    class PretalxViewSetMixin {
        +Event event
        +str write_permission
    }

    class StreamScheduleViewSet {
        +QuerySet queryset
        +StreamScheduleSerializer serializer_class
        +str endpoint
        +tuple~str~ search_fields
        +str write_permission
        +Room get_room()
        +dict get_serializer_context()
        +QuerySet get_queryset()
        +Response create(request, *args, **kwargs)
        +Response update(request, *args, **kwargs)
        +void perform_destroy(instance)
    }

    class Event {
        +int id
        +Organizer organizer
    }

    class Organizer {
        +int id
    }

    class broadcast_stream_change {
        +void __call__(int room_id, StreamSchedule current_stream, bool reload)
    }

    class notify_event_change {
        +void __call__(int event_id)
    }

    Room "1" --> "*" StreamSchedule : stream_schedules
    StreamScheduleViewSet --|> PretalxViewSetMixin
    StreamScheduleViewSet --> StreamSchedule : manages
    StreamScheduleViewSet --> StreamScheduleSerializer : uses
    StreamSchedule --> Room : room
    StreamScheduleViewSet ..> broadcast_stream_change : calls
    StreamScheduleViewSet ..> notify_event_change : calls
    Room --> Event : event
    Event --> Organizer : organizer
Loading

Class diagram for frontend room editing and room type inference

classDiagram
    class EditForm {
        +Object config
        +bool creating
        +Object allRoomTypes
        +Object typeComponents
        +bool saving
        +str error
        +Object modules
        +Object inferredType
        +str localizedName
        +str localizedDescription
        +void save()
    }

    class ROOM_TYPES {
        +list~RoomTypeDefinition~ types
    }

    class RoomTypeDefinition {
        +str id
        +str icon
        +str name
        +str description
        +str startingModule
        +str behindFeatureFlag
    }

    class room_types_helper {
        +list~RoomTypeDefinition~ ROOM_TYPES
        +RoomTypeDefinition inferType(config)
        +RoomTypeDefinition inferRoomType(room)
    }

    class StreamScheduleComponent {
        +int roomId
    }

    class StageComponent {
        +Object config
        +Object modules
        +void beforeSave()
    }

    class features {
        +bool enabled(flag)
    }

    EditForm --> room_types_helper : uses inferType
    room_types_helper --> ROOM_TYPES : filters
    ROOM_TYPES --> RoomTypeDefinition : elements
    EditForm --> StageComponent : renders for stage type
    EditForm --> StreamScheduleComponent : renders for stage type
    room_types_helper ..> features : uses enabled
Loading

File-Level Changes

Change Details Files
Add a reusable room edit form that conditionally exposes stream scheduling only for non-new stage rooms.
  • Introduce EditForm.vue with a generic room configuration form using Vuelidate and Vuex permissions.
  • Infer the room type from its module_config via inferType and map to specific type edit components (stage, channels, pages, posters).
  • Render the StreamSchedule child component only when editing an existing room whose inferred type is a stage (using room id as prop).
app/eventyay/webapp/video/src/views/admin/rooms/EditForm.vue
Centralize room type metadata and inference logic for media vs non-media rooms.
  • Define ROOM_TYPES with IDs, icons, descriptions, starting modules, and optional feature flags.
  • Implement inferType(config) to resolve a room type from module_config, treating livestream and call modules as media rooms and mapping single-module non-media rooms by startingModule.
  • Expose inferRoomType(room) as a thin wrapper around inferType using room.modules.
app/eventyay/webapp/video/src/lib/room-types.js
Introduce a StreamSchedule domain model with validation for non-overlapping time ranges per room.
  • Create StreamSchedule model with FK to Room, title/url/time range/stream_type/config fields, timestamps, and index on (room, start_time, end_time).
  • Implement clean() to enforce end_time > start_time and prevent overlapping schedules within the same room, excluding self on update.
  • Override save() to run full_clean by default with an option to skip validation, and add is_active() helper based on current time.
app/eventyay/base/models/stream_schedule.py
Expose StreamSchedule CRUD operations via a room-scoped API that updates live stream state and event metadata.
  • Add StreamScheduleViewSet with PretalxViewSetMixin, search/filtering, and room- and event-scoped queryset resolution via get_room and get_queryset.
  • Ensure serializer context carries the room, both for create and update, and apply validation errors as structured 400 responses.
  • On create/update/destroy, compute previous vs current room stream, broadcast changes via broadcast_stream_change when the effective stream changes, and notify_event_change for the owning event.
app/eventyay/api/views/stream_schedule.py

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The new inferType helper assumes config.module_config is always present and an array; consider defaulting to an empty array (e.g. (config.module_config || []).reduce(...)) to avoid runtime errors when the config is incomplete or coming from unexpected sources.
  • The StreamScheduleViewSet.create and update methods duplicate the same ValidationError-to-response mapping logic; extracting this into a small helper (e.g. _validation_error_response(e)) would simplify the code and make future changes to that behavior easier.
  • In StreamScheduleViewSet.perform_destroy, the room is fetched twice in some branches; you can reduce redundant queries by fetching it once up front (or always via instance.room before deletion) and reusing that reference when computing event_id.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `inferType` helper assumes `config.module_config` is always present and an array; consider defaulting to an empty array (e.g. `(config.module_config || []).reduce(...)`) to avoid runtime errors when the config is incomplete or coming from unexpected sources.
- The `StreamScheduleViewSet.create` and `update` methods duplicate the same `ValidationError`-to-response mapping logic; extracting this into a small helper (e.g. `_validation_error_response(e)`) would simplify the code and make future changes to that behavior easier.
- In `StreamScheduleViewSet.perform_destroy`, the room is fetched twice in some branches; you can reduce redundant queries by fetching it once up front (or always via `instance.room` before deletion) and reusing that reference when computing `event_id`.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Collaborator

@Saksham-Sirohi Saksham-Sirohi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closing as the changes do not make a change to the current branch, also, this functionality was already created a while back

@github-project-automation github-project-automation bot moved this from Backlog to Done in Eventyay Next Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants