Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1365 daten zum live view count #1366

Merged
merged 14 commits into from
Sep 11, 2024
78 changes: 73 additions & 5 deletions api/statistics.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

type statReq struct {
Interval string `form:"interval" json:"interval" xml:"interval" binding:"required"`
Lecture string `form:"lecture" json:"lecture" xml:"lecture"`
}

type statExportReq struct {
Expand Down Expand Up @@ -46,11 +47,35 @@ func (r coursesRoutes) getStats(c *gin.Context) {
} else { // use course from context
cid = ctx.(tools.TUMLiveContext).Course.ID
}

var sid uint
if req.Lecture != "" {
sidTemp, err := strconv.ParseUint(req.Lecture, 10, 32)
if err != nil {
logger.Warn("strconv.Atoi failed", "err", err, "courseId", cid)
_ = c.Error(tools.RequestError{
Status: http.StatusBadRequest,
CustomMessage: "strconv.Atoi failed",
Err: err,
})
return
}
sid = uint(sidTemp)
} else {
sid = ^uint(0)
}

switch req.Interval {
case "week":
fallthrough
case "day":
res, err := r.StatisticsDao.GetCourseStatsWeekdays(cid)
var res []dao.Stat
var err error
if sid != ^uint(0) {
res, err = r.StatisticsDao.GetLectureStatsWeekdays(cid, sid)
} else {
res, err = r.StatisticsDao.GetCourseStatsWeekdays(cid)
}
if err != nil {
logger.Warn("GetCourseStatsWeekdays failed", "err", err, "courseId", cid)
_ = c.Error(tools.RequestError{
Expand All @@ -69,7 +94,13 @@ func (r coursesRoutes) getStats(c *gin.Context) {
resp.Data.Datasets[0].Data = res
c.JSON(http.StatusOK, resp)
case "hour":
res, err := r.StatisticsDao.GetCourseStatsHourly(cid)
var res []dao.Stat
var err error
if sid != ^uint(0) {
res, err = r.StatisticsDao.GetLectureStatsHourly(cid, sid)
} else {
res, err = r.StatisticsDao.GetCourseStatsHourly(cid)
}
if err != nil {
logger.Warn("GetCourseStatsHourly failed", "err", err, "courseId", cid)
_ = c.Error(tools.RequestError{
Expand All @@ -87,6 +118,25 @@ func (r coursesRoutes) getStats(c *gin.Context) {
resp.Data.Datasets[0].Label = "Sum(viewers)"
resp.Data.Datasets[0].Data = res
c.JSON(http.StatusOK, resp)
case "lecture":
res, err := r.StatisticsDao.GetLectureStats(cid, sid)
if err != nil {
logger.Warn("GetLectureStats failed", "err", err, "courseId", cid)
_ = c.Error(tools.RequestError{
Status: http.StatusInternalServerError,
CustomMessage: "can not get course stats hourly",
Err: err,
})
return
}
resp := chartJs{
ChartType: "bar",
Data: chartJsData{Datasets: []chartJsDataset{newChartJsDataset()}},
Options: newChartJsOptions(),
}
resp.Data.Datasets[0].Label = "View Count"
resp.Data.Datasets[0].Data = res
c.JSON(http.StatusOK, resp)
case "activity-live":
resLive, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, true)
if err != nil {
Expand Down Expand Up @@ -144,7 +194,13 @@ func (r coursesRoutes) getStats(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"res": res})
}
case "vodViews":
res, err := r.StatisticsDao.GetCourseNumVodViews(cid)
var res int
var err error
if sid != ^uint(0) {
res, err = r.StatisticsDao.GetLectureNumVodViews(sid)
} else {
res, err = r.StatisticsDao.GetCourseNumVodViews(cid)
}
if err != nil {
logger.Warn("GetCourseNumVodViews failed", "err", err, "courseId", cid)
_ = c.Error(tools.RequestError{
Expand All @@ -157,7 +213,13 @@ func (r coursesRoutes) getStats(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"res": res})
}
case "liveViews":
res, err := r.StatisticsDao.GetCourseNumLiveViews(cid)
var res int
var err error
if sid != ^uint(0) {
res, err = r.StatisticsDao.GetLectureNumLiveViews(sid)
} else {
res, err = r.StatisticsDao.GetCourseNumLiveViews(cid)
}
if err != nil {
logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid)
_ = c.Error(tools.RequestError{
Expand All @@ -171,7 +233,13 @@ func (r coursesRoutes) getStats(c *gin.Context) {
}
case "allDays":
{
res, err := r.StatisticsDao.GetCourseNumVodViewsPerDay(cid)
var res []dao.Stat
var err error
if sid != ^uint(0) {
res, err = r.StatisticsDao.GetLectureNumVodViewsPerDay(sid)
} else {
res, err = r.StatisticsDao.GetCourseNumVodViewsPerDay(cid)
}
if err != nil {
logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid)
_ = c.Error(tools.RequestError{
Expand Down
74 changes: 74 additions & 0 deletions dao/statistics.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@ type StatisticsDao interface {
GetCourseNumStudents(courseID uint) (int64, error)
GetCourseNumVodViews(courseID uint) (int, error)
GetCourseNumLiveViews(courseID uint) (int, error)
GetLectureNumVodViews(streamID uint) (int, error)
GetLectureNumLiveViews(streamID uint) (int, error)
GetCourseNumVodViewsPerDay(courseID uint) ([]Stat, error)
GetLectureNumVodViewsPerDay(streamID uint) ([]Stat, error)
GetCourseStatsWeekdays(courseID uint) ([]Stat, error)
GetCourseStatsHourly(courseID uint) ([]Stat, error)
GetLectureStatsWeekdays(courseID uint, streamID uint) ([]Stat, error)
GetLectureStatsHourly(courseID uint, streamID uint) ([]Stat, error)
GetLectureStats(courseID uint, lectureID uint) ([]Stat, error)
GetStudentActivityCourseStats(courseID uint, live bool) ([]Stat, error)
GetStreamNumLiveViews(streamID uint) (int, error)
}
Expand Down Expand Up @@ -66,6 +72,21 @@ func (d statisticsDao) GetCourseNumLiveViews(courseID uint) (int, error) {
return res, err
}

// GetLectureNumVodViews returns the sum of vod views of a lecture
func (d statisticsDao) GetLectureNumVodViews(streamID uint) (int, error) {
var res int
err := DB.Raw(`SELECT IFNULL(SUM(viewers), 0) FROM stats
WHERE live = 0 AND stream_id = ?`, streamID).Scan(&res).Error
return res, err
}

// GetLectureNumLiveViews returns the sum of live views of a lecture
func (d statisticsDao) GetLectureNumLiveViews(streamID uint) (int, error) {
var res int
err := DB.Raw(`SELECT MAX(viewers) from stats where stream_id = ?`, streamID).Scan(&res).Error
return res, err
}

// GetCourseNumVodViewsPerDay returns the daily amount of vod views for each day
func (d statisticsDao) GetCourseNumVodViewsPerDay(courseID uint) ([]Stat, error) {
var res []Stat
Expand All @@ -78,6 +99,17 @@ func (d statisticsDao) GetCourseNumVodViewsPerDay(courseID uint) ([]Stat, error)
return res, err
}

// GetLectureNumVodViewsPerDay returns the daily amount of vod views for each day
func (d statisticsDao) GetLectureNumVodViewsPerDay(streamID uint) ([]Stat, error) {
var res []Stat
err := DB.Raw(`SELECT DATE_FORMAT(stats.time, GET_FORMAT(DATE, 'EUR')) AS x, sum(viewers) AS y
FROM stats
WHERE stream_id = ? AND live = 0
GROUP BY DATE(stats.time);`,
streamID).Scan(&res).Error
return res, err
}

// GetCourseStatsWeekdays returns the days and their sum of vod views of a course
func (d statisticsDao) GetCourseStatsWeekdays(courseID uint) ([]Stat, error) {
var res []Stat
Expand All @@ -102,6 +134,41 @@ func (d statisticsDao) GetCourseStatsHourly(courseID uint) ([]Stat, error) {
return res, err
}

// GetLectureStatsWeekdays returns the days and their sum of vod views of a lecture
func (d statisticsDao) GetLectureStatsWeekdays(courseID uint, streamID uint) ([]Stat, error) {
var res []Stat
err := DB.Raw(`SELECT DAYNAME(stats.time) AS x, SUM(stats.viewers) as y
FROM stats
JOIN streams s ON s.id = stats.stream_id
WHERE (s.course_id = ? OR ? = 0) AND stats.live = 0 AND stats.stream_id = ?
GROUP BY DAYOFWEEK(stats.time);`,
courseID, courseID, streamID).Scan(&res).Error
SebiWrn marked this conversation as resolved.
Show resolved Hide resolved
return res, err
}

// GetLectureStatsHourly returns the hours with most vod viewing activity of a lecture
func (d statisticsDao) GetLectureStatsHourly(courseID uint, streamID uint) ([]Stat, error) {
var res []Stat
err := DB.Raw(`SELECT HOUR(stats.time) AS x, SUM(stats.viewers) as y
FROM stats
JOIN streams s ON s.id = stats.stream_id
WHERE (s.course_id = ? or ? = 0) AND stats.live = 0 AND stats.stream_id = ?
GROUP BY HOUR(stats.time);`,
courseID, courseID, streamID).Scan(&res).Error
return res, err
}

// GetLectureStats returns the number of viewers during a lecture
func (d statisticsDao) GetLectureStats(courseID uint, streamID uint) ([]Stat, error) {
var res []Stat
err := DB.Raw(`SELECT Date_FORMAT(stats.time, "%H:%i") AS x, stats.viewers AS y
FROM stats
JOIN streams s ON s.id = stats.stream_id
WHERE s.course_id = ? AND s.id = ? AND stats.live = 1
ORDER BY x;`, courseID, streamID).Scan(&res).Error
return res, err
}

// GetStreamNumLiveViews returns the number of viewers currently watching a live stream.
func (d statisticsDao) GetStreamNumLiveViews(streamID uint) (int, error) {
var res int
Expand Down Expand Up @@ -155,6 +222,13 @@ func (d statisticsDao) GetStudentActivityCourseStats(courseID uint, live bool) (
return retVal, err
}

func (d statisticsDao) GetLectureLiveStats(streamID uint) ([]model.Stat, error) {
var res []model.Stat
err := DB.Raw("SELECT * FROM stats WHERE stream_id = ? AND live = 1", streamID).Scan(&res).Error

return res, err
}

// Stat key value struct that is parsable by Chart.js without further modifications.
// See https://www.chartjs.org/docs/master/general/data-structures.html
type Stat struct {
Expand Down
Loading
Loading