package v1 import ( "context" "encoding/json" "fmt" "net/http" "strings" "git.jamestombleson.com/jtom38/newsbot-api/internal/database" "git.jamestombleson.com/jtom38/newsbot-api/internal/domain" "git.jamestombleson.com/jtom38/newsbot-api/internal/domain/models" "github.com/go-chi/chi/v5" "github.com/google/uuid" "github.com/labstack/echo/v4" ) func (s *Handler) GetSourcesRouter() http.Handler { r := chi.NewRouter() return r } type ListSources struct { ApiStatusModel Payload []models.SourceDto `json:"payload"` } type GetSource struct { ApiStatusModel Payload models.SourceDto `json:"payload"` } // ListSources // @Summary Lists the top 50 records // @Produce application/json // @Tags Source // @Router /sources [get] // @Success 200 {object} ListSources "ok" // @Failure 400 {object} ApiError "Unable to reach SQL or Data problems" func (s *Handler) listSources(c echo.Context) error { //TODO Add top? /* top := chi.URLParam(r, "top") topInt, err := strconv.ParseInt(top, 0, 32) if err != nil { panic(err) } res, err := s.Db.ListSources(r.Context(), int32(topInt)) */ p := ListSources{ ApiStatusModel: ApiStatusModel{ StatusCode: http.StatusOK, Message: "OK", }, } // Default way of showing all sources items, err := s.dto.ListSources(c.Request().Context(), 50) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } p.Payload = items return c.JSON(http.StatusOK, p) } // ListSourcesBySource // @Summary Lists the top 50 records based on the name given. Example: reddit // @Param source query string true "Source Name" // @Produce application/json // @Tags Source // @Router /sources/by/source [get] // @Success 200 {object} ListSources "ok" // @Failure 400 {object} ApiError "Unable to query SQL." // @Failure 500 {object} ApiError "Problems with data." func (s *Handler) listSourcesBySource(c echo.Context) error { //TODO Add top? /* top := chi.URLParam(r, "top") topInt, err := strconv.ParseInt(top, 0, 32) if err != nil { panic(err) } res, err := s.Db.ListSources(r.Context(), int32(topInt)) */ p := ListSources{ ApiStatusModel: ApiStatusModel{ StatusCode: http.StatusOK, Message: "OK", }, } source := c.QueryParam("source") // Shows the list by Sources.source res, err := s.dto.ListSourcesBySource(c.Request().Context(), source) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } p.Payload = res return c.JSON(http.StatusOK, p) } // GetSource // @Summary Returns a single entity by ID // @Param id path string true "uuid" // @Produce application/json // @Tags Source // @Router /sources/{id} [get] // @Success 200 {object} GetSource "ok" // @Failure 204 {object} ApiError "No record found." // @Failure 400 {object} ApiError "Unable to query SQL." // @Failure 500 {object} ApiError "Failed to process data from SQL." func (s *Handler) getSources(c echo.Context) error { payload := GetSource{ ApiStatusModel: ApiStatusModel{ Message: "OK", StatusCode: http.StatusOK, }, } id := c.Param("ID") uuid, err := uuid.Parse(id) if err != nil { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: ErrUnableToParseId, }) } res, err := s.dto.GetSourceById(c.Request().Context(), uuid) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: ErrNoRecordFound, }) } payload.Payload = res return c.JSON(http.StatusOK, payload) } // GetSourceByNameAndSource // @Summary Returns a single entity by ID // @Param name query string true "dadjokes" // @Param source query string true "reddit" // @Produce application/json // @Tags Source // @Router /sources/by/sourceAndName [get] // @Success 200 {object} GetSource "ok" // @Failure 204 {object} ApiError "No record found." // @Failure 400 {object} ApiError "Unable to query SQL." // @Failure 500 {object} ApiError "Failed to process data from SQL." func (s *Handler) GetSourceBySourceAndName(c echo.Context) error { p := GetSource{ ApiStatusModel: ApiStatusModel{ Message: "OK", StatusCode: http.StatusOK, }, } var param domain.GetSourceBySourceAndNameParamRequest err := c.Bind(¶m) if err != nil { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: err.Error(), }) } //name := c.QueryParam("name") //if name == "" { // s.WriteError(w, "Parameter 'name' was missing in the query.", http.StatusInternalServerError) // return c.JSON(http.bad) //} //source := query["source"][0] //if source == "" { // s.WriteError(w, "The parameter 'source' was missing in the query.", http.StatusInternalServerError) // return //} item, err := s.dto.GetSourceByNameAndSource(c.Request().Context(), param.Name, param.Source) if err != nil { return c.JSON(http.StatusInternalServerError, err.Error()) } p.Payload = item return c.JSON(http.StatusOK, p) } // NewRedditSource // @Summary Creates a new reddit source to monitor. // @Param name query string true "name" // @Param url query string true "url" // @Tags Source // @Router /sources/new/reddit [post] func (s *Handler) newRedditSource(c echo.Context) error { var param domain.NewSourceParamRequest err := c.Bind(¶m) if err != nil { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: err.Error(), }) } //query := r.URL.Query() //_name := query["name"][0] //_url := query["url"][0] //_tags := query["tags"][0] if param.Url == "" { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: "Url is missing a value", }) } if !strings.Contains(param.Url, "reddit.com") { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: "Invalid URL given", }) } /* var tags string if _tags == "" { tags = fmt.Sprintf("twitch, %v", _name) } else { } */ tags := fmt.Sprintf("twitch, %v", param.Name) params := database.CreateSourceParams{ ID: uuid.New(), Site: "reddit", Name: param.Name, Source: "reddit", Type: "feed", Enabled: true, Url: param.Url, Tags: tags, } err = s.Db.CreateSource(c.Request().Context(), params) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } //s.WriteJson(w, ¶ms) bJson, err := json.Marshal(¶ms) if err != nil { return c.JSON(http.StatusInternalServerError, err.Error()) } return c.JSON(http.StatusOK, bJson) } // NewYoutubeSource // @Summary Creates a new youtube source to monitor. // @Param name query string true "name" // @Param url query string true "url" // @Tags Source // @Router /sources/new/youtube [post] func (s *Handler) newYoutubeSource(c echo.Context) error { var param domain.NewSourceParamRequest err := c.Bind(¶m) if err != nil { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: err.Error(), }) } //query := r.URL.Query() //_name := query["name"][0] //_url := query["url"][0] ////_tags := query["tags"][0] if param.Url == "" { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: "url is missing a value", }) } if !strings.Contains(param.Url, "youtube.com") { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: "Invalid URL", }) } /* if _tags == "" { tags = fmt.Sprintf("twitch, %v", _name) } else { } */ tags := fmt.Sprintf("twitch, %v", param.Name) params := database.CreateSourceParams{ ID: uuid.New(), Site: "youtube", Name: param.Name, Source: "youtube", Type: "feed", Enabled: true, Url: param.Url, Tags: tags, } err = s.Db.CreateSource(context.Background(), params) if err != nil { return c.JSON(http.StatusInternalServerError, err.Error()) } bJson, err := json.Marshal(¶ms) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } return c.JSON(http.StatusOK, bJson) } // NewTwitchSource // @Summary Creates a new twitch source to monitor. // @Param name query string true "name" // @Tags Source // @Router /sources/new/twitch [post] func (s *Handler) newTwitchSource(c echo.Context) error { var param domain.NewSourceParamRequest err := c.Bind(¶m) if err != nil { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: err.Error(), }) } //query := r.URL.Query() //_name := query["name"][0] tags := fmt.Sprintf("twitch, %v", param.Name) _url := fmt.Sprintf("https://twitch.tv/%v", param.Name) params := database.CreateSourceParams{ ID: uuid.New(), Site: "twitch", Name: param.Name, Source: "twitch", Type: "api", Enabled: true, Url: _url, Tags: tags, } err = s.Db.CreateSource(c.Request().Context(), params) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } bJson, err := json.Marshal(¶ms) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } return c.JSON(http.StatusOK, bJson) } // DeleteSource // @Summary Marks a source as deleted based on its ID value. // @Param id path string true "id" // @Tags Source // @Router /sources/{id} [POST] func (s *Handler) deleteSources(c echo.Context) error { id := c.Param("ID") uuid, err := uuid.Parse(id) if err != nil { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: err.Error(), }) } // Check to make sure we can find the record _, err = s.Db.GetSourceByID(c.Request().Context(), uuid) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } // Delete the record err = s.Db.DeleteSource(c.Request().Context(), uuid) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } p := ApiStatusModel{ Message: "OK", StatusCode: http.StatusOK, } b, err := json.Marshal(p) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } return c.JSON(http.StatusOK, b) } // DisableSource // @Summary Disables a source from processing. // @Param id path string true "id" // @Tags Source // @Router /sources/{id}/disable [post] func (s *Handler) disableSource(c echo.Context) error { id := c.Param("ID") uuid, err := uuid.Parse(id) if err != nil { return c.JSON(http.StatusBadRequest, domain.ErrorResponse{ Message: err.Error(), }) } // Check to make sure we can find the record _, err = s.Db.GetSourceByID(c.Request().Context(), uuid) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } err = s.Db.DisableSource(context.Background(), uuid) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } p := ApiStatusModel{ Message: "OK", StatusCode: http.StatusOK, } b, err := json.Marshal(p) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } return c.JSON(http.StatusOK, b) } // EnableSource // @Summary Enables a source to continue processing. // @Param id path string true "id" // @Tags Source // @Router /sources/{id}/enable [post] func (s *Handler) enableSource(c echo.Context) error { id := c.Param("ID") uuid, err := uuid.Parse(id) if err != nil { return c.JSON(http.StatusBadRequest, err.Error()) } // Check to make sure we can find the record _, err = s.Db.GetSourceByID(c.Request().Context(), uuid) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } err = s.Db.EnableSource(c.Request().Context(), uuid) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } p := ApiStatusModel{ Message: "OK", StatusCode: http.StatusOK, } b, err := json.Marshal(p) if err != nil { return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ Message: err.Error(), }) } return c.JSON(http.StatusOK, b) }