From 8f0de04ec7ed6cba88059542d1b4b94a2bc12add Mon Sep 17 00:00:00 2001 From: gempir Date: Sat, 8 Oct 2022 20:56:52 +0200 Subject: [PATCH] implement available logs endpoint for channels #173 --- api/server.go | 5 ++++ api/user.go | 21 ++++++++++++-- filelog/userlog.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/api/server.go b/api/server.go index b1da124..03551c2 100644 --- a/api/server.go +++ b/api/server.go @@ -82,6 +82,11 @@ type logList struct { AvailableLogs []filelog.UserLogFile `json:"availableLogs"` } +// swagger:model +type channelLogList struct { + AvailableLogs []filelog.ChannelLogFile `json:"availableLogs"` +} + type chatMessage struct { Text string `json:"text"` Username string `json:"username"` diff --git a/api/user.go b/api/user.go index 8124425..78fb82b 100644 --- a/api/user.go +++ b/api/user.go @@ -75,7 +75,7 @@ func (s *Server) getRandomQuote(request logRequest) (*chatLog, error) { // swagger:route GET /list logs list // -// Lists available logs of a user +// Lists available logs of a user or channel, channel response also includes the day. OpenAPI 2 does not support multiple responses with the same http code right now. // // Produces: // - application/json @@ -86,9 +86,24 @@ func (s *Server) getRandomQuote(request logRequest) (*chatLog, error) { // Responses: // 200: logList func (s *Server) writeAvailableLogs(w http.ResponseWriter, r *http.Request, q url.Values) { - logs, err := s.fileLogger.GetAvailableLogsForUser(q.Get("channelid"), q.Get("userid")) + channelid := q.Get("channelid") + userid := q.Get("userid") + + if userid == "" { + logs, err := s.fileLogger.GetAvailableLogsForChannel(channelid) + if err != nil { + http.Error(w, "failed to get available channel logs: "+err.Error(), http.StatusNotFound) + return + } + + writeCacheControl(w, r, time.Hour) + writeJSON(&channelLogList{logs}, http.StatusOK, w, r) + return + } + + logs, err := s.fileLogger.GetAvailableLogsForUser(channelid, userid) if err != nil { - http.Error(w, "failed to get available logs: "+err.Error(), http.StatusNotFound) + http.Error(w, "failed to get available user logs: "+err.Error(), http.StatusNotFound) return } diff --git a/filelog/userlog.go b/filelog/userlog.go index 2bf0733..d47060a 100644 --- a/filelog/userlog.go +++ b/filelog/userlog.go @@ -194,6 +194,74 @@ func (l *Logger) GetAvailableLogsForUser(channelID, userID string) ([]UserLogFil return logFiles, errors.New("No logs file") } +type ChannelLogFile struct { + path string + Year string `json:"year"` + Month string `json:"month"` + Day string `json:"day"` +} + +func (l *Logger) GetAvailableLogsForChannel(channelID string) ([]ChannelLogFile, error) { + if channelID == "" { + return []ChannelLogFile{}, fmt.Errorf("Invalid channelID: %s", channelID) + } + + logFiles := []ChannelLogFile{} + + years, _ := ioutil.ReadDir(l.logPath + "/" + channelID) + + for _, yearDir := range years { + year := yearDir.Name() + months, _ := ioutil.ReadDir(l.logPath + "/" + channelID + "/" + year + "/") + for _, monthDir := range months { + month := monthDir.Name() + + days, _ := ioutil.ReadDir(l.logPath + "/" + channelID + "/" + year + "/" + month + "/") + for _, dayDir := range days { + day := dayDir.Name() + path := fmt.Sprintf("%s/%s/%s/%s/%s/channel.txt", l.logPath, channelID, year, month, day) + + if _, err := os.Stat(path); err == nil { + logFile := ChannelLogFile{path, year, month, day} + logFiles = append(logFiles, logFile) + } else if _, err := os.Stat(path + ".gz"); err == nil { + logFile := ChannelLogFile{path + ".gz", year, month, day} + logFiles = append(logFiles, logFile) + } + } + } + } + + sort.Slice(logFiles, func(i, j int) bool { + yearA, _ := strconv.Atoi(logFiles[i].Year) + yearB, _ := strconv.Atoi(logFiles[j].Year) + monthA, _ := strconv.Atoi(logFiles[i].Month) + monthB, _ := strconv.Atoi(logFiles[j].Month) + dayA, _ := strconv.Atoi(logFiles[j].Day) + dayB, _ := strconv.Atoi(logFiles[j].Day) + + if yearA == yearB { + if monthA == monthB { + return dayA > dayB + } + + return monthA > monthB + } + + if monthA == monthB { + return dayA > dayB + } + + return yearA > yearB + }) + + if len(logFiles) > 0 { + return logFiles, nil + } + + return logFiles, errors.New("No logs file") +} + // ReadLogForUser fetch logs func (l *Logger) ReadLogForUser(channelID, userID string, year string, month string) ([]string, error) { if channelID == "" || userID == "" {