diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c531a2e44..5e30fab8d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -55,7 +55,7 @@ jobs: # uses a compiled language #- run: | - # make bootstrap + # make all # make release - name: Perform CodeQL Analysis diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 53e79d7ba..142575890 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -8,7 +8,7 @@ jobs: test: strategy: matrix: - go-version: [ 1.20.x ] + go-version: [ 1.21.x ] os: [ ubuntu-latest ] runs-on: ${{ matrix.os }} steps: diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index e8a5eade6..2db1a4cf4 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: 1.21 - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 diff --git a/.golangci.yml b/.golangci.yml index d42a24da6..ebfc5505f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,7 +25,7 @@ linters: fast: false run: - go: '1.19' + go: '1.21' timeout: 10m skip-dirs: - node_modules @@ -67,7 +67,7 @@ linters-settings: - name: modifies-value-receiver gofumpt: extra-rules: false - lang-version: "1.19" + lang-version: "1.21" issues: max-issues-per-linter: 0 diff --git a/.idea/runConfigurations/all.xml b/.idea/runConfigurations/all.xml deleted file mode 100644 index 38b79f9b7..000000000 --- a/.idea/runConfigurations/all.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index c32a96118..1ef96930c 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ docker run --detach \ ### Install go -- Install **go >=1.18** by following the steps [here](https://go.dev/doc/install) +- Install **go >=1.21** by following the steps [here](https://go.dev/doc/install) - Preferably use [JetBrains GoLand](https://youtu.be/vetAfxQxyJE) and open this project as it simplifies this entire process - Go to File -> Settings -> Go -> Go Modules and enable go modules integration. - Run `npm i` in the `./web` directory to install the required node modules diff --git a/api/api_logger.go b/api/api_logger.go new file mode 100644 index 000000000..d7a7b552c --- /dev/null +++ b/api/api_logger.go @@ -0,0 +1,10 @@ +package api + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "api") diff --git a/api/chat.go b/api/chat.go index bc6b575ab..f66c02dba 100644 --- a/api/chat.go +++ b/api/chat.go @@ -19,7 +19,6 @@ import ( "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" ) const ( @@ -65,7 +64,7 @@ func RegisterRealtimeChatChannel() { req, err := parseChatPayload(message) if err != nil { - log.WithError(err).Warn("could not unmarshal request") + logger.Warn("could not unmarshal request", "err", err) return } @@ -89,7 +88,7 @@ func RegisterRealtimeChatChannel() { case "react_to": routes.handleReactTo(tumLiveContext, message.Payload) default: - log.WithField("type", req.Type).Warn("unknown websocket request type") + logger.Warn("unknown websocket request type", "type", req.Type) } }, }) @@ -121,7 +120,7 @@ type chatRoutes struct { func (r chatRoutes) handleSubmitPollOptionVote(ctx tools.TUMLiveContext, msg []byte) { var req submitPollOptionVote if err := json.Unmarshal(msg, &req); err != nil { - log.WithError(err).Warn("could not unmarshal submit poll answer request") + logger.Warn("could not unmarshal submit poll answer request", "err", err) return } if ctx.User == nil { @@ -129,7 +128,7 @@ func (r chatRoutes) handleSubmitPollOptionVote(ctx tools.TUMLiveContext, msg []b } if err := r.ChatDao.AddChatPollOptionVote(req.PollOptionId, ctx.User.ID); err != nil { - log.WithError(err).Warn("could not add poll option vote") + logger.Warn("could not add poll option vote", "err", err) return } @@ -144,7 +143,7 @@ func (r chatRoutes) handleSubmitPollOptionVote(ctx tools.TUMLiveContext, msg []b if voteUpdateJson, err := json.Marshal(voteUpdateMap); err == nil { broadcastStreamToAdmins(ctx.Stream.ID, voteUpdateJson) } else { - log.WithError(err).Warn("could not marshal vote update map") + logger.Warn("could not marshal vote update map", "err", err) return } } @@ -158,7 +157,7 @@ func (r chatRoutes) handleStartPoll(ctx tools.TUMLiveContext, msg []byte) { var req startPollReq if err := json.Unmarshal(msg, &req); err != nil { - log.WithError(err).Warn("could not unmarshal start poll request") + logger.Warn("could not unmarshal start poll request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -166,14 +165,14 @@ func (r chatRoutes) handleStartPoll(ctx tools.TUMLiveContext, msg []byte) { } if len(req.Question) == 0 { - log.Warn("could not create poll with empty question") + logger.Warn("could not create poll with empty question") return } var pollOptions []model.PollOption for _, answer := range req.PollAnswers { if len(answer) == 0 { - log.Warn("could not create poll with empty answer") + logger.Warn("could not create poll with empty answer") return } pollOptions = append(pollOptions, model.PollOption{ @@ -244,7 +243,7 @@ func (r chatRoutes) handleResolve(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message delete request") + logger.Warn("could not unmarshal message delete request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -253,7 +252,7 @@ func (r chatRoutes) handleResolve(ctx tools.TUMLiveContext, msg []byte) { err = r.ChatDao.ResolveChat(req.Id) if err != nil { - log.WithError(err).Error("could not delete chat") + logger.Error("could not delete chat", "err", err) } broadcast := gin.H{ @@ -261,7 +260,7 @@ func (r chatRoutes) handleResolve(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal delete message") + logger.Error("could not marshal delete message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -271,7 +270,7 @@ func (r chatRoutes) handleDelete(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message delete request") + logger.Warn("could not unmarshal message delete request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -279,14 +278,14 @@ func (r chatRoutes) handleDelete(ctx tools.TUMLiveContext, msg []byte) { } err = r.ChatDao.DeleteChat(req.Id) if err != nil { - log.WithError(err).Error("could not delete chat") + logger.Error("could not delete chat", "err", err) } broadcast := gin.H{ "delete": req.Id, } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal delete message") + logger.Error("could not marshal delete message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -296,7 +295,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message approve request") + logger.Warn("could not unmarshal message approve request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -305,7 +304,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { err = r.ChatDao.ApproveChat(req.Id) if err != nil { - log.WithError(err).Error("could not approve chat") + logger.Error("could not approve chat", "err", err) return } @@ -315,7 +314,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { */ chat, err := r.ChatDao.GetChat(req.Id, 0) if err != nil { - log.WithError(err).Error("could not get chat") + logger.Error("could not get chat", "err", err) } broadcast := gin.H{ "approve": req.Id, @@ -323,7 +322,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal approve message") + logger.Error("could not marshal approve message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -333,23 +332,23 @@ func (r chatRoutes) handleReactTo(ctx tools.TUMLiveContext, msg []byte) { var req wsReactToReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal reactTo request") + logger.Warn("could not unmarshal reactTo request", "err", err) return } if _, isAllowed := allowedReactions[req.Reaction]; !isAllowed { - log.Warn("user tried to add illegal reaction") + logger.Warn("user tried to add illegal reaction") return } err = r.ChatDao.ToggleReaction(ctx.User.ID, req.wsIdReq.Id, ctx.User.Name, req.Reaction) if err != nil { - log.WithError(err).Error("error reacting to message") + logger.Error("error reacting to message", "err", err) return } reactions, err := r.ChatDao.GetReactions(req.Id) if err != nil { - log.WithError(err).Error("error getting num of chat reactions") + logger.Error("error getting num of chat reactions", "err", err) return } broadcast := gin.H{ @@ -358,7 +357,7 @@ func (r chatRoutes) handleReactTo(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("Can't marshal reactions message") + logger.Error("Can't marshal reactions message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -368,7 +367,7 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message retract request") + logger.Warn("could not unmarshal message retract request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -377,19 +376,19 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { err = r.ChatDao.RetractChat(req.Id) if err != nil { - log.WithError(err).Error("could not retract chat") + logger.Error("could not retract chat", "err", err) return } err = r.ChatDao.RemoveReactions(req.Id) if err != nil { - log.WithError(err).Error("could not remove reactions from chat") + logger.Error("could not remove reactions from chat", "err", err) return } chat, err := r.ChatDao.GetChat(req.Id, 0) if err != nil { - log.WithError(err).Error("could not get chat") + logger.Error("could not get chat", "err", err) } broadcast := gin.H{ "retract": req.Id, @@ -397,7 +396,7 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal retract message") + logger.Error("could not marshal retract message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -406,7 +405,7 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { func (r chatRoutes) handleMessage(ctx tools.TUMLiveContext, context *realtime.Context, msg []byte) { var chat chatReq if err := json.Unmarshal(msg, &chat); err != nil { - log.WithError(err).Error("error unmarshalling chat message") + logger.Error("error unmarshalling chat message", "err", err) return } if !ctx.Course.ChatEnabled && !ctx.Stream.ChatEnabled { @@ -578,7 +577,7 @@ func (r chatRoutes) getActivePoll(c *gin.Context) { if isAdminOfCourse { voteCount, err = r.ChatDao.GetPollOptionVoteCount(option.ID) if err != nil { - log.WithError(err).Warn("could not get poll option vote count") + logger.Warn("could not get poll option vote count", "err", err) } } @@ -681,7 +680,7 @@ func CollectStats(daoWrapper dao.DaoWrapper) func() { if s.LiveNow { // store stats for livestreams only s.Stats = append(s.Stats, stat) if err := daoWrapper.AddStat(stat); err != nil { - log.WithError(err).Error("Saving stat failed") + logger.Error("Saving stat failed", "err", err) } } } @@ -734,7 +733,7 @@ func afterUnsubscribe(id string, joinTime time.Time, recording bool, daoWrapper if recording && joinTime.Before(time.Now().Add(time.Minute*-5)) { err := daoWrapper.AddVodView(id) if err != nil { - log.WithError(err).Error("Can't save vod view") + logger.Error("Can't save vod view", "err", err) } } } diff --git a/api/courseimport.go b/api/courseimport.go index 77e81a55d..18db73131 100644 --- a/api/courseimport.go +++ b/api/courseimport.go @@ -6,13 +6,12 @@ import ( "errors" "fmt" campusonline "github.com/RBG-TUM/CAMPUSOnline" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/tum" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "html/template" "net/http" "strconv" @@ -90,7 +89,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { for _, event := range courseReq.Events { lectureHall, err := r.LectureHallsDao.GetLectureHallByPartialName(event.RoomName) if err != nil { - log.WithError(err).Error("No room found for request") + logger.Error("No room found for request", "err", err) continue } var eventID uint @@ -122,7 +121,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { mail := contact.Email user, err := tum.FindUserWithEmail(mail) if err != nil || user == nil { - log.WithError(err).Errorf("can't find user %v", mail) + logger.Error("can't find user "+mail, "err", err) continue } time.Sleep(time.Millisecond * 200) // wait a bit, otherwise ldap locks us out @@ -130,14 +129,14 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { user.Role = model.LecturerType err = r.UsersDao.UpsertUser(user) if err != nil { - log.Error(err) + logger.Error("Could not upsert user", "err", err) } else { users = append(users, user) } } for _, user := range users { if err := r.CoursesDao.AddAdminToCourse(user.ID, course.ID); err != nil { - log.WithError(err).Error("can't add admin to course") + logger.Error("can't add admin to course", "err", err) } err := r.notifyCourseCreated(MailTmpl{ Name: user.Name, @@ -146,7 +145,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { OptIn: req.OptIn, }, user.Email.String, fmt.Sprintf("Vorlesungsstreams %s | Lecture streaming %s", course.Name, course.Name)) if err != nil { - log.WithFields(log.Fields{"course": course.Name, "email": user.Email.String}).WithError(err).Error("can't send email") + logger.Error("can't send email", "course", course.Name, "email", user.Email.String, "err", err) } time.Sleep(time.Millisecond * 100) // 1/10th second delay, being nice to our mailrelay } @@ -172,7 +171,7 @@ func (r lectureHallRoutes) notifyCourseCreated(d MailTmpl, mailAddr string, subj var body bytes.Buffer err = templ.ExecuteTemplate(&body, "mail-course-registered.gotemplate", d) if err != nil { - log.Error(err) + logger.Error("Could not execute mail-course-registered.gotemplate", "err", err) } return r.EmailDao.Create(context.Background(), &model.Email{ From: tools.Cfg.Mail.Sender, @@ -219,7 +218,7 @@ func (r lectureHallRoutes) getSchedule(c *gin.Context) { //todo figure out right token campus, err := campusonline.New(tools.Cfg.Campus.Tokens[0], "") if err != nil { - log.WithError(err).Error("Can't create campus client") + logger.Error("Can't create campus client", "err", err) return } var room campusonline.ICalendar @@ -245,7 +244,7 @@ func (r lectureHallRoutes) getSchedule(c *gin.Context) { room, err = campus.GetXCalOrg(from, to, depInt) } if err != nil { - log.WithError(err).Error("can not get room schedule") + logger.Error("can not get room schedule", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get room schedule", diff --git a/api/courses.go b/api/courses.go index 7502d87f5..599f2bbaa 100644 --- a/api/courses.go +++ b/api/courses.go @@ -14,7 +14,6 @@ import ( "github.com/gin-gonic/gin" "github.com/meilisearch/meilisearch-go" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "gorm.io/gorm" "io" "net/http" @@ -161,7 +160,7 @@ func (r coursesRoutes) getLive(c *gin.Context) { if stream.LectureHallID != 0 { lh, err := r.LectureHallsDao.GetLectureHallByID(stream.LectureHallID) if err != nil { - log.WithError(err).Error(err) + logger.Error("Could not get Lecture Hall ID", "err", err) } else { lectureHall = &lh } @@ -400,7 +399,7 @@ func isUserAllowedToWatchPrivateCourse(course model.Course, user *model.User) bo } func (r coursesRoutes) createVOD(c *gin.Context) { - log.Info("createVOD") + logger.Info("createVOD") var req createVODReq err := c.BindQuery(&req) if err != nil { @@ -433,7 +432,7 @@ func (r coursesRoutes) createVOD(c *gin.Context) { } func (r coursesRoutes) uploadVODMedia(c *gin.Context) { - log.Info("uploadVODMedia") + logger.Info("uploadVODMedia") var req uploadVodMediaReq if err := c.BindQuery(&req); err != nil { @@ -541,7 +540,7 @@ func (r coursesRoutes) updateSourceSettings(c *gin.Context) { Message: fmt.Sprintf("%s:'%s'", tumLiveContext.Course.Name, tumLiveContext.Course.Slug), Type: model.AuditCourseEdit, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } course.SetCameraPresetPreference(presetSettings) @@ -557,7 +556,7 @@ func (r coursesRoutes) updateSourceSettings(c *gin.Context) { course.SetSourcePreference(sourceModeSettings) if err = r.CoursesDao.UpdateCourse(c, *course); err != nil { - log.WithError(err).Error("failed to update course") + logger.Error("failed to update course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to update course", @@ -600,7 +599,7 @@ func (r coursesRoutes) activateCourseByToken(c *gin.Context) { } err = r.AuditDao.Create(&model.Audit{User: tlctx.User, Type: model.AuditCourseCreate, Message: fmt.Sprintf("opted in by token, %s:'%s'", course.Name, course.Slug)}) if err != nil { - log.WithError(err).Error("create opt in audit failed") + logger.Error("create opt in audit failed", "err", err) } } @@ -618,7 +617,7 @@ func (r coursesRoutes) removeAdminFromCourse(c *gin.Context) { admins, err := r.CoursesDao.GetCourseAdmins(tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("could not get course admins") + logger.Error("could not get course admins", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not get course admins", @@ -653,12 +652,12 @@ func (r coursesRoutes) removeAdminFromCourse(c *gin.Context) { Message: fmt.Sprintf("%s:'%s' remove: %s (%d)", tumLiveContext.Course.Name, tumLiveContext.Course.Slug, user.GetPreferredName(), user.ID), // e.g. "eidi:'Einführung in die Informatik' (2020, S)" Type: model.AuditCourseEdit, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } err = r.CoursesDao.RemoveAdminFromCourse(user.ID, tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("could not remove admin from course") + logger.Error("could not remove admin from course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not remove admin from course", @@ -700,12 +699,12 @@ func (r coursesRoutes) addAdminToCourse(c *gin.Context) { Message: fmt.Sprintf("%s:'%s' add: %s (%d)", tumLiveContext.Course.Name, tumLiveContext.Course.Slug, user.GetPreferredName(), user.ID), // e.g. "eidi:'Einführung in die Informatik' (2020, S)" Type: model.AuditCourseEdit, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } err = r.CoursesDao.AddAdminToCourse(user.ID, tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("could not add admin to course") + logger.Error("could not add admin to course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not add admin to course", @@ -717,7 +716,7 @@ func (r coursesRoutes) addAdminToCourse(c *gin.Context) { user.Role = model.LecturerType err = r.UsersDao.UpdateUser(user) if err != nil { - log.WithError(err).Error("could not update user") + logger.Error("could not update user", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not update user", @@ -737,7 +736,7 @@ func (r coursesRoutes) getAdmins(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) admins, err := r.CoursesDao.GetCourseAdmins(tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("error getting course admins") + logger.Error("error getting course admins", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } @@ -820,7 +819,7 @@ func (r coursesRoutes) lectureHalls(c *gin.Context, course model.Course) { for u := range lectureHallIDs { lh, err := r.LectureHallsDao.GetLectureHallByID(u) if err != nil { - log.WithError(err).Error("Can't fetch lecture hall for stream") + logger.Error("Can't fetch lecture hall for stream", "err", err) } else { // Find if sourceMode is specified for this lecture hall lectureHallData = append(lectureHallData, lhResp{ @@ -987,7 +986,7 @@ func (r coursesRoutes) updateDescription(c *gin.Context) { if msg, err := json.Marshal(wsMsg); err == nil { broadcastStream(sID, msg) } else { - log.WithError(err).Error("couldn't marshal stream rename ws msg") + logger.Error("couldn't marshal stream rename ws msg", "err", err) } } @@ -1035,7 +1034,7 @@ func (r coursesRoutes) renameLecture(c *gin.Context) { if msg, err := json.Marshal(wsMsg); err == nil { broadcastStream(sID, msg) } else { - log.WithError(err).Error("couldn't marshal stream rename ws msg") + logger.Error("couldn't marshal stream rename ws msg", "err", err) } } @@ -1062,7 +1061,7 @@ func (r coursesRoutes) updateLectureSeries(c *gin.Context) { } if err = r.StreamsDao.UpdateLectureSeries(stream); err != nil { - log.WithError(err).Error("couldn't update lecture series") + logger.Error("couldn't update lecture series", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "couldn't update lecture series", @@ -1101,10 +1100,10 @@ func (r coursesRoutes) deleteLectureSeries(c *gin.Context) { Message: fmt.Sprintf("'%s': %s (%d and series)", ctx.Course.Name, stream.Start.Format("2006 02 Jan, 15:04"), stream.ID), Type: model.AuditStreamDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } if err := r.StreamsDao.DeleteLectureSeries(stream.SeriesIdentifier); err != nil { - log.WithError(err).Error("couldn't delete lecture series") + logger.Error("couldn't delete lecture series", "err", err) c.AbortWithStatusJSON(http.StatusInternalServerError, "couldn't delete lecture series") return } @@ -1143,7 +1142,7 @@ func (r coursesRoutes) deleteLectures(c *gin.Context) { Message: fmt.Sprintf("'%s': %s (%d)", tumLiveContext.Course.Name, stream.Start.Format("2006 02 Jan, 15:04"), stream.ID), Type: model.AuditStreamDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } r.StreamsDao.DeleteStream(strconv.Itoa(int(stream.ID))) } @@ -1154,7 +1153,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { var req createLectureRequest if err := c.ShouldBind(&req); err != nil { - log.WithError(err).Error("invalid form") + logger.Error("invalid form", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "invalid form", @@ -1165,7 +1164,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { // Forbid setting lectureHall for vod or premiere if (req.Premiere || req.Vodup) && req.LectureHallId != "0" { - log.Error("cannot set lectureHallId on 'Premiere' or 'Vodup' Lecture.") + logger.Error("cannot set lectureHallId on 'Premiere' or 'Vodup' Lecture.") _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "cannot set lectureHallId on 'Premiere' or 'Vodup' Lecture.", @@ -1176,7 +1175,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { // try parse lectureHallId lectureHallId, err := strconv.ParseInt(req.LectureHallId, 10, 32) if err != nil { - log.WithError(err).Error("invalid LectureHallID format") + logger.Error("invalid LectureHallID format", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "invalid LectureHallId format", @@ -1197,7 +1196,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { if req.Premiere || req.Vodup { err = os.MkdirAll(premiereFolder, os.ModePerm) if err != nil { - log.WithError(err).Error("can not create folder for premiere") + logger.Error("can not create folder for premiere", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not create folder for premiere", @@ -1210,7 +1209,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { if req.Vodup { err = tools.UploadLRZ(fmt.Sprintf("%s/%s", premiereFolder, premiereFileName)) if err != nil { - log.WithError(err).Error("can not upload file for premiere") + logger.Error("can not upload file for premiere", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not upload file for premiere", @@ -1269,7 +1268,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { Message: fmt.Sprintf("Stream for '%s' Created. Time: %s", tumLiveContext.Course.Name, lecture.Start.Format("2006 02 Jan, 15:04")), Type: model.AuditStreamCreate, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit", "err", err) } tumLiveContext.Course.Streams = append(tumLiveContext.Course.Streams, lecture) @@ -1277,7 +1276,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { err = r.CoursesDao.UpdateCourse(context.Background(), *tumLiveContext.Course) if err != nil { - log.WithError(err).Warn("can not update course") + logger.Warn("can not update course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update course", @@ -1401,7 +1400,7 @@ func (r coursesRoutes) createCourse(c *gin.Context) { Message: fmt.Sprintf("%s:'%s' (%d, %s)", course.Slug, course.Name, course.Year, course.TeachingTerm), // e.g. "eidi:'Einführung in die Informatik' (2020, S)" Type: model.AuditCourseCreate, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } err = r.CoursesDao.CreateCourse(context.Background(), &course, true) @@ -1457,7 +1456,7 @@ func (r coursesRoutes) deleteCourseByToken(c *gin.Context) { Message: fmt.Sprintf("'%s' (%d, %s)[%d]. Token: %s", course.Name, course.Year, course.TeachingTerm, course.ID, token), Type: model.AuditCourseDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } r.CoursesDao.DeleteCourse(course) @@ -1467,17 +1466,14 @@ func (r coursesRoutes) deleteCourseByToken(c *gin.Context) { func (r coursesRoutes) deleteCourse(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) - log.WithFields(log.Fields{ - "user": tumLiveContext.User.ID, - "course": tumLiveContext.Course.ID, - }).Info("Delete Course Called") + logger.Info("Delete Course Called", "user", tumLiveContext.User.ID, "course", tumLiveContext.Course.ID) if err := r.AuditDao.Create(&model.Audit{ User: tumLiveContext.User, Message: fmt.Sprintf("'%s' (%d, %s)[%d]", tumLiveContext.Course.Name, tumLiveContext.Course.Year, tumLiveContext.Course.TeachingTerm, tumLiveContext.Course.ID), Type: model.AuditCourseDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit", "err", err) } r.CoursesDao.DeleteCourse(*tumLiveContext.Course) @@ -1515,7 +1511,7 @@ func (r coursesRoutes) courseInfo(c *gin.Context) { } } if err != nil { // course not found - log.WithError(err).Warn("Error getting course information") + logger.Warn("Error getting course information", "err", err) c.AbortWithStatus(http.StatusNotFound) return } @@ -1556,7 +1552,7 @@ func (r coursesRoutes) copyCourse(c *gin.Context) { admins, err := r.DaoWrapper.CoursesDao.GetCourseAdmins(course.ID) if err != nil { - log.WithError(err).Error("Error getting course admins") + logger.Error("Error getting course admins", "err", err) admins = []model.User{} } course.Model = gorm.Model{} @@ -1579,7 +1575,7 @@ func (r coursesRoutes) copyCourse(c *gin.Context) { err = r.CoursesDao.CreateCourse(c, course, true) if err != nil { - log.WithError(err).Error("Can't create course") + logger.Error("Can't create course", "err", err) _ = c.Error(tools.RequestError{Status: http.StatusInternalServerError, CustomMessage: "Can't create course", Err: err}) return } @@ -1589,14 +1585,14 @@ func (r coursesRoutes) copyCourse(c *gin.Context) { stream.Model = gorm.Model{} err := r.StreamsDao.CreateStream(&stream) if err != nil { - log.WithError(err).Error("Can't create stream") + logger.Error("Can't create stream", "err", err) numErrors++ } } for _, admin := range admins { err := r.CoursesDao.AddAdminToCourse(admin.ID, course.ID) if err != nil { - log.WithError(err).Error("Can't add admin to course") + logger.Error("Can't add admin to course", "err", err) numErrors++ } } diff --git a/api/download.go b/api/download.go index 47f2ddf51..76fc97201 100644 --- a/api/download.go +++ b/api/download.go @@ -3,12 +3,11 @@ package api import ( "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "net/http" "os" ) @@ -119,7 +118,7 @@ func sendDownloadFile(c *gin.Context, file model.File, tumLiveContext tools.TUML if tumLiveContext.User != nil { uid = tumLiveContext.User.ID } - log.Info(fmt.Sprintf("Download request, user: %d, file: %d[%s]", uid, file.ID, file.Path)) + logger.Info(fmt.Sprintf("Download request, user: %d, file: %d[%s]", uid, file.ID, file.Path)) f, err := os.Open(file.Path) if err != nil { _ = c.Error(tools.RequestError{ diff --git a/api/download_ics.go b/api/download_ics.go index 3217eb5f8..3660f658c 100644 --- a/api/download_ics.go +++ b/api/download_ics.go @@ -1,11 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "html/template" "net/http" "strconv" @@ -15,7 +14,7 @@ import ( func configGinDownloadICSRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) { templates, err := template.ParseFS(staticFS, "template/*.gotemplate") if err != nil { - log.WithError(err).Fatal("could not parse templates") + logger.Error("could not parse templates", "err", err) return } routes := downloadICSRoutes{daoWrapper, templates} diff --git a/api/lecture_halls.go b/api/lecture_halls.go index 725669ed3..7c2f40da0 100644 --- a/api/lecture_halls.go +++ b/api/lecture_halls.go @@ -4,12 +4,11 @@ import ( "embed" "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "net/http" "strconv" "strings" @@ -91,7 +90,7 @@ func (r lectureHallRoutes) updateLectureHall(c *gin.Context) { lectureHall.PwrCtrlIp = req.PwrCtrlIp err = r.LectureHallsDao.SaveLectureHall(lectureHall) if err != nil { - log.WithError(err).Error("error while updating lecture hall") + logger.Error("error while updating lecture hall", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error while updating lecture hall", @@ -126,7 +125,7 @@ func (r lectureHallRoutes) updateLectureHallsDefaultPreset(c *gin.Context) { preset.IsDefault = true err = r.LectureHallsDao.UnsetDefaults(c.Param("id")) if err != nil { - log.WithError(err).Error("error unsetting default presets") + logger.Error("error unsetting default presets", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error unsetting default presets", @@ -136,7 +135,7 @@ func (r lectureHallRoutes) updateLectureHallsDefaultPreset(c *gin.Context) { } err = r.LectureHallsDao.SavePreset(preset) if err != nil { - log.WithError(err).Error("error saving preset as default") + logger.Error("error saving preset as default", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error saving preset as default", @@ -244,7 +243,7 @@ func (r lectureHallRoutes) lectureHallIcal(c *gin.Context) { c.Header("content-type", "text/calendar") err = templ.ExecuteTemplate(c.Writer, "ical.gotemplate", icalData) if err != nil { - log.Printf("%v", err) + logger.Error("Error executing template ical.gotemplate", "err", err) } } @@ -310,7 +309,7 @@ func (r lectureHallRoutes) setLectureHall(c *gin.Context) { streams, err := r.StreamsDao.GetStreamsByIds(req.StreamIDs) if err != nil || len(streams) != len(req.StreamIDs) { - log.WithError(err).Error("can not get all streams to update lecture hall") + logger.Error("can not get all streams to update lecture hall", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get all streams to update lecture hall", @@ -322,7 +321,7 @@ func (r lectureHallRoutes) setLectureHall(c *gin.Context) { if req.LectureHallID == 0 { err = r.StreamsDao.UnsetLectureHall(req.StreamIDs) if err != nil { - log.WithError(err).Error("can not update lecture hall for streams") + logger.Error("can not update lecture hall for streams", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update lecture hall for streams", @@ -343,7 +342,7 @@ func (r lectureHallRoutes) setLectureHall(c *gin.Context) { } err = r.StreamsDao.SetLectureHall(req.StreamIDs, req.LectureHallID) if err != nil { - log.WithError(err).Error("can not update lecture hall") + logger.Error("can not update lecture hall", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update lecture hall", diff --git a/api/live_update.go b/api/live_update.go index 443126c3c..d728d0750 100644 --- a/api/live_update.go +++ b/api/live_update.go @@ -4,14 +4,13 @@ import ( "encoding/json" "errors" "github.com/RBG-TUM/commons" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/realtime" "github.com/TUM-Dev/gocast/tools/tum" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "sync" ) @@ -85,13 +84,13 @@ func liveUpdateOnSubscribe(psc *realtime.Context) { if tumLiveContext.User != nil { userId = tumLiveContext.User.ID if userCourses, err = daoWrapper.(dao.DaoWrapper).CoursesDao.GetPublicAndLoggedInCourses(year, term); err != nil { - log.WithError(err).Error("could not fetch public and logged in courses") + logger.Error("could not fetch public and logged in courses", "err", err) return } userCourses = commons.Unique(userCourses, func(c model.Course) uint { return c.ID }) } else { if userCourses, err = daoWrapper.(dao.DaoWrapper).CoursesDao.GetPublicCourses(year, term); err != nil { - log.WithError(err).Error("could not fetch public courses") + logger.Error("could not fetch public courses", "err", err) return } } diff --git a/api/maintenance.go b/api/maintenance.go index 0a321e510..10c848ab2 100644 --- a/api/maintenance.go +++ b/api/maintenance.go @@ -1,11 +1,11 @@ package api import ( - "github.com/gin-gonic/gin" + "fmt" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" "strconv" ) @@ -50,11 +50,11 @@ func (r *maintenanceRoutes) generateThumbnails(c *gin.Context) { }) return } - log.Info("generating ", noFiles, " thumbs") + logger.Info("generating " + strconv.FormatInt(noFiles, 10) + " thumbs") go func() { courses, err := r.GetAllCourses() if err != nil { - log.WithError(err).Error("Can't get courses") + logger.Error("Can't get courses", "err", err) } processed := 0 r.thumbGenRunning = true @@ -72,14 +72,14 @@ func (r *maintenanceRoutes) generateThumbnails(c *gin.Context) { // Request thumbnail for VoD. err := RegenerateThumbs(dao.NewDaoWrapper(), file, &stream, &course) if err != nil { - log.WithError(err).Errorf( + logger.Error(fmt.Sprintf( "Can't regenerate thumbnail for stream %d with file %s", stream.ID, file.Path, - ) + )) continue } - log.Info("Processed thumbnail", processed, "of", noFiles) + logger.Info("Processed thumbnail" + string(rune(processed)) + "of" + strconv.FormatInt(noFiles, 10)) processed++ r.thumbGenProgress = float32(processed) / float32(noFiles) } @@ -110,7 +110,7 @@ func (r *maintenanceRoutes) runCronJob(c *gin.Context) { return } jobName := c.Request.FormValue("job") - log.Info("request to run ", jobName) + logger.Info("request to run " + jobName) tools.Cron.RunJob(jobName) } diff --git a/api/notifications.go b/api/notifications.go index 2d51c5802..aa11b9265 100644 --- a/api/notifications.go +++ b/api/notifications.go @@ -1,11 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" "strconv" ) @@ -81,7 +80,7 @@ func (r notificationRoutes) createNotification(c *gin.Context) { } notification.Body = notification.SanitizedBody // reverse json binding if err := r.NotificationsDao.AddNotification(¬ification); err != nil { - log.Error(err) + logger.Error("Error adding notification", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not add notification", @@ -104,7 +103,7 @@ func (r notificationRoutes) deleteNotification(c *gin.Context) { } err = r.NotificationsDao.DeleteNotification(uint(id)) if err != nil { - log.WithError(err).Error("error deleting notification") + logger.Error("error deleting notification", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error deleting notification", diff --git a/api/progress.go b/api/progress.go index 5af7b4986..bcf50ab73 100644 --- a/api/progress.go +++ b/api/progress.go @@ -12,7 +12,6 @@ import ( "time" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" ) var progressBuff *progressBuffer @@ -57,7 +56,7 @@ func (b *progressBuffer) run() { time.Sleep(b.interval) err := b.flush() if err != nil { - log.WithError(err).Error("Error flushing progress buffer") + logger.Error("Error flushing progress buffer", "err", err) } } } @@ -91,7 +90,7 @@ func (r progressRoutes) saveProgress(c *gin.Context) { err := c.BindJSON(&request) if err != nil { - log.WithError(err).Warn("Could not bind JSON.") + logger.Warn("Could not bind JSON.", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -133,7 +132,7 @@ func (r progressRoutes) markWatched(c *gin.Context) { var request watchedRequest err := c.BindJSON(&request) if err != nil { - log.WithError(err).Error("Could not bind JSON.") + logger.Error("Could not bind JSON.", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -164,7 +163,7 @@ func (r progressRoutes) markWatched(c *gin.Context) { } err = r.ProgressDao.SaveWatchedState(&prog) if err != nil { - log.WithError(err).Error("can not mark VoD as watched.") + logger.Error("can not mark VoD as watched.", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not mark VoD as watched.", diff --git a/api/realtime.go b/api/realtime.go index 0d8f5779e..302248660 100644 --- a/api/realtime.go +++ b/api/realtime.go @@ -1,11 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools/realtime" "github.com/TUM-Dev/gocast/tools/realtime/connector" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" ) type realtimeRoutes struct { @@ -25,6 +24,6 @@ func (r realtimeRoutes) handleRealtimeConnect(c *gin.Context) { properties["dao"] = r.DaoWrapper if err := RealtimeInstance.HandleRequest(c.Writer, c.Request, properties); err != nil { - log.WithError(err).Warn("Something went wrong while handling Realtime-Socket request") + logger.Warn("Something went wrong while handling Realtime-Socket request", "err", err) } } diff --git a/api/seek_stats.go b/api/seek_stats.go index 90e8b0f3f..f2e2a5510 100644 --- a/api/seek_stats.go +++ b/api/seek_stats.go @@ -1,9 +1,8 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" ) @@ -34,7 +33,7 @@ func (r seekStatsRoutes) reportSeek(c *gin.Context) { } if err := r.VideoSeekDao.Add(c.Param("streamID"), req.Position); err != nil { - log.WithError(err).Error("Could not add seek hit") + logger.Error("Could not add seek hit", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } @@ -50,7 +49,7 @@ func (r seekStatsRoutes) getSeek(c *gin.Context) { chunks, err := r.VideoSeekDao.Get(c.Param("streamID")) if err != nil { - log.WithError(err).Error("Could not get seek hits") + logger.Error("Could not get seek hits", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } diff --git a/api/server-notifications.go b/api/server-notifications.go index 17bf6e97e..2ceb1537e 100644 --- a/api/server-notifications.go +++ b/api/server-notifications.go @@ -1,11 +1,11 @@ package api import ( - "github.com/gin-gonic/gin" + "fmt" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - "log" + "github.com/gin-gonic/gin" "net/http" "time" ) @@ -25,7 +25,7 @@ type serverNotificationRoutes struct { func (r serverNotificationRoutes) updateServerNotification(c *gin.Context) { var req notificationReq if err := c.ShouldBind(&req); err != nil { - log.Printf("%v", err) + logger.Debug(fmt.Sprintf("%v", err)) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -54,7 +54,7 @@ func (r serverNotificationRoutes) updateServerNotification(c *gin.Context) { func (r serverNotificationRoutes) createServerNotification(c *gin.Context) { var req notificationReq if err := c.ShouldBind(&req); err != nil { - log.Printf("%v", err) + logger.Debug(fmt.Sprintf("%v", err)) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", diff --git a/api/statistics.go b/api/statistics.go index ae3373d58..af063ab5e 100644 --- a/api/statistics.go +++ b/api/statistics.go @@ -2,11 +2,10 @@ package api import ( "encoding/json" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" "strconv" ) @@ -52,7 +51,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "day": res, err := r.StatisticsDao.GetCourseStatsWeekdays(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsWeekdays failed") + logger.Warn("GetCourseStatsWeekdays failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course stats weekdays", @@ -71,7 +70,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "hour": res, err := r.StatisticsDao.GetCourseStatsHourly(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsHourly failed") + logger.Warn("GetCourseStatsHourly failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course stats hourly", @@ -90,7 +89,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "activity-live": resLive, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, true) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsLive failed") + logger.Warn("GetCourseStatsLive failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get student activity course stats", @@ -112,7 +111,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "activity-vod": resVod, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, false) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsVod failed") + logger.Warn("GetCourseStatsVod failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get student activity course stats", @@ -133,7 +132,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "numStudents": res, err := r.StatisticsDao.GetCourseNumStudents(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumStudents failed") + logger.Warn("GetCourseNumStudents failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course num students", @@ -146,7 +145,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "vodViews": res, err := r.StatisticsDao.GetCourseNumVodViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumVodViews failed") + logger.Warn("GetCourseNumVodViews failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not getcourse num vod views", @@ -159,7 +158,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "liveViews": res, err := r.StatisticsDao.GetCourseNumLiveViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumLiveViews failed") + logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course num live views", @@ -173,7 +172,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { { res, err := r.StatisticsDao.GetCourseNumVodViewsPerDay(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumLiveViews failed") + logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course num vod views per day", @@ -231,7 +230,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { } if req.Format != "json" && req.Format != "csv" { - log.WithField("courseId", cid).Warn("exportStats failed, invalid format") + logger.Warn("exportStats failed, invalid format", "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "exportStats failed, invalid format", @@ -247,7 +246,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "day": res, err := r.StatisticsDao.GetCourseStatsWeekdays(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsWeekdays failed") + logger.Warn("GetCourseStatsWeekdays failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -259,7 +258,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "hour": res, err := r.StatisticsDao.GetCourseStatsHourly(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsHourly failed") + logger.Warn("GetCourseStatsHourly failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -271,7 +270,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "activity-live": resLive, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, true) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetStudentActivityCourseStats failed") + logger.Warn("GetStudentActivityCourseStats failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -283,7 +282,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "activity-vod": resVod, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, false) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetStudentActivityCourseStats failed") + logger.Warn("GetStudentActivityCourseStats failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -295,7 +294,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "allDays": res, err := r.StatisticsDao.GetCourseNumVodViewsPerDay(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumVodViewsPerDay failed") + logger.Warn("GetCourseNumVodViewsPerDay failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -309,21 +308,21 @@ func (r coursesRoutes) exportStats(c *gin.Context) { numStudents, err := r.StatisticsDao.GetCourseNumStudents(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumStudents failed") + logger.Warn("GetCourseNumStudents failed", "err", err, "courseId", cid) } else { quickStats = append(quickStats, dao.Stat{X: "Enrolled Students", Y: int(numStudents)}) } vodViews, err := r.StatisticsDao.GetCourseNumVodViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumVodViews failed") + logger.Warn("GetCourseNumVodViews failed", "err", err, "courseId", cid) } else { quickStats = append(quickStats, dao.Stat{X: "Vod Views", Y: int(vodViews)}) } liveViews, err := r.StatisticsDao.GetCourseNumLiveViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumLiveViews failed") + logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid) } else { quickStats = append(quickStats, dao.Stat{X: "Live Views", Y: int(liveViews)}) } @@ -335,14 +334,14 @@ func (r coursesRoutes) exportStats(c *gin.Context) { }) default: - log.WithField("courseId", cid).Warn("Invalid export interval") + logger.Warn("Invalid export interval", "courseId", cid) } } if req.Format == "json" { jsonResult, err := json.Marshal(result.ExportJson()) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("json.Marshal failed for stats export") + logger.Warn("json.Marshal failed for stats export", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "json.Marshal failed for stats export", @@ -399,7 +398,7 @@ func newChartJsOptions() chartJsOptions { } } -//chartJsDataset is a single dataset ready to be used in a Chart.js chart +// chartJsDataset is a single dataset ready to be used in a Chart.js chart type chartJsDataset struct { Label string `json:"label"` Fill bool `json:"fill"` @@ -409,7 +408,7 @@ type chartJsDataset struct { Options chartJsOptions `json:"options"` } -//New creates a chartJsDataset with some defaults +// New creates a chartJsDataset with some defaults func newChartJsDataset() chartJsDataset { return chartJsDataset{ Fill: false, diff --git a/api/stream.go b/api/stream.go index 82b83bb0a..104d5c38f 100644 --- a/api/stream.go +++ b/api/stream.go @@ -20,7 +20,6 @@ import ( "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "gorm.io/gorm" ) @@ -209,7 +208,7 @@ func (r streamRoutes) liveStreams(c *gin.Context) { var res []liveStreamDto streams, err := r.StreamsDao.GetCurrentLive(c) if err != nil { - log.Error(err) + logger.Error("Error getting current live", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get current live streams", @@ -220,13 +219,13 @@ func (r streamRoutes) liveStreams(c *gin.Context) { for _, s := range streams { course, err := r.CoursesDao.GetCourseById(c, s.CourseID) if err != nil { - log.Error(err) + logger.Error("Error fetching course", "err", err) } lectureHall := "Selfstream" if s.LectureHallID != 0 { l, err := r.LectureHallsDao.GetLectureHallByID(s.LectureHallID) if err != nil { - log.Error(err) + logger.Error("Error fetching lecture hall", "err", err) } else { lectureHall = l.Name } @@ -247,7 +246,7 @@ func (r streamRoutes) liveStreams(c *gin.Context) { func (r streamRoutes) endStream(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) discardVoD := c.Request.URL.Query().Get("discard") == "true" - log.Info(discardVoD) + logger.Info("End stream: " + strconv.FormatBool(discardVoD)) NotifyWorkersToStopStream(*tumLiveContext.Stream, discardVoD, r.DaoWrapper) } @@ -388,7 +387,7 @@ func (r streamRoutes) getVideoSections(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) sections, err := r.VideoSectionDao.GetByStreamId(tumLiveContext.Stream.ID) if err != nil { - log.WithError(err).Error("Can't get video sections") + logger.Error("Can't get video sections", "err", err) } c.JSON(http.StatusOK, sections) @@ -406,17 +405,17 @@ func (r streamRoutes) RegenerateThumbs(c *gin.Context) { // The thumbnails are generated automatically by the worker which then notifies the backend. err := RegenerateThumbs(r.DaoWrapper, file, stream, course) if err != nil { - log.WithError(err).Errorf("Can't regenerate thumbnail for stream %d with file %s", stream.ID, file.Path) + logger.Error(fmt.Sprintf("Can't regenerate thumbnail for stream %d with file %s", stream.ID, file.Path)) continue } sections, err := r.DaoWrapper.VideoSectionDao.GetByStreamId(stream.ID) if err != nil { - log.WithError(err).Errorf("Can't get video sections for stream %d", stream.ID) + logger.Error(fmt.Sprintf("Can't get video sections for stream %d", stream.ID)) continue } err = tools.SetSignedPlaylists(stream, nil, false) if err != nil { - log.WithError(err).Errorf("Can't set signed playlists for stream %d", stream.ID) + logger.Error(fmt.Sprintf("Can't set signed playlists for stream %d", stream.ID)) continue } // Completely redo the video section image generation. This also updates the database, if the naming scheme has changed. @@ -430,7 +429,7 @@ func (r streamRoutes) RegenerateThumbs(c *gin.Context) { } err := GenerateVideoSectionImages(r.DaoWrapper, ¶meters) if err != nil { - log.WithError(err).Error("failed to generate video section images") + logger.Error("failed to generate video section images", "err", err) } }() } @@ -442,7 +441,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { stream := context.Stream var sections []model.VideoSection if err := c.BindJSON(§ions); err != nil { - log.WithError(err).Error("failed to bind video section JSON") + logger.Error("failed to bind video section JSON", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -453,7 +452,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { err := r.VideoSectionDao.Create(sections) if err != nil { - log.WithError(err).Error("failed to create video sections") + logger.Error("failed to create video sections", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to create video sections", @@ -464,7 +463,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { sections, err = r.VideoSectionDao.GetByStreamId(context.Stream.ID) if err != nil { - log.WithError(err).Error("failed to get video sections") + logger.Error("failed to get video sections", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to get video sections", @@ -475,7 +474,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { err = tools.SetSignedPlaylists(stream, nil, false) if err != nil { - log.WithError(err).Error("failed to set signed playlists") + logger.Error("failed to set signed playlists", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to set signed playlists", @@ -493,7 +492,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { } err := GenerateVideoSectionImages(r.DaoWrapper, ¶meters) if err != nil { - log.WithError(err).Error("failed to generate video section images") + logger.Error("failed to generate video section images", "err", err) } }() @@ -511,7 +510,7 @@ func (r streamRoutes) updateVideoSection(c *gin.Context) { idAsString := c.Param("id") id, err := strconv.Atoi(idAsString) if err != nil { - log.WithError(err).Error("can not parse video-section id in request url") + logger.Error("can not parse video-section id in request url", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not parse video-section id in request url", @@ -523,7 +522,7 @@ func (r streamRoutes) updateVideoSection(c *gin.Context) { var update UpdateVideoSectionRequest err = c.BindJSON(&update) if err != nil { - log.WithError(err).Error("failed to bind video section JSON") + logger.Error("failed to bind video section JSON", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -539,7 +538,7 @@ func (r streamRoutes) updateVideoSection(c *gin.Context) { StartMinutes: update.StartMinutes, StartSeconds: update.StartSeconds}) if err != nil { - log.WithError(err).Error("failed to update video section") + logger.Error("failed to update video section", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update video section", @@ -553,7 +552,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { idAsString := c.Param("id") id, err := strconv.Atoi(idAsString) if err != nil { - log.WithError(err).Error("can not parse video-section id in request url") + logger.Error("can not parse video-section id in request url", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not parse video-section id in request url", @@ -564,7 +563,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { old, err := r.VideoSectionDao.Get(uint(id)) if err != nil { - log.WithError(err).Error("invalid video-section id") + logger.Error("invalid video-section id", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "invalid video-section id", @@ -575,7 +574,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { err = r.VideoSectionDao.Delete(uint(id)) if err != nil { - log.WithError(err).Error("can not delete video-section") + logger.Error("can not delete video-section", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete video-section", @@ -586,7 +585,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { file, err := r.FileDao.GetFileById(fmt.Sprintf("%d", old.FileID)) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("can not get video section thumbnail file") + logger.Error("can not get video section thumbnail file", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get video section thumbnail file", @@ -597,7 +596,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { go func() { err := DeleteVideoSectionImage(r.DaoWrapper.WorkerDao, file.Path) if err != nil { - log.WithError(err).Error("failed to generate video section images") + logger.Error("failed to generate video section images", "err", err) } }() } @@ -654,7 +653,7 @@ func (r streamRoutes) newAttachment(c *gin.Context) { } if err = c.SaveUploadedFile(file, path); err != nil { - log.WithError(err).Error("could not save file with path: " + path) + logger.Error("could not save file with path: "+path, "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not save file with path: " + path, @@ -706,7 +705,7 @@ func (r streamRoutes) deleteAttachment(c *gin.Context) { if !toDelete.IsURL() { err = os.Remove(toDelete.Path) if err != nil { - log.WithError(err).Error("can not delete file with path: " + toDelete.Path) + logger.Error("can not delete file with path: "+toDelete.Path, "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete file with path: " + toDelete.Path, @@ -717,7 +716,7 @@ func (r streamRoutes) deleteAttachment(c *gin.Context) { } err = r.FileDao.DeleteFile(toDelete.ID) if err != nil { - log.WithError(err).Error("can not delete file from database") + logger.Error("can not delete file from database", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete file from database", @@ -825,7 +824,7 @@ func (r streamRoutes) updateStreamVisibility(c *gin.Context) { Type: model.AuditStreamEdit, }) if err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit", "err", err) } err = r.DaoWrapper.StreamsDao.ToggleVisibility(ctx.Stream.ID, req.Private) diff --git a/api/token.go b/api/token.go index 41fc9a368..420ae01a2 100644 --- a/api/token.go +++ b/api/token.go @@ -2,12 +2,11 @@ package api import ( "database/sql" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" + "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "net/http" "time" ) @@ -28,7 +27,7 @@ func (r tokenRoutes) deleteToken(c *gin.Context) { id := c.Param("id") err := r.TokenDao.DeleteToken(id) if err != nil { - log.WithError(err).Error("can not delete token") + logger.Error("can not delete token", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete token", @@ -78,7 +77,7 @@ func (r tokenRoutes) createToken(c *gin.Context) { } err = r.TokenDao.AddToken(token) if err != nil { - log.WithError(err).Error("can not create token") + logger.Error("can not create token", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not create token", diff --git a/api/users.go b/api/users.go index e96921e63..f8935d8e4 100644 --- a/api/users.go +++ b/api/users.go @@ -11,12 +11,11 @@ import ( "strings" "time" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "gorm.io/gorm" ) @@ -26,6 +25,7 @@ func configGinUsersRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) { router.POST("/api/users/settings/name", routes.updatePreferredName) router.POST("/api/users/settings/greeting", routes.updatePreferredGreeting) router.POST("/api/users/settings/playbackSpeeds", routes.updatePlaybackSpeeds) + router.POST("/api/users/settings/customSpeeds", routes.updateCustomSpeeds) router.POST("/api/users/resetPassword", routes.resetPassword) @@ -113,7 +113,7 @@ func (r usersRoutes) updateUser(c *gin.Context) { user.Role = req.Role err = r.UsersDao.UpdateUser(user) if err != nil { - log.WithError(err).Error("can not update user") + logger.Error("can not update user", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update user", @@ -304,7 +304,7 @@ func (r usersRoutes) addSingleUserToCourse(name string, email string, course mod Courses: []model.Course{course}, } if err = r.UsersDao.CreateUser(context.Background(), &createdUser); err != nil { - log.Printf("%v", err) + logger.Error("Error creating User", "err", err) } else { go r.forgotPassword(email) } @@ -313,7 +313,7 @@ func (r usersRoutes) addSingleUserToCourse(name string, email string, course mod foundUser.Courses = append(foundUser.Courses, course) err := r.UsersDao.UpdateUser(foundUser) if err != nil { - log.WithError(err).Error("Can't update user") + logger.Error("Can't update user", "err", err) return } err = r.EmailDao.Create(context.Background(), &model.Email{ @@ -325,7 +325,7 @@ func (r usersRoutes) addSingleUserToCourse(name string, email string, course mod course.Name), }) if err != nil { - log.Printf("%v", err) + logger.Error("Some error", "err", err) } } } @@ -372,7 +372,7 @@ func (r usersRoutes) pinCourse(pin bool) gin.HandlerFunc { } err := c.BindJSON(&request) if err != nil { - log.WithError(err).Error("Could not bind JSON.") + logger.Error("Could not bind JSON.", "err", err) c.AbortWithStatus(http.StatusBadRequest) return } @@ -397,7 +397,7 @@ func (r usersRoutes) pinCourse(pin bool) gin.HandlerFunc { // Update user in database err = r.UsersDao.PinCourse(*tumLiveContext.User, course, pin) if err != nil { - log.WithError(err).Error("Can't update user") + logger.Error("Can't update user", "err", err) return } } @@ -508,12 +508,12 @@ func (r usersRoutes) createUserHelper(request createUserRequest, userType uint) func (r usersRoutes) forgotPassword(email string) { u, err := r.UsersDao.GetUserByEmail(context.Background(), email) if err != nil { - log.Println("couldn't get user by email") + logger.Error("couldn't get user by email") return } registerLink, err := r.UsersDao.CreateRegisterLink(context.Background(), u) if err != nil { - log.Println("couldn't create register link") + logger.Error("couldn't create register link") return } body := fmt.Sprintf("Hello!\n"+ @@ -527,7 +527,7 @@ func (r usersRoutes) forgotPassword(email string) { Body: body, }) if err != nil { - log.Println("couldn't send password mail") + logger.Error("couldn't send password mail") } } @@ -619,6 +619,42 @@ func (r usersRoutes) updatePreferredGreeting(c *gin.Context) { } } +func (r usersRoutes) updateCustomSpeeds(c *gin.Context) { + u := c.MustGet("TUMLiveContext").(tools.TUMLiveContext).User + if u == nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusUnauthorized, + CustomMessage: "login required", + }) + return + } + + var req struct{ Value []float32 } + if err := c.BindJSON(&req); err != nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusBadRequest, + CustomMessage: "can not bind body", + Err: err, + }) + return + } + settingsString := "[]" + if len(req.Value) != 0 { + settingBytes, _ := json.Marshal(req.Value) + settingsString = string(settingBytes) + } + err := r.DaoWrapper.AddUserSetting(&model.UserSetting{UserID: u.ID, Type: model.UserDefinedSpeeds, Value: settingsString}) + if err != nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusInternalServerError, + CustomMessage: "can not add user setting", + Err: err, + }) + return + } + +} + func (r usersRoutes) updatePlaybackSpeeds(c *gin.Context) { u := c.MustGet("TUMLiveContext").(tools.TUMLiveContext).User if u == nil { @@ -736,12 +772,12 @@ func (r usersRoutes) resetPassword(c *gin.Context) { return } if err != nil { - log.WithError(err).Error("can't get user for password reset") + logger.Error("can't get user for password reset", "err", err) return } link, err := r.UsersDao.CreateRegisterLink(c, user) if err != nil { - log.WithError(err).Error("can't create register link") + logger.Error("can't create register link", "err", err) return } err = r.EmailDao.Create(c, &model.Email{ @@ -751,7 +787,7 @@ func (r usersRoutes) resetPassword(c *gin.Context) { Body: "Hi! \n\nYou can reset your TUM-Live password by clicking on the following link: \n\n" + tools.Cfg.WebUrl + "/setPassword/" + link.RegisterSecret + "\n\nIf you did not request a password reset, please ignore this email. \n\nBest regards", }) if err != nil { - log.WithError(err).Error("can't save reset password email") + logger.Error("can't save reset password email", "err", err) } } diff --git a/api/voice_service_grpc.go b/api/voice_service_grpc.go index b2da029b7..ed195728f 100644 --- a/api/voice_service_grpc.go +++ b/api/voice_service_grpc.go @@ -9,7 +9,6 @@ import ( "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/voice-service/pb" - log "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" @@ -38,10 +37,10 @@ func (s subtitleReceiverServer) Receive(_ context.Context, request *pb.ReceiveRe } func init() { - log.Info("starting grpc voice-receiver") + logger.Info("starting grpc voice-receiver") lis, err := net.Listen("tcp", ":50053") if err != nil { - log.WithError(err).Error("failed to init voice-receiver server") + logger.Error("failed to init voice-receiver server", "err", err) return } grpcServer := grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{ @@ -56,7 +55,7 @@ func init() { reflection.Register(grpcServer) go func() { if err := grpcServer.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) + logger.Error("failed to serve", "err", err) } }() } @@ -78,6 +77,6 @@ func GetSubtitleGeneratorClient() (SubtitleGeneratorClient, error) { func (s SubtitleGeneratorClient) CloseConn() { err := s.ClientConn.Close() if err != nil { - log.WithError(err).Error("could not close voice-service connection") + logger.Error("could not close voice-service connection", "err", err) } } diff --git a/api/worker.go b/api/worker.go index aac2413cd..ba2787248 100644 --- a/api/worker.go +++ b/api/worker.go @@ -1,10 +1,9 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" ) @@ -25,7 +24,7 @@ func (r workerRoutes) deleteWorker(c *gin.Context) { id := c.Param("id") err := r.dao.DeleteWorker(id) if err != nil { - log.WithError(err).Error("can not delete worker") + logger.Error("can not delete worker", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete worker", diff --git a/api/worker_grpc.go b/api/worker_grpc.go index 0aa754f9e..26eb20267 100644 --- a/api/worker_grpc.go +++ b/api/worker_grpc.go @@ -19,14 +19,13 @@ import ( "time" go_anel_pwrctrl "github.com/RBG-TUM/go-anel-pwrctrl" - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/camera" "github.com/TUM-Dev/gocast/worker/pb" + "github.com/getsentry/sentry-go" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" @@ -48,20 +47,20 @@ type server struct { func dialIn(targetWorker model.Worker) (*grpc.ClientConn, error) { credentials := insecure.NewCredentials() - log.Info("Connecting to:" + fmt.Sprintf("%s:50051", targetWorker.Host)) + logger.Info("Connecting to:" + fmt.Sprintf("%s:50051", targetWorker.Host)) conn, err := grpc.Dial(fmt.Sprintf("%s:50051", targetWorker.Host), grpc.WithTransportCredentials(credentials)) return conn, err } func endConnection(conn *grpc.ClientConn) { if err := conn.Close(); err != nil { - log.WithError(err).Error("Could not close connection to worker") + logger.Error("Could not close connection to worker", "err", err) } } // JoinWorkers is a request from a worker to join the pool. On success, the workerID is returned. func (s server) JoinWorkers(ctx context.Context, request *pb.JoinWorkersRequest) (*pb.JoinWorkersResponse, error) { - log.WithField("host", request.Hostname).Info("JoinWorkers called") + logger.Info("JoinWorkers called", "host", request.Hostname) if request.Token != tools.Cfg.WorkerToken { return nil, status.Error(codes.Unauthenticated, "Invalid token") } @@ -84,10 +83,10 @@ func (s server) JoinWorkers(ctx context.Context, request *pb.JoinWorkersRequest) LastSeen: time.Now(), } if err := s.DaoWrapper.WorkerDao.CreateWorker(&worker); err != nil { - log.WithError(err).Error("Could not add worker to database") + logger.Error("Could not add worker to database", "err", err) return nil, status.Errorf(codes.Internal, "Could not add worker to database") } - log.Info("Added worker to database") + logger.Info("Added worker to database") return &pb.JoinWorkersResponse{ WorkerId: worker.WorkerID, }, nil @@ -141,7 +140,7 @@ func (s server) SendSelfStreamRequest(ctx context.Context, request *pb.SelfStrea } // reject streams that are more than 30 minutes in the future or more than 30 minutes past if !(time.Now().After(stream.Start.Add(time.Minute*-30)) && time.Now().Before(stream.End.Add(time.Minute*30))) { - log.WithFields(log.Fields{"streamId": stream.ID}).Warn("Stream rejected, time out of bounds") + logger.Warn("Stream rejected, time out of bounds", "streamId", stream.ID) return nil, errors.New("stream rejected") } ingestServer, err := s.DaoWrapper.IngestServerDao.GetBestIngestServer() @@ -177,12 +176,12 @@ func (s server) NotifyStreamStart(ctx context.Context, request *pb.StreamStarted defer mutex.Unlock() _, err := s.DaoWrapper.WorkerDao.GetWorkerByID(ctx, request.GetWorkerID()) if err != nil { - log.WithField("request", request).Warn("Got stream start with invalid WorkerID") + logger.Warn("Got stream start with invalid WorkerID", "request", request) return nil, err } stream, err := s.StreamsDao.GetStreamByID(ctx, fmt.Sprintf("%d", request.StreamID)) if err != nil { - log.WithError(err).Warn("Can't get stream by ID to set live") + logger.Warn("Can't get stream by ID to set live", "err", err) return nil, err } stream.LiveNow = true @@ -197,7 +196,7 @@ func (s server) NotifyStreamStart(ctx context.Context, request *pb.StreamStarted } err = s.StreamsDao.SaveStream(&stream) if err != nil { - log.WithError(err).Error("Can't save stream when setting live") + logger.Error("Can't save stream when setting live", "err", err) return nil, err } return nil, nil @@ -210,27 +209,27 @@ func (s server) NotifyStreamFinished(ctx context.Context, request *pb.StreamFini } else { stream, err := s.StreamsDao.GetStreamByID(ctx, fmt.Sprintf("%d", request.StreamID)) if err != nil { - log.WithError(err).Error("Can't find stream to set not live") + logger.Error("Can't find stream to set not live", "err", err) } else { go func() { err := handleLightOffSwitch(stream, s.DaoWrapper) if err != nil { - log.WithError(err).Error("Can't handle light off switch") + logger.Error("Can't handle light off switch", "err", err) } err = s.StreamsDao.SaveEndedState(stream.ID, true) if err != nil { - log.WithError(err).Error("Can't set stream done") + logger.Error("Can't set stream done", "err", err) } }() } err = s.DaoWrapper.IngestServerDao.RemoveStreamFromSlot(stream.ID) if err != nil { - log.WithError(err).Error("Can't remove stream from streamName") + logger.Error("Can't remove stream from streamName", "err", err) } err = s.StreamsDao.SetStreamNotLiveById(uint(request.StreamID)) if err != nil { - log.WithError(err).Error("Can't set stream not live") + logger.Error("Can't set stream not live", "err", err) } NotifyViewersLiveState(uint(request.StreamID), false) } @@ -372,7 +371,7 @@ func (s server) NotifyTranscodingFinished(ctx context.Context, request *pb.Trans err = s.StreamsDao.RemoveTranscodingProgress(model.StreamVersion(request.SourceType), stream.ID) if err != nil { - log.WithError(err).Error("error removing transcoding progress") + logger.Error("error removing transcoding progress", "err", err) } // look for file to prevent duplication @@ -392,7 +391,7 @@ func (s server) NotifyTranscodingFinished(ctx context.Context, request *pb.Trans } err = s.DaoWrapper.StreamsDao.SaveStream(&stream) if err != nil { - log.WithError(err).Error("Can't save stream") + logger.Error("Can't save stream", "err", err) return nil, err } return &pb.Status{Ok: true}, nil @@ -414,7 +413,7 @@ func (s server) NotifyUploadFinished(ctx context.Context, req *pb.UploadFinished return nil, err } if stream.LiveNow { - log.WithField("req", req).Warn("VoD not saved, stream is live.") + logger.Warn("VoD not saved, stream is live.", "req", req) return nil, nil } stream.Recording = true @@ -479,7 +478,7 @@ func (s server) NotifyThumbnailsFinished(ctx context.Context, req *pb.Thumbnails func generateCombinedThumb(streamID uint, dao dao.DaoWrapper) { stream, err := dao.StreamsDao.GetStreamByID(context.Background(), fmt.Sprintf("%d", streamID)) if err != nil { - log.WithError(err).Warn("error getting stream") + logger.Warn("error getting stream", "err", err) return } var thumbCam, thumbPres string @@ -501,7 +500,7 @@ func generateCombinedThumb(streamID uint, dao dao.DaoWrapper) { w := workers[getWorkerWithLeastWorkload(workers)] wConn, err := dialIn(w) if err != nil { - log.WithError(err).Warn("error dialing in") + logger.Warn("error dialing in", "err", err) return } client := pb.NewToWorkerClient(wConn) @@ -511,11 +510,11 @@ func generateCombinedThumb(streamID uint, dao dao.DaoWrapper) { Path: strings.ReplaceAll(thumbPres, "PRES", "CAM_PRES"), }) if err != nil { - log.WithError(err).Warn("error combining thumbnails") + logger.Warn("error combining thumbnails", "err", err) return } if err := dao.FileDao.SetThumbnail(stream.ID, model.File{StreamID: stream.ID, Path: thumbnails.FilePath, Type: model.FILETYPE_THUMB_LG_CAM_PRES}); err != nil { - log.WithError(err).Warn("error saving thumbnail") + logger.Warn("error saving thumbnail", "err", err) } } @@ -536,7 +535,7 @@ func (s server) GetStreamInfoForUpload(ctx context.Context, request *pb.GetStrea } err = dao.NewUploadKeyDao().DeleteUploadKey(key) if err != nil { - log.WithError(err).Error("Can't delete upload key") + logger.Error("Can't delete upload key", "err", err) } return &pb.GetStreamInfoForUploadResponse{ CourseSlug: course.Slug, @@ -559,26 +558,26 @@ func (s server) NotifyStreamStarted(ctx context.Context, request *pb.StreamStart } stream, err := s.StreamsDao.GetStreamByID(ctx, fmt.Sprintf("%d", request.GetStreamID())) if err != nil { - log.WithError(err).Println("Can't find stream") + logger.Error("Can't find stream", "err", err) return nil, err } course, err := s.CoursesDao.GetCourseById(ctx, stream.CourseID) if err != nil { - log.WithError(err).Println("Can't find course") + logger.Error("Can't find course", "err", err) return nil, err } go func() { err := handleLightOnSwitch(stream, s.DaoWrapper) if err != nil { - log.WithError(err).Error("Can't handle light on switch") + logger.Error("Can't handle light on switch", "err", err) } err = handleCameraPositionSwitch(stream, s.DaoWrapper) if err != nil { - log.WithError(err).Error("Can't handle camera position switch") + logger.Error("Can't handle camera position switch", "err", err) } err = s.DaoWrapper.DeleteSilences(fmt.Sprintf("%d", stream.ID)) if err != nil { - log.WithError(err).Error("Can't delete silences") + logger.Error("Can't delete silences", "err", err) } }() go func() { @@ -587,12 +586,12 @@ func (s server) NotifyStreamStarted(ctx context.Context, request *pb.StreamStart err := s.StreamsDao.SaveStream(&stream) if err != nil { - log.WithError(err).Error("Can't save stream") + logger.Error("Can't save stream", "err", err) } err = s.StreamsDao.SetStreamLiveNowTimestampById(uint(request.StreamID), time.Now()) if err != nil { - log.WithError(err).Error("Can't set StreamLiveNowTimestamp") + logger.Error("Can't set StreamLiveNowTimestamp", "err", err) } time.Sleep(time.Second * 5) @@ -630,7 +629,7 @@ func (s server) NotifyTranscodingProgress(srv pb.FromWorker_NotifyTranscodingPro return nil } if err != nil { - log.Warnf("cannot receive %v", err) + logger.Warn("cannot receive", "err", err) return nil } err = s.DaoWrapper.StreamsDao.SaveTranscodingProgress(model.TranscodingProgress{ @@ -676,7 +675,7 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course } server, err := daoWrapper.IngestServerDao.GetBestIngestServer() if err != nil { - log.WithError(err).Error("Can't find ingest server") + logger.Error("Can't find ingest server", "err", err) return } var slot model.StreamName @@ -686,7 +685,7 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course if sourceType != "COMB" || err != nil { slot, err = daoWrapper.IngestServerDao.GetStreamSlot(server.ID) if err != nil { - log.WithError(err).Error("No free stream slot") + logger.Error("No free stream slot", "err", err) return } } @@ -710,12 +709,12 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course workers[workerIndex].Workload += 3 err = daoWrapper.StreamsDao.SaveWorkerForStream(stream, workers[workerIndex]) if err != nil { - log.WithError(err).Error("Could not save worker for stream") + logger.Error("Could not save worker for stream", "err", err) return } conn, err := dialIn(workers[workerIndex]) if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) workers[workerIndex].Workload -= 1 // decrease workers load only by one (backoff) return } @@ -723,7 +722,7 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course req.WorkerId = workers[workerIndex].WorkerID resp, err := client.RequestStream(context.Background(), &req) if err != nil || !resp.Ok { - log.WithError(err).Error("could not assign stream!") + logger.Error("could not assign stream!", "err", err) workers[workerIndex].Workload -= 1 // decrease workers load only by one (backoff) } endConnection(conn) @@ -738,25 +737,25 @@ func NotifyWorkers(daoWrapper dao.DaoWrapper) func() { streams := daoWrapper.StreamsDao.GetDueStreamsForWorkers() workers := daoWrapper.WorkerDao.GetAliveWorkers() if len(workers) == 0 && len(streams) != 0 { - log.Error("not enough workers to handle streams") + logger.Error("not enough workers to handle streams") return } for i := range streams { err := daoWrapper.StreamsDao.SaveEndedState(streams[i].ID, false) if err != nil { - log.WithError(err).Warn("Can't set stream undone") + logger.Warn("Can't set stream undone", "err", err) sentry.CaptureException(err) continue } courseForStream, err := daoWrapper.CoursesDao.GetCourseById(context.Background(), streams[i].CourseID) if err != nil { - log.WithError(err).Warn("Can't get course for stream, skipping") + logger.Warn("Can't get course for stream, skipping", "err", err) sentry.CaptureException(err) continue } lectureHallForStream, err := daoWrapper.LectureHallsDao.GetLectureHallByID(streams[i].LectureHallID) if err != nil { - log.WithError(err).Error("Can't get lecture hall for stream, skipping") + logger.Error("Can't get lecture hall for stream, skipping", "err", err) sentry.CaptureException(err) continue } @@ -786,25 +785,25 @@ func notifyWorkersPremieres(daoWrapper dao.DaoWrapper) { workers := daoWrapper.WorkerDao.GetAliveWorkers() if len(workers) == 0 && len(streams) != 0 { - log.Error("Not enough alive workers for premiere") + logger.Error("Not enough alive workers for premiere") return } for i := range streams { err := daoWrapper.StreamsDao.SaveEndedState(streams[i].ID, false) if err != nil { - log.WithError(err).Warn("Can't set stream undone") + logger.Warn("Can't set stream undone", "err", err) sentry.CaptureException(err) continue } if len(streams[i].Files) == 0 { - log.WithField("streamID", streams[i].ID).Warn("Request to self stream without file") + logger.Warn("Request to self stream without file", "streamID", streams[i].ID) continue } workerIndex := getWorkerWithLeastWorkload(workers) workers[workerIndex].Workload += 3 ingestServer, err := daoWrapper.IngestServerDao.GetBestIngestServer() if err != nil { - log.WithError(err).Error("Can't find ingest server") + logger.Error("Can't find ingest server", "err", err) continue } req := pb.PremiereRequest{ @@ -815,7 +814,7 @@ func notifyWorkersPremieres(daoWrapper dao.DaoWrapper) { } conn, err := dialIn(workers[workerIndex]) if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) endConnection(conn) workers[workerIndex].Workload -= 1 continue @@ -824,7 +823,7 @@ func notifyWorkersPremieres(daoWrapper dao.DaoWrapper) { req.WorkerID = workers[workerIndex].WorkerID resp, err := client.RequestPremiere(context.Background(), &req) if err != nil || !resp.Ok { - log.WithError(err).Error("could not assign premiere!") + logger.Error("could not assign premiere!", "err", err) workers[workerIndex].Workload -= 1 } endConnection(conn) @@ -852,7 +851,7 @@ func FetchLivePreviews(daoWrapper dao.DaoWrapper) func() { } conn, err := dialIn(workers[workerIndex]) if err != nil { - log.WithError(err).Error("Could not connect to worker") + logger.Error("Could not connect to worker", "err", err) endConnection(conn) continue } @@ -860,7 +859,7 @@ func FetchLivePreviews(daoWrapper dao.DaoWrapper) func() { workers[workerIndex].Workload += 1 if err := getLivePreviewFromWorker(&s, workers[workerIndex].WorkerID, client); err != nil { workers[workerIndex].Workload -= 1 - log.WithError(err).Error("Could not generate live preview") + logger.Error("Could not generate live preview", "err", err) endConnection(conn) continue } @@ -909,7 +908,7 @@ func RegenerateThumbs(daoWrapper dao.DaoWrapper, file model.File, stream *model. endConnection(conn) }() if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) return err } client := pb.NewToWorkerClient(conn) @@ -925,7 +924,7 @@ func RegenerateThumbs(daoWrapper dao.DaoWrapper, file model.File, stream *model. Start: timestamppb.New(stream.Start), }) if !res.Ok { - log.WithError(err).Error("did not get response from worker for thumbnail generation request") + logger.Error("did not get response from worker for thumbnail generation request", "err", err) } return nil @@ -948,7 +947,7 @@ func DeleteVideoSectionImage(workerDao dao.WorkerDao, path string) error { endConnection(conn) }() if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) return err } @@ -969,7 +968,7 @@ func GenerateVideoSectionImages(daoWrapper dao.DaoWrapper, parameters *generateV endConnection(conn) }() if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) return err } @@ -1016,12 +1015,12 @@ func GenerateVideoSectionImages(daoWrapper dao.DaoWrapper, parameters *generateV func NotifyWorkersToStopStream(stream model.Stream, discardVoD bool, daoWrapper dao.DaoWrapper) { workers, err := daoWrapper.StreamsDao.GetWorkersForStream(stream) if err != nil { - log.WithError(err).Error("Could not get workers for stream") + logger.Error("Could not get workers for stream", "err", err) return } if len(workers) == 0 { - log.Error("No workers for stream found") + logger.Error("No workers for stream found") return } @@ -1034,13 +1033,13 @@ func NotifyWorkersToStopStream(stream model.Stream, discardVoD bool, daoWrapper } conn, err := dialIn(currentWorker) if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) continue } client := pb.NewToWorkerClient(conn) resp, err := client.RequestStreamEnd(context.Background(), &req) if err != nil || !resp.Ok { - log.WithError(err).Error("Could not end stream") + logger.Error("Could not end stream", "err", err) } endConnection(conn) } @@ -1048,7 +1047,7 @@ func NotifyWorkersToStopStream(stream model.Stream, discardVoD bool, daoWrapper // All workers for stream are assumed to be done err = daoWrapper.StreamsDao.ClearWorkersForStream(stream) if err != nil { - log.WithError(err).Error("Could not delete workers for stream") + logger.Error("Could not delete workers for stream", "err", err) return } } @@ -1092,10 +1091,10 @@ func getWorkerWithLeastWorkload(workers []model.Worker) int { // ServeWorkerGRPC initializes a gRPC server on port 50052 func ServeWorkerGRPC() { - log.Info("Serving heartbeat") + logger.Info("Serving heartbeat") lis, err := net.Listen("tcp", ":50052") if err != nil { - log.WithError(err).Error("Failed to init grpc server") + logger.Error("Failed to init grpc server", "err", err) return } grpcServer := grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{ @@ -1109,7 +1108,7 @@ func ServeWorkerGRPC() { reflection.Register(grpcServer) go func() { if err = grpcServer.Serve(lis); err != nil { - log.WithError(err).Errorf("Can't serve grpc") + logger.Error("Can't serve grpc", "err", err) } }() } diff --git a/api/wsHub.go b/api/wsHub.go index d2876263f..0a4265165 100644 --- a/api/wsHub.go +++ b/api/wsHub.go @@ -5,12 +5,11 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/realtime" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "strconv" "strings" "sync" @@ -52,11 +51,12 @@ var connHandler = func(context *realtime.Context) { msg, _ := json.Marshal(gin.H{"viewers": len(sessionsMap[tumLiveContext.Stream.ID])}) err := context.Send(msg) if err != nil { - log.WithError(err).Error("can't write initial stats to session") + logger.Error("can't write initial stats to session", "err", err) } } // sendServerMessageWithBackoff sends a message to the client(if it didn't send a message to this user in the last 10 Minutes and the client is logged in) +// //lint:ignore U1000 Ignore unused function func sendServerMessageWithBackoff(session *realtime.Context, userId uint, streamId uint, msg string, t string) { if userId == 0 { @@ -71,7 +71,7 @@ func sendServerMessageWithBackoff(session *realtime.Context, userId uint, stream msgBytes, _ := json.Marshal(gin.H{"server": msg, "type": t}) err := session.Send(msgBytes) if err != nil { - log.WithError(err).Error("can't write server message to session") + logger.Error("can't write server message to session", "err", err) } // set cache item with ttl, so the user won't get a message for 10 Minutes tools.SetCacheItem(cacheKey, true, time.Minute*10) @@ -83,7 +83,7 @@ func sendServerMessage(msg string, t string, sessions ...*realtime.Context) { for _, session := range sessions { err := session.Send(msgBytes) if err != nil { - log.WithError(err).Error("can't write server message to session") + logger.Error("can't write server message to session", "err", err) } } diff --git a/cmd/tumlive/tumlive.go b/cmd/tumlive/tumlive.go index 9fa949cc0..967803c12 100755 --- a/cmd/tumlive/tumlive.go +++ b/cmd/tumlive/tumlive.go @@ -2,21 +2,22 @@ package main import ( "fmt" - "github.com/dgraph-io/ristretto" - "github.com/getsentry/sentry-go" - sentrygin "github.com/getsentry/sentry-go/gin" - "github.com/gin-contrib/gzip" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/api" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/tum" "github.com/TUM-Dev/gocast/web" + "github.com/dgraph-io/ristretto" + "github.com/getsentry/sentry-go" + sentrygin "github.com/getsentry/sentry-go/gin" + "github.com/gin-contrib/gzip" + "github.com/gin-gonic/gin" + slogGorm "github.com/orandin/slog-gorm" "github.com/pkg/profile" - log "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/gorm" + "log/slog" "net/http" _ "net/http/pprof" "os" @@ -29,6 +30,10 @@ var VersionTag = "development" type initializer func() +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "main") + var initializers = []initializer{ tools.LoadConfig, api.ServeWorkerGRPC, @@ -43,7 +48,8 @@ func initAll(initializers []initializer) { // GinServer launches the gin server func GinServer() (err error) { - router := gin.Default() + router := gin.New() + router.Use(gin.Recovery()) gin.SetMode(gin.ReleaseMode) // capture performance with sentry router.Use(sentrygin.New(sentrygin.Options{Repanic: true})) @@ -51,6 +57,16 @@ func GinServer() (err error) { tools.CookieSecure = true } + router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { + return fmt.Sprintf("{\"service\": \"GIN\", \"time\": %s, \"status\": %d, \"client\": \"%s\", \"path\": \"%s\", \"agent\": %s}\n", + param.TimeStamp.Format(time.DateTime), + param.StatusCode, + param.ClientIP, + param.Path, + param.Request.UserAgent(), + ) + })) + router.Use(tools.InitContext(dao.NewDaoWrapper())) liveUpdates := router.Group("/api/pub-sub") @@ -67,7 +83,7 @@ func GinServer() (err error) { //err = router.RunTLS(":443", tools.Cfg.Saml.Cert, tools.Cfg.Saml.Privkey) if err != nil { sentry.CaptureException(err) - log.WithError(err).Fatal("Error starting tumlive") + logger.Error("Error starting tumlive", "err", err) } return } @@ -85,7 +101,7 @@ func main() { }() // log with time, fmt "23.09.2021 10:00:00" - log.SetFormatter(&log.TextFormatter{TimestampFormat: "02.01.2006 15:04:05", FullTimestamp: true}) + //log.SetFormatter(&log.TextFormatter{TimestampFormat: "02.01.2006 15:04:05", FullTimestamp: true}) web.VersionTag = VersionTag osSignal = make(chan os.Signal, 1) @@ -104,12 +120,15 @@ func main() { Environment: env, }) if err != nil { - log.Fatalf("sentry.Init: %s", err) + logger.Error("sentry.Init", "err", err) } // Flush buffered events before the program terminates. defer sentry.Flush(2 * time.Second) defer sentry.Recover() } + + gormJSONLogger := slogGorm.New() + db, err := gorm.Open(mysql.Open(fmt.Sprintf( "%s:%s@tcp(%s:%d)/%s?parseTime=true&loc=Local", tools.Cfg.Db.User, @@ -119,18 +138,19 @@ func main() { tools.Cfg.Db.Database), ), &gorm.Config{ PrepareStmt: true, + Logger: gormJSONLogger, }) if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.Fatalf("%v", err) + logger.Error("Error opening database", "err", err) } dao.DB = db err = dao.Migrator.RunBefore(db) if err != nil { - log.Error(err) + logger.Error("Error running before db", "err", err) return } @@ -172,11 +192,11 @@ func main() { if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.WithError(err).Fatal("can't migrate database") + logger.Error("can't migrate database", "err", err) } err = dao.Migrator.RunAfter(db) if err != nil { - log.Error(err) + logger.Error("Error running after db", "err", err) return } @@ -191,7 +211,7 @@ func main() { if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.Fatalf("%v", err) + logger.Error("Error risretto.NewCache", "err", err) } dao.Cache = *cache @@ -207,7 +227,7 @@ func main() { if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.WithError(err).Fatal("can't launch gin server") + logger.Error("can't launch gin server", "err", err) } }() keepAlive() @@ -236,5 +256,5 @@ func initCron() { func keepAlive() { signal.Notify(osSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1) s := <-osSignal - log.Infof("Exiting on signal %s", s.String()) + logger.Info("Exiting on signal" + s.String()) } diff --git a/dao/courses.go b/dao/courses.go index 18294dfea..7a169f0c9 100644 --- a/dao/courses.go +++ b/dao/courses.go @@ -10,7 +10,6 @@ import ( "github.com/RBG-TUM/commons" "github.com/getsentry/sentry-go" - log "github.com/sirupsen/logrus" "gorm.io/gorm" ) @@ -305,16 +304,16 @@ func (d coursesDao) DeleteCourse(course model.Course) { for _, stream := range course.Streams { err := DB.Delete(&stream).Error if err != nil { - log.WithError(err).Error("Can't delete stream") + logger.Error("Can't delete stream", "err", err) } } err := DB.Model(&course).Updates(map[string]interface{}{"vod_enabled": false}).Error if err != nil { - log.WithError(err).Error("Can't update course settings when deleting") + logger.Error("Can't update course settings when deleting", "err", err) } err = DB.Delete(&course, course.ID).Error if err != nil { - log.WithError(err).Error("Can't delete course") + logger.Error("Can't delete course", "err", err) } } diff --git a/dao/dao_logger.go b/dao/dao_logger.go new file mode 100644 index 000000000..63eb896b4 --- /dev/null +++ b/dao/dao_logger.go @@ -0,0 +1,10 @@ +package dao + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "dao") diff --git a/dao/video-seek.go b/dao/video-seek.go index 4cc7200ed..165650cc0 100644 --- a/dao/video-seek.go +++ b/dao/video-seek.go @@ -3,7 +3,6 @@ package dao import ( "errors" "github.com/TUM-Dev/gocast/model" - log "github.com/sirupsen/logrus" "gorm.io/gorm" "gorm.io/gorm/clause" ) @@ -32,7 +31,7 @@ func (d videoSeekDao) Add(streamID string, pos float64) error { } if (pos / float64(stream.Duration.Int32)) > 1 { - log.Error("position is bigger than stream duration") + logger.Error("position is bigger than stream duration") return errors.New("position is bigger than stream duration") } diff --git a/go.mod b/go.mod index dd030c58c..1206996fa 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/TUM-Dev/gocast -go 1.18 +go 1.21 require ( github.com/RBG-TUM/CAMPUSOnline v0.0.0-20230412070523-8db58ed5c0b4 @@ -30,7 +30,7 @@ require ( google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 gorm.io/driver/mysql v1.5.1 - gorm.io/gorm v1.25.3 + gorm.io/gorm v1.25.5 mvdan.cc/xurls/v2 v2.5.0 ) @@ -50,6 +50,7 @@ require ( github.com/asticode/go-astisub v0.26.0 github.com/matthiasreumann/gomino v0.0.2 github.com/meilisearch/meilisearch-go v0.25.0 + github.com/orandin/slog-gorm v1.0.1 ) require ( diff --git a/go.sum b/go.sum index 1b9e9cfab..04b5da18a 100644 --- a/go.sum +++ b/go.sum @@ -126,6 +126,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -145,6 +146,7 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -155,6 +157,7 @@ github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSz github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -175,7 +178,9 @@ github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -271,13 +276,17 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= @@ -323,11 +332,13 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/meilisearch/meilisearch-go v0.25.0 h1:xIp+8YWterHuDvpdYlwQ4Qp7im3JlRHmSKiP0NvjyXs= github.com/meilisearch/meilisearch-go v0.25.0/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/microsoft/go-mssqldb v0.21.0 h1:p2rpHIL7TlSv1QrbXJUAcbyRKnIT0C9rRkH2E4OjLn8= +github.com/microsoft/go-mssqldb v0.21.0/go.mod h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -344,11 +355,14 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/olahol/melody v0.0.0-20180227134253-7bd65910e5ab/go.mod h1:3lo03f1jM3KFUG/rsujuLB1rBmlvIzVM3SCqbuHqsBU= +github.com/orandin/slog-gorm v1.0.1 h1:Hyhaajes1rXsgwbH59+qS2JaN31PNEBzMywiFsa2Eiw= +github.com/orandin/slog-gorm v1.0.1/go.mod h1:QLR+9XefjS+lz7Xw3ZXkDkT5U59h7/0c8TZlMZPqXpI= github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -367,6 +381,7 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= @@ -803,11 +818,14 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= gorm.io/driver/sqlite v1.5.1 h1:hYyrLkAWE71bcarJDPdZNTLWtr8XrSjOWyjUYI6xdL4= +gorm.io/driver/sqlite v1.5.1/go.mod h1:7MZZ2Z8bqyfSQA1gYEV6MagQWj3cpUkJj9Z+d1HEMEQ= gorm.io/driver/sqlserver v1.5.0 h1:zol7ePfY1XiPfjEvjjBh4VatIF3kycNcPE0EMCXznHY= +gorm.io/driver/sqlserver v1.5.0/go.mod h1:tBAqioK34BHl0Iiez+BFfG5/K9nDAlhLxRkgc2qy3+4= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.3 h1:zi4rHZj1anhZS2EuEODMhDisGy+Daq9jtPrNGgbQYD8= -gorm.io/gorm v1.25.3/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= +gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= diff --git a/go.work b/go.work index 61b4b2a9a..71de48fe3 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.19 +go 1.21 use ( . diff --git a/go.work.sum b/go.work.sum index 20e0d67ff..542938353 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,156 +1,314 @@ -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/RBG-TUM/CAMPUSOnline v0.0.0-20230412070523-8db58ed5c0b4/go.mod h1:pcWaw3hQOKmvRfldxtPlYBGAFbWQXUU44+KcDYwqduc= -github.com/RBG-TUM/commons v0.0.0-20220406105618-030c095f6a1b/go.mod h1:Nw30dUekEb8ZrJwoGck0lILeVDCIX9dqJsEAPSOxBs0= -github.com/RBG-TUM/go-anel-pwrctrl v1.0.0/go.mod h1:6c2j1rcryE6BWphhJtGb+yXFIGRzmIXi+31TjE9Cft4= -github.com/TUM-Dev/CampusProxy/client v0.0.0-20230226120508-3e8bb2411921/go.mod h1:UuXuuqgljQbgtLAw5NY+VcThXAwO6UISn6U3s4TJx8k= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antchfx/xmlquery v1.3.17/go.mod h1:Afkq4JIeXut75taLSuI31ISJ/zeq+3jG7TunF7noreA= -github.com/antchfx/xpath v1.2.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= -github.com/asticode/go-astikit v0.20.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= -github.com/asticode/go-astikit v0.30.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= -github.com/asticode/go-astikit v0.40.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= -github.com/asticode/go-astisub v0.26.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2zLRVFf6bIFQK8= -github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ= -github.com/asticode/go-astits v1.13.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI= -github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= -github.com/beevik/etree v1.2.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA= +cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ= +cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU= +cloud.google.com/go/storage v1.14.0 h1:6RRlFMv1omScs6iq2hfE3IvgE+l6RfJPampq8UZc5TU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= +github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME= +github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= +github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= +github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk= +github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU= +github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= +github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bketelsen/crypt v0.0.4 h1:w/jqZtC9YD4DS/Vp9GhWfWcCpuAL58oTnLoI8vE9YHU= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= -github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4= -github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA= -github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gabstv/melody v1.0.2/go.mod h1:fvJW9enOHGIN1E4nCuBZ3lIZxHiPbnMIIYEXcSKQq9o= -github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-gormigrate/gormigrate/v2 v2.1.0/go.mod h1:gpA97koYGyjqaiLDTmLE5W7nyYTmI26AYIf2a/earuo= -github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= +github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= +github.com/coreos/go-etcd v2.0.0+incompatible h1:bXhRBIXoTm9BYHS3gE0TtQuyNZyeEMux2sDi4oo5YOo= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g= +github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/djherbis/atime v1.1.0 h1:rgwVbP/5by8BvvjBNrbh64Qz33idKT3pSnMSJsxhi0g= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f h1:7T++XKzy4xg7PKy+bM+Sa9/oe1OC88yz2hXQUISoXfA= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/icholy/digest v0.1.22/go.mod h1:uLAeDdWKIWNFMH0wqbwchbTQOmJWhzSnL7zmqSPqEEc= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= -github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= -github.com/matthiasreumann/gomino v0.0.2/go.mod h1:bmKxa4ZOGY6RSFH4NnfYf7hk7FbMu2nkSpoAF5TD6fY= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/meilisearch/meilisearch-go v0.25.0/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= -github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/olahol/melody v0.0.0-20180227134253-7bd65910e5ab/go.mod h1:3lo03f1jM3KFUG/rsujuLB1rBmlvIzVM3SCqbuHqsBU= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60= +github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= +github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE= +github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= +github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/hashicorp/consul/api v1.20.0 h1:9IHTjNVSZ7MIwjlW3N3a7iGiykCMDpxZu8jsxFJh0yc= +github.com/hashicorp/consul/api v1.20.0/go.mod h1:nR64eD44KQ59Of/ECwt2vUmIK2DKsDzAwTmwmLl8Wpo= +github.com/hashicorp/consul/sdk v0.1.1 h1:LnuDWGNsoajlhGyHJvuWW6FVqRl8JOTPqS6CPTsYjhY= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= +github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= +github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= +github.com/hashicorp/mdns v1.0.0 h1:WhIgCr5a7AaVH6jPUwjtRuuE7/RDufnUvzIr48smyxs= +github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= +github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab h1:BA4a7pe6ZTd9F8kXETBoijjFJ/ntaa//1wiH9BZu4zU= +github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= +github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/iris-contrib/httpexpect/v2 v2.3.1 h1:A69ilxKGW1jDRKK5UAhjTL4uJYh3RjD4qzt9vNZ7fpY= +github.com/iris-contrib/jade v1.1.4 h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0= +github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kataras/blocks v0.0.7 h1:cF3RDY/vxnSRezc7vLFlQFTYXG/yAr1o7WImJuZbzC4= +github.com/kataras/golog v0.1.8 h1:isP8th4PJH2SrbkciKnylaND9xoTtfxv++NB+DF0l9g= +github.com/kataras/golog v0.1.8/go.mod h1:rGPAin4hYROfk1qT9wZP6VY2rsb4zzc37QpdPjdkqVw= +github.com/kataras/iris/v12 v12.2.0 h1:WzDY5nGuW/LgVaFS5BtTkW3crdSKJ/FEgWnxPnIVVLI= +github.com/kataras/iris/v12 v12.2.0/go.mod h1:BLzBpEunc41GbE68OUaQlqX4jzi791mx5HU04uPb90Y= +github.com/kataras/jwt v0.1.8 h1:u71baOsYD22HWeSOg32tCHbczPjdCk7V4MMeJqTtmGk= +github.com/kataras/neffos v0.0.20 h1:swTzKZ3Mo2sIQ8ATKSKf0xDG1tuhr6w4tZmmRsvCYlg= +github.com/kataras/pio v0.0.11 h1:kqreJ5KOEXGMwHAWHDwIl+mjfNCPhAwZPa8gK7MKlyw= +github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY= +github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA= +github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/knz/go-libedit v1.10.1 h1:0pHpWtx9vcvC0xGZqEQlQdfSQs7WRlAjuPvk3fOZDCo= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/labstack/echo/v4 v4.10.0 h1:5CiyngihEO4HXsz3vVsJn7f8xAlWwRr3aY6Ih280ZKA= +github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ= +github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= +github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw= +github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 h1:JAEbJn3j/FrhdWA9jW8B5ajsLIjeuEHLi8xE4fk997o= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mediocregopher/radix/v3 v3.8.0 h1:HI8EgkaM7WzsrFpYAkOXIgUKbjNonb2Ne7K6Le61Pmg= +github.com/microsoft/go-mssqldb v0.21.0/go.mod h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4= +github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc= +github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI= +github.com/nats-io/nats-server/v2 v2.8.4 h1:0jQzze1T9mECg8YZEl8+WYUXb9JKluJfCBriPUtluB4= +github.com/nats-io/nats.go v1.16.0 h1:zvLE7fGBQYW6MWaFaRdsgm9qT39PJDQoju+DS8KsO1g= +github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 h1:D6paGObi5Wud7xg83MaEFyjxQB1W5bz5d0IFppr+ymk= +github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c h1:bY6ktFuJkt+ZXkX0RChQch2FtHpWQLVS8Qo1YasiIVk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/olahol/melody v0.0.0-20180227134253-7bd65910e5ab h1:2fsluM+sAZRIQtvloPaokkWWjV8strYfmXsDCtZMqt0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/panjf2000/ants/v2 v2.4.2 h1:kesjjo8JipN3vNNg1XaiXaeSs6xJweBTgenkBtsrHf8= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= +github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= +github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= -github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= -github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f h1:UFr9zpz4xgTnIE5yIMtWAMngCdZ9p/+q6lTbgelo80M= +github.com/sagikazarmark/crypt v0.10.0 h1:96E1qrToLBU6fGzo+PRRz7KGOc9FkYFiPnR3/zf8Smg= +github.com/sagikazarmark/crypt v0.10.0/go.mod h1:gwTNHQVoOS3xp9Xvz5LLR+1AauC5M6880z5NWzdhOyQ= +github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk= +github.com/schollz/progressbar/v3 v3.8.6 h1:QruMUdzZ1TbEP++S1m73OqRJk20ON11m6Wqv4EoGg8c= +github.com/schollz/progressbar/v3 v3.8.6/go.mod h1:W5IEwbJecncFGBvuEh4A7HT1nZZ6WNIL2i3qbnI0WKY= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 h1:aSISeOcal5irEhJd1M+IrApc0PdcN7e7Aj4yuEnOrfQ= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= +github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/tdewolff/minify/v2 v2.12.4 h1:kejsHQMM17n6/gwdw53qsi6lg0TGddZADVyQOz1KMdE= +github.com/tdewolff/parse/v2 v2.6.4 h1:KCkDvNUMof10e3QExio9OPZJT8SbdKojLBumw8YZycQ= +github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM= github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= -github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= +github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= +go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= +go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= +go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= +go.etcd.io/etcd/client/v2 v2.305.7 h1:AELPkjNR3/igjbO7CjyF1fPuVPjrblliiKj+Y6xSGOU= +go.etcd.io/etcd/client/v2 v2.305.7/go.mod h1:GQGT5Z3TBuAQGvgPfhR7VPySu/SudxmEkRq9BgzFU6s= +go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= +go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.122.0 h1:zDobeejm3E7pEG1mNHvdxvjs5XJoCMzyNH+CmwL94Es= +google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= -gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= +gorm.io/driver/sqlite v1.5.1/go.mod h1:7MZZ2Z8bqyfSQA1gYEV6MagQWj3cpUkJj9Z+d1HEMEQ= +gorm.io/driver/sqlserver v1.5.0/go.mod h1:tBAqioK34BHl0Iiez+BFfG5/K9nDAlhLxRkgc2qy3+4= gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= -gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.3/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= +moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8= +nullprogram.com/x/optparse v1.0.0 h1:xGFgVi5ZaWOnYdac2foDT3vg0ZZC9ErXFV57mr4OHrI= +rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= +rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= diff --git a/model/course.go b/model/course.go index e902bba18..65c3524f8 100755 --- a/model/course.go +++ b/model/course.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" "gorm.io/gorm" "log" "time" @@ -148,7 +147,7 @@ func (c Course) CanUseSource(lectureHallID uint, sourceType string) bool { func (c *Course) SetSourcePreference(pref []SourcePreference) { pBytes, err := json.Marshal(pref) if err != nil { - logrus.WithError(err).Error("Could not marshal source preference") + logger.Error("Could not marshal source preference", "err", err) return } c.SourcePreferences = string(pBytes) diff --git a/model/model_logger.go b/model/model_logger.go new file mode 100644 index 000000000..2464568ee --- /dev/null +++ b/model/model_logger.go @@ -0,0 +1,10 @@ +package model + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "model") diff --git a/model/user.go b/model/user.go index 5856e127f..b16c956e9 100755 --- a/model/user.go +++ b/model/user.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "sort" "strings" "time" @@ -54,6 +55,7 @@ const ( PreferredName UserSettingType = iota + 1 Greeting CustomPlaybackSpeeds + UserDefinedSpeeds ) type UserSetting struct { @@ -79,6 +81,8 @@ type PlaybackSpeedSetting struct { Enabled bool `json:"enabled"` } +type CustomSpeeds []float32 + type PlaybackSpeedSettings []PlaybackSpeedSetting func (s PlaybackSpeedSettings) GetEnabled() (res []float32) { @@ -90,6 +94,22 @@ func (s PlaybackSpeedSettings) GetEnabled() (res []float32) { return res } +func (u *User) GetEnabledPlaybackSpeeds() (res []float32) { + if u == nil { + return []float32{1} + } + for _, setting := range u.GetPlaybackSpeeds().GetEnabled() { + res = append(res, setting) + } + for _, setting := range u.GetCustomSpeeds() { + res = append(res, setting) + } + sort.SliceStable(res, func(i, j int) bool { + return res[i] < res[j] + }) + return res +} + var defaultPlaybackSpeeds = PlaybackSpeedSettings{ {0.25, false}, {0.5, true}, @@ -120,6 +140,22 @@ func (u *User) GetPlaybackSpeeds() (speeds PlaybackSpeedSettings) { return defaultPlaybackSpeeds } +func (u *User) GetCustomSpeeds() (speeds CustomSpeeds) { + if u == nil { + return []float32{} + } + for _, setting := range u.Settings { + if setting.Type == UserDefinedSpeeds { + err := json.Unmarshal([]byte(setting.Value), &speeds) + if err != nil { + break + } + return speeds + } + } + return []float32{} +} + // GetPreferredGreeting returns the preferred greeting of the user if set, otherwise Moin func (u User) GetPreferredGreeting() string { for _, setting := range u.Settings { diff --git a/tools/bot/bot.go b/tools/bot/bot.go index 572e448e8..87272a37a 100644 --- a/tools/bot/bot.go +++ b/tools/bot/bot.go @@ -1,11 +1,10 @@ package bot import ( - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" + "github.com/getsentry/sentry-go" "github.com/microcosm-cc/bluemonday" - log "github.com/sirupsen/logrus" "strings" "time" ) @@ -147,7 +146,7 @@ func hasPrio(streamID uint, statsDao dao.StatisticsDao) bool { liveViewers, err := statsDao.GetStreamNumLiveViews(streamID) if err != nil { sentry.CaptureException(err) - log.WithError(err).Error("Failed to get current live viewers") + logger.Error("Failed to get current live viewers", "err", err) return false } diff --git a/tools/bot/bot_logger.go b/tools/bot/bot_logger.go new file mode 100644 index 000000000..8af169b64 --- /dev/null +++ b/tools/bot/bot_logger.go @@ -0,0 +1,10 @@ +package bot + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "bot") diff --git a/tools/bot/matrix.go b/tools/bot/matrix.go index 0bd8e8e2d..f1e81f7ed 100644 --- a/tools/bot/matrix.go +++ b/tools/bot/matrix.go @@ -5,9 +5,8 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" "io" "math/rand" "net/http" @@ -74,14 +73,14 @@ func (m *Matrix) getClientUrl() string { func (m *Matrix) SendBotMessage(message Message) error { err := m.sendMessageToRoom(tools.Cfg.Alerts.Matrix.LogRoomID, message) if err != nil { - log.WithError(err).Error("Failed to send message to matrix log room") + logger.Error("Failed to send message to matrix log room", "err", err) sentry.CaptureException(err) return err } if message.Prio { err = m.sendMessageToRoom(tools.Cfg.Alerts.Matrix.AlertRoomID, message) if err != nil { - log.WithError(err).Error("Failed to send message to matrix alert room") + logger.Error("Failed to send message to matrix alert room", "err", err) sentry.CaptureException(err) } } diff --git a/tools/branding.go b/tools/branding.go index 644e4c349..5abd222c9 100644 --- a/tools/branding.go +++ b/tools/branding.go @@ -2,7 +2,6 @@ package tools import ( "fmt" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" ) @@ -38,7 +37,7 @@ func InitBranding() { err := v.ReadInConfig() if err == nil { err = v.Unmarshal(&branding) - log.Info("Using branding.yaml.") + logger.Info("Using branding.yaml.") if err != nil { panic(fmt.Errorf("fatal error branding file: %v", err)) } diff --git a/tools/camera/camera_logger.go b/tools/camera/camera_logger.go new file mode 100644 index 000000000..ba5b22c5d --- /dev/null +++ b/tools/camera/camera_logger.go @@ -0,0 +1,10 @@ +package camera + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "camera") diff --git a/tools/camera/panasonic.go b/tools/camera/panasonic.go index 65864c6d7..27c0ab10a 100644 --- a/tools/camera/panasonic.go +++ b/tools/camera/panasonic.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/TUM-Dev/gocast/model" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" ) /** @@ -18,21 +17,21 @@ import ( const panasonicBaseUrl = "http://%s/cgi-bin" -//PanasonicCam represents Panasonic IP cameras the TUM uses +// PanasonicCam represents Panasonic IP cameras the TUM uses type PanasonicCam struct { Ip string Auth *string // currently unused as our cams have auth deactivated for PTZ operation } -//NewPanasonicCam Acts as a constructor for cameras. -//ip: the ip address of the camera -//auth: username and password of the camera (e.g. "user:password") +// NewPanasonicCam Acts as a constructor for cameras. +// ip: the ip address of the camera +// auth: username and password of the camera (e.g. "user:password") func NewPanasonicCam(ip string, auth *string) *PanasonicCam { return &PanasonicCam{Ip: ip, Auth: auth} } func (c PanasonicCam) TakeSnapshot(outDir string) (filename string, err error) { - log.Info(fmt.Sprintf("%s/view.cgi?action=snapshot", fmt.Sprintf(panasonicBaseUrl, c.Ip))) + logger.Info(fmt.Sprintf("%s/view.cgi?action=snapshot", fmt.Sprintf(panasonicBaseUrl, c.Ip))) resp, err := makeAuthenticatedRequest(c.Auth, "GET", "", fmt.Sprintf("%s/view.cgi?action=snapshot", fmt.Sprintf(panasonicBaseUrl, c.Ip))) if err != nil { return "", err @@ -45,13 +44,13 @@ func (c PanasonicCam) TakeSnapshot(outDir string) (filename string, err error) { return filename, nil } -//SetPreset tells the camera to use a preset specified by presetId +// SetPreset tells the camera to use a preset specified by presetId func (c PanasonicCam) SetPreset(presetId int) error { _, err := makeAuthenticatedRequest(c.Auth, "GET", "", fmt.Sprintf("%s/camctrl?preset=%d", fmt.Sprintf(panasonicBaseUrl, c.Ip), presetId)) return err } -//GetPresets fetches all presets stored on the camera +// GetPresets fetches all presets stored on the camera func (c PanasonicCam) GetPresets() ([]model.CameraPreset, error) { // panasonic cameras come with 100 slots for presets. These are always present but usually only a few are configured. // we therefore just return 10 stubs here. diff --git a/tools/config.go b/tools/config.go index c7639690f..145fd3cad 100644 --- a/tools/config.go +++ b/tools/config.go @@ -9,7 +9,6 @@ import ( "fmt" "github.com/meilisearch/meilisearch-go" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" "os" "time" @@ -23,7 +22,7 @@ func LoadConfig() { var err error Loc, err = time.LoadLocation("Europe/Berlin") if err != nil { - log.WithError(err).Error("tools.config.LoadConfig: can't get time.location") + logger.Error("tools.config.LoadConfig: can't get time.location", "err", err) } initConfig() } @@ -39,12 +38,12 @@ func initConfig() { err := viper.ReadInConfig() if err != nil { if errors.Is(err, viper.ConfigFileNotFoundError{}) { - log.WithError(err).Warn("tools.config.LoadConfig: can't find config file") + logger.Warn("tools.config.LoadConfig: can't find config file", "err", err) } else { panic(fmt.Errorf("fatal error config file: %v", err)) } } - log.Info("Using Config file ", viper.ConfigFileUsed()) + logger.Info("Using Config file " + viper.ConfigFileUsed()) err = viper.Unmarshal(&Cfg) if err != nil { panic(fmt.Errorf("fatal error config file: %v", err)) @@ -56,14 +55,14 @@ func initConfig() { viper.Set("workerToken", Cfg.WorkerToken) err = viper.WriteConfig() if err != nil { - log.Warn("Can't write out config ", err) + logger.Warn("Can't write out config ", "err", err) } } if Cfg.JWTKey == nil { - log.Info("Generating new JWT key") + logger.Info("Generating new JWT key") JWTKey, err := rsa.GenerateKey(rand.Reader, rsaKeySize) if err != nil { - log.WithError(err).Fatal("Can't generate JWT key") + logger.Error("Can't generate JWT key", "err", err) } armoured := string(pem.EncodeToMemory( &pem.Block{ @@ -74,14 +73,14 @@ func initConfig() { viper.Set("jwtKey", armoured) err = viper.WriteConfig() if err != nil { - log.Warn("Can't write out config ", err) + logger.Warn("Can't write out config ", "err", err) } jwtKey = JWTKey } else { k, _ := pem.Decode([]byte(*Cfg.JWTKey)) key, err := x509.ParsePKCS1PrivateKey(k.Bytes) if err != nil { - log.WithError(err).Fatal("Can't parse JWT key") + logger.Error("Can't parse JWT key", "err", err) return } jwtKey = key diff --git a/tools/email.go b/tools/email.go index 02700d7e9..270f959f1 100644 --- a/tools/email.go +++ b/tools/email.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "github.com/TUM-Dev/gocast/dao" - "log" "net/smtp" "os/exec" "strings" @@ -33,7 +32,7 @@ func (m *Mailer) Run() { lastRun = time.Now() emails, err := m.Dao.EmailDao.GetDue(context.Background(), m.MaxMailsPerMinute) if err != nil { - log.Printf("error getting due emails: %v", err) + logger.Error("error getting due emails", "err", err) continue } for _, email := range emails { @@ -47,7 +46,7 @@ func (m *Mailer) Run() { } err = m.Dao.EmailDao.Save(context.Background(), &email) if err != nil { - log.Printf("error saving email: %v", err) + logger.Error("error saving email", "err", err) } sleepDur := time.Duration(1000 * (60 / m.MaxMailsPerMinute)) @@ -57,7 +56,7 @@ func (m *Mailer) Run() { } func (m *Mailer) sendMail(addr, from, subject, body string, to []string) error { - log.Printf("sending mail to %v, subject: %s body:\n%s", to, subject, body) + logger.Info("sending mail", "to", to, "subject", subject, "body", body) r := strings.NewReplacer("\r\n", "", "\r", "", "\n", "", "%0a", "", "%0d", "") signed, err := openssl([]byte(body), "smime", "-text", "-sign", "-signer", Cfg.Mail.SMIMECert, "-inkey", Cfg.Mail.SMIMEKey) diff --git a/tools/meiliExporter.go b/tools/meiliExporter.go index 2fbd595e6..d72da9833 100644 --- a/tools/meiliExporter.go +++ b/tools/meiliExporter.go @@ -3,10 +3,9 @@ package tools import ( "errors" "fmt" - "github.com/asticode/go-astisub" "github.com/TUM-Dev/gocast/dao" + "github.com/asticode/go-astisub" "github.com/meilisearch/meilisearch-go" - log "github.com/sirupsen/logrus" "strings" ) @@ -39,7 +38,7 @@ func NewMeiliExporter(d dao.DaoWrapper) *MeiliExporter { if err != nil && errors.Is(err, ErrMeiliNotConfigured) { return nil } else if err != nil { - log.WithError(err).Error("could not get meili client") + logger.Error("could not get meili client", "err", err) return nil } @@ -53,7 +52,7 @@ func (m *MeiliExporter) Export() { index := m.c.Index("STREAMS") _, err := m.c.Index("SUBTITLES").DeleteAllDocuments() if err != nil { - log.WithError(err).Warn("could not delete all old subtitles") + logger.Warn("could not delete all old subtitles", "err", err) } m.d.StreamsDao.ExecAllStreamsWithCoursesAndSubtitles(func(streams []dao.StreamWithCourseAndSubtitles) { @@ -75,7 +74,7 @@ func (m *MeiliExporter) Export() { vtt, err := astisub.ReadFromWebVTT(strings.NewReader(stream.Subtitles)) if err != nil { - log.WithError(err).Warn("could not parse subtitles") + logger.Warn("could not parse subtitles", "err", err) continue } for i, _ := range vtt.Items { @@ -96,14 +95,14 @@ func (m *MeiliExporter) Export() { if len(meiliSubtitles) > 0 { _, err := m.c.Index("SUBTITLES").AddDocuments(&meiliSubtitles, "ID") if err != nil { - log.WithError(err).Error("issue adding subtitles to meili") + logger.Error("issue adding subtitles to meili", "err", err) } } } } _, err := index.AddDocuments(&meilistreams, "ID") if err != nil { - log.WithError(err).Error("issue adding documents to meili") + logger.Error("issue adding documents to meili", "err", err) } }) @@ -120,7 +119,7 @@ func (m *MeiliExporter) SetIndexSettings() { } _, err := index.UpdateSynonyms(&synonyms) if err != nil { - log.WithError(err).Error("could not set synonyms for meili index STREAMS") + logger.Error("could not set synonyms for meili index STREAMS", "err", err) } _, err = m.c.Index("SUBTITLES").UpdateSettings(&meilisearch.Settings{ @@ -129,6 +128,6 @@ func (m *MeiliExporter) SetIndexSettings() { SortableAttributes: []string{"timestamp"}, }) if err != nil { - log.WithError(err).Warn("could not set settings for meili index SUBTITLES") + logger.Warn("could not set settings for meili index SUBTITLES", "err", err) } } diff --git a/tools/meiliSearch.go b/tools/meiliSearch.go index 9b3b8a035..4770dfae1 100644 --- a/tools/meiliSearch.go +++ b/tools/meiliSearch.go @@ -3,7 +3,6 @@ package tools import ( "fmt" "github.com/meilisearch/meilisearch-go" - log "github.com/sirupsen/logrus" ) func SearchSubtitles(q string, streamID uint) *meilisearch.SearchResponse { @@ -16,7 +15,7 @@ func SearchSubtitles(q string, streamID uint) *meilisearch.SearchResponse { Limit: 10, }) if err != nil { - log.WithError(err).Error("could not search meili") + logger.Error("could not search meili", "err", err) return nil } return response diff --git a/tools/middlewares.go b/tools/middlewares.go index b523ba213..dee069940 100644 --- a/tools/middlewares.go +++ b/tools/middlewares.go @@ -2,13 +2,12 @@ package tools import ( "errors" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" - "github.com/golang-jwt/jwt/v4" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools/realtime" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v4" "net/http" "net/url" "strconv" @@ -50,13 +49,13 @@ func InitContext(daoWrapper dao.DaoWrapper) gin.HandlerFunc { return key, nil }) if err != nil { - log.Info("JWT parsing error: ", err) + logger.Info("JWT parsing error: ", "err", err) c.Set("TUMLiveContext", TUMLiveContext{}) c.SetCookie("jwt", "", -1, "/", "", false, true) return } if !token.Valid { - log.Info("JWT token is not valid") + logger.Info("JWT token is not valid") c.Set("TUMLiveContext", TUMLiveContext{}) c.SetCookie("jwt", "", -1, "/", "", false, true) return @@ -90,7 +89,7 @@ func RenderErrorPage(c *gin.Context, status int, message string) { Branding: BrandingCfg, }) if err != nil { - log.Error(err) + logger.Error("Error on executing template error.gohtml", "err", err) } c.Abort() } @@ -371,7 +370,7 @@ func AdminToken(daoWrapper dao.DaoWrapper) gin.HandlerFunc { } err = daoWrapper.TokenDao.TokenUsed(t) if err != nil { - log.WithError(err).Warn("error marking token as used") + logger.Warn("error marking token as used", "err", err) return } } diff --git a/tools/presets.go b/tools/presets.go index 317725ec0..b0d3f8647 100644 --- a/tools/presets.go +++ b/tools/presets.go @@ -3,11 +3,10 @@ package tools import ( "context" "errors" - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools/camera" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" "time" ) @@ -39,7 +38,7 @@ func (p presetUtility) ProvideCamera(ctype model.CameraType, ip string) (camera. return nil, errors.New("invalid camera type") } -//FetchCameraPresets Queries all cameras of lecture halls for their camera presets and saves them to the database +// FetchCameraPresets Queries all cameras of lecture halls for their camera presets and saves them to the database func (p presetUtility) FetchCameraPresets(ctx context.Context) { span := sentry.StartSpan(ctx, "FetchCameraPresets") defer span.Finish() @@ -53,12 +52,12 @@ func (p presetUtility) FetchLHPresets(lectureHall model.LectureHall) { if lectureHall.CameraIP != "" { cam, err := p.ProvideCamera(lectureHall.CameraType, lectureHall.CameraIP) if err != nil { - log.WithError(err) + logger.Error("Error providing camera", "err", err) return } presets, err := cam.GetPresets() if err != nil { - log.WithError(err).WithField("AxisCam", lectureHall.CameraIP).Warn("FetchCameraPresets: failed to get Presets") + logger.Warn("FetchCameraPresets: failed to get Presets", "err", err, "AxisCam", lectureHall.CameraIP) return } /*for i := range presets { @@ -78,17 +77,17 @@ func (p presetUtility) UsePreset(preset model.CameraPreset) { } cam, err := p.ProvideCamera(lectureHall.CameraType, lectureHall.CameraIP) if err != nil { - log.WithError(err) + logger.Error("Error providing camera", "err", err) return } err = cam.SetPreset(preset.PresetID) if err != nil { - log.WithError(err).Error("UsePreset: unable to set preset for camera") + logger.Error("UsePreset: unable to set preset for camera", "err", err) } } -//TakeSnapshot Creates an image for a preset. Saves it to the disk and database. -//Function is blocking and needs ~20 Seconds to complete! Only call in goroutine. +// TakeSnapshot Creates an image for a preset. Saves it to the disk and database. +// Function is blocking and needs ~20 Seconds to complete! Only call in goroutine. func (p presetUtility) TakeSnapshot(preset model.CameraPreset) { p.UsePreset(preset) time.Sleep(time.Second * 10) @@ -99,18 +98,18 @@ func (p presetUtility) TakeSnapshot(preset model.CameraPreset) { } cam, err := p.ProvideCamera(lectureHall.CameraType, lectureHall.CameraIP) if err != nil { - log.WithError(err) + logger.Error("Error providing camera", "err", err) return } fileName, err := cam.TakeSnapshot(Cfg.Paths.Static) if err != nil { - log.WithField("cam", lectureHall.CameraIP).WithError(err).Error("TakeSnapshot: failed to get camera snapshot") + logger.Error("TakeSnapshot: failed to get camera snapshot", "err", err, "cam", lectureHall.CameraIP) return } preset.Image = fileName err = p.LectureHallDao.SavePreset(preset) if err != nil { - log.WithField("cam", lectureHall.CameraIP).WithError(err).Error("TakeSnapshot: failed to save snapshot file") + logger.Error("TakeSnapshot: failed to save snapshot file", "err", err, "cam", lectureHall.CameraIP) return } } diff --git a/tools/realtime/channel_store.go b/tools/realtime/channel_store.go index 9ed1abf71..eebc67c62 100644 --- a/tools/realtime/channel_store.go +++ b/tools/realtime/channel_store.go @@ -1,7 +1,6 @@ package realtime import ( - log "github.com/sirupsen/logrus" "strings" ) @@ -45,7 +44,7 @@ func (s *ChannelStore) OnMessage(client *Client, message *Message) { return } - log.WithField("channel", message.Channel).Warn("unknown channel on websocket message") + logger.Warn("unknown channel on websocket message", "channel", message.Channel) } func (s *ChannelStore) Subscribe(client *Client, channelPath string) bool { diff --git a/tools/realtime/realtime.go b/tools/realtime/realtime.go index 4b44e3da7..da4372e46 100644 --- a/tools/realtime/realtime.go +++ b/tools/realtime/realtime.go @@ -3,7 +3,6 @@ package realtime import ( "encoding/json" "errors" - log "github.com/sirupsen/logrus" "net/http" ) @@ -86,7 +85,7 @@ func (r *Realtime) messageHandler(c *Client, msg []byte) { var req Message err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal request") + logger.Warn("could not unmarshal request", "err", err) return } @@ -98,6 +97,6 @@ func (r *Realtime) messageHandler(c *Client, msg []byte) { case MessageTypeChannelMessage: r.channels.OnMessage(c, &req) default: - log.WithField("type", req.Type).Warn("unknown pubsub websocket request type") + logger.Warn("unknown pubsub websocket request type", "type", req.Type) } } diff --git a/tools/realtime/realtime_logger.go b/tools/realtime/realtime_logger.go new file mode 100644 index 000000000..229f391e2 --- /dev/null +++ b/tools/realtime/realtime_logger.go @@ -0,0 +1,10 @@ +package realtime + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "realtime") diff --git a/tools/session.go b/tools/session.go index 9231cc794..2d8112010 100644 --- a/tools/session.go +++ b/tools/session.go @@ -3,8 +3,6 @@ package tools import ( "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v4" - log "github.com/sirupsen/logrus" - "time" ) @@ -16,7 +14,7 @@ type SessionData struct { func StartSession(c *gin.Context, data *SessionData) { token, err := createToken(data.Userid, data.SamlSubjectID) if err != nil { - log.WithError(err).Error("Could not create token") + logger.Error("Could not create token", "err", err) return } c.SetCookie("jwt", token, 60*60*24*7, "/", "", CookieSecure, true) diff --git a/tools/template_executor.go b/tools/template_executor.go index f0aa4e6ad..cfc62c5f4 100644 --- a/tools/template_executor.go +++ b/tools/template_executor.go @@ -2,7 +2,6 @@ package tools import ( "github.com/Masterminds/sprig/v3" - log "github.com/sirupsen/logrus" "html/template" "io" ) @@ -22,14 +21,14 @@ func (e DebugTemplateExecutor) ExecuteTemplate(w io.Writer, name string, data in var t, err = template.New("base").Funcs(sprig.FuncMap()).ParseGlob(e.Patterns[0]) if err != nil { - log.Print("Failed to load pattern: '" + e.Patterns[0] + "'. Error: " + err.Error()) + logger.Error("Failed to load pattern: '"+e.Patterns[0], "err", err.Error()) } for i := 1; i < len(e.Patterns); i++ { pattern := e.Patterns[i] _, err := t.ParseGlob(pattern) if err != nil { - log.Print("Failed to load pattern: '" + pattern + "'. Error: " + err.Error()) + logger.Error("Failed to load pattern: '"+pattern+"'.", "err", err.Error()) } } diff --git a/tools/tools_logger.go b/tools/tools_logger.go new file mode 100644 index 000000000..d5f0d766d --- /dev/null +++ b/tools/tools_logger.go @@ -0,0 +1,10 @@ +package tools + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "tools") diff --git a/tools/tum/campus-online-base.go b/tools/tum/campus-online-base.go index b990327e0..7cb8c63b4 100644 --- a/tools/tum/campus-online-base.go +++ b/tools/tum/campus-online-base.go @@ -4,10 +4,9 @@ import ( "context" "errors" "fmt" - "github.com/antchfx/xmlquery" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/antchfx/xmlquery" ) func GetCourseInformation(courseID string, token string) (CourseInfo, error) { @@ -34,7 +33,7 @@ func FetchCourses(daoWrapper dao.DaoWrapper) func() { y, t := GetCurrentSemester() courses, err := daoWrapper.CoursesDao.GetAllCoursesWithTUMIDFromSemester(context.Background(), y, t) if err != nil { - log.WithError(err).Error("Could not get courses with TUM online identifier:", err) + logger.Error("Could not get courses with TUM online identifier:", "err", err) return } FindStudentsForCourses(courses, daoWrapper.UsersDao) diff --git a/tools/tum/courses.go b/tools/tum/courses.go index 9d0b731e5..93ecc870b 100644 --- a/tools/tum/courses.go +++ b/tools/tum/courses.go @@ -7,7 +7,6 @@ import ( "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model/search" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" "strconv" "strings" ) @@ -17,7 +16,7 @@ func PrefetchCourses(dao dao.DaoWrapper) func() { return func() { client, err := tools.Cfg.GetMeiliClient() if err != nil { - log.Info("Skipping course prefetching, reason: ", err) + logger.Info("Skipping course prefetching, reason: ", "err", err) return } @@ -28,16 +27,16 @@ func PrefetchCourses(dao dao.DaoWrapper) func() { for _, org := range *tools.Cfg.Campus.RelevantOrgs { r, err := getCoursesForOrg(org) if err != nil { - log.Error(err) + logger.Error("Error getting courses for organisation "+org, "err", err) } else { res = append(res, r...) } } index := client.Index("PREFETCHED_COURSES") _, err = index.AddDocuments(&res, "courseID") - log.Info(len(res)) + logger.Info(string(rune(len(res)))) if err != nil { - log.WithError(err).Error("issue adding documents to meili") + logger.Error("issue adding documents to meili", "err", err) } } } diff --git a/tools/tum/events.go b/tools/tum/events.go index f56b83f3b..e61eaab2b 100644 --- a/tools/tum/events.go +++ b/tools/tum/events.go @@ -4,12 +4,11 @@ import ( "context" "errors" "fmt" - "github.com/antchfx/xmlquery" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" + "github.com/antchfx/xmlquery" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "strconv" "strings" "time" @@ -32,12 +31,12 @@ func getEventsForCourse(courseID string, token string) (events map[time.Time]Eve start, timeErr1 := time.ParseInLocation("20060102T150405", xmlquery.FindOne(event, "//cor:attribute[@cor:attrID='dtstart']").InnerText(), tools.Loc) end, timeErr2 := time.ParseInLocation("20060102T150405", xmlquery.FindOne(event, "//cor:attribute[@cor:attrID='dtend']").InnerText(), tools.Loc) if timeErr1 != nil || timeErr2 != nil { - log.WithFields(log.Fields{"timeErr1": timeErr1, "timeErr2": timeErr2}).Warn("getEventsForCourse: couldn't parse time") + logger.Warn("getEventsForCourse: couldn't parse time", "timeErr1", timeErr1, "timeErr2", timeErr2) break } eventID64, err := strconv.Atoi(xmlquery.FindOne(event, "//cor:attribute[@cor:attrID='singleEventID']").InnerText()) if err != nil { - log.WithField("TUMOnlineCourseID", courseID).WithError(err).Error("getEventsForCourse: EventID not an int") + logger.Error("getEventsForCourse: EventID not an int", "err", err, "TUMOnlineCourseID", courseID) break } var eventTypeName, status, roomCode, roomName string @@ -91,7 +90,7 @@ func GetEventsForCourses(courses []model.Course, daoWrapper dao.DaoWrapper) { for _, event := range events { stream, err := daoWrapper.StreamsDao.GetStreamByTumOnlineID(context.Background(), event.SingleEventID) if err != nil { // Lecture does not exist yet - log.Info("Adding course") + logger.Info("Adding course") course.Streams = append(course.Streams, model.Stream{ CourseID: course.ID, Start: event.Start, @@ -114,7 +113,7 @@ func GetEventsForCourses(courses []model.Course, daoWrapper dao.DaoWrapper) { } err = daoWrapper.CoursesDao.UpdateCourse(context.Background(), course) if err != nil { - log.WithError(err).WithField("CourseID", course.ID).Warn("Can't update course") + logger.Warn("Can't update course", "err", err, "CourseID", course.ID) } } } diff --git a/tools/tum/students.go b/tools/tum/students.go index 127cb3bf9..f8def6ff8 100644 --- a/tools/tum/students.go +++ b/tools/tum/students.go @@ -3,11 +3,10 @@ package tum import ( "errors" "fmt" - "github.com/antchfx/xmlquery" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/antchfx/xmlquery" ) func FindStudentsForCourses(courses []model.Course, usersDao dao.UsersDao) { @@ -21,12 +20,12 @@ func FindStudentsForCourses(courses []model.Course, usersDao dao.UsersDao) { } } if err != nil { - log.WithError(err).WithField("TUMOnlineIdentifier", courses[i].TUMOnlineIdentifier).Error("FindStudentsForCourses: Can't get Students for course with id") + logger.Error("FindStudentsForCourses: Can't get Students for course with id", "err", err, "TUMOnlineIdentifier", courses[i].TUMOnlineIdentifier) continue } err = usersDao.AddUsersToCourseByTUMIDs(studentIDs, courses[i].ID) if err != nil { - log.WithError(err).Error("FindStudentsForCourses: Can't add users to course") + logger.Error("FindStudentsForCourses: Can't add users to course", "err", err) } } } diff --git a/tools/tum/tum_logger.go b/tools/tum/tum_logger.go new file mode 100644 index 000000000..a7a83d01d --- /dev/null +++ b/tools/tum/tum_logger.go @@ -0,0 +1,10 @@ +package tum + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "tum") diff --git a/vod-service/internal/internal_logger.go b/vod-service/internal/internal_logger.go new file mode 100644 index 000000000..15ff05489 --- /dev/null +++ b/vod-service/internal/internal_logger.go @@ -0,0 +1,10 @@ +package internal + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "internal_vod_service") diff --git a/vod-service/internal/vodService.go b/vod-service/internal/vodService.go index 176a36a76..fdad7827e 100644 --- a/vod-service/internal/vodService.go +++ b/vod-service/internal/vodService.go @@ -3,7 +3,6 @@ package internal import ( "fmt" "io" - "log" "net/http" "os" "os/exec" @@ -22,7 +21,7 @@ type App struct { func NewApp() *App { outputDir := os.Getenv("OUTPUT_DIR") if outputDir == "" { - log.Fatal("OUTPUT_DIR environment variable not set.") + logger.Error("OUTPUT_DIR environment variable not set.") } if !strings.HasSuffix(outputDir, "/") { outputDir += "/" @@ -67,7 +66,7 @@ func (a *App) uploadHandler(w http.ResponseWriter, r *http.Request) { _, err = io.Copy(tempFile, file) if err != nil { - log.Println(err) + logger.Error("Error on io copy", "err", err) return } // write this byte array to our temporary file @@ -82,19 +81,19 @@ func (a *App) packageFile(file, name string) { defer func() { err := os.Remove(file) if err != nil { - log.Printf("Error cleaning up file: %v", err) + logger.Error("Error cleaning up file", "err", err) } }() name = fileNameIllegal.ReplaceAllString(name, "_") // override eventually existing files err := os.RemoveAll(a.config.outputDir + name) if err != nil { - log.Println(err) + logger.Error("Error on removing files", "err", err) // try to continue anyway } err = os.MkdirAll(a.config.outputDir+name, os.ModePerm) if err != nil { - log.Println(err) + logger.Error("Error on creating directories", "err", err) return } c := exec.Command("ffmpeg", diff --git a/web/admin.go b/web/admin.go index 9a7b992f7..63e9fc1dc 100755 --- a/web/admin.go +++ b/web/admin.go @@ -5,13 +5,12 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/tum" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "gorm.io/gorm" "net/http" "regexp" @@ -34,7 +33,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { _ = r.UsersDao.GetAllAdminsAndLecturers(&users) courses, err := r.CoursesDao.GetAdministeredCoursesByUserId(context.Background(), tumLiveContext.User.ID, "", 0) if err != nil { - log.WithError(err).Error("couldn't query courses for user.") + logger.Error("couldn't query courses for user.", "err", err) courses = []model.Course{} } workers, err := r.WorkerDao.GetAllWorkers() @@ -74,7 +73,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "notifications" found, err := r.NotificationsDao.GetAllNotifications() if err != nil { - log.WithError(err).Error("couldn't query notifications") + logger.Error("couldn't query notifications", "err", err) } else { notifications = found } @@ -84,7 +83,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "token" tokens, err = r.TokenDao.GetAllTokens() if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("couldn't query tokens") + logger.Error("couldn't query tokens", "err", err) c.AbortWithStatus(http.StatusInternalServerError) } } @@ -93,7 +92,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "info-pages" infopages, err = r.InfoPageDao.GetAll() if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("couldn't query texts") + logger.Error("couldn't query texts", "err", err) c.AbortWithStatus(http.StatusInternalServerError) } } @@ -101,7 +100,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "serverStats" streams, err := r.StreamsDao.GetAllStreams() if err != nil { - log.WithError(err).Error("Can't get all streams") + logger.Error("Can't get all streams", "err", err) sentry.CaptureException(err) streams = []model.Stream{} } @@ -116,7 +115,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { if res, err := r.ServerNotificationDao.GetAllServerNotifications(); err == nil { serverNotifications = res } else { - log.WithError(err).Warn("could not get all server notifications") + logger.Warn("could not get all server notifications", "err", err) } } semesters := r.CoursesDao.GetAvailableSemesters(c) @@ -137,7 +136,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { Notifications: notifications, }) if err != nil { - log.Printf("%v", err) + logger.Error("Error executing template admin.gohtml", "err", err) } } @@ -155,7 +154,7 @@ func (r mainRoutes) LectureCutPage(c *gin.Context) { } tumLiveContext := foundContext.(tools.TUMLiveContext) if err := templateExecutor.ExecuteTemplate(c.Writer, "lecture-cut.gohtml", tumLiveContext); err != nil { - log.Fatalln(err) + logger.Error("Error executing template lecture-cut.gohtml", "err", err) } } @@ -190,7 +189,7 @@ func (r mainRoutes) CourseStatsPage(c *gin.Context) { indexData.TUMLiveContext = tumLiveContext courses, err := r.CoursesDao.GetAdministeredCoursesByUserId(context.Background(), tumLiveContext.User.ID, "", 0) if err != nil { - log.Printf("couldn't query courses for user. %v\n", err) + logger.Error("couldn't query courses for user.", "err", err) courses = []model.Course{} } semesters := r.CoursesDao.GetAvailableSemesters(c) @@ -203,7 +202,7 @@ func (r mainRoutes) CourseStatsPage(c *gin.Context) { CurT: tumLiveContext.Course.TeachingTerm, }) if err != nil { - log.Printf("%v\n", err) + logger.Error("Error getting available semesters", "err", err) } } @@ -218,20 +217,20 @@ func (r mainRoutes) EditCoursePage(c *gin.Context) { lectureHalls := r.LectureHallsDao.GetAllLectureHalls() err := r.CoursesDao.GetInvitedUsersForCourse(tumLiveContext.Course) if err != nil { - log.Printf("%v", err) + logger.Error("Error getting invited users for course", "err", err) } indexData := NewIndexData() indexData.TUMLiveContext = tumLiveContext courses, err := r.CoursesDao.GetAdministeredCoursesByUserId(context.Background(), tumLiveContext.User.ID, "", 0) if err != nil { - log.Printf("couldn't query courses for user. %v\n", err) + logger.Error("couldn't query courses for user.", "err", err) courses = []model.Course{} } semesters := r.CoursesDao.GetAvailableSemesters(c) for i := range tumLiveContext.Course.Streams { err := tools.SetSignedPlaylists(&tumLiveContext.Course.Streams[i], tumLiveContext.User, true) if err != nil { - log.WithError(err).Error("could not set signed playlist for admin page") + logger.Error("could not set signed playlist for admin page", "err", err) } } err = templateExecutor.ExecuteTemplate(c.Writer, "admin.gohtml", AdminPageData{ @@ -244,7 +243,7 @@ func (r mainRoutes) EditCoursePage(c *gin.Context) { EditCourseData: EditCourseData{IndexData: indexData, IngestBase: tools.Cfg.IngestBase, LectureHalls: lectureHalls}, }) if err != nil { - log.Printf("%v\n", err) + logger.Error("Error executing template admin.gohtml", "err", err) } } diff --git a/web/course.go b/web/course.go index d6c076790..f9fde23ec 100644 --- a/web/course.go +++ b/web/course.go @@ -8,8 +8,6 @@ import ( "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" - "github.com/getsentry/sentry-go" sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" @@ -52,7 +50,7 @@ func (r mainRoutes) editCourseByTokenPage(c *gin.Context) { err = templateExecutor.ExecuteTemplate(c.Writer, "edit-course-by-token.gohtml", d) if err != nil { - log.Println(err) + logger.Error("Error executing template edit-course-by-token.gohtml", "err", err) } } @@ -90,7 +88,7 @@ func (r mainRoutes) optOutPage(c *gin.Context) { } err = templateExecutor.ExecuteTemplate(c.Writer, "opt-out.gohtml", d) if err != nil { - log.WithError(err).Error("can't render template") + logger.Error("can't render template", "err", err) } } @@ -119,7 +117,7 @@ func (r mainRoutes) HighlightPage(c *gin.Context) { return } else { sentry.CaptureException(err) - log.Printf("%v", err) + logger.Error("Error getting current or next lecture for course", "err", err) } description := "" if indexData.TUMLiveContext.Stream != nil { @@ -133,7 +131,7 @@ func (r mainRoutes) HighlightPage(c *gin.Context) { IsHighlightPage: true, } if err = templateExecutor.ExecuteTemplate(c.Writer, "watch.gohtml", d2); err != nil { - log.Printf("%v", err) + logger.Error("Error executing template watch.gohtml", "err", err) return } } @@ -164,7 +162,7 @@ func (r mainRoutes) CoursePage(c *gin.Context) { streamsWithWatchState, err := r.StreamsDao.GetStreamsWithWatchState((*tumLiveContext.Course).ID, (*tumLiveContext.User).ID) if err != nil { sentry.CaptureException(err) - log.WithError(err).Error("loading streamsWithWatchState and progresses for a given course and user failed") + logger.Error("loading streamsWithWatchState and progresses for a given course and user failed", "err", err) } tumLiveContext.Course.Streams = streamsWithWatchState // Update the course streams to contain the watch state. @@ -172,7 +170,7 @@ func (r mainRoutes) CoursePage(c *gin.Context) { for i := range tumLiveContext.Course.Streams { err = tools.SetSignedPlaylists(&tumLiveContext.Course.Streams[i], tumLiveContext.User, false) if err != nil { - log.WithError(err).Warn("Can't sign playlists") + logger.Warn("Can't sign playlists", "err", err) } } @@ -197,7 +195,7 @@ func (r mainRoutes) CoursePage(c *gin.Context) { encoded, err := json.Marshal(clientWatchState) if err != nil { sentry.CaptureException(err) - log.WithError(err).Error("marshalling watched infos for client failed") + logger.Error("marshalling watched infos for client failed", "err", err) } err = templateExecutor.ExecuteTemplate(c.Writer, "course-overview.gohtml", CoursePageData{IndexData: indexData, Course: *tumLiveContext.Course, WatchedData: string(encoded)}) diff --git a/web/index.go b/web/index.go index fbb2f692e..8179ae34a 100644 --- a/web/index.go +++ b/web/index.go @@ -4,13 +4,12 @@ import ( "context" "errors" "github.com/RBG-TUM/commons" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/tum" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "gorm.io/gorm" "html/template" "net/http" @@ -45,7 +44,7 @@ func (r mainRoutes) MainPage(c *gin.Context) { indexData.LoadPinnedCourses() if err := templateExecutor.ExecuteTemplate(c.Writer, "index.gohtml", indexData); err != nil { - log.WithError(err).Errorf("Could not execute template: 'index.gohtml'") + logger.Error("Could not execute template: 'index.gohtml'", "err", err) } } @@ -66,7 +65,7 @@ func (r mainRoutes) InfoPage(id uint, name string) gin.HandlerFunc { text, err := r.InfoPageDao.GetById(id) if err != nil { - log.WithError(err).Error("Could not get text with id") + logger.Error("Could not get text with id", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } @@ -114,7 +113,7 @@ func NewIndexDataWithContext(c *gin.Context) IndexData { tumLiveContext = tumLiveContextQueried.(tools.TUMLiveContext) indexData.TUMLiveContext = tumLiveContext } else { - log.Warn("could not get TUMLiveContext") + logger.Warn("could not get TUMLiveContext") c.AbortWithStatus(http.StatusInternalServerError) } @@ -139,7 +138,7 @@ func (d *IndexData) LoadCurrentNotifications(serverNoticationDao dao.ServerNotif if notifications, err := serverNoticationDao.GetCurrentServerNotifications(); err == nil { d.ServerNotifications = notifications } else if err != gorm.ErrRecordNotFound { - log.WithError(err).Warn("could not get server notifications") + logger.Warn("could not get server notifications", "err", err) } } @@ -174,7 +173,7 @@ func (d *IndexData) LoadSemesters(spanMain *sentry.Span, coursesDao dao.CoursesD func (d *IndexData) LoadLivestreams(c *gin.Context, daoWrapper dao.DaoWrapper) { streams, err := daoWrapper.GetCurrentLive(context.Background()) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("could not get current live streams") + logger.Error("could not get current live streams", "err", err) c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"message": "Could not load current livestream from database."}) } @@ -203,7 +202,7 @@ func (d *IndexData) LoadLivestreams(c *gin.Context, daoWrapper dao.DaoWrapper) { if tumLiveContext.User != nil && tumLiveContext.User.Role == model.AdminType && stream.LectureHallID != 0 { lh, err := daoWrapper.LectureHallsDao.GetLectureHallByID(stream.LectureHallID) if err != nil { - log.WithError(err).Error(err) + logger.Error("Error getting lecture hall by id", "err", err) } else { lectureHall = &lh } diff --git a/web/popup.go b/web/popup.go index d4c1a8eac..f39f6eb0a 100644 --- a/web/popup.go +++ b/web/popup.go @@ -2,10 +2,9 @@ package web import ( "errors" + "github.com/TUM-Dev/gocast/tools" "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" - "github.com/TUM-Dev/gocast/tools" - "log" "net/http" ) @@ -26,6 +25,6 @@ func (r mainRoutes) PopOutChat(c *gin.Context) { err := templateExecutor.ExecuteTemplate(c.Writer, "popup-chat.gohtml", data) if err != nil { - log.Printf("couldn't render template: %v\n", err) + logger.Error("couldn't render template popup-chat.gohtml", "err", err) } } diff --git a/web/router.go b/web/router.go index 90d2faea0..89a6943e8 100755 --- a/web/router.go +++ b/web/router.go @@ -4,16 +4,15 @@ import ( "embed" "fmt" "github.com/getsentry/sentry-go" - log "github.com/sirupsen/logrus" "html/template" "net/http" "os" "path" "github.com/Masterminds/sprig/v3" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" + "github.com/gin-gonic/gin" ) var templateExecutor tools.TemplateExecutor @@ -199,7 +198,7 @@ func (r mainRoutes) home(c *gin.Context) { indexData := NewIndexDataWithContext(c) if err := templateExecutor.ExecuteTemplate(c.Writer, "home.gohtml", indexData); err != nil { - log.WithError(err).Errorf("Could not execute template: 'home.gohtml'") + logger.Error("Could not execute template: 'home.gohtml'", "err", err) } } diff --git a/web/saml.go b/web/saml.go index b38426f05..338894aff 100644 --- a/web/saml.go +++ b/web/saml.go @@ -9,13 +9,12 @@ import ( "net/url" "strings" - "github.com/crewjam/saml" - "github.com/crewjam/saml/samlsp" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/crewjam/saml" + "github.com/crewjam/saml/samlsp" + "github.com/gin-gonic/gin" ) func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { @@ -27,27 +26,27 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { // create saml.ServiceProvider keyPair, err := tls.LoadX509KeyPair(tools.Cfg.Saml.Cert, tools.Cfg.Saml.Privkey) if err != nil { - log.WithError(err).Fatal("Could not load SAML keypair") + logger.Error("Could not load SAML keypair", "err", err) } keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0]) if err != nil { - log.WithError(err).Fatal("Could not parse SAML keypair") + logger.Error("Could not parse SAML keypair", "err", err) } idpMetadataURL, err := url.Parse(tools.Cfg.Saml.IdpMetadataURL) if err != nil { - log.WithError(err).Fatal("Could not parse Identity Provider metadata URL") + logger.Error("Could not parse Identity Provider metadata URL", "err", err) } idpMetadata, err := samlsp.FetchMetadata(context.Background(), http.DefaultClient, *idpMetadataURL) if err != nil { - log.WithError(err).Error("Could not load Identity Provider metadata") + logger.Error("Could not load Identity Provider metadata", "err", err) } var samlSPs []*samlsp.Middleware for _, l := range tools.Cfg.Saml.RootURLs { u, err := url.Parse(l) if err != nil { - log.WithError(err).Error("Could not parse Root URL") + logger.Error("Could not parse Root URL", "err", err) continue } samlSP, err := samlsp.New(samlsp.Options{ @@ -59,7 +58,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { AllowIDPInitiated: true, }) if err != nil { - log.WithError(err).Fatal("Could not create SAML Service Provider") + logger.Error("Could not create SAML Service Provider", "err", err) } samlSP.ServiceProvider.AcsURL = *u samlSPs = append(samlSPs, samlSP) @@ -101,7 +100,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { if err != nil { return } - log.Info("Logout request: ", request) + logger.Info("Logout request: " + request.String()) c.Redirect(http.StatusFound, request.String()) } }) @@ -131,12 +130,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { matrNr = extractSamlField(response, "eduPersonPrincipalName") // MWN id if no matrNr s := strings.Split(matrNr, "@") if len(s) == 0 || s[0] == "" { - log.WithFields(log.Fields{ - "LRZ-ID": lrzID, - "firstName": firstName, - "lastName": lastName, - "mwnID": matrNr, - }).Error("Can't extract mwn id") + logger.Error("Can't extract mwn id", "LRZ-ID", lrzID, "firstName", firstName, "lastName", lastName, "mwnID", matrNr) c.AbortWithStatus(http.StatusInternalServerError) } matrNr = s[0] @@ -149,7 +143,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { } err = daoWrapper.UsersDao.UpsertUser(&user) if err != nil { - log.WithError(err).Error("Could not upsert user") + logger.Error("Could not upsert user", "err", err) c.AbortWithStatus(http.StatusInternalServerError) } HandleValidLogin(c, &tools.SessionData{Userid: user.ID, SamlSubjectID: &subjectID}) diff --git a/web/template/user-settings.gohtml b/web/template/user-settings.gohtml index 135495f1f..7a528301e 100644 --- a/web/template/user-settings.gohtml +++ b/web/template/user-settings.gohtml @@ -34,7 +34,7 @@ -
+
@@ -75,9 +75,10 @@ @change="global.updatePreference(global.UserSetting.Greeting, currentGreeting).then((r) => {err=r;})"> -
+

Playback Speeds

- +
+ +
+

Custom Speeds

+
+ + + + +

Privacy & Data Protection

diff --git a/web/template/video_only.gohtml b/web/template/video_only.gohtml index aeb73f0ea..372d9382f 100644 --- a/web/template/video_only.gohtml +++ b/web/template/video_only.gohtml @@ -75,7 +75,7 @@