Skip to content

Add Stream Reactions#1565

Open
SebiWrn wants to merge 51 commits into
devfrom
enh/add-reactions
Open

Add Stream Reactions#1565
SebiWrn wants to merge 51 commits into
devfrom
enh/add-reactions

Conversation

@SebiWrn
Copy link
Copy Markdown
Collaborator

@SebiWrn SebiWrn commented Apr 17, 2025

Motivation and Context

This pull request adds previously mentioned reactions by students (look at #1564).
Closes #127.

The percentage below the reactions shows the usage in the last few minutes.

Available reactions can be modified in the config.yaml.

Important

Do not merge before #1564 !!

Screenshots

image
image

@SebiWrn SebiWrn requested a review from a team April 17, 2025 14:17
@SebiWrn SebiWrn self-assigned this Apr 17, 2025
@SebiWrn SebiWrn linked an issue Apr 17, 2025 that may be closed by this pull request
Comment thread api/stream_reactions.go
Comment thread api/stream_reactions.go Outdated
Comment thread api/stream_reactions.go
CustomMessage: "user not eligible to watch course",
})
return
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

optional: these three conditionals seem like they could be a separate function that could be reused?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I will leave them there for now and they can be extracted if we need them somewhere else

Comment thread api/stream_reactions.go
go func() {
// Notify admins every 5 seconds
logger.Info("Starting periodic notification of reaction percentages")
for {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't this a leaking goroutine? You never end it or cancel it via a context?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This should be ok as this is only started once at the initialize and it will be stopped when the program stops.

Comment thread config.yaml Outdated
Comment thread web/admin.go Outdated
@SebiWrn SebiWrn mentioned this pull request Jun 18, 2025
@SebiWrn SebiWrn requested a review from a team October 16, 2025 07:41
@alexanderstephan
Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

# Conflicts:
#	tools/config.go
#	web/template/watch.gohtml

Co-authored-by: alexanderstephan <30267166+alexanderstephan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 18, 2026

@copilot resolve the merge conflicts in this pull request

Resolved the merge conflicts in commit 7dccd7a. Two files had conflicts:

  • tools/config.go: kept both AllowedReactions (from this PR) and RtmpProxyService (from dev)
  • web/template/watch.gohtml: merged dev's updated responsive CSS classes with this PR's reactions button and overlay, and replaced the old separate desktop chat button with dev's unified chat button

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces live “stream reactions” so students can submit quick emoji feedback during a livestream, and admins can see live reaction highlights plus short-window usage percentages. It also adds configuration for allowed reactions and wires the new feature into the existing watch/admin UI and realtime infrastructure.

Changes:

  • Add backend persistence + REST endpoints for submitting reactions and fetching allowed reactions.
  • Add realtime channel to push reaction events and rolling percentage updates to the live admin management page.
  • Add frontend UI components (watch page reaction picker overlay + admin live view visualization) and a new TS API module.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
web/ts/watch.ts Adds an import related to seekbar overlay exports (currently unused).
web/ts/entry/video.ts Exposes the new reactions TS API via the watch/video bundle exports.
web/ts/api/stream-reactions.ts New TS API module for submitting reactions, fetching allowed reactions, and subscribing to realtime reaction updates.
web/template/watch.gohtml Adds a reactions button + overlay on the watch page and a link to live stream management for admins.
web/template/components/stream-reactions.gohtml New component rendering available reaction buttons driven by allowed reactions API.
web/template/admin/lecture-live-management.gohtml Adds live reaction visualization (highlight + percentage) and modifies stream end modal request handling.
tools/config.go Logs presence/absence of configured allowed reactions on startup.
pkg/campus/campusonline/campusonline.go Minor import reordering cleanup.
model/stream-reaction.go New GORM model for persisting per-user reactions per stream.
mock_dao/stream-reaction.go New generated GoMock for the StreamReactionDao interface.
dao/stream-reaction.go New DAO for creating/querying reactions, including time-window queries.
dao/dao_base.go Wires StreamReactionDao into DaoWrapper.
api/stream_reactions.go New API routes + realtime channel implementation for reactions and periodic percentage updates.
api/stream.go Registers REST endpoints under /api/stream/:streamID/reaction and /reaction/allowed.
api/router.go Registers the new realtime channel at startup.
cmd/tumlive/main.go Adds StreamReaction to AutoMigrate.
config.yaml Adds allowedReactions configuration with default emoji set.
api/worker_grpc.go Removes unused helper/imports (cleanup).
go.mod Adds github.com/getsentry/sentry-go dependency.
go.sum Adds checksums for the new sentry-go dependency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread dao/stream-reaction.go Outdated
Comment thread web/ts/api/stream-reactions.ts Outdated
Comment thread api/stream_reactions.go
Comment thread api/stream_reactions.go
Comment on lines +244 to +248
stream, err := daoWrapper.StreamsDao.GetStreamByID(context.TODO(), messageObj.StreamID)
if err != nil {
logger.Error("Cant get stream by id", "err", err)
return
}
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

This code relies on the package-level daoWrapper variable (set by a different realtime channel in api/runner.go). That creates a hidden dependency on registration order and makes this channel fragile. Pass the DaoWrapper into RegisterReactionUpdateRealtimeChannel and store it in a dedicated variable for reactions instead of reusing the runner global.

Copilot uses AI. Check for mistakes.
Comment thread api/stream_reactions.go
Comment on lines +31 to +35
func (r StreamReactionRoutes) addReaction(c *gin.Context) {
tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext)
user := tumLiveContext.User
stream := tumLiveContext.Stream

Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

New reactions endpoints and realtime update logic are introduced here, but there are no accompanying tests. Given the repo’s existing API test coverage, please add tests for allowed reactions, disallowed reactions, cooldown behavior, and permission checks.

Copilot uses AI. Check for mistakes.
Comment thread api/stream_reactions.go Outdated
Comment on lines 183 to 185
<button class="bg-green-500 inline-block text-center w-24 text-white hover:bg-green-600 dark:hover:bg-green-600 font-bold rounded cursor-pointer p-1 mr-3"
@click="fetch(`/api/stream/${streamID}/end?discard=${false}`).then((response) => {if (response.ok) showModal=false; else throw new Error('Response not ok');}).catch((err) => {
console.log('Some error occurred while ending the stream:', err);
});">
@click="fetch(`/api/stream/${streamID}/end?discard=${false}`).then(showModal=false)">
Yes
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

fetch(...).then(showModal=false) assigns showModal immediately and passes a boolean to .then(), so the modal closes regardless of request success and response errors are ignored (the same pattern is repeated on the "No" button). Use a callback in .then(...) and ideally check response.ok like before.

Copilot uses AI. Check for mistakes.
Comment thread api/stream_reactions.go
Comment on lines +233 to +237
type Message struct {
StreamID string `json:"streamId"`
}

var messageObj Message
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

The server expects streamId in the message payload (json:"streamId"), but the client currently sends streamID. With the current mismatch messageObj.StreamID will be empty and stream lookup will fail. Update either the JSON tag or the client payload key so they match.

Copilot uses AI. Check for mistakes.
Comment thread api/stream_reactions.go
Comment on lines +85 to +89
lastReaction, _ := r.DaoWrapper.StreamReactionDao.GetLastReactionOfUser(c, user.ID)
// This contains the cooldown logic, to change this value change the time.Duration(10) to the desired cooldown time
if lastReaction.Reaction != "" && lastReaction.CreatedAt.Add(time.Duration(10)*time.Second).After(time.Now()) {
_ = c.Error(tools.RequestError{
Status: http.StatusTooManyRequests,
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

Cooldown is enforced using GetLastReactionOfUser(user.ID) without filtering by stream. This means a reaction in one stream can block reactions in another stream during the cooldown window. Consider looking up the last reaction per (user, stream) so cooldown is applied per stream.

Copilot uses AI. Check for mistakes.
Comment thread dao/stream-reaction.go Outdated
@kordianbruck kordianbruck changed the title Enh/add reactions Add Stream Reactions May 5, 2026
Mazi02 and others added 5 commits May 18, 2026 00:33
Tested: the string version is different that the one in db. It's also messy. So the normal version is used as it gets formatted automatically.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Correct, in api/stream_reactions.go we use streamId.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Cleaner api design.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Live reactions for lectures

6 participants